diff options
author | bms <bms@FreeBSD.org> | 2006-09-29 10:40:53 +0000 |
---|---|---|
committer | bms <bms@FreeBSD.org> | 2006-09-29 10:40:53 +0000 |
commit | 8405ff182feb5e479edb4b36b3345b5e9c1c0d84 (patch) | |
tree | e56d5fc72f962232dc433104ccb2a45a0f4e3069 /usr.sbin | |
parent | 24cf9e1f8fb00ed9b939aa764555a29d30afc353 (diff) | |
download | FreeBSD-src-8405ff182feb5e479edb4b36b3345b5e9c1c0d84.zip FreeBSD-src-8405ff182feb5e479edb4b36b3345b5e9c1c0d84.tar.gz |
Remove mrouted from -CURRENT.
Discussed with: fenner, net@
Diffstat (limited to 'usr.sbin')
43 files changed, 0 insertions, 18634 deletions
diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE deleted file mode 100644 index ef7da47..0000000 --- a/usr.sbin/mrouted/LICENSE +++ /dev/null @@ -1,48 +0,0 @@ - -The mrouted program is covered by the following license. Use of the -mrouted program represents acceptance of these terms and conditions. - -1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license -to use, copy and modify the computer software ``mrouted'' (hereinafter -called the ``Program''), upon the terms and conditions hereinafter set -out and until Licensee discontinues use of the Licensed Program. - -2. LICENSEE acknowledges that the Program is a research tool still in -the development state, that it is being supplied ``as is,'' without any -accompanying services from STANFORD, and that this license is entered -into in order to encourage scientific collaboration aimed at further -development and application of the Program. - -3. LICENSEE may copy the Program and may sublicense others to use object -code copies of the Program or any derivative version of the Program. -All copies must contain all copyright and other proprietary notices found -in the Program as provided by STANFORD. Title to copyright to the -Program remains with STANFORD. - -4. LICENSEE may create derivative versions of the Program. LICENSEE -hereby grants STANFORD a royalty-free license to use, copy, modify, -distribute and sublicense any such derivative works. At the time -LICENSEE provides a copy of a derivative version of the Program to a -third party, LICENSEE shall provide STANFORD with one copy of the source -code of the derivative version at no charge to STANFORD. - -5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. -By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION -OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR -THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS, -COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable -for any liability nor for any direct, indirect or consequential damages -with respect to any claim by LICENSEE or any third party on account of or -arising from this Agreement or use of the Program. - -6. This agreement shall be construed, interpreted and applied in -accordance with the State of California and any legal action arising -out of this Agreement or use of the Program shall be filed in a court -in the State of California. - -7. Nothing in this Agreement shall be construed as conferring rights to -use in advertising, publicity or otherwise any trademark or the name -of ``Stanford''. - -The mrouted program is COPYRIGHT 1989 by The Board of Trustees of -Leland Stanford Junior University. diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile deleted file mode 100644 index 43fe8b1..0000000 --- a/usr.sbin/mrouted/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# $FreeBSD$ - -SUBDIR= common mrouted mrinfo map-mbone mtrace testrsrr - -.include <bsd.subdir.mk> diff --git a/usr.sbin/mrouted/Makefile.inc b/usr.sbin/mrouted/Makefile.inc deleted file mode 100644 index 6ecd80d..0000000 --- a/usr.sbin/mrouted/Makefile.inc +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -CFLAGS+= -DRSRR -Dlog=logit - -LIBMROUTED= ${.OBJDIR}/../common/libmrouted.a - -.include "../Makefile.inc" diff --git a/usr.sbin/mrouted/RELEASE b/usr.sbin/mrouted/RELEASE deleted file mode 100644 index 9790650..0000000 --- a/usr.sbin/mrouted/RELEASE +++ /dev/null @@ -1,493 +0,0 @@ -README-3.9-beta3.mrouted,v 1.1.2.1 1998/03/01 03:00:20 fenner Exp - - IP Multicast Extensions for BSD-Derived Unix Systems - Multicast Routing Daemon - - Release 3.9-beta3 - February 28, 1998 - - available from parcftp.xerox.com, - file pub/net-research/ipmulti/beta-test/mrouted3.9-beta3.tar.Z - binaries: - pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sparc-sunos41x.tar.Z - pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sparc-solaris2.tar.Z - pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-i386-freebsd22.tar.Z - pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-alpha-osf1.tar.Z - pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sgi-irix6.tar.Z - -Note: The 3.9 release is mrouted-only, and will run on top of a 3.5 kernel. -It is a drop-in replacement for mrouted 3.5, 3.6, 3.7 or 3.8. - -NOTE WELL: This is a beta-test release of mrouted. The basic -functionality has been extensively tested in CAIRN and other -testbeds, but it is expected to have bugs. Please report bugs to Bill -Fenner <fenner@parc.xerox.com>. - - -The 3.9-beta3 release fixes the following bugs: - o There was a bug handling routing updates which caused random black - holes. - - o There was a race condition in the timer handlers causing free'd memory - to sometimes get touched. - - o "allow_nonpruners" wasn't allowed in the configuration file (and almost - nobody noticed! - probably a good sign) - - o When a prune times out and the source has been active "recently", - mrouted now waits for further traffic instead of triggering a new - prune. - - o mrouted now ignores unreachable routes when making a routing decision - (previously it would blackhole, now it can find a less-specific) - -The 3.9-beta3 release has the following new features: - o A "blaster" keyword for mrouted.conf, to turn on handling of routers - (mostly ciscos) which overwhelm the socket buffers by blasting the - whole routing table at once. - - o A "notransit" keyword; routes learned on a "notransit" vif will not be - readvertised onto another "notransit" vif. - - o The 500kbps default rate limit on tunnels has been removed. - - o An ICMP listener which logs ICMP errors which appear to be in response to - tunnel packets that we sent. - - o A tunnel traffic encapsulator, which encapsulates control traffic - inside the tunnel instead of unicasting it "beside" the tunnel. - This is turned off by default; use "beside off" to turn it on. - - o A "force_leaf" flag to ignore any potential neighbors on a given interface. - - -========= -3.9-beta2 -June 11, 1997 - -The 3.9-beta2 release fixes the following bugs: - o There was a bug in 3.9-beta1's raw socket buffer processing that - would cause an immediate lockup on startup on some systems. - - o RSRR would not clear out the group membership information if - further notification of changes to this route entry was not possible. - -There is no need to upgrade to 3.9-beta2 if you are not experiencing -one of the aforementioned bugs. - -========= -3.9-beta1 -June 6, 1997 - -The 3.9-beta1 release has the following known bugs: - - o The startup message doesn't print properly if you have too many - interfaces. - -The 3.9-beta1 release fixes the following bugs: - - o mrouted did not properly keep track of subordinates, and would not - time out subordinateness. This caused 2 major problems: - 1. pruning did not happen when there were equal-cost paths to - the same multi-access link - 2. subordinateness which did not get cancelled by a non-poisoned - route (e.g. in the face of route filtering) did not time out, - causing traffic to continue to flow. - - o mrouted's IGMPv2 processing when it is not the querier now - conforms to draft-ietf-idmr-igmp-v2-06.txt Thanks to Lorenzo - VICISANO <L.Vicisano@cs.ucl.ac.uk> for finding a problem. - - o mrouted is much more careful about forgetting prunes; 3.8 - would forget prunes whenever any route change ocurred. - -The 3.9-beta1 release has the following new features: - - o Longer prune lifetimes (2 hours) by default. Prune lifetimes may - be configured per-vif, with the "prune_lifetime N" mrouted.conf - configuration file entry (where N is in seconds). This helps to - work around the black holes caused on restart when you have a Cisco - upstream which does not handle genid's; if this is your situation - the recommended value is 300. - - o mrouted's behavior of flooding new routes by default at startup - in order to speed healing of paths during startup can be turned off - per-vif or globally with the "noflood" configuration option. - Turning this option off means you are likely to experience - black holes for a minute or two when you restart a router. The - default is to flood for a minute or two until mrouted is able to - learn subordinate relationships. - - o mrouted now retransmits prunes by default on point-to-point links. - prune retransmission can be turned on or off per vif via the - "rexmit_prunes [on|off]" mrouted.conf command. Prune retransmission - helps on lossy links, and also helps when a router has forgotten - about a prune (e.g. if it is out of memory and needs to shed state, - or due to a bug). - - o The new "passive" mode causes mrouted to not actively send probes - looking for neighbors. This allows a dialup link to become quiescent - if there is no DVMRP neighbor on the other end. Configuring - "passive" on both ends of a link will cause it to never come up. - - o mrouted defaults to not peering with DVMRP routers that do not - prune. Use the "allow_nonpruners" mrouted.conf option on a vif - on which you want to allow such peerings. - - o mrouted now allows route filtering. mrouted.conf syntax: - accept 13/8 - - accepts all routes matching 13/8 (e.g. accepts - 13.2.116/22). If you want to accept only exactly - 13/8, use - - accept 13/8 exact - - deny 10/8 64/2 130/8 exact 172/8 exact - - denies some common MBone martians - - Only "accept" or "deny" is allowed, no combinations. - - Add "bidir" to apply the filter to output too, otherwise - it's input only. - - Expected usage: - - Providers filter routes that customers send them - - Martian removal - - Topology modification (e.g. don't let the existence of - private tunnel foo out into the world). - - - o mrouted now malloc's the buffer it uses for SIOCGIFCONF, to allow - for more interfaces. Thanks to Danny Mitzel - - o mrouted now ignores multiple entries for a single interface - name (temporary hack until mrouted understands interface aliases) - - o mrouted's "-d" flag has been modified to accept the names of the - systems which you would like to debug. - packet, prunes, routes, peers, cache, timeout, interface, - membership, traceroute, igmp - - o mrouted now times neighbors out fater, and fully detects and - ignores routes from one-way peerings. - - o mrouted's route processing has been sped up, especially at startup. - - o mrouted uses the biggest SO_RCVBUF the operating system allows - (up to 256Kbytes) - - o mrouted uses TOS 0xc0 ("Internet Control") for DVMRP messages. - -=========== -Release 3.8 -November 29, 1995 - -The 3.8 release fixes the following bugs: - - o mrouted would fail to forget prunes when a neighbor went away, - thus potentially sending traffic down a tunnel after the tunnel - endpoint has gone down. This was due to some research code making - it into the "emergency" 3.7 release, sigh. - - o mrouted could send prunes with negative lifetimes. This causes - slightly higher prune traffic but shouldn't be any major problem. - -=========== -Release 3.7 -November 28, 1995 - -The 3.7 release fixes the following bugs: - - o mrouted now ignores route reports that include bogus netmasks. - There was a bug in 3.5 that would mangle default routes into - tens of bogus routes; this should prevent that bug from killing - the MBONE. - - This solution can cause route flaps and black holes until the - 3.5's are gone or all of the 3.5's neighbors are 3.7 . - - o mrouted now ignores duplicate routes. Ciscos and the above 3.5 - bug could cause two copies of the same route to appear in a single - routing update; mrouted would insert two copies of the same route - into its routing table and wreak all sorts of havoc. - - o mrouted now sends a group-specific query for both retransmissions - of a g-s query; previous versions sent a general query the second - time. - - o mrouted now loops back multicasted mtrace responses and - group-specific membership queries - - o mrouted now performs deterministic tiebreaking between two - neighbors on the same vif. - - o mrouted now only does duplicate suppression on traceroute requests, - not all traceroute packets, so that a loop can be nicely detected - via a duplicate router instead of just a timeout. - - o the buffer size that mrouted uses has been increased to allow - more than 16 hops in mtrace messages. - - o mtrace's hop-by-hop termination is now more likely to be correct. - - o mrinfo now waits for the responses to its retransmitted queries. - -The 3.7 release has the following new features: - - o The configuration file can accept a hostname as the other end - of a tunnel. There must be a single name->ip mapping for the - given name, however, or mrouted will fail to start up. - - o mrinfo now sends requests to all interfaces of a multihomed host. - - o mtrace's passive mode has been implemented. - - o The first screen of mtrace statistics is shorter and more likely - to fit on one screen. - -=========== -Release 3.6 -June 26, 1995 - -The 3.6 release fixes the following bugs: - - o mrouted would dump core when attempting to report no routes (i.e. upon - startup, if you have no enabled phyint's) - - o mrouted would dump core if requested to traceroute a source for which it - had no route - - o neighbor flags were not always properly updated on probe or report - - o mrouted would sometimes reply to a multicast traceroute on a disabled - phyint; now it uses the first configured phyint to reply to traceroutes. - - o host routes (i.e. netmask 0xffffffff) works now; it was discarding - IGMP from the host because it was coming from the "broadcast address" - of the subnet. - - o send_igmp() now treats the failure to send an mtrace or a neighbor - reply as informational, as opposed to warning. - - o mrouted would go into an infinite loop trying to respond to a traceroute - for a source with a netmask of 0xffffffff. - - o vifs_with_neighbors was not being reset if the mrouted was restarted - with SIGHUP - - o the default route was not being properly advertised to neighbors (although - it was accepted if it was advertised to it) - - o ANSI-fication for those who it helps, still-K&R-ish for those it doesn't. - - o mtrace now attempts to trace three hops past a non-responding router, - in the hopes that it does support traceroute but just couldn't respond - (i.e. unicast didn't work and it can't source multicast because all its - phyints are disabled). - - o mrinfo now times out even on a multicast router. - - -=========== -Release 3.5 -May 8, 1995 - -The 3.5 release has the following new features: - - o The kernel and mrouted make sure that each is the correct version, to - prevent problems with mismatched kernel/mrouted versions. A too-old - mrouted will die with the error: - - can't enable DVMRP routing in kernel: Option not supported by protocol - - o mrouted can accept and propogate a default route (essential for - heirarchical multicast routing) - - o Kernel route cache keeps source-specific routes instead of subnet routes, - eliminating hashing and longest-match problems. - (allows classless routing, longest-match and default routing) - - o Cached kernel routes only get deleted if no traffic is flowing, to - facilitate multicast traceroute - - o mrouted has a new configuration file parser, which provides better error - messages than before, and allows named boundaries (see man page) - - o added "netmask" to phyint configuration, at the suggestion of - Anders Klemets - - o System V and FreeBSD compatibility from John Brezak <brezak@ch.hp.com> - - o phyint's can have additional subnets configured, for people with - multiple subnets on one physical network. mrouted.conf syntax is - altnet 1.2.3.0, or altnet 1.2.3.0/24 if you need to specify - a different netmask. There can be as many altnet statements - as you need. - - o both mrouted and the kernel now support classless addresses. - - o the kernel supports PIM assert processing by notifying the router - when a packet arrives on the wrong interface - - o the kernel keeps additional counters, and mrouted can be compiled to - support SNMP and the Multicast MIB - - o the packet classifier in the kernel now uses the following udp port - ranges: - [0, 16384) - lowest priority, unclassified - [16384, 32768) - highest priority, i.e. audio - [32768, 49152) - medium priority, i.e. whiteboard - [49152, 65536) - low priority, i.e. video - A future release of a session directory will allocate ports in these - ranges. - - o the configuration code has been modified to default tunnels' rate_limit - parameters to 500kbps. This is easily modified with a rate_limit keyword - in mrouted.conf, but should be a good default for the MBONE in general. - - o The tunnel sending code now caches a route for ip_output(), this should - help performance on machines with lots of tunnels. - - o Dispatching for de-capsulating packets is now via protosw[], making - reception of other raw protocols more efficient - - o Neighbor capabilities are discovered via a bitmask as opposed to - version number. - - o Multicast traceroute code improved - - o mrouted can be compiled with Routing Support for Resource Reservation - (RSRR), required for RSVP. - - -The 3.5 release fixes the following bugs: - - o The IGMPv2 query timeout field was interpreted as being in units of - 200ms as opposed to 100ms, thus the maximum timeout was set to twice - the expected value. This is not fatal, as mrouted always queries - twice in the expectation that a packet could get loss, but it does - make it less robust in the face of packet loss. - - o IGMP could report membership in local-only groups (i.e. 224.0.0.X) - - o IGMP could get confused by hearing its own new membership reports, thus - a router would never perform fast leave. - - o IGMP could reset timers for the wrong interface. - - o mrouted put a bogus value in the maximum timeout field of IGMPv2 query - packets. - - o Non-querier mrouters would respond to IGMP leave messages - - o mrouted was not performing fast leave properly - - o If the last member goes away on a transit network, the upstream router - would stop forwarding even if there are downstream members. - - o Kernel hash function improved - - o Eliminated possibility of panic(): timeout in cache maintenance - - o Reordered resource allocation when sending upcall to handle failure properly - - o some endian-ness bugs squashed in mrouted, probably more to go. - - o Multicast traceroute could send a reply on a disabled interface. - - -This release consists of the following files: - - - README-3.8.mrouted - this file - - mrouted/* - version 3.8 of mrouted, - mrinfo, map-mbone and - mtrace. - - ifconfig/* - Changes to ifconfig to - show multicast interfaces - - netstat/* - Diffs to netstat - - ping/* - sources for ping - which support - multicasting - - mtest/* - utility for testing - multicast group - membership - - -MROUTED 3.8 - -Mrouted 3.8 has two optional features: SNMP and RSRR. RSRR support -is required for running RSVP; the SNMP code, with the help of the -ISODE snmpd, implements both the Multicast MIB and the DVMRP MIB. - -RSRR ----- -Routing Support for Resource Reservations (RSRR) was contributed by -Daniel Zappala <daniel@isi.edu>. - -To enable RSRR support, uncomment the three lines starting with -RSRR near the top of the Makefile and "make clean; make". Or use -the prebuilt binary, mrouted.rsrr . - -RSRR allows RSVP to query mrouted for its routing entry for a particular -source-group pair. Using the routing entry and the IP_MULTICAST_VIF -socket call, RSVP can forward distinct control messages out each -outgoing interface. This version of mrouted supports RSRR messages -using a Unix datagram socket. - -RSRR currently includes two pairs of query-reply messages. RSVP sends -an Initial Query when it starts. Mrouted responds with an Initial Reply -that includes the set of vifs it is using, flagging those that are -administratively disabled. When RSVP needs the routing entry for a -source-group pair, it sends a Route Query. Mrouted responds with a -Route Reply that includes the incoming vif and outgoing vifs for the -source-group pair. - -RSVP may request route change notification by setting the notification -bit in the Route Query. If mrouted can provide route change -notification for the source-group pair, it sets the notification bit in -its Route Reply. When the routing entry for the source-group pair -changes, mrouted sends an unsolicited Route Reply containing the new -routing information. The initial release of mrouted 3.5 did not support -route change notification and always returned a Route Reply with the -notification bit cleared. This release of mrouted provides route change -notification when possible. - -SNMP ----- -SNMP support was contributed by David Thaler <thalerd@eecs.umich.edu>. - -To enable SNMP support, uncomment the six lines near the top of -the Makefile below the description of SNMP support, or use the -prebuilt binary, mrouted.snmp or mrouted.rsrr.snmp . - -To link the SNMP-capable mrouted, you need the CMU libraries. -See http://nic.merit.edu/~mbone/ for a full mrouted-snmp distribution. - -Make sure to add the "sysName", "sysContact", "sysVersion" and -"sysLocation" variables to your /etc/mrouted.conf if you want them -to provide anything other than default values. - -Example: - -sysName "tibia" -sysContact "Bill Fenner <fenner@parc.xerox.com> +1 415 812-4816" -sysVersion "SunOS 4.1.3 and mrouted 3.8" -sysLocation "MAXC room, PARC building 35" - -The SNMP version of mrouted has an additional command line flag: - - -P snmp_port - - Specifies a port for SNMP communication (default 161). This option - should be used when another SNMP daemon already exists. The - preferred alternate port in this case is port 9161. - -The mstat(8) program allows querying of statistics using SNMP. diff --git a/usr.sbin/mrouted/VERSION b/usr.sbin/mrouted/VERSION deleted file mode 100644 index a0ba149..0000000 --- a/usr.sbin/mrouted/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.9-beta3+IOS12 diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c deleted file mode 100644 index 8b8ea9c..0000000 --- a/usr.sbin/mrouted/callout.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * callout.c,v 3.8.4.8 1998/01/06 01:58:45 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -/* the code below implements a callout queue */ -static int id = 0; -static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */ - -struct timeout_q { - struct timeout_q *next; /* next event */ - int id; - cfunc_t func; /* function to call */ - void *data; /* func's data */ - int time; /* time offset to next event*/ -}; - -#ifdef IGMP_DEBUG -static void print_Q __P((void)); -#else -#define print_Q() -#endif - -void -callout_init() -{ - Q = (struct timeout_q *) 0; -} - -void -free_all_callouts() -{ - struct timeout_q *p; - - while (Q) { - p = Q; - Q = Q->next; - free(p); - } -} - - -/* - * elapsed_time seconds have passed; perform all the events that should - * happen. - */ -void -age_callout_queue(elapsed_time) - int elapsed_time; -{ - struct timeout_q *ptr; - int i = 0; - - for (ptr = Q; ptr; ptr = Q, i++) { - if (ptr->time > elapsed_time) { - ptr->time -= elapsed_time; - return; - } else { - elapsed_time -= ptr->time; - Q = Q->next; - IF_DEBUG(DEBUG_TIMEOUT) - log(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i); - if (ptr->func) - ptr->func(ptr->data); - free(ptr); - } - } -} - -/* - * Return in how many seconds age_callout_queue() would like to be called. - * Return -1 if there are no events pending. - */ -int -timer_nextTimer() -{ - if (Q) { - if (Q->time < 0) { - log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", - Q->time); - return 0; - } - return Q->time; - } - return -1; -} - -/* - * sets the timer - */ -int -timer_setTimer(delay, action, data) - int delay; /* number of units for timeout */ - cfunc_t action; /* function to be called on timeout */ - void *data; /* what to call the timeout function with */ -{ - struct timeout_q *ptr, *node, *prev; - int i = 0; - - /* create a node */ - node = (struct timeout_q *)malloc(sizeof(struct timeout_q)); - if (node == 0) { - log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n"); - return -1; - } - node->func = action; - node->data = data; - node->time = delay; - node->next = 0; - node->id = ++id; - - prev = ptr = Q; - - /* insert node in the queue */ - - /* if the queue is empty, insert the node and return */ - if (!Q) - Q = node; - else { - /* chase the pointer looking for the right place */ - while (ptr) { - - if (delay < ptr->time) { - /* right place */ - - node->next = ptr; - if (ptr == Q) - Q = node; - else - prev->next = node; - ptr->time -= node->time; - print_Q(); - IF_DEBUG(DEBUG_TIMEOUT) - log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i); - return node->id; - } else { - /* keep moving */ - - delay -= ptr->time; node->time = delay; - prev = ptr; - ptr = ptr->next; - } - i++; - } - prev->next = node; - } - print_Q(); - IF_DEBUG(DEBUG_TIMEOUT) - log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i); - return node->id; -} - -/* returns the time until the timer is scheduled */ -int -timer_leftTimer(timer_id) - int timer_id; -{ - struct timeout_q *ptr; - int left = 0; - - if (!timer_id) - return -1; - - for (ptr = Q; ptr; ptr = ptr->next) { - left += ptr->time; - if (ptr->id == timer_id) - return left; - } - return -1; -} - -/* clears the associated timer. Returns 1 if succeeded. */ -int -timer_clearTimer(timer_id) - int timer_id; -{ - struct timeout_q *ptr, *prev; - int i = 0; - - if (!timer_id) - return 0; - - prev = ptr = Q; - - /* - * find the right node, delete it. the subsequent node's time - * gets bumped up - */ - - print_Q(); - while (ptr) { - if (ptr->id == timer_id) { - /* got the right node */ - - /* unlink it from the queue */ - if (ptr == Q) - Q = Q->next; - else - prev->next = ptr->next; - - /* increment next node if any */ - if (ptr->next != 0) - (ptr->next)->time += ptr->time; - - if (ptr->data) - free(ptr->data); - IF_DEBUG(DEBUG_TIMEOUT) - log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i); - free(ptr); - print_Q(); - return 1; - } - prev = ptr; - ptr = ptr->next; - i++; - } - IF_DEBUG(DEBUG_TIMEOUT) - log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i); - print_Q(); - return 0; -} - -#ifdef IGMP_DEBUG -/* - * debugging utility - */ -static void -print_Q() -{ - struct timeout_q *ptr; - - IF_DEBUG(DEBUG_TIMEOUT) - for (ptr = Q; ptr; ptr = ptr->next) - log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time); -} -#endif /* IGMP_DEBUG */ diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y deleted file mode 100644 index 9ab1f62..0000000 --- a/usr.sbin/mrouted/cfparse.y +++ /dev/null @@ -1,927 +0,0 @@ -%{ -/* - * Configuration file parser for mrouted. - * - * Written by Bill Fenner, NRL, 1994 - * - * $FreeBSD$ - * cfparse.y,v 3.8.4.30 1998/03/01 01:48:58 fenner Exp - */ -#include <stdio.h> -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif -#include "defs.h" -#include <netdb.h> -#include <ifaddrs.h> - -/* - * Local function declarations - */ -static void fatal __P((char *fmt, ...)) __printflike(1, 2); -static void warn __P((char *fmt, ...)) __printflike(1, 2); -static void yyerror __P((char *s)); -static char * next_word __P((void)); -static int yylex __P((void)); -static u_int32 valid_if __P((char *s)); -static const char * ifconfaddr(u_int32_t a); -int yyparse __P((void)); - -static FILE *f; - -char *configfilename = _PATH_MROUTED_CONF; - -extern int cache_lifetime; -extern int prune_lifetime; - -/* imported from config.c, with slight memory leak */ -extern struct ifconf ifc; - -int allow_black_holes = 0; - -static int lineno; - -static struct uvif *v; - -static int order, state; -static int noflood = 0; -static int rexmit = VIFF_REXMIT_PRUNES; - -struct addrmask { - u_int32 addr; - int mask; -}; - -struct boundnam { - char *name; - struct addrmask bound; -}; - -#define MAXBOUNDS 20 - -struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */ -int numbounds = 0; /* Number of named boundaries */ - -%} - -%union -{ - int num; - char *ptr; - struct addrmask addrmask; - u_int32 addr; - struct vf_element *filterelem; -}; - -%token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD -%token PHYINT TUNNEL NAME -%token DISABLE IGMPV1 SRCRT BESIDE -%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC -%token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2 -%token PASSIVE ALLOW_NONPRUNERS -%token NOTRANSIT BLASTER FORCE_LEAF -%token PRUNE_LIFETIME2 NOFLOOD2 -%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION -%token <num> BOOLEAN -%token <num> NUMBER -%token <ptr> STRING -%token <addrmask> ADDRMASK -%token <addr> ADDR - -%type <addr> interface addrname -%type <addrmask> bound boundary addrmask -%type <filterelem> filter filtlist filtelement filtelem - -%start conf - -%% - -conf : stmts - ; - -stmts : /* Empty */ - | stmts stmt - ; - -stmt : error - | PHYINT interface { - - vifi_t vifi; - - state++; - - if (order) - fatal("phyints must appear before tunnels"); - - for (vifi = 0, v = uvifs; - vifi < numvifs; - ++vifi, ++v) - if (!(v->uv_flags & VIFF_TUNNEL) && - $2 == v->uv_lcl_addr) - break; - - if (vifi == numvifs) - fatal("%s is not a configured interface", - inet_fmt($2,s1)); - - } - ifmods - | TUNNEL interface addrname { - const char *ifname; - struct ifreq ffr; - vifi_t vifi; - - order++; - - ifname = ifconfaddr($2); - if (ifname == 0) - fatal("Tunnel local address %s is not mine", - inet_fmt($2, s1)); - - if (((ntohl($2) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == - IN_LOOPBACKNET) - fatal("Tunnel local address %s is a loopback address", - inet_fmt($2, s1)); - - if (ifconfaddr($3) != 0) - fatal("Tunnel remote address %s is one of mine", - inet_fmt($3, s1)); - - for (vifi = 0, v = uvifs; - vifi < numvifs; - ++vifi, ++v) - if (v->uv_flags & VIFF_TUNNEL) { - if ($3 == v->uv_rmt_addr) - fatal("Duplicate tunnel to %s", - inet_fmt($3, s1)); - } else if (!(v->uv_flags & VIFF_DISABLED)) { - if (($3 & v->uv_subnetmask) == v->uv_subnet) - fatal("Unnecessary tunnel to %s, same subnet as vif %d (%s)", - inet_fmt($3,s1), vifi, v->uv_name); - } - - if (numvifs == MAXVIFS) - fatal("too many vifs"); - - strlcpy(ffr.ifr_name, ifname, sizeof(ffr.ifr_name)); - if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0) - fatal("ioctl SIOCGIFFLAGS on %s", ffr.ifr_name); - - v = &uvifs[numvifs]; - zero_vif(v, 1); - v->uv_flags = VIFF_TUNNEL | rexmit | noflood; - v->uv_flags |= VIFF_OTUNNEL; /*XXX*/ - v->uv_lcl_addr = $2; - v->uv_rmt_addr = $3; - v->uv_dst_addr = $3; - strlcpy(v->uv_name, ffr.ifr_name, sizeof(v->uv_name)); - - if (!(ffr.ifr_flags & IFF_UP)) { - v->uv_flags |= VIFF_DOWN; - vifs_down = TRUE; - } - } - tunnelmods - { - - if (!(v->uv_flags & VIFF_OTUNNEL)) { - init_ipip_on_vif(v); - } - - log(LOG_INFO, 0, - "installing tunnel from %s to %s as vif #%u - rate=%d", - inet_fmt($2, s1), inet_fmt($3, s2), - numvifs, v->uv_rate_limit); - - ++numvifs; - - } - | CACHE_LIFETIME NUMBER { - - if ($2 < MIN_CACHE_LIFETIME) { - warn("cache_lifetime %d must be at least %d", - $2, MIN_CACHE_LIFETIME); - } else { - cache_lifetime = $2; - } - - } - | PRUNE_LIFETIME NUMBER { - - if ($2 < MIN_PRUNE_LIFETIME) { - warn("prune_lifetime %d must be at least %d", - $2, MIN_PRUNE_LIFETIME); - } else { - prune_lifetime = $2; - } - - } - | PRUNING BOOLEAN { - - if ($2 != 1) { - warn("Disabling pruning is no longer supported"); - } - - } - | BLACK_HOLE { -#ifdef ALLOW_BLACK_HOLES - allow_black_holes = 1; -#endif - } - /* - * Turn off initial flooding (until subordinateness is learned - * via route exchange) on all phyints and set the default for - * all further tunnels. - */ - | NOFLOOD { - - vifi_t vifi; - - noflood = VIFF_NOFLOOD; - for (vifi = 0, v = uvifs; - vifi < numvifs; - ++vifi, ++v) - v->uv_flags |= VIFF_NOFLOOD; - - } - /* - * Turn on prune retransmission on all interfaces. - * Tunnels default to retransmitting, so this just - * needs to turn on phyints. - */ - | REXMIT_PRUNES { - - vifi_t vifi; - - for (vifi = 0, v = uvifs; - vifi < numvifs; - ++vifi, ++v) - v->uv_flags |= VIFF_REXMIT_PRUNES; - - } - /* - * If true, do as above. If false, no need to turn - * it off for phyints since they default to not - * rexmit; need to set flag to not rexmit on tunnels. - */ - | REXMIT_PRUNES BOOLEAN { - - if ($2) { - vifi_t vifi; - - for (vifi = 0, v = uvifs; - vifi < numvifs; - ++vifi, ++v) - v->uv_flags |= VIFF_REXMIT_PRUNES; - } else { - rexmit = 0; - } - - } - | NAME STRING boundary { if (numbounds >= MAXBOUNDS) { - fatal("Too many named boundaries (max %d)", MAXBOUNDS); - } - - boundlist[numbounds].name = malloc(strlen($2) + 1); - strcpy(boundlist[numbounds].name, $2); - boundlist[numbounds++].bound = $3; - } - | SYSNAM STRING { -#ifdef SNMP - set_sysName($2); -#endif /* SNMP */ - } - | SYSCONTACT STRING { -#ifdef SNMP - set_sysContact($2); -#endif /* SNMP */ - } - | SYSVERSION STRING { -#ifdef SNMP - set_sysVersion($2); -#endif /* SNMP */ - } - | SYSLOCATION STRING { -#ifdef SNMP - set_sysLocation($2); -#endif /* SNMP */ - } - ; - -tunnelmods : /* empty */ - | tunnelmods tunnelmod - ; - -tunnelmod : mod - | BESIDE { v->uv_flags |= VIFF_OTUNNEL; } - | BESIDE BOOLEAN { - - if ($2) { - v->uv_flags |= VIFF_OTUNNEL; - } else { - v->uv_flags &= ~VIFF_OTUNNEL; - } - - } - | SRCRT { fatal("Source-route tunnels not supported"); } - ; - -ifmods : /* empty */ - | ifmods ifmod - ; - -ifmod : mod - | DISABLE { v->uv_flags |= VIFF_DISABLED; } - | IGMPV1 { v->uv_flags |= VIFF_IGMPV1; } - | NETMASK addrname { - u_int32 subnet, mask; - - mask = $2; - subnet = v->uv_lcl_addr & mask; - if (!inet_valid_subnet(subnet, mask)) - fatal("Invalid netmask"); - v->uv_subnet = subnet; - v->uv_subnetmask = mask; - v->uv_subnetbcast = subnet | ~mask; - } - | NETMASK { - - warn("Expected address after netmask keyword, ignored"); - - } - | ALTNET addrmask { - - struct phaddr *ph; - - ph = (struct phaddr *)malloc(sizeof(struct phaddr)); - if (ph == NULL) - fatal("out of memory"); - if ($2.mask) { - VAL_TO_MASK(ph->pa_subnetmask, $2.mask); - } else - ph->pa_subnetmask = v->uv_subnetmask; - ph->pa_subnet = $2.addr & ph->pa_subnetmask; - ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask; - if ($2.addr & ~ph->pa_subnetmask) - warn("Extra subnet %s/%d has host bits set", - inet_fmt($2.addr,s1), $2.mask); - ph->pa_next = v->uv_addrs; - v->uv_addrs = ph; - - } - | ALTNET { - - warn("Expected address after altnet keyword, ignored"); - - } - | FORCE_LEAF { - - v->uv_flags |= VIFF_FORCE_LEAF; - - } - | FORCE_LEAF BOOLEAN { - - if ($2) { - v->uv_flags |= VIFF_FORCE_LEAF; - } else { - v->uv_flags &= ~VIFF_FORCE_LEAF; - } - - } - ; - -mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) - fatal("Invalid threshold %d",$2); - v->uv_threshold = $2; - } - | THRESHOLD { - - warn("Expected number after threshold keyword, ignored"); - - } - | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE) - fatal("Invalid metric %d",$2); - v->uv_metric = $2; - } - | METRIC { - - warn("Expected number after metric keyword, ignored"); - - } - | ADVERT_METRIC NUMBER { if ($2 < 0 || $2 > UNREACHABLE - 1) - fatal("Invalid advert_metric %d", $2); - v->uv_admetric = $2; - } - | ADVERT_METRIC { - - warn("Expected number after advert_metric keyword, ignored"); - - } - | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT) - fatal("Invalid rate_limit %d",$2); - v->uv_rate_limit = $2; - } - | RATE_LIMIT { - - warn("Expected number after rate_limit keyword, ignored"); - - } - | BOUNDARY bound { - - struct vif_acl *v_acl; - - v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl)); - if (v_acl == NULL) - fatal("out of memory"); - VAL_TO_MASK(v_acl->acl_mask, $2.mask); - v_acl->acl_addr = $2.addr & v_acl->acl_mask; - if ($2.addr & ~v_acl->acl_mask) - warn("Boundary spec %s/%d has host bits set", - inet_fmt($2.addr,s1),$2.mask); - v_acl->acl_next = v->uv_acl; - v->uv_acl = v_acl; - - } - | BOUNDARY { - - warn("Expected boundary spec after boundary keyword, ignored"); - - } - | REXMIT_PRUNES2 { - - v->uv_flags |= VIFF_REXMIT_PRUNES; - - } - | REXMIT_PRUNES2 BOOLEAN { - - if ($2) { - v->uv_flags |= VIFF_REXMIT_PRUNES; - } else { - v->uv_flags &= ~VIFF_REXMIT_PRUNES; - } - - } - | PASSIVE { - - v->uv_flags |= VIFF_PASSIVE; - - } - | NOFLOOD2 { - - v->uv_flags |= VIFF_NOFLOOD; - - } - | NOTRANSIT { - - v->uv_flags |= VIFF_NOTRANSIT; - - } - | BLASTER { - - v->uv_flags |= VIFF_BLASTER; - blaster_alloc(v - uvifs); - - } - | ALLOW_NONPRUNERS { - - v->uv_flags |= VIFF_ALLOW_NONPRUNERS; - - } - | PRUNE_LIFETIME2 NUMBER { - - if ($2 < MIN_PRUNE_LIFETIME) { - warn("prune_lifetime %d must be at least %d", - $2, MIN_PRUNE_LIFETIME); - } else { - v->uv_prune_lifetime = $2; - } - - } - | ACCEPT filter { - - if (v->uv_filter == NULL) { - struct vif_filter *v_filter; - - v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter)); - if (v_filter == NULL) - fatal("out of memory"); - v_filter->vf_flags = 0; - v_filter->vf_type = VFT_ACCEPT; - v_filter->vf_filter = $2; - v->uv_filter = v_filter; - } else if (v->uv_filter->vf_type != VFT_ACCEPT) { - fatal("can't accept and deny"); - } else { - struct vf_element *p; - - p = v->uv_filter->vf_filter; - while (p->vfe_next) - p = p->vfe_next; - p->vfe_next = $2; - } - - } - | ACCEPT { - - warn("Expected filter spec after accept keyword, ignored"); - - } - | DENY filter { - - if (v->uv_filter == NULL) { - struct vif_filter *v_filter; - - v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter)); - if (v_filter == NULL) - fatal("out of memory"); - v_filter->vf_flags = 0; - v_filter->vf_type = VFT_DENY; - v_filter->vf_filter = $2; - v->uv_filter = v_filter; - } else if (v->uv_filter->vf_type != VFT_DENY) { - fatal("can't accept and deny"); - } else { - struct vf_element *p; - - p = v->uv_filter->vf_filter; - while (p->vfe_next) - p = p->vfe_next; - p->vfe_next = $2; - } - - } - | DENY { - - warn("Expected filter spec after deny keyword, ignored"); - - } - | BIDIR { - - if (v->uv_filter == NULL) { - fatal("bidir goes after filters"); - } - v->uv_filter->vf_flags |= VFF_BIDIR; - - } - ; - -interface : ADDR { $$ = $1; } - | STRING { - $$ = valid_if($1); - if ($$ == 0) - fatal("Invalid interface name %s",$1); - } - ; - -addrname : ADDR { $$ = $1; } - | STRING { struct hostent *hp; - - if ((hp = gethostbyname($1)) == NULL || - hp->h_length != sizeof($$)) - fatal("No such host %s", $1); - - if (hp->h_addr_list[1]) - fatal("Hostname %s does not %s", - $1, "map to a unique address"); - - bcopy(hp->h_addr_list[0], &$$, - hp->h_length); - } - -bound : boundary { $$ = $1; } - | STRING { int i; - - for (i=0; i < numbounds; i++) { - if (!strcmp(boundlist[i].name, $1)) { - $$ = boundlist[i].bound; - break; - } - } - if (i == numbounds) { - fatal("Invalid boundary name %s",$1); - } - } - ; - -boundary : ADDRMASK { - -#ifdef ALLOW_BLACK_HOLES - if (!allow_black_holes) -#endif - if ((ntohl($1.addr) & 0xff000000) != 0xef000000) { - fatal("Boundaries must be 239.x.x.x, not %s/%d", - inet_fmt($1.addr, s1), $1.mask); - } - $$ = $1; - - } - ; - -addrmask : ADDRMASK { $$ = $1; } - | ADDR { $$.addr = $1; $$.mask = 0; } - ; - -filter : filtlist { $$ = $1; } - | STRING { fatal("named filters no implemented yet"); } - ; - -filtlist : filtelement { $$ = $1; } - | filtelement filtlist { $1->vfe_next = $2; $$ = $1; } - ; - -filtelement : filtelem { $$ = $1; } - | filtelem EXACT { $1->vfe_flags |= VFEF_EXACT; $$ = $1; } - ; - -filtelem : ADDRMASK { - - struct vf_element *vfe; - - vfe = (struct vf_element *)malloc(sizeof(struct vf_element)); - if (vfe == NULL) - fatal("out of memory"); - - vfe->vfe_addr = $1.addr; - VAL_TO_MASK(vfe->vfe_mask, $1.mask); - vfe->vfe_flags = 0; - vfe->vfe_next = NULL; - - $$ = vfe; - - } -%% -#ifdef __STDC__ -static void -fatal(char *fmt, ...) -{ - va_list ap; - char buf[MAXHOSTNAMELEN + 100]; - - va_start(ap, fmt); -#else -/*VARARGS1*/ -static void -fatal(fmt, va_alist) -char *fmt; -va_dcl -{ - va_list ap; - char buf[MAXHOSTNAMELEN + 100]; - - va_start(ap); -#endif - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno); -} - -#ifdef __STDC__ -static void -warn(char *fmt, ...) -{ - va_list ap; - char buf[200]; - - va_start(ap, fmt); -#else -/*VARARGS1*/ -static void -warn(fmt, va_alist) -char *fmt; -va_dcl -{ - va_list ap; - char buf[200]; - - va_start(ap); -#endif - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno); -} - -static void -yyerror(s) -char *s; -{ - log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); -} - -static char * -next_word() -{ - static char buf[1024]; - static char *p=NULL; - char *q; - - while (1) { - if (!p || !*p) { - lineno++; - if (fgets(buf, sizeof(buf), f) == NULL) - return NULL; - p = buf; - } - while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ - p++; - if (*p == '#') { - p = NULL; /* skip comments */ - continue; - } - q = p; -#ifdef SNMP - if (*p == '"') { - p++; - while (*p && *p != '"' && *p != '\n') - p++; /* find next whitespace */ - if (*p == '"') - p++; - } else -#endif - while (*p && *p != ' ' && *p != '\t' && *p != '\n') - p++; /* find next whitespace */ - *p++ = '\0'; /* null-terminate string */ - - if (!*q) { - p = NULL; - continue; /* if 0-length string, read another line */ - } - - return q; - } -} - -/* - * List of keywords. Must have an empty record at the end to terminate - * list. If a second value is specified, the first is used at the beginning - * of the file and the second is used while parsing interfaces (e.g. after - * the first "phyint" or "tunnel" keyword). - */ -static struct keyword { - char *word; - int val1; - int val2; -} words[] = { - { "cache_lifetime", CACHE_LIFETIME }, - { "prune_lifetime", PRUNE_LIFETIME, PRUNE_LIFETIME2 }, - { "pruning", PRUNING }, - { "phyint", PHYINT }, - { "tunnel", TUNNEL }, - { "disable", DISABLE }, - { "metric", METRIC }, - { "advert_metric", ADVERT_METRIC }, - { "threshold", THRESHOLD }, - { "rate_limit", RATE_LIMIT }, - { "force_leaf", FORCE_LEAF }, - { "srcrt", SRCRT }, - { "sourceroute", SRCRT }, - { "boundary", BOUNDARY }, - { "netmask", NETMASK }, - { "igmpv1", IGMPV1 }, - { "altnet", ALTNET }, - { "name", NAME }, - { "accept", ACCEPT }, - { "deny", DENY }, - { "exact", EXACT }, - { "bidir", BIDIR }, - { "allow_nonpruners", ALLOW_NONPRUNERS }, -#ifdef ALLOW_BLACK_HOLES - { "allow_black_holes", BLACK_HOLE }, -#endif - { "noflood", NOFLOOD, NOFLOOD2}, - { "notransit", NOTRANSIT }, - { "blaster", BLASTER }, - { "rexmit_prunes", REXMIT_PRUNES, REXMIT_PRUNES2 }, - { "passive", PASSIVE }, - { "beside", BESIDE }, -#ifdef SNMP - { "sysName", SYSNAM }, - { "sysContact", SYSCONTACT }, - { "sysVersion", SYSVERSION }, - { "sysLocation", SYSLOCATION }, -#endif - { NULL, 0 } -}; - - -static int -yylex() -{ - int n; - u_int32 addr; - char *q; - struct keyword *w; - - if ((q = next_word()) == NULL) { - return 0; - } - - for (w = words; w->word; w++) - if (!strcmp(q, w->word)) - return (state && w->val2) ? w->val2 : w->val1; - - if (!strcmp(q,"on") || !strcmp(q,"yes")) { - yylval.num = 1; - return BOOLEAN; - } - if (!strcmp(q,"off") || !strcmp(q,"no")) { - yylval.num = 0; - return BOOLEAN; - } - if (!strcmp(q,"default")) { - yylval.addrmask.mask = 0; - yylval.addrmask.addr = 0; - return ADDRMASK; - } - if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) { - if ((addr = inet_parse(s1,1)) != 0xffffffff) { - yylval.addrmask.mask = n; - yylval.addrmask.addr = addr; - return ADDRMASK; - } - /* fall through to returning STRING */ - } - if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) { - if ((addr = inet_parse(s1,4)) != 0xffffffff && - inet_valid_host(addr)) { - yylval.addr = addr; - return ADDR; - } - } - if (sscanf(q,"0x%8x%c",&n,s1) == 1) { - yylval.addr = n; - return ADDR; - } - if (sscanf(q,"%d%c",&n,s1) == 1) { - yylval.num = n; - return NUMBER; - } -#ifdef SNMP - if (*q=='"') { - if (q[ strlen(q)-1 ]=='"') - q[ strlen(q)-1 ]='\0'; /* trash trailing quote */ - yylval.ptr = q+1; - return STRING; - } -#endif - yylval.ptr = q; - return STRING; -} - -void -config_vifs_from_file() -{ - order = 0; - state = 0; - numbounds = 0; - lineno = 0; - - if ((f = fopen(configfilename, "r")) == NULL) { - if (errno != ENOENT) - log(LOG_ERR, errno, "can't open %s", configfilename); - return; - } - - yyparse(); - - fclose(f); -} - -static u_int32 -valid_if(s) -char *s; -{ - register vifi_t vifi; - register struct uvif *v; - - for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) - if (!strcmp(v->uv_name, s)) - return v->uv_lcl_addr; - - return 0; -} - -static const char * -ifconfaddr(u_int32_t a) -{ - static char ifname[IFNAMSIZ]; - struct ifaddrs *ifap, *ifa; - - if (getifaddrs(&ifap) != 0) - return (NULL); - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family == AF_INET && - ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == a) { - strlcpy(ifname, ifa->ifa_name, sizeof(ifname)); - freeifaddrs(ifap); - return (ifname); - } - } - - freeifaddrs(ifap); - return (NULL); -} diff --git a/usr.sbin/mrouted/common/Makefile b/usr.sbin/mrouted/common/Makefile deleted file mode 100644 index 903b50b..0000000 --- a/usr.sbin/mrouted/common/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -LIB= mrouted -INTERNALLIB= -SRCS= igmp.c inet.c kern.c - -CFLAGS+= -I$S - -.include <bsd.lib.mk> diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c deleted file mode 100644 index 9f83fb7..0000000 --- a/usr.sbin/mrouted/config.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * config.c,v 3.8.4.10 1998/01/06 01:57:41 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" -#include <ifaddrs.h> - -/* - * Query the kernel to find network interfaces that are multicast-capable - * and install them in the uvifs array. - */ -void -config_vifs_from_kernel() -{ - struct ifaddrs *ifa, *ifap; - register struct uvif *v; - register vifi_t vifi; - u_int32 addr, mask, subnet; - int flags; - - if (getifaddrs(&ifap) < 0) - log(LOG_ERR, errno, "getifaddrs"); - /* - * Loop through all of the interfaces. - */ - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - /* - * Ignore any interface for an address family other than IP. - */ - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - - addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; - - /* - * Ignore loopback interfaces and interfaces that do not support - * multicast. - */ - flags = ifa->ifa_flags; - if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) - continue; - - /* - * Ignore any interface whose address and mask do not define a - * valid subnet number, or whose address is of the form {subnet,0} - * or {subnet,-1}. - */ - mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr; - subnet = addr & mask; - if (!inet_valid_subnet(subnet, mask) || - addr == subnet || - addr == (subnet | ~mask)) { - log(LOG_WARNING, 0, - "ignoring %s, has invalid address (%s) and/or mask (%s)", - ifa->ifa_name, inet_fmt(addr, s1), inet_fmt(mask, s2)); - continue; - } - - /* - * Ignore any interface that is connected to the same subnet as - * one already installed in the uvifs array. - */ - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (strcmp(v->uv_name, ifa->ifa_name) == 0) { - log(LOG_DEBUG, 0, "skipping %s (%s on subnet %s) (alias for vif#%u?)", - v->uv_name, inet_fmt(addr, s1), - inet_fmts(subnet, mask, s2), vifi); - break; - } - if ((addr & v->uv_subnetmask) == v->uv_subnet || - (v->uv_subnet & mask) == subnet) { - log(LOG_WARNING, 0, "ignoring %s, same subnet as %s", - ifa->ifa_name, v->uv_name); - break; - } - } - if (vifi != numvifs) continue; - - /* - * If there is room in the uvifs array, install this interface. - */ - if (numvifs == MAXVIFS) { - log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifa->ifa_name); - continue; - } - v = &uvifs[numvifs]; - zero_vif(v, 0); - v->uv_lcl_addr = addr; - v->uv_subnet = subnet; - v->uv_subnetmask = mask; - v->uv_subnetbcast = subnet | ~mask; - strlcpy(v->uv_name, ifa->ifa_name, sizeof(v->uv_name)); - - if (flags & IFF_POINTOPOINT) - v->uv_flags |= VIFF_REXMIT_PRUNES; - - log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d", - v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2), - numvifs, v->uv_rate_limit); - - ++numvifs; - - /* - * If the interface is not yet up, set the vifs_down flag to - * remind us to check again later. - */ - if (!(flags & IFF_UP)) { - v->uv_flags |= VIFF_DOWN; - vifs_down = TRUE; - } - } - - freeifaddrs(ifap); -} diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h deleted file mode 100644 index 40b9cf0..0000000 --- a/usr.sbin/mrouted/defs.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * defs.h,v 3.8.4.15 1998/03/01 02:51:42 fenner Exp - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <ctype.h> -#include <errno.h> -#include <syslog.h> -#include <signal.h> -#include <string.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/uio.h> -#include <net/if.h> -#define rtentry kern_rtentry /* XXX !!! UGH */ -#include <net/route.h> -#undef rtentry -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/igmp.h> -#define rtentry kernel_rtentry -#include <net/route.h> -#undef rtentry -#include <netinet/ip_mroute.h> -#ifdef RSRR -#include <sys/un.h> -#endif /* RSRR */ - -/*XXX*/ -typedef u_int u_int32; - -typedef void (*cfunc_t)(void *); -typedef void (*ihfunc_t)(int, fd_set *); - -#include "dvmrp.h" -#include "igmpv2.h" -#include "vif.h" -#include "route.h" -#include "prune.h" -#include "pathnames.h" -#ifdef RSRR -#include "rsrr.h" -#include "rsrr_var.h" -#endif /* RSRR */ - -/* - * Miscellaneous constants and macros. - */ -#define FALSE 0 -#define TRUE 1 - -#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) - -#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY - -#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */ -#define MROUTED_VERSION 9 /* not in DVMRP packets at all */ - -#define DVMRP_CONSTANT 0x000eff00 /* constant portion of 'group' field */ - -#define MROUTED_LEVEL (DVMRP_CONSTANT | PROTOCOL_VERSION) - /* for IGMP 'group' field of DVMRP messages */ - -#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0) - /* more for IGMP 'group' field of DVMRP messages */ - -#define DEL_RTE_GROUP 0 -#define DEL_ALL_ROUTES 1 - /* for Deleting kernel table entries */ - -#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ - -#ifdef RSRR -#define BIT_ZERO(X) ((X) = 0) -#define BIT_SET(X,n) ((X) |= 1 << (n)) -#define BIT_CLR(X,n) ((X) &= ~(1 << (n))) -#define BIT_TST(X,n) ((X) & 1 << (n)) -#endif /* RSRR */ - -#define HAVE_SA_LEN - -/* - * External declarations for global variables and functions. - */ -#define RECV_BUF_SIZE 8192 -extern char *recv_buf; -extern char *send_buf; -extern int igmp_socket; -#ifdef RSRR -extern int rsrr_socket; -#endif /* RSRR */ -extern u_int32 allhosts_group; -extern u_int32 allrtrs_group; -extern u_int32 dvmrp_group; -extern u_int32 dvmrp_genid; - -#define IF_DEBUG(l) if (debug && debug & (l)) - -#define DEBUG_PKT 0x0001 -#define DEBUG_PRUNE 0x0002 -#define DEBUG_ROUTE 0x0004 -#define DEBUG_PEER 0x0008 -#define DEBUG_CACHE 0x0010 -#define DEBUG_TIMEOUT 0x0020 -#define DEBUG_IF 0x0040 -#define DEBUG_MEMBER 0x0080 -#define DEBUG_TRACE 0x0100 -#define DEBUG_IGMP 0x0200 -#define DEBUG_RTDETAIL 0x0400 -#define DEBUG_KERN 0x0800 -#define DEBUG_RSRR 0x1000 -#define DEBUG_ICMP 0x2000 - -#define DEFAULT_DEBUG 0x02de /* default if "-d" given without value */ - -extern int debug; -extern int did_final_init; - -extern int routes_changed; -extern int delay_change_reports; -extern unsigned nroutes; - -extern struct uvif uvifs[MAXVIFS]; -extern vifi_t numvifs; -extern int vifs_down; -extern int udp_socket; -extern int vifs_with_neighbors; - -extern char s1[]; -extern char s2[]; -extern char s3[]; -extern char s4[]; - -#ifndef IGMP_PIM -#define IGMP_PIM 0x14 -#endif -#ifndef IPPROTO_IPIP -#define IPPROTO_IPIP 4 -#endif - -/* - * The original multicast releases defined - * IGMP_HOST_{MEMBERSHIP_QUERY,MEMBERSHIP_REPORT,NEW_MEMBERSHIP_REPORT - * ,LEAVE_MESSAGE}. Later releases removed the HOST and inserted - * the IGMP version number. NetBSD inserted the version number in - * a different way. mrouted uses the new names, so we #define them - * to the old ones if needed. - */ -#if !defined(IGMP_MEMBERSHIP_QUERY) && defined(IGMP_HOST_MEMBERSHIP_QUERY) -#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY -#define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE -#endif -#ifndef IGMP_V1_MEMBERSHIP_REPORT -#ifdef IGMP_HOST_MEMBERSHIP_REPORT -#define IGMP_V1_MEMBERSHIP_REPORT IGMP_HOST_MEMBERSHIP_REPORT -#define IGMP_V2_MEMBERSHIP_REPORT IGMP_HOST_NEW_MEMBERSHIP_REPORT -#endif -#ifdef IGMP_v1_HOST_MEMBERSHIP_REPORT -#define IGMP_V1_MEMBERSHIP_REPORT IGMP_v1_HOST_MEMBERSHIP_REPORT -#define IGMP_V2_MEMBERSHIP_REPORT IGMP_v2_HOST_MEMBERSHIP_REPORT -#endif -#endif - -/* - * NetBSD also renamed the mtrace types. - */ -#if !defined(IGMP_MTRACE_RESP) && defined(IGMP_MTRACE_REPLY) -#define IGMP_MTRACE_RESP IGMP_MTRACE_REPLY -#define IGMP_MTRACE IGMP_MTRACE_QUERY -#endif - -/* main.c */ -extern char * scaletime __P((u_long)); -extern void log __P((int, int, char *, ...)) __printflike(3, 4); -extern int register_input_handler __P((int, ihfunc_t)); - -/* igmp.c */ -extern void init_igmp __P((void)); -extern void accept_igmp __P((int)); -extern void build_igmp __P((u_int32, u_int32, int, int, u_int32, - int)); -extern void send_igmp __P((u_int32, u_int32, int, int, u_int32, - int)); -extern char * igmp_packet_kind __P((u_int, u_int)); -extern int igmp_debug_kind __P((u_int, u_int)); - -/* icmp.c */ -extern void init_icmp __P((void)); - -/* ipip.c */ -extern void init_ipip __P((void)); -extern void init_ipip_on_vif __P((struct uvif *)); -extern void send_ipip __P((u_int32, u_int32, int, int, u_int32, - int, struct uvif *)); - -/* callout.c */ -extern void callout_init __P((void)); -extern void free_all_callouts __P((void)); -extern void age_callout_queue __P((int)); -extern int timer_nextTimer __P((void)); -extern int timer_setTimer __P((int, cfunc_t, void *)); -extern int timer_clearTimer __P((int)); -extern int timer_leftTimer __P((int)); - -/* route.c */ -extern void init_routes __P((void)); -extern void start_route_updates __P((void)); -extern void update_route __P((u_int32, u_int32, u_int, u_int32, - vifi_t, struct listaddr *)); -extern void age_routes __P((void)); -extern void expire_all_routes __P((void)); -extern void free_all_routes __P((void)); -extern void accept_probe __P((u_int32, u_int32, char *, int, - u_int32)); -extern void accept_report __P((u_int32, u_int32, char *, int, - u_int32)); -extern struct rtentry * determine_route __P((u_int32 src)); -extern void report __P((int, vifi_t, u_int32)); -extern void report_to_all_neighbors __P((int)); -extern int report_next_chunk __P((void)); -extern void blaster_alloc __P((vifi_t)); -extern void add_vif_to_routes __P((vifi_t)); -extern void delete_vif_from_routes __P((vifi_t)); -extern void add_neighbor_to_routes __P((vifi_t, int)); -extern void delete_neighbor_from_routes __P((u_int32, - vifi_t, int)); -extern void dump_routes __P((FILE *fp)); - -/* vif.c */ -extern void init_vifs __P((void)); -extern void zero_vif __P((struct uvif *, int)); -extern void init_installvifs __P((void)); -extern void check_vif_state __P((void)); -extern void send_on_vif __P((struct uvif *, u_int32, int, int)); -extern vifi_t find_vif __P((u_int32, u_int32)); -extern void age_vifs __P((void)); -extern void dump_vifs __P((FILE *)); -extern void stop_all_vifs __P((void)); -extern struct listaddr *neighbor_info __P((vifi_t, u_int32)); -extern void accept_group_report __P((u_int32, u_int32, - u_int32, int)); -extern void query_groups __P((void)); -extern void probe_for_neighbors __P((void)); -extern struct listaddr *update_neighbor __P((vifi_t, u_int32, int, char *, int, - u_int32)); -extern void accept_neighbor_request __P((u_int32, u_int32)); -extern void accept_neighbor_request2 __P((u_int32, u_int32)); -extern void accept_info_request __P((u_int32, u_int32, - u_char *, int)); -extern void accept_info_reply __P((u_int32, u_int32, - u_char *, int)); -extern void accept_neighbors __P((u_int32, u_int32, - u_char *, int, u_int32)); -extern void accept_neighbors2 __P((u_int32, u_int32, - u_char *, int, u_int32)); -extern void accept_leave_message __P((u_int32, u_int32, - u_int32)); -extern void accept_membership_query __P((u_int32, u_int32, - u_int32, int)); - -/* config.c */ -extern void config_vifs_from_kernel __P((void)); - -/* cfparse.y */ -extern void config_vifs_from_file __P((void)); - -/* inet.c */ -extern int inet_valid_host __P((u_int32)); -extern int inet_valid_mask __P((u_int32)); -extern int inet_valid_subnet __P((u_int32, u_int32)); -extern char * inet_fmt __P((u_int32, char *)); -extern char * inet_fmts __P((u_int32, u_int32, char *)); -extern u_int32 inet_parse __P((char *, int)); -extern int inet_cksum __P((u_short *, u_int)); - -/* prune.c */ -extern unsigned kroutes; -extern void determine_forwvifs __P((struct gtable *)); -extern void send_prune_or_graft __P((struct gtable *)); -extern void add_table_entry __P((u_int32, u_int32)); -extern void del_table_entry __P((struct rtentry *, - u_int32, u_int)); -extern void update_table_entry __P((struct rtentry *, u_int32)); -extern int find_src_grp __P((u_int32, u_int32, u_int32)); -extern void init_ktable __P((void)); -extern void steal_sources __P((struct rtentry *)); -extern void reset_neighbor_state __P((vifi_t, u_int32)); -extern int grplst_mem __P((vifi_t, u_int32)); -extern void free_all_prunes __P((void)); -extern void age_table_entry __P((void)); -extern void dump_cache __P((FILE *)); -extern void update_lclgrp __P((vifi_t, u_int32)); -extern void delete_lclgrp __P((vifi_t, u_int32)); -extern void chkgrp_graft __P((vifi_t, u_int32)); -extern void accept_prune __P((u_int32, u_int32, char *, int)); -extern void accept_graft __P((u_int32, u_int32, char *, int)); -extern void accept_g_ack __P((u_int32, u_int32, char *, int)); -/* u_int is promoted u_char */ -extern void accept_mtrace __P((u_int32, u_int32, - u_int32, char *, u_int, int)); - -/* kern.c */ -extern void k_set_rcvbuf __P((int, int)); -extern void k_hdr_include __P((int)); -extern void k_set_ttl __P((int)); -extern void k_set_loop __P((int)); -extern void k_set_if __P((u_int32)); -extern void k_join __P((u_int32, u_int32)); -extern void k_leave __P((u_int32, u_int32)); -extern void k_init_dvmrp __P((void)); -extern void k_stop_dvmrp __P((void)); -extern void k_add_vif __P((vifi_t, struct uvif *)); -extern void k_del_vif __P((vifi_t)); -extern void k_add_rg __P((u_int32, struct gtable *)); -extern int k_del_rg __P((u_int32, struct gtable *)); -extern int k_get_version __P((void)); - -#ifdef SNMP -/* prune.c */ -extern struct gtable * find_grp __P((u_int32)); -extern struct stable * find_grp_src __P((struct gtable *, u_int32)); -extern int next_grp_src_mask __P((struct gtable **, - struct stable **, u_int32, - u_int32, u_int32)); -extern void refresh_sg __P((struct sioc_sg_req *, struct gtable *, - struct stable *)); -extern int next_child __P((struct gtable **, struct stable **, - u_int32, u_int32, u_int32, - vifi_t *)); - -/* route.c */ -extern struct rtentry * snmp_find_route __P((u_int32, u_int32)); -extern int next_route __P((struct rtentry **, u_int32, u_int32)); -extern int next_route_child __P((struct rtentry **, - u_int32, u_int32, vifi_t *)); -#endif - -#ifdef RSRR -/* prune.c */ -extern struct gtable *kernel_table; -extern struct gtable *gtp; - -/* rsrr.c */ -extern void rsrr_init __P((void)); -extern void rsrr_clean __P((void)); -extern void rsrr_cache_send __P((struct gtable *, int)); -extern void rsrr_cache_clean __P((struct gtable *)); -#endif /* RSRR */ diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h deleted file mode 100644 index 2f11872..0000000 --- a/usr.sbin/mrouted/dvmrp.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * dvmrp.h,v 3.8.4.5 1997/11/18 23:25:57 fenner Exp - */ - -/* - * A DVMRP message consists of an IP header + an IGMP header + (for some types) - * zero or more bytes of data. - * - * For REPORT messages, the data is route information; the route information - * consists of one or more lists of the following form: - * - * (mask, (origin, metric), (origin, metric), ...) - * - * where: - * - * "mask" is the subnet mask for all the origins in the list. - * It is always THREE bytes long, containing the low-order - * three bytes of the mask (the high-order byte is always - * 0xff and therefore need not be transmitted). - * - * "origin" is the number of a subnet from which multicast datagrams - * may originate. It is from one to four bytes long, - * depending on the value of "mask": - * if all bytes of the mask are zero - * the subnet number is one byte long - * else if the low-order two bytes of the mask are zero - * the subnet number is two bytes long - * else if the lowest-order byte of the mask is zero - * the subnet number is three bytes long, - * else - * the subnet number is four bytes long. - * - * "metric" is a one-byte value consisting of two subfields: - * - the high-order bit is a flag which, when set, indicates - * the last (origin, metric) pair of a list. - * - the low-order seven bits contain the routing metric for - * the corresponding origin, relative to the sender of the - * DVMRP report. The metric may have the value of UNREACHABLE - * added to it as a "split horizon" indication (so called - * "poisoned reverse"). - * - * Within a list, the origin subnet numbers must be in ascending order, and - * the lists themselves are in order of increasing mask value. A message may - * not exceed 576 bytes, the default maximum IP reassembly size, including - * the IP and IGMP headers; the route information may be split across more - * than one message if necessary, by terminating a list in one message and - * starting a new list in the next message (repeating the same mask value, - * if necessary). - * - * For NEIGHBORS messages, the data is neighboring-router information - * consisting of one or more lists of the following form: - * - * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...) - * - * where: - * - * "local-addr" is the sending router's address as seen by the neighbors - * in this list; it is always four bytes long. - * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding - * packets to any of the neighbors on this list. - * "threshold" is a one-byte unsigned value, a lower bound on the TTL a - * packet must have to be forwarded to any of the neighbors on - * this list. - * "ncount" is the number of neighbors in this list. - * "neighbor" is the address of a neighboring router, four bytes long. - * - * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes, - * including the IP and IGMP headers; split longer messages by terminating the - * list in one and continuing in another, repeating the local-addr, etc., if - * necessary. - * - * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except - * there is a flags byte before the neighbor count: - * - * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...) - */ - -/* - * DVMRP message types (carried in the "code" field of an IGMP header) - */ -#define DVMRP_PROBE 1 /* for finding neighbors */ -#define DVMRP_REPORT 2 /* for reporting some or all routes */ -#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ - /* of this router's neighbors. */ -#define DVMRP_NEIGHBORS 4 /* response to such a request */ -#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ -#define DVMRP_NEIGHBORS2 6 -#define DVMRP_PRUNE 7 /* prune message */ -#define DVMRP_GRAFT 8 /* graft message */ -#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */ -#define DVMRP_INFO_REQUEST 10 /* information request */ -#define DVMRP_INFO_REPLY 11 /* information reply */ - -/* - * 'flags' byte values in DVMRP_NEIGHBORS2 reply. - */ -#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ -#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ -#define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */ -#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ -#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ -#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ -#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */ - -/* - * Request/reply types for info queries/replies - */ -#define DVMRP_INFO_VERSION 1 /* version string */ -#define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */ - -/* - * Limit on length of route data - */ -#define MAX_IP_PACKET_LEN 576 -#define MIN_IP_HEADER_LEN 20 -#define MAX_IP_HEADER_LEN 60 -#define MAX_DVMRP_DATA_LEN \ - ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN ) - -/* - * Various protocol constants (all times in seconds) - */ - /* address for multicast DVMRP msgs */ -#define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */ -/* - * The IGMPv2 <netinet/in.h> defines INADDR_ALLRTRS_GROUP, but earlier - * ones don't, so we define it conditionally here. - */ -#ifndef INADDR_ALLRTRS_GROUP - /* address for multicast mtrace msg */ -#define INADDR_ALLRTRS_GROUP (u_int32)0xe0000002 /* 224.0.0.2 */ -#endif - -#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */ - /* (This is the timer interrupt */ - /* interval; all times must be */ - /* multiples of this value.) */ - -#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */ -#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */ -#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */ -#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */ - -#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */ - -#define NEIGHBOR_PROBE_INTERVAL 10 /* periodic neighbor probe interval */ -#define NEIGHBOR_EXPIRE_TIME 30 /* time to consider neighbor gone */ -#define OLD_NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */ - -#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */ -#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */ -#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */ - -#define MAX_RATE_LIMIT 100000 /* max rate limit */ -#define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */ -#define DEFAULT_TUN_RATE_LIMIT 0 /* default tunnel rate limit */ - -#define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */ -#define MIN_CACHE_LIFETIME 60 /* minimum allowed cache lifetime */ -#define AVERAGE_PRUNE_LIFETIME 7200 /* average lifetime of prunes sent */ -#define MIN_PRUNE_LIFETIME 120 /* minimum allowed prune lifetime */ -#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */ -#define PRUNE_REXMIT_VAL 3 /* initial time for prune rexmission*/ diff --git a/usr.sbin/mrouted/icmp.c b/usr.sbin/mrouted/icmp.c deleted file mode 100644 index 72efa0a..0000000 --- a/usr.sbin/mrouted/icmp.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp - */ - -#include "defs.h" - -#ifndef lint -static char rcsid[] = "@(#) $Id: \ -icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp $"; -#endif - -static int icmp_socket; - -static void icmp_handler __P((int, fd_set *)); -static char * icmp_name __P((struct icmp *)); - -void -init_icmp() -{ - if ((icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) - log(LOG_ERR, errno, "ICMP socket"); - - register_input_handler(icmp_socket, icmp_handler); - - IF_DEBUG(DEBUG_ICMP) - log(LOG_DEBUG, 0, "registering icmp socket fd %d\n", icmp_socket); -} - -static void -icmp_handler(fd, rfds) - int fd; - fd_set *rfds; -{ - u_char icmp_buf[RECV_BUF_SIZE]; - struct sockaddr_in from; - int fromlen, recvlen, iphdrlen, ipdatalen; - struct icmp *icmp; - struct ip *ip; - vifi_t i; - struct uvif *v; - u_int32 src; - - fromlen = sizeof(from); - recvlen = recvfrom(icmp_socket, icmp_buf, RECV_BUF_SIZE, 0, - (struct sockaddr *)&from, &fromlen); - if (recvlen < 0) { - if (errno != EINTR) - log(LOG_WARNING, errno, "icmp_socket recvfrom"); - return; - } - ip = (struct ip *)icmp_buf; - iphdrlen = ip->ip_hl << 2; -#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len) - iphdrlen; -#else - ipdatalen = ip->ip_len; -#endif - if (iphdrlen + ipdatalen != recvlen) { - IF_DEBUG(DEBUG_ICMP) - log(LOG_DEBUG, 0, "hdr %d data %d != rcv %d", iphdrlen, ipdatalen, recvlen); - /* Malformed ICMP, just return. */ - return; - } - if (ipdatalen < ICMP_MINLEN + sizeof(struct ip)) { - /* Not enough data for us to be interested in it. */ - return; - } - src = ip->ip_src.s_addr; - icmp = (struct icmp *)(icmp_buf + iphdrlen); - IF_DEBUG(DEBUG_ICMP) - log(LOG_DEBUG, 0, "got ICMP type %d from %s", - icmp->icmp_type, inet_fmt(src, s1)); - /* - * Eventually: - * have registry of ICMP listeners, by type, code and ICMP_ID - * (and maybe fields of the original packet too -- maybe need a - * generalized packet filter!) to allow ping and traceroute - * from the monitoring tool. - */ - switch (icmp->icmp_type) { - case ICMP_UNREACH: - case ICMP_TIMXCEED: - /* Look at returned packet to see if it's us sending on a tunnel */ - ip = &icmp->icmp_ip; - if (ip->ip_p != IPPROTO_IGMP && ip->ip_p != IPPROTO_IPIP) - return; - for (v = uvifs, i = 0; i < numvifs; v++, i++) { - if (ip->ip_src.s_addr == v->uv_lcl_addr && - ip->ip_dst.s_addr == v->uv_dst_addr) { - char *p; - int n; - /* - * I sent this packet on this vif. - */ - n = ++v->uv_icmp_warn; - while (n && !(n & 1)) - n >>= 1; - if (n == 1 && ((p = icmp_name(icmp)) != NULL)) - log(LOG_WARNING, 0, "Received ICMP %s from %s %s %s on vif %d", - p, inet_fmt(src, s1), "for traffic sent to", - inet_fmt(ip->ip_dst.s_addr, s2), - i); - - break; - } - } - break; - } -} - -/* - * Return NULL for ICMP informational messages. - * Return string describing the error for ICMP errors. - */ -static char * -icmp_name(icmp) - struct icmp *icmp; -{ - static char retval[30]; - - switch (icmp->icmp_type) { - case ICMP_UNREACH: - switch (icmp->icmp_code) { - case ICMP_UNREACH_NET: - return "network unreachable"; - case ICMP_UNREACH_HOST: - return "host unreachable"; - case ICMP_UNREACH_PROTOCOL: - return "protocol unreachable"; - case ICMP_UNREACH_PORT: - return "port unreachable"; - case ICMP_UNREACH_NEEDFRAG: - return "needs fragmentation"; - case ICMP_UNREACH_SRCFAIL: - return "source route failed"; -#ifndef ICMP_UNREACH_NET_UNKNOWN -#define ICMP_UNREACH_NET_UNKNOWN 6 -#endif - case ICMP_UNREACH_NET_UNKNOWN: - return "network unknown"; -#ifndef ICMP_UNREACH_HOST_UNKNOWN -#define ICMP_UNREACH_HOST_UNKNOWN 7 -#endif - case ICMP_UNREACH_HOST_UNKNOWN: - return "host unknown"; -#ifndef ICMP_UNREACH_ISOLATED -#define ICMP_UNREACH_ISOLATED 8 -#endif - case ICMP_UNREACH_ISOLATED: - return "source host isolated"; -#ifndef ICMP_UNREACH_NET_PROHIB -#define ICMP_UNREACH_NET_PROHIB 9 -#endif - case ICMP_UNREACH_NET_PROHIB: - return "network access prohibited"; -#ifndef ICMP_UNREACH_HOST_PROHIB -#define ICMP_UNREACH_HOST_PROHIB 10 -#endif - case ICMP_UNREACH_HOST_PROHIB: - return "host access prohibited"; -#ifndef ICMP_UNREACH_TOSNET -#define ICMP_UNREACH_TOSNET 11 -#endif - case ICMP_UNREACH_TOSNET: - return "bad TOS for net"; -#ifndef ICMP_UNREACH_TOSHOST -#define ICMP_UNREACH_TOSHOST 12 -#endif - case ICMP_UNREACH_TOSHOST: - return "bad TOS for host"; -#ifndef ICMP_UNREACH_FILTER_PROHIB -#define ICMP_UNREACH_FILTER_PROHIB 13 -#endif - case ICMP_UNREACH_FILTER_PROHIB: - return "prohibited by filter"; -#ifndef ICMP_UNREACH_HOST_PRECEDENCE -#define ICMP_UNREACH_HOST_PRECEDENCE 14 -#endif - case ICMP_UNREACH_HOST_PRECEDENCE: - return "host precedence violation"; -#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF -#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 -#endif - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - return "precedence cutoff"; - default: - sprintf(retval, "unreachable code %d", icmp->icmp_code); - return retval; - } - case ICMP_SOURCEQUENCH: - return "source quench"; - case ICMP_REDIRECT: - return NULL; /* XXX */ - case ICMP_TIMXCEED: - switch (icmp->icmp_code) { - case ICMP_TIMXCEED_INTRANS: - return "time exceeded in transit"; - case ICMP_TIMXCEED_REASS: - return "time exceeded in reassembly"; - default: - sprintf(retval, "time exceeded code %d", icmp->icmp_code); - return retval; - } - case ICMP_PARAMPROB: - switch (icmp->icmp_code) { -#ifndef ICMP_PARAMPROB_OPTABSENT -#define ICMP_PARAMPROB_OPTABSENT 1 -#endif - case ICMP_PARAMPROB_OPTABSENT: - return "required option absent"; - default: - sprintf(retval, "parameter problem code %d", icmp->icmp_code); - return retval; - } - } - return NULL; -} diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c deleted file mode 100644 index f343035..0000000 --- a/usr.sbin/mrouted/igmp.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * igmp.c,v 3.8.4.19 1998/01/06 01:57:43 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -/* - * Exported variables. - */ -char *recv_buf; /* input packet buffer */ -char *send_buf; /* output packet buffer */ -int igmp_socket; /* socket for all network I/O */ -u_int32 allhosts_group; /* All hosts addr in net order */ -u_int32 allrtrs_group; /* All-Routers " in net order */ -u_int32 dvmrp_group; /* DVMRP grp addr in net order */ -u_int32 dvmrp_genid; /* IGMP generation id */ - -/* - * Local function definitions. - */ -/* u_char promoted to u_int */ -static int igmp_log_level __P((u_int type, u_int code)); - -/* - * Open and initialize the igmp socket, and fill in the non-changing - * IP header fields in the output packet buffer. - */ -void -init_igmp() -{ - struct ip *ip; - - recv_buf = malloc(RECV_BUF_SIZE); - send_buf = malloc(RECV_BUF_SIZE); - - if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) - log(LOG_ERR, errno, "IGMP socket"); - - k_hdr_include(TRUE); /* include IP header when sending */ - k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering */ - k_set_ttl(1); /* restrict multicasts to one hop */ - k_set_loop(FALSE); /* disable multicast loopback */ - - ip = (struct ip *)send_buf; - bzero(ip, sizeof(struct ip)); - /* - * Fields zeroed that aren't filled in later: - * - IP ID (let the kernel fill it in) - * - Offset (we don't send fragments) - * - Checksum (let the kernel fill it in) - */ - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(struct ip) >> 2; - ip->ip_tos = 0xc0; /* Internet Control */ - ip->ip_ttl = MAXTTL; /* applies to unicasts only */ - ip->ip_p = IPPROTO_IGMP; - - allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); - dvmrp_group = htonl(INADDR_DVMRP_GROUP); - allrtrs_group = htonl(INADDR_ALLRTRS_GROUP); -} - -#define PIM_QUERY 0 -#define PIM_REGISTER 1 -#define PIM_REGISTER_STOP 2 -#define PIM_JOIN_PRUNE 3 -#define PIM_RP_REACHABLE 4 -#define PIM_ASSERT 5 -#define PIM_GRAFT 6 -#define PIM_GRAFT_ACK 7 - -char * -igmp_packet_kind(type, code) - u_int type, code; -{ - static char unknown[20]; - - switch (type) { - case IGMP_MEMBERSHIP_QUERY: return "membership query "; - case IGMP_V1_MEMBERSHIP_REPORT: return "V1 member report "; - case IGMP_V2_MEMBERSHIP_REPORT: return "V2 member report "; - case IGMP_V2_LEAVE_GROUP: return "leave message "; - case IGMP_DVMRP: - switch (code) { - case DVMRP_PROBE: return "neighbor probe "; - case DVMRP_REPORT: return "route report "; - case DVMRP_ASK_NEIGHBORS: return "neighbor request "; - case DVMRP_NEIGHBORS: return "neighbor list "; - case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2"; - case DVMRP_NEIGHBORS2: return "neighbor list 2 "; - case DVMRP_PRUNE: return "prune message "; - case DVMRP_GRAFT: return "graft message "; - case DVMRP_GRAFT_ACK: return "graft message ack "; - case DVMRP_INFO_REQUEST: return "info request "; - case DVMRP_INFO_REPLY: return "info reply "; - default: - sprintf(unknown, "unknown DVMRP %3d ", code); - return unknown; - } - case IGMP_PIM: - switch (code) { - case PIM_QUERY: return "PIM Router-Query "; - case PIM_REGISTER: return "PIM Register "; - case PIM_REGISTER_STOP: return "PIM Register-Stop "; - case PIM_JOIN_PRUNE: return "PIM Join/Prune "; - case PIM_RP_REACHABLE: return "PIM RP-Reachable "; - case PIM_ASSERT: return "PIM Assert "; - case PIM_GRAFT: return "PIM Graft "; - case PIM_GRAFT_ACK: return "PIM Graft-Ack "; - default: - sprintf(unknown, "unknown PIM msg%3d", code); - return unknown; - } - case IGMP_MTRACE: return "IGMP trace query "; - case IGMP_MTRACE_RESP: return "IGMP trace reply "; - default: - sprintf(unknown, "unk: 0x%02x/0x%02x ", type, code); - return unknown; - } -} - -int -igmp_debug_kind(type, code) - u_int type, code; -{ - switch (type) { - case IGMP_MEMBERSHIP_QUERY: return DEBUG_IGMP; - case IGMP_V1_MEMBERSHIP_REPORT: return DEBUG_IGMP; - case IGMP_V2_MEMBERSHIP_REPORT: return DEBUG_IGMP; - case IGMP_V2_LEAVE_GROUP: return DEBUG_IGMP; - case IGMP_DVMRP: - switch (code) { - case DVMRP_PROBE: return DEBUG_PEER; - case DVMRP_REPORT: return DEBUG_ROUTE; - case DVMRP_ASK_NEIGHBORS: return 0; - case DVMRP_NEIGHBORS: return 0; - case DVMRP_ASK_NEIGHBORS2: return 0; - case DVMRP_NEIGHBORS2: return 0; - case DVMRP_PRUNE: return DEBUG_PRUNE; - case DVMRP_GRAFT: return DEBUG_PRUNE; - case DVMRP_GRAFT_ACK: return DEBUG_PRUNE; - case DVMRP_INFO_REQUEST: return 0; - case DVMRP_INFO_REPLY: return 0; - default: return 0; - } - case IGMP_PIM: - switch (code) { - case PIM_QUERY: return 0; - case PIM_REGISTER: return 0; - case PIM_REGISTER_STOP: return 0; - case PIM_JOIN_PRUNE: return 0; - case PIM_RP_REACHABLE: return 0; - case PIM_ASSERT: return 0; - case PIM_GRAFT: return 0; - case PIM_GRAFT_ACK: return 0; - default: return 0; - } - case IGMP_MTRACE: return DEBUG_TRACE; - case IGMP_MTRACE_RESP: return DEBUG_TRACE; - default: return DEBUG_IGMP; - } -} - -/* - * Process a newly received IGMP packet that is sitting in the input - * packet buffer. - */ -void -accept_igmp(recvlen) - int recvlen; -{ - register u_int32 src, dst, group; - struct ip *ip; - struct igmp *igmp; - int ipdatalen, iphdrlen, igmpdatalen; - - if (recvlen < sizeof(struct ip)) { - log(LOG_WARNING, 0, - "received packet too short (%u bytes) for IP header", recvlen); - return; - } - - ip = (struct ip *)recv_buf; - src = ip->ip_src.s_addr; - dst = ip->ip_dst.s_addr; - - /* - * this is most likely a message from the kernel indicating that - * a new src grp pair message has arrived and so, it would be - * necessary to install a route into the kernel for this. - */ - if (ip->ip_p == 0) { - if (src == 0 || dst == 0) - log(LOG_WARNING, 0, "kernel request not accurate"); - else - add_table_entry(src, dst); - return; - } - - iphdrlen = ip->ip_hl << 2; -#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len) - iphdrlen; -#else - ipdatalen = ip->ip_len; -#endif - if (iphdrlen + ipdatalen != recvlen) { - log(LOG_WARNING, 0, - "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", - inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen); - return; - } - - igmp = (struct igmp *)(recv_buf + iphdrlen); - group = igmp->igmp_group.s_addr; - igmpdatalen = ipdatalen - IGMP_MINLEN; - if (igmpdatalen < 0) { - log(LOG_WARNING, 0, - "received IP data field too short (%u bytes) for IGMP, from %s", - ipdatalen, inet_fmt(src, s1)); - return; - } - - IF_DEBUG(DEBUG_PKT|igmp_debug_kind(igmp->igmp_type, igmp->igmp_code)) - log(LOG_DEBUG, 0, "RECV %s from %-15s to %s", - igmp_packet_kind(igmp->igmp_type, igmp->igmp_code), - inet_fmt(src, s1), inet_fmt(dst, s2)); - - switch (igmp->igmp_type) { - - case IGMP_MEMBERSHIP_QUERY: - accept_membership_query(src, dst, group, igmp->igmp_code); - return; - - case IGMP_V1_MEMBERSHIP_REPORT: - case IGMP_V2_MEMBERSHIP_REPORT: - accept_group_report(src, dst, group, igmp->igmp_type); - return; - - case IGMP_V2_LEAVE_GROUP: - accept_leave_message(src, dst, group); - return; - - case IGMP_DVMRP: - group = ntohl(group); - - switch (igmp->igmp_code) { - case DVMRP_PROBE: - accept_probe(src, dst, - (char *)(igmp+1), igmpdatalen, group); - return; - - case DVMRP_REPORT: - accept_report(src, dst, - (char *)(igmp+1), igmpdatalen, group); - return; - - case DVMRP_ASK_NEIGHBORS: - accept_neighbor_request(src, dst); - return; - - case DVMRP_ASK_NEIGHBORS2: - accept_neighbor_request2(src, dst); - return; - - case DVMRP_NEIGHBORS: - accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen, - group); - return; - - case DVMRP_NEIGHBORS2: - accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen, - group); - return; - - case DVMRP_PRUNE: - accept_prune(src, dst, (char *)(igmp+1), igmpdatalen); - return; - - case DVMRP_GRAFT: - accept_graft(src, dst, (char *)(igmp+1), igmpdatalen); - return; - - case DVMRP_GRAFT_ACK: - accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen); - return; - - case DVMRP_INFO_REQUEST: - accept_info_request(src, dst, (char *)(igmp+1), - igmpdatalen); - return; - - case DVMRP_INFO_REPLY: - accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen); - return; - - default: - log(LOG_INFO, 0, - "ignoring unknown DVMRP message code %u from %s to %s", - igmp->igmp_code, inet_fmt(src, s1), - inet_fmt(dst, s2)); - return; - } - - case IGMP_PIM: - return; - - case IGMP_MTRACE_RESP: - return; - - case IGMP_MTRACE: - accept_mtrace(src, dst, group, (char *)(igmp+1), - igmp->igmp_code, igmpdatalen); - return; - - default: - log(LOG_INFO, 0, - "ignoring unknown IGMP message type %x from %s to %s", - igmp->igmp_type, inet_fmt(src, s1), - inet_fmt(dst, s2)); - return; - } -} - -/* - * Some IGMP messages are more important than others. This routine - * determines the logging level at which to log a send error (often - * "No route to host"). This is important when there is asymmetric - * reachability and someone is trying to, i.e., mrinfo me periodically. - */ -static int -igmp_log_level(type, code) - u_int type, code; -{ - switch (type) { - case IGMP_MTRACE_RESP: - return LOG_INFO; - - case IGMP_DVMRP: - switch (code) { - case DVMRP_NEIGHBORS: - case DVMRP_NEIGHBORS2: - return LOG_INFO; - } - } - return LOG_WARNING; -} - -/* - * Construct an IGMP message in the output packet buffer. The caller may - * have already placed data in that buffer, of length 'datalen'. - */ -void -build_igmp(src, dst, type, code, group, datalen) - u_int32 src, dst; - int type, code; - u_int32 group; - int datalen; -{ - struct ip *ip; - struct igmp *igmp; - extern int curttl; - - ip = (struct ip *)send_buf; - ip->ip_src.s_addr = src; - ip->ip_dst.s_addr = dst; - ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; -#ifdef RAW_OUTPUT_IS_RAW - ip->ip_len = htons(ip->ip_len); -#endif - if (IN_MULTICAST(ntohl(dst))) { - ip->ip_ttl = curttl; - } else { - ip->ip_ttl = MAXTTL; - } - - igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); - igmp->igmp_type = type; - igmp->igmp_code = code; - igmp->igmp_group.s_addr = group; - igmp->igmp_cksum = 0; - igmp->igmp_cksum = inet_cksum((u_short *)igmp, - IGMP_MINLEN + datalen); -} - -/* - * Call build_igmp() to build an IGMP message in the output packet buffer. - * Then send the message from the interface with IP address 'src' to - * destination 'dst'. - */ -void -send_igmp(src, dst, type, code, group, datalen) - u_int32 src, dst; - int type, code; - u_int32 group; - int datalen; -{ - struct sockaddr_in sdst; - int setloop = 0; - - build_igmp(src, dst, type, code, group, datalen); - - if (IN_MULTICAST(ntohl(dst))) { - k_set_if(src); - if (type != IGMP_DVMRP || dst == allhosts_group) { - setloop = 1; - k_set_loop(TRUE); - } - } - - bzero(&sdst, sizeof(sdst)); - sdst.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - sdst.sin_len = sizeof(sdst); -#endif - sdst.sin_addr.s_addr = dst; - if (sendto(igmp_socket, send_buf, - MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0, - (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { - if (errno == ENETDOWN) - check_vif_state(); - else - log(igmp_log_level(type, code), errno, - "sendto to %s on %s", - inet_fmt(dst, s1), inet_fmt(src, s2)); - } - - if (setloop) - k_set_loop(FALSE); - - IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code)) - log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", - igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" : - inet_fmt(src, s1), inet_fmt(dst, s2)); -} diff --git a/usr.sbin/mrouted/igmpv2.h b/usr.sbin/mrouted/igmpv2.h deleted file mode 100644 index 5f5ae27..0000000 --- a/usr.sbin/mrouted/igmpv2.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * igmpv2.h,v 3.8.4.1 1997/11/18 23:25:58 fenner Exp - */ - -/* - * Constants for IGMP Version 2. Several of these, especially the - * robustness variable, should be variables and not constants. - */ -#define IGMP_ROBUSTNESS_VARIABLE 2 -#define IGMP_QUERY_INTERVAL 125 -#define IGMP_QUERY_RESPONSE_INTERVAL 10 -#define IGMP_GROUP_MEMBERSHIP_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ - IGMP_QUERY_INTERVAL + \ - IGMP_QUERY_RESPONSE_INTERVAL) -#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ - IGMP_QUERY_INTERVAL + \ - IGMP_QUERY_RESPONSE_INTERVAL / 2) - /* Round to the nearest TIMER_INTERVAL */ -#define IGMP_STARTUP_QUERY_INTERVAL (((IGMP_QUERY_INTERVAL / 4) \ - / TIMER_INTERVAL) * TIMER_INTERVAL) -#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE -#define IGMP_LAST_MEMBER_QUERY_INTERVAL 1 -#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE - -/* - * OLD_AGE_THRESHOLD is the number of IGMP_QUERY_INTERVAL's to remember the - * presence of an IGMPv1 group member. According to the IGMPv2 specification, - * routers remember this presence for [Robustness Variable] * [Query Interval] + - * [Query Response Interval]. However, OLD_AGE_THRESHOLD is in units of - * [Query Interval], so doesn't have sufficient resolution to represent - * [Query Response Interval]. When the timer mechanism gets an efficient - * method of refreshing timers, this should get fixed. - */ -#define OLD_AGE_THRESHOLD IGMP_ROBUSTNESS_VARIABLE diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c deleted file mode 100644 index 53aad7c..0000000 --- a/usr.sbin/mrouted/inet.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * inet.c,v 3.8.4.2 1998/01/06 01:57:44 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -/* - * Exported variables. - */ -char s1[19]; /* buffers to hold the string representations */ -char s2[19]; /* of IP addresses, to be passed to inet_fmt() */ -char s3[19]; /* or inet_fmts(). */ -char s4[19]; - - -/* - * Verify that a given IP address is credible as a host address. - * (Without a mask, cannot detect addresses of the form {subnet,0} or - * {subnet,-1}.) - */ -int -inet_valid_host(naddr) - u_int32 naddr; -{ - register u_int32 addr; - - addr = ntohl(naddr); - - return (!(IN_MULTICAST(addr) || - IN_BADCLASS (addr) || - (addr & 0xff000000) == 0)); -} - -/* - * Verify that a given netmask is plausible; - * make sure that it is a series of 1's followed by - * a series of 0's with no discontiguous 1's. - */ -int -inet_valid_mask(mask) - u_int32 mask; -{ - if (~(((mask & -mask) - 1) | mask) != 0) { - /* Mask is not contiguous */ - return (FALSE); - } - - return (TRUE); -} - -/* - * Verify that a given subnet number and mask pair are credible. - * - * With CIDR, almost any subnet and mask are credible. mrouted still - * can't handle aggregated class A's, so we still check that, but - * otherwise the only requirements are that the subnet address is - * within the [ABC] range and that the host bits of the subnet - * are all 0. - */ -int -inet_valid_subnet(nsubnet, nmask) - u_int32 nsubnet, nmask; -{ - register u_int32 subnet, mask; - - subnet = ntohl(nsubnet); - mask = ntohl(nmask); - - if ((subnet & mask) != subnet) return (FALSE); - - if (subnet == 0) - return (mask == 0); - - if (IN_CLASSA(subnet)) { - if (mask < 0xff000000 || - (subnet & 0xff000000) == 0x7f000000 || - (subnet & 0xff000000) == 0x00000000) return (FALSE); - } - else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) { - /* Above Class C address space */ - return (FALSE); - } - if (subnet & ~mask) { - /* Host bits are set in the subnet */ - return (FALSE); - } - if (!inet_valid_mask(mask)) { - /* Netmask is not contiguous */ - return (FALSE); - } - - return (TRUE); -} - - -/* - * Convert an IP address in u_long (network) format into a printable string. - */ -char * -inet_fmt(addr, s) - u_int32 addr; - char *s; -{ - register u_char *a; - - a = (u_char *)&addr; - sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); - return (s); -} - - -/* - * Convert an IP subnet number in u_long (network) format into a printable - * string including the netmask as a number of bits. - */ -char * -inet_fmts(addr, mask, s) - u_int32 addr, mask; - char *s; -{ - register u_char *a, *m; - int bits; - - if ((addr == 0) && (mask == 0)) { - sprintf(s, "default"); - return (s); - } - a = (u_char *)&addr; - m = (u_char *)&mask; - bits = 33 - ffs(ntohl(mask)); - - if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3], - bits); - else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits); - else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits); - else sprintf(s, "%u/%d", a[0], bits); - - return (s); -} - -/* - * Convert the printable string representation of an IP address into the - * u_long (network) format. Return 0xffffffff on error. (To detect the - * legal address with that value, you must explicitly compare the string - * with "255.255.255.255".) - */ -u_int32 -inet_parse(s,n) - char *s; - int n; -{ - u_int32 a = 0; - u_int a0 = 0, a1 = 0, a2 = 0, a3 = 0; - int i; - char c; - - i = sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c); - if (i < n || i > 4 || a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255) - return (0xffffffff); - - ((u_char *)&a)[0] = a0; - ((u_char *)&a)[1] = a1; - ((u_char *)&a)[2] = a2; - ((u_char *)&a)[3] = a3; - - return (a); -} - - -/* - * inet_cksum extracted from: - * P I N G . C - * - * Author - - * Mike Muuss - * U. S. Army Ballistic Research Laboratory - * December, 1983 - * Modified at Uc Berkeley - * - * (ping.c) Status - - * Public Domain. Distribution Unlimited. - * - * I N _ C K S U M - * - * Checksum routine for Internet Protocol family headers (C Version) - * - */ -int -inet_cksum(addr, len) - u_short *addr; - u_int len; -{ - register int nleft = (int)len; - register u_short *w = addr; - u_short answer = 0; - register int sum = 0; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), - * we add sequential 16 bit words to it, and at the end, fold - * back all the carry bits from the top 16 bits into the lower - * 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) { - *(u_char *) (&answer) = *(u_char *)w ; - sum += answer; - } - - /* - * add back carry outs from top 16 bits to low 16 bits - */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return (answer); -} diff --git a/usr.sbin/mrouted/ipip.c b/usr.sbin/mrouted/ipip.c deleted file mode 100644 index 6e88d93..0000000 --- a/usr.sbin/mrouted/ipip.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp - */ - - -#include "defs.h" - -#ifndef lint -static char rcsid[] = "@(#) $Id: \ -ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp $"; -#endif - -/* - * Exported variables. - */ -#ifdef notyet -int raw_socket; /* socket for raw network I/O */ -#endif -/* - *XXX For now, we just use the IGMP socket to send packets. - * This is legal in BSD, because the protocol # is not checked - * on raw sockets. The k_* interfaces need to gain a socket - * argument so that we can call them on the raw_socket also. - */ -#define raw_socket igmp_socket - -/* - * Private variables. - */ -static int rawid = 0; - -/* - * Open and initialize the raw socket. - */ -void -init_ipip() -{ -#ifdef notyet - if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) - log(LOG_ERR, errno, "Raw IP socket"); -#endif -} - -/* - * Allocate and fill in static IP header for encapsulating on a tunnel. - */ -void -init_ipip_on_vif(v) - struct uvif *v; -{ - struct ip *ip; - - ip = v->uv_encap_hdr = (struct ip *)malloc(sizeof(struct ip)); - if (ip == NULL) - log(LOG_ERR, 0, "out of memory"); - bzero(ip, sizeof(struct ip)); - /* - * Fields zeroed that aren't filled in later: - * - IP ID (let the kernel fill it in) - * - Offset (we don't send fragments) - * - Checksum (let the kernel fill it in) - */ - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(struct ip) >> 2; - ip->ip_tos = 0xc0; /* Internet Control */ - ip->ip_ttl = MAXTTL; /* applies to unicasts only */ - ip->ip_p = IPPROTO_IPIP; - ip->ip_src.s_addr = v->uv_lcl_addr; - ip->ip_dst.s_addr = v->uv_rmt_addr; -} - -/* - * Call build_igmp() to build an IGMP message in the output packet buffer. - * Then fill in the fields of the IP packet that build_igmp() left for the - * kernel to fill in, and encapsulate the original packet with the - * pre-created ip header for this vif. - */ -void -send_ipip(src, dst, type, code, group, datalen, v) - u_int32 src, dst; - int type, code; - u_int32 group; - int datalen; - struct uvif *v; -{ - struct msghdr msg; - struct iovec iov[2]; - struct sockaddr_in sdst; - struct ip *ip; - - build_igmp(src, dst, type, code, group, datalen); - ip = (struct ip *)send_buf; -#ifndef RAW_OUTPUT_IS_RAW - ip->ip_len = htons(ip->ip_len); -#endif - ip->ip_id = htons(rawid++); - ip->ip_sum = 0; - ip->ip_sum = inet_cksum((u_short *)ip, ip->ip_hl << 2); - - ip = v->uv_encap_hdr; - ip->ip_len = 2 * MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; -#ifdef RAW_OUTPUT_IS_RAW - ip->ip_len = htons(ip->ip_len); -#endif - - bzero(&sdst, sizeof(sdst)); - sdst.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - sdst.sin_len = sizeof(sdst); -#endif - sdst.sin_addr = ip->ip_dst; - - iov[0].iov_base = (caddr_t)v->uv_encap_hdr; - iov[0].iov_len = sizeof(struct ip); - iov[1].iov_base = (caddr_t)send_buf; - iov[1].iov_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; - - bzero(&msg, sizeof(msg)); - msg.msg_name = (caddr_t)&sdst; - msg.msg_namelen = sizeof(sdst); - msg.msg_iov = iov; - msg.msg_iovlen = 2; - if (sendmsg(raw_socket, &msg, 0) < 0) { - if (errno == ENETDOWN) - check_vif_state(); - else - log(LOG_WARNING, errno, - "sendmsg to %s on %s", - inet_fmt(sdst.sin_addr.s_addr, s1), inet_fmt(src, s2)); - } - - IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code)) - log(LOG_DEBUG, 0, "SENT %s from %-15s to %s encaped to %s", - igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" : - inet_fmt(src, s1), inet_fmt(dst, s2), - inet_fmt(sdst.sin_addr.s_addr, s3)); -} diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c deleted file mode 100644 index 716b479..0000000 --- a/usr.sbin/mrouted/kern.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * kern.c,v 3.8.4.10 1998/01/06 02:00:51 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -int curttl = 0; - -void k_set_rcvbuf(bufsize, minsize) - int bufsize; - int minsize; -{ - int delta = bufsize / 2; - int iter = 0; - - /* - * Set the socket buffer. If we can't set it as large as we - * want, search around to try to find the highest acceptable - * value. The highest acceptable value being smaller than - * minsize is a fatal error. - */ - if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, - (char *)&bufsize, sizeof(bufsize)) < 0) { - bufsize -= delta; - while (1) { - iter++; - if (delta > 1) - delta /= 2; - - if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, - (char *)&bufsize, sizeof(bufsize)) < 0) { - bufsize -= delta; - } else { - if (delta < 1024) - break; - bufsize += delta; - } - } - if (bufsize < minsize) { - log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u", - bufsize, minsize); - /*NOTREACHED*/ - } - } - IF_DEBUG(DEBUG_KERN) - log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations", - bufsize, iter); -} - - -void k_hdr_include(bool) - int bool; -{ -#ifdef IP_HDRINCL - if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, - (char *)&bool, sizeof(bool)) < 0) - log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool); -#endif -} - - -void k_set_ttl(t) - int t; -{ -#ifndef RAW_OUTPUT_IS_RAW - u_char ttl; - - ttl = t; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, - (char *)&ttl, sizeof(ttl)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl); -#endif - curttl = t; -} - - -void k_set_loop(l) - int l; -{ - u_char loop; - - loop = l; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, - (char *)&loop, sizeof(loop)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop); -} - - -void k_set_if(ifa) - u_int32 ifa; -{ - struct in_addr adr; - - adr.s_addr = ifa; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&adr, sizeof(adr)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s", - inet_fmt(ifa, s1)); -} - - -void k_join(grp, ifa) - u_int32 grp; - u_int32 ifa; -{ - struct ip_mreq mreq; - - mreq.imr_multiaddr.s_addr = grp; - mreq.imr_interface.s_addr = ifa; - - if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) < 0) - log(LOG_WARNING, errno, "can't join group %s on interface %s", - inet_fmt(grp, s1), inet_fmt(ifa, s2)); -} - - -void k_leave(grp, ifa) - u_int32 grp; - u_int32 ifa; -{ - struct ip_mreq mreq; - - mreq.imr_multiaddr.s_addr = grp; - mreq.imr_interface.s_addr = ifa; - - if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) < 0) - log(LOG_WARNING, errno, "can't leave group %s on interface %s", - inet_fmt(grp, s1), inet_fmt(ifa, s2)); -} - - -void k_init_dvmrp() -{ -#ifdef OLD_KERNEL - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, - (char *)NULL, 0) < 0) -#else - int v=1; - - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, - (char *)&v, sizeof(int)) < 0) -#endif - log(LOG_ERR, errno, "can't enable Multicast routing in kernel"); -} - - -void k_stop_dvmrp() -{ - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE, - (char *)NULL, 0) < 0) - log(LOG_WARNING, errno, "can't disable Multicast routing in kernel"); -} - - -void k_add_vif(vifi, v) - vifi_t vifi; - struct uvif *v; -{ - struct vifctl vc; - - vc.vifc_vifi = vifi; - vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS; - vc.vifc_threshold = v->uv_threshold; - vc.vifc_rate_limit = v->uv_rate_limit; - vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr; - vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr; - - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF, - (char *)&vc, sizeof(vc)) < 0) - log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi); -} - - -void k_del_vif(vifi) - vifi_t vifi; -{ - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF, - (char *)&vifi, sizeof(vifi)) < 0) - log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi); -} - - -/* - * Adds a (source, mcastgrp) entry to the kernel - */ -void k_add_rg(origin, g) - u_int32 origin; - struct gtable *g; -{ - struct mfcctl mc; - vifi_t i; - -#ifdef DEBUG_MFC - md_log(MD_ADD, origin, g->gt_mcastgrp); -#endif - /* copy table values so that setsockopt can process it */ - mc.mfcc_origin.s_addr = origin; -#ifdef OLD_KERNEL - mc.mfcc_originmask.s_addr = 0xffffffff; -#endif - mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp; - mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF; - for (i = 0; i < numvifs; i++) - mc.mfcc_ttls[i] = g->gt_ttls[i]; - - /* write to kernel space */ - if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC, - (char *)&mc, sizeof(mc)) < 0) { -#ifdef DEBUG_MFC - md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp); -#endif - log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC", - inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2)); - } -} - - -/* - * Deletes a (source, mcastgrp) entry from the kernel - */ -int k_del_rg(origin, g) - u_int32 origin; - struct gtable *g; -{ - struct mfcctl mc; - int retval; - -#ifdef DEBUG_MFC - md_log(MD_DEL, origin, g->gt_mcastgrp); -#endif - /* copy table values so that setsockopt can process it */ - mc.mfcc_origin.s_addr = origin; -#ifdef OLD_KERNEL - mc.mfcc_originmask.s_addr = 0xffffffff; -#endif - mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp; - - /* write to kernel space */ - if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC, - (char *)&mc, sizeof(mc))) < 0) { -#ifdef DEBUG_MFC - md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp); -#endif - log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)", - inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2)); - } - - return retval; -} - -/* - * Get the kernel's idea of what version of mrouted needs to run with it. - */ -int k_get_version() -{ -#ifdef OLD_KERNEL - return -1; -#else - int vers; - int len = sizeof(vers); - - if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION, - (char *)&vers, &len) < 0) - log(LOG_ERR, errno, - "getsockopt MRT_VERSION: perhaps your kernel is too old"); - - return vers; -#endif -} - -#if 0 -/* - * Get packet counters - */ -int -k_get_vif_count(vifi, icount, ocount, ibytes, obytes) - vifi_t vifi; - int *icount, *ocount, *ibytes, *obytes; -{ - struct sioc_vif_req vreq; - int retval = 0; - - vreq.vifi = vifi; - if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) { - log(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi); - vreq.icount = vreq.ocount = vreq.ibytes = - vreq.obytes = 0xffffffff; - retval = 1; - } - if (icount) - *icount = vreq.icount; - if (ocount) - *ocount = vreq.ocount; - if (ibytes) - *ibytes = vreq.ibytes; - if (obytes) - *obytes = vreq.obytes; - return retval; -} - -/* - * Get counters for a desired source and group. - */ -int -k_get_sg_count(src, grp, pktcnt, bytecnt, wrong_if) - u_int32 src; - u_int32 grp; - struct sg_count *retval; -{ - struct sioc_sg_req sgreq; - int retval = 0; - - sgreq.src.s_addr = src; - sgreq.grp.s_addr = grp; - if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sgreq) < 0) { - log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)", - inet_fmt(src, s1), inet_fmt(grp, s2)); - sgreq.pktcnt = sgreq.bytecnt = sgreq.wrong_if = 0xffffffff; - return 1; - } - if (pktcnt) - *pktcnt = sgreq.pktcnt; - if (bytecnt) - *bytecnt = sgreq.bytecnt; - if (wrong_if) - *wrong_if = sgreq.wrong_if; - return retval; -} -#endif diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c deleted file mode 100644 index 7558990..0000000 --- a/usr.sbin/mrouted/main.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * main.c,v 3.8.4.29 1998/03/01 01:49:00 fenner Exp - */ - -/* - * Written by Steve Deering, Stanford University, February 1989. - * - * (An earlier version of DVMRP was implemented by David Waitzman of - * BBN STC by extending Berkeley's routed program. Some of Waitzman's - * extensions have been incorporated into mrouted, but none of the - * original routed code has been adopted.) - */ - - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#include <err.h> -#include "defs.h" -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif -#include <fcntl.h> -#include <paths.h> - -#ifdef SNMP -#include "snmp.h" -#endif - -extern char *configfilename; -char versionstring[100]; - -static char pidfilename[] = _PATH_MROUTED_PID; -static char dumpfilename[] = _PATH_MROUTED_DUMP; -static char cachefilename[] = _PATH_MROUTED_CACHE; -static char genidfilename[] = _PATH_MROUTED_GENID; - -static int haveterminal = 1; -int did_final_init = 0; - -static int sighandled = 0; -#define GOT_SIGINT 0x01 -#define GOT_SIGHUP 0x02 -#define GOT_SIGUSR1 0x04 -#define GOT_SIGUSR2 0x08 - -int cache_lifetime = DEFAULT_CACHE_LIFETIME; -int prune_lifetime = AVERAGE_PRUNE_LIFETIME; - -int debug = 0; -char *progname; -time_t mrouted_init_time; - -#ifdef SNMP -#define NHANDLERS 34 -#else -#define NHANDLERS 2 -#endif - -static struct ihandler { - int fd; /* File descriptor */ - ihfunc_t func; /* Function to call with &fd_set */ -} ihandlers[NHANDLERS]; -static int nhandlers = 0; - -static struct debugname { - char *name; - int level; - int nchars; -} debugnames[] = { - { "packet", DEBUG_PKT, 2 }, - { "pkt", DEBUG_PKT, 3 }, - { "pruning", DEBUG_PRUNE, 1 }, - { "prunes", DEBUG_PRUNE, 1 }, - { "routing", DEBUG_ROUTE, 1 }, - { "routes", DEBUG_ROUTE, 1 }, - { "route_detail", DEBUG_RTDETAIL, 6 }, - { "rtdetail", DEBUG_RTDETAIL, 2 }, - { "peers", DEBUG_PEER, 2 }, - { "neighbors", DEBUG_PEER, 1 }, - { "cache", DEBUG_CACHE, 1 }, - { "timeout", DEBUG_TIMEOUT, 1 }, - { "callout", DEBUG_TIMEOUT, 2 }, - { "interface", DEBUG_IF, 2 }, - { "vif", DEBUG_IF, 1 }, - { "membership", DEBUG_MEMBER, 1 }, - { "groups", DEBUG_MEMBER, 1 }, - { "traceroute", DEBUG_TRACE, 2 }, - { "mtrace", DEBUG_TRACE, 2 }, - { "igmp", DEBUG_IGMP, 1 }, - { "icmp", DEBUG_ICMP, 2 }, - { "rsrr", DEBUG_RSRR, 2 }, - { "3", 0xffffffff, 1 } /* compat. */ -}; - -/* - * Forward declarations. - */ -static void final_init __P((void *)); -static void fasttimer __P((void *)); -static void timer __P((void *)); -static void dump __P((void)); -static void dump_version __P((FILE *)); -static void fdump __P((void)); -static void cdump __P((void)); -static void restart __P((void)); -static void handler __P((int)); -static void cleanup __P((void)); -static void resetlogging __P((void *)); -static void usage __P((void)); - -/* To shut up gcc -Wstrict-prototypes */ -int main __P((int argc, char **argv)); - -int -register_input_handler(fd, func) - int fd; - ihfunc_t func; -{ - if (nhandlers >= NHANDLERS) - return -1; - - ihandlers[nhandlers].fd = fd; - ihandlers[nhandlers++].func = func; - - return 0; -} - -int -main(argc, argv) - int argc; - char *argv[]; -{ - register int recvlen; - int dummy; - FILE *fp; - struct timeval tv, difftime, curtime, lasttime, *timeout; - u_int32 prev_genid; - int vers; - fd_set rfds, readers; - int nfds, n, i, secs; - extern char todaysversion[]; - struct sigaction sa; -#ifdef SNMP - struct timeval timeout, *tvp = &timeout; - struct timeval sched, *svp = &sched, now, *nvp = &now; - int index, block; -#endif - - setlinebuf(stderr); - - if (geteuid() != 0) - errx(1, "must be root"); - - progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - argv++, argc--; - while (argc > 0 && *argv[0] == '-') { - if (strcmp(*argv, "-d") == 0) { - if (argc > 1 && *(argv + 1)[0] != '-') { - char *p,*q; - int i, len; - struct debugname *d; - - argv++, argc--; - debug = 0; - p = *argv; q = NULL; - while (p) { - q = strchr(p, ','); - if (q) - *q++ = '\0'; - len = strlen(p); - for (i = 0, d = debugnames; - i < sizeof(debugnames) / sizeof(debugnames[0]); - i++, d++) - if (len >= d->nchars && strncmp(d->name, p, len) == 0) - break; - if (i == sizeof(debugnames) / sizeof(debugnames[0])) { - int j = 0xffffffff; - int k = 0; - fprintf(stderr, "Valid debug levels: "); - for (i = 0, d = debugnames; - i < sizeof(debugnames) / sizeof(debugnames[0]); - i++, d++) { - if ((j & d->level) == d->level) { - if (k++) - putc(',', stderr); - fputs(d->name, stderr); - j &= ~d->level; - } - } - putc('\n', stderr); - usage(); - } - debug |= d->level; - p = q; - } - } else - debug = DEFAULT_DEBUG; - } else if (strcmp(*argv, "-c") == 0) { - if (argc > 1) { - argv++, argc--; - configfilename = *argv; - } else - usage(); - } else if (strcmp(*argv, "-p") == 0) { - log(LOG_WARNING, 0, "disabling pruning is no longer supported"); -#ifdef SNMP - } else if (strcmp(*argv, "-P") == 0) { - if (argc > 1 && isdigit(*(argv + 1)[0])) { - argv++, argc--; - dest_port = atoi(*argv); - } else - dest_port = DEFAULT_PORT; -#endif - } else - usage(); - argv++, argc--; - } - - if (argc > 0) - usage(); - - if (debug != 0) { - struct debugname *d; - char c; - int tmpd = debug; - - fprintf(stderr, "debug level 0x%x ", debug); - c = '('; - for (d = debugnames; d < debugnames + - sizeof(debugnames) / sizeof(debugnames[0]); d++) { - if ((tmpd & d->level) == d->level) { - tmpd &= ~d->level; - fprintf(stderr, "%c%s", c, d->name); - c = ','; - } - } - fprintf(stderr, ")\n"); - } - -#ifdef LOG_DAEMON - (void)openlog("mrouted", LOG_PID, LOG_DAEMON); - (void)setlogmask(LOG_UPTO(LOG_NOTICE)); -#else - (void)openlog("mrouted", LOG_PID); -#endif - sprintf(versionstring, "mrouted version %s", todaysversion); - - log(LOG_DEBUG, 0, "%s starting", versionstring); - -#ifdef SYSV - srand48(time(NULL)); -#endif - - /* - * Get generation id - */ - gettimeofday(&tv, 0); - dvmrp_genid = tv.tv_sec; - - fp = fopen(genidfilename, "r"); - if (fp != NULL) { - fscanf(fp, "%d", &prev_genid); - if (prev_genid == dvmrp_genid) - dvmrp_genid++; - (void) fclose(fp); - } - - fp = fopen(genidfilename, "w"); - if (fp != NULL) { - fprintf(fp, "%d", dvmrp_genid); - (void) fclose(fp); - } - - /* Start up the log rate-limiter */ - resetlogging(NULL); - - callout_init(); - init_igmp(); - init_icmp(); - init_ipip(); - init_routes(); - init_ktable(); -#ifndef OLD_KERNEL - /* - * Unfortunately, you can't k_get_version() unless you've - * k_init_dvmrp()'d. Now that we want to move the - * k_init_dvmrp() to later in the initialization sequence, - * we have to do the disgusting hack of initializing, - * getting the version, then stopping the kernel multicast - * forwarding. - */ - k_init_dvmrp(); - vers = k_get_version(); - k_stop_dvmrp(); - /*XXX - * This function must change whenever the kernel version changes - */ - if ((((vers >> 8) & 0xff) != 3) || - ((vers & 0xff) != 5)) - log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch", - (vers >> 8) & 0xff, vers & 0xff, - PROTOCOL_VERSION, MROUTED_VERSION); -#endif - -#ifdef SNMP - if (i = snmp_init()) - return i; - - gettimeofday(nvp, 0); - if (nvp->tv_usec < 500000L){ - svp->tv_usec = nvp->tv_usec + 500000L; - svp->tv_sec = nvp->tv_sec; - } else { - svp->tv_usec = nvp->tv_usec - 500000L; - svp->tv_sec = nvp->tv_sec + 1; - } -#endif /* SNMP */ - - init_vifs(); - -#ifdef RSRR - rsrr_init(); -#endif /* RSRR */ - - sa.sa_handler = handler; - sa.sa_flags = 0; /* Interrupt system calls */ - sigemptyset(&sa.sa_mask); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGUSR1, &sa, NULL); - sigaction(SIGUSR2, &sa, NULL); - - if (igmp_socket >= FD_SETSIZE) - log(LOG_ERR, 0, "descriptor too big"); - FD_ZERO(&readers); - FD_SET(igmp_socket, &readers); - nfds = igmp_socket + 1; - for (i = 0; i < nhandlers; i++) { - if (ihandlers[i].fd >= FD_SETSIZE) - log(LOG_ERR, 0, "descriptor too big"); - FD_SET(ihandlers[i].fd, &readers); - if (ihandlers[i].fd >= nfds) - nfds = ihandlers[i].fd + 1; - } - - IF_DEBUG(DEBUG_IF) - dump_vifs(stderr); - IF_DEBUG(DEBUG_ROUTE) - dump_routes(stderr); - - /* schedule first timer interrupt */ - timer_setTimer(1, fasttimer, NULL); - timer_setTimer(TIMER_INTERVAL, timer, NULL); - - if (debug == 0) { - /* - * Detach from the terminal - */ - int t; - - haveterminal = 0; - if (fork()) exit(0); - (void)close(0); - (void)close(1); - (void)close(2); - (void)open("/", 0); - (void)dup2(0, 1); - (void)dup2(0, 2); -#if defined(SYSV) || defined(linux) - (void)setpgrp(); -#else -#ifdef TIOCNOTTY - t = open(_PATH_TTY, 2); - if (t >= 0) { - (void)ioctl(t, TIOCNOTTY, (char *)0); - (void)close(t); - } -#else - if (setsid() < 0) - perror("setsid"); -#endif -#endif - } - - fp = fopen(pidfilename, "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", (int)getpid()); - (void) fclose(fp); - } - - /* XXX HACK - * This will cause black holes for the first few seconds after startup, - * since we are exchanging routes but not actually forwarding. - * However, it eliminates much of the startup transient. - * - * It's possible that we can set a flag which says not to report any - * routes (just accept reports) until this timer fires, and then - * do a report_to_all_neighbors(ALL_ROUTES) immediately before - * turning on DVMRP. - */ - timer_setTimer(10, final_init, NULL); - - /* - * Main receive loop. - */ - dummy = 0; - difftime.tv_usec = 0; - gettimeofday(&curtime, NULL); - lasttime = curtime; - for(;;) { - bcopy((char *)&readers, (char *)&rfds, sizeof(rfds)); - secs = timer_nextTimer(); - if (secs == -1) - timeout = NULL; - else { - timeout = &tv; - timeout->tv_sec = secs; - timeout->tv_usec = 0; - } -#ifdef SNMP - THIS IS BROKEN - if (nvp->tv_sec > svp->tv_sec - || (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){ - alarmTimer(nvp); - eventTimer(nvp); - if (nvp->tv_usec < 500000L){ - svp->tv_usec = nvp->tv_usec + 500000L; - svp->tv_sec = nvp->tv_sec; - } else { - svp->tv_usec = nvp->tv_usec - 500000L; - svp->tv_sec = nvp->tv_sec + 1; - } - } - - tvp = &timeout; - tvp->tv_sec = 0; - tvp->tv_usec = 500000L; - - block = 0; - snmp_select_info(&nfds, &rfds, tvp, &block); - if (block == 1) - tvp = NULL; /* block without timeout */ - if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0) -#endif - if (sighandled) { - if (sighandled & GOT_SIGINT) { - sighandled &= ~GOT_SIGINT; - break; - } - if (sighandled & GOT_SIGHUP) { - sighandled &= ~GOT_SIGHUP; - restart(); - } - if (sighandled & GOT_SIGUSR1) { - sighandled &= ~GOT_SIGUSR1; - fdump(); - } - if (sighandled & GOT_SIGUSR2) { - sighandled &= ~GOT_SIGUSR2; - cdump(); - } - } - if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) { - if (errno != EINTR) - log(LOG_WARNING, errno, "select failed"); - continue; - } - - if (n > 0) { - if (FD_ISSET(igmp_socket, &rfds)) { - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, NULL, &dummy); - if (recvlen < 0) { - if (errno != EINTR) log(LOG_ERR, errno, "recvfrom"); - continue; - } - accept_igmp(recvlen); - } - - for (i = 0; i < nhandlers; i++) { - if (FD_ISSET(ihandlers[i].fd, &rfds)) { - (*ihandlers[i].func)(ihandlers[i].fd, &rfds); - } - } - } - -#ifdef SNMP - THIS IS BROKEN - snmp_read(&rfds); - snmp_timeout(); /* poll */ -#endif - /* - * Handle timeout queue. - * - * If select + packet processing took more than 1 second, - * or if there is a timeout pending, age the timeout queue. - * - * If not, collect usec in difftime to make sure that the - * time doesn't drift too badly. - * - * If the timeout handlers took more than 1 second, - * age the timeout queue again. XXX This introduces the - * potential for infinite loops! - */ - do { - /* - * If the select timed out, then there's no other - * activity to account for and we don't need to - * call gettimeofday. - */ - if (n == 0) { - curtime.tv_sec = lasttime.tv_sec + secs; - curtime.tv_usec = lasttime.tv_usec; - n = -1; /* don't do this next time through the loop */ - } else - gettimeofday(&curtime, NULL); - difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; - difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec; - while (difftime.tv_usec >= 1000000) { - difftime.tv_sec++; - difftime.tv_usec -= 1000000; - } - if (difftime.tv_usec < 0) { - difftime.tv_sec--; - difftime.tv_usec += 1000000; - } - lasttime = curtime; - if (secs == 0 || difftime.tv_sec > 0) - age_callout_queue(difftime.tv_sec); - secs = -1; - } while (difftime.tv_sec > 0); - } - log(LOG_NOTICE, 0, "%s exiting", versionstring); - cleanup(); - exit(0); -} - -static void -usage() -{ - fprintf(stderr, - "usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n"); - exit(1); -} - -static void -final_init(i) - void *i; -{ - char *s = (char *)i; - - log(LOG_NOTICE, 0, "%s%s", versionstring, s ? s : ""); - if (s) - free(s); - - k_init_dvmrp(); /* enable DVMRP routing in kernel */ - - /* - * Install the vifs in the kernel as late as possible in the - * initialization sequence. - */ - init_installvifs(); - - time(&mrouted_init_time); - did_final_init = 1; -} - -/* - * routine invoked every second. Its main goal is to cycle through - * the routing table and send partial updates to all neighbors at a - * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL - * seconds. Also, every TIMER_INTERVAL seconds it calls timer() to - * do all the other time-based processing. - */ -static void -fasttimer(i) - void *i; -{ - static unsigned int tlast; - static unsigned int nsent; - register unsigned int t = tlast + 1; - register int n; - - /* - * if we're in the last second, send everything that's left. - * otherwise send at least the fraction we should have sent by now. - */ - if (t >= ROUTE_REPORT_INTERVAL) { - register int nleft = nroutes - nsent; - while (nleft > 0) { - if ((n = report_next_chunk()) <= 0) - break; - nleft -= n; - } - tlast = 0; - nsent = 0; - } else { - register unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL; - while (nsent < ncum) { - if ((n = report_next_chunk()) <= 0) - break; - nsent += n; - } - tlast = t; - } - - timer_setTimer(1, fasttimer, NULL); -} - -/* - * The 'virtual_time' variable is initialized to a value that will cause the - * first invocation of timer() to send a probe or route report to all vifs - * and send group membership queries to all subnets for which this router is - * querier. This first invocation occurs approximately TIMER_INTERVAL seconds - * after the router starts up. Note that probes for neighbors and queries - * for group memberships are also sent at start-up time, as part of initial- - * ization. This repetition after a short interval is desirable for quickly - * building up topology and membership information in the presence of possible - * packet loss. - * - * 'virtual_time' advances at a rate that is only a crude approximation of - * real time, because it does not take into account any time spent processing, - * and because the timer intervals are sometimes shrunk by a random amount to - * avoid unwanted synchronization with other routers. - */ - -u_long virtual_time = 0; - - -/* - * Timer routine. Performs periodic neighbor probing, route reporting, and - * group querying duties, and drives various timers in routing entries and - * virtual interface data structures. - */ -static void -timer(i) - void *i; -{ - age_routes(); /* Advance the timers in the route entries */ - age_vifs(); /* Advance the timers for neighbors */ - age_table_entry(); /* Advance the timers for the cache entries */ - - if (virtual_time % IGMP_QUERY_INTERVAL == 0) { - /* - * Time to query the local group memberships on all subnets - * for which this router is the elected querier. - */ - query_groups(); - } - - if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) { - /* - * Time to send a probe on all vifs from which no neighbors have - * been heard. Also, check if any inoperative interfaces have now - * come up. (If they have, they will also be probed as part of - * their initialization.) - */ - probe_for_neighbors(); - - if (vifs_down) - check_vif_state(); - } - - delay_change_reports = FALSE; - if (routes_changed) { - /* - * Some routes have changed since the last timer interrupt, but - * have not been reported yet. Report the changed routes to all - * neighbors. - */ - report_to_all_neighbors(CHANGED_ROUTES); - } - -#ifdef SNMP - sync_timer(); -#endif - - /* - * Advance virtual time - */ - virtual_time += TIMER_INTERVAL; - timer_setTimer(TIMER_INTERVAL, timer, NULL); -} - - -static void -cleanup() -{ - static int in_cleanup = 0; - - if (!in_cleanup) { - in_cleanup++; -#ifdef RSRR - rsrr_clean(); -#endif /* RSRR */ - expire_all_routes(); - report_to_all_neighbors(ALL_ROUTES); - if (did_final_init) - k_stop_dvmrp(); - } -} - -/* - * Signal handler. Take note of the fact that the signal arrived - * so that the main loop can take care of it. - */ -static void -handler(sig) - int sig; -{ - switch (sig) { - case SIGINT: - case SIGTERM: - sighandled |= GOT_SIGINT; - break; - - case SIGHUP: - sighandled |= GOT_SIGHUP; - break; - - case SIGUSR1: - sighandled |= GOT_SIGUSR1; - break; - - case SIGUSR2: - sighandled |= GOT_SIGUSR2; - break; - } -} - -/* - * Dump internal data structures to stderr. - */ -static void -dump() -{ - dump_vifs(stderr); - dump_routes(stderr); -} - -static void -dump_version(fp) - FILE *fp; -{ - time_t t; - - time(&t); - fprintf(fp, "%s ", versionstring); - if (did_final_init) - fprintf(fp, "up %s", - scaletime(t - mrouted_init_time)); - else - fprintf(fp, "(not yet initialized)"); - fprintf(fp, " %s\n", ctime(&t)); -} - -/* - * Dump internal data structures to a file. - */ -static void -fdump() -{ - FILE *fp; - - fp = fopen(dumpfilename, "w"); - if (fp != NULL) { - dump_version(fp); - dump_vifs(fp); - dump_routes(fp); - (void) fclose(fp); - } -} - - -/* - * Dump local cache contents to a file. - */ -static void -cdump() -{ - FILE *fp; - - fp = fopen(cachefilename, "w"); - if (fp != NULL) { - dump_version(fp); - dump_cache(fp); - (void) fclose(fp); - } -} - - -/* - * Restart mrouted - */ -static void -restart() -{ - char *s; - - s = (char *)malloc(sizeof(" restart")); - if (s == NULL) - log(LOG_ERR, 0, "out of memory"); - strcpy(s, " restart"); - - /* - * reset all the entries - */ - free_all_prunes(); - free_all_routes(); - free_all_callouts(); - stop_all_vifs(); - k_stop_dvmrp(); - close(igmp_socket); - close(udp_socket); - did_final_init = 0; - - /* - * start processing again - */ - dvmrp_genid++; - - init_igmp(); - init_routes(); - init_ktable(); - init_vifs(); - /*XXX Schedule final_init() as main does? */ - final_init(s); - - /* schedule timer interrupts */ - timer_setTimer(1, fasttimer, NULL); - timer_setTimer(TIMER_INTERVAL, timer, NULL); -} - -#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */ -#define LOG_SHUT_UP 600 /* shut up for 10 minutes */ -static int log_nmsgs = 0; - -static void -resetlogging(arg) - void *arg; -{ - int nxttime = 60; - void *narg = NULL; - - if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) { - nxttime = LOG_SHUT_UP; - narg = (void *)&log_nmsgs; /* just need some valid void * */ - syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes", - LOG_SHUT_UP / 60); - } else { - log_nmsgs = 0; - } - - timer_setTimer(nxttime, resetlogging, narg); -} - -char * -scaletime(t) - u_long t; -{ -#define SCALETIMEBUFLEN 20 - static char buf1[20]; - static char buf2[20]; - static char *buf = buf1; - char *p; - - p = buf; - if (buf == buf1) - buf = buf2; - else - buf = buf1; - - /* XXX snprintf */ - sprintf(p, "%2ld:%02ld:%02ld", t / 3600, (t % 3600) / 60, t % 60); - p[SCALETIMEBUFLEN - 1] = '\0'; - return p; -} - -#ifdef RINGBUFFER -#define NLOGMSGS 10000 -#define LOGMSGSIZE 200 -char *logmsg[NLOGMSGS]; -static int logmsgno = 0; - -void -printringbuf() -{ - FILE *f; - int i; - - f = fopen("/var/tmp/mrouted.log", "a"); - if (f == NULL) { - log(LOG_ERR, errno, "can't open /var/tmp/mrouted.log"); - /*NOTREACHED*/ - } - fprintf(f, "--------------------------------------------\n"); - - i = (logmsgno + 1) % NLOGMSGS; - - while (i != logmsgno) { - if (*logmsg[i]) { - fprintf(f, "%s\n", logmsg[i]); - *logmsg[i] = '\0'; - } - i = (i + 1) % NLOGMSGS; - } - - fclose(f); -} -#endif - -/* - * Log errors and other messages to the system log daemon and to stderr, - * according to the severity of the message and the current debug level. - * For errors of severity LOG_ERR or worse, terminate the program. - */ -#ifdef __STDC__ -void -log(int severity, int syserr, char *format, ...) -{ - va_list ap; - static char fmt[211] = "warning - "; - char *msg; - struct timeval now; - time_t now_sec; - struct tm *thyme; -#ifdef RINGBUFFER - static int ringbufinit = 0; -#endif - - va_start(ap, format); -#else -/*VARARGS3*/ -void -log(severity, syserr, format, va_alist) - int severity, syserr; - char *format; - va_dcl -{ - va_list ap; - static char fmt[311] = "warning - "; - char *msg; - char tbuf[20]; - struct timeval now; - time_t now_sec; - struct tm *thyme; -#ifdef RINGBUFFER - static int ringbufinit = 0; -#endif - - va_start(ap); -#endif - vsnprintf(&fmt[10], sizeof(fmt) - 10, format, ap); - va_end(ap); - msg = (severity == LOG_WARNING) ? fmt : &fmt[10]; - -#ifdef RINGBUFFER - if (!ringbufinit) { - int i; - - for (i = 0; i < NLOGMSGS; i++) { - logmsg[i] = malloc(LOGMSGSIZE); - if (logmsg[i] == 0) { - syslog(LOG_ERR, "out of memory"); - exit(-1); - } - *logmsg[i] = 0; - } - ringbufinit = 1; - } - gettimeofday(&now,NULL); - now_sec = now.tv_sec; - thyme = localtime(&now_sec); - snprintf(logmsg[logmsgno++], LOGMSGSIZE, "%02d:%02d:%02d.%03ld %s err %d", - thyme->tm_hour, thyme->tm_min, thyme->tm_sec, - now.tv_usec / 1000, msg, syserr); - logmsgno %= NLOGMSGS; - if (severity <= LOG_NOTICE) -#endif - /* - * Log to stderr if we haven't forked yet and it's a warning or worse, - * or if we're debugging. - */ - if (haveterminal && (debug || severity <= LOG_WARNING)) { - gettimeofday(&now,NULL); - now_sec = now.tv_sec; - thyme = localtime(&now_sec); - if (!debug) - fprintf(stderr, "%s: ", progname); - fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour, - thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg); - if (syserr == 0) - fprintf(stderr, "\n"); - else if (syserr < sys_nerr) - fprintf(stderr, ": %s\n", sys_errlist[syserr]); - else - fprintf(stderr, ": errno %d\n", syserr); - } - - /* - * Always log things that are worse than warnings, no matter what - * the log_nmsgs rate limiter says. - * Only count things worse than debugging in the rate limiter - * (since if you put daemon.debug in syslog.conf you probably - * actually want to log the debugging messages so they shouldn't - * be rate-limited) - */ - if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) { - if (severity < LOG_DEBUG) - log_nmsgs++; - if (syserr != 0) { - errno = syserr; - syslog(severity, "%s: %m", msg); - } else - syslog(severity, "%s", msg); - } - - if (severity <= LOG_ERR) exit(-1); -} - -#ifdef DEBUG_MFC -void -md_log(what, origin, mcastgrp) - int what; - u_int32 origin, mcastgrp; -{ - static FILE *f = NULL; - struct timeval tv; - u_int32 buf[4]; - - if (!f) { - if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) { - log(LOG_ERR, errno, "open /tmp/mrouted.clog"); - } - } - - gettimeofday(&tv, NULL); - buf[0] = tv.tv_sec; - buf[1] = what; - buf[2] = origin; - buf[3] = mcastgrp; - - fwrite(buf, sizeof(u_int32), 4, f); -} -#endif diff --git a/usr.sbin/mrouted/map-mbone.8 b/usr.sbin/mrouted/map-mbone.8 deleted file mode 100644 index a6e9e58..0000000 --- a/usr.sbin/mrouted/map-mbone.8 +++ /dev/null @@ -1,96 +0,0 @@ -.\" $FreeBSD$ -.\" -.Dd May 8, 1995 -.Dt MAP-MBONE 8 -.Os -.Sh NAME -.Nm map-mbone -.Nd multicast connection mapper -.Sh SYNOPSIS -.Nm -.Op Fl d Ar debug_level -.Op Fl f -.Op Fl g -.Op Fl n -.Op Fl r Ar retry_count -.Op Fl t Ar timeout_count -.Op Ar starting_router -.Sh DESCRIPTION -The -.Nm -utility -attempts to display all multicast routers that are reachable from the multicast -.Ar starting_router . -If not specified on the command line, the default multicast -.Ar starting_router -is the localhost. -.Pp -The -.Nm -utility -traverses neighboring multicast routers by sending the ASK_NEIGHBORS IGMP -message to the multicast starting_router. -If this multicast router responds, -the version number and a list of their neighboring multicast router addresses is -part of that response. -If the responding router has recent multicast version -number, then -.Nm -requests additional information such as metrics, thresholds, and flags from the -multicast router. -For each new occurrence of neighboring multicast router in -the reply and provided the flooding option has been selected, then -.Nm -asks each of this multicast router for a list of neighbors. -This search -for unique routers will continue until no new neighboring multicast routers -are reported. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl d -Set the debug level. -When the debug level is greater than the -default value of 0, addition debugging messages are printed. -Regardless of -the debug level, an error condition, will always write an error message and will -cause -.Nm -to terminate. -Non-zero debug levels have the following effects: -.Bl -tag -width indent -.It "level 1" -packet warnings are printed to stderr. -.It "level 2" -all level 1 messages plus notifications down networks are printed to stderr. -.It "level 3" -all level 2 messages plus notifications of all packet -timeouts are printed to stderr. -.El -.It Fl f -Set flooding option. -Flooding allows the recursive search -of neighboring multicast routers and is enable by default when starting_router -is not used. -.It Fl g -Set graphing in GraphEd format. -.It Fl n -Disable the DNS lookup for the multicast routers names. -.It Fl r Ar retry_count -Set the neighbor query retry limit. -Default is 1 retry. -.It Fl t Ar timeout_count -Set the number of seconds to wait for a neighbor query -reply before retrying. -Default timeout is 2 seconds. -.El -.Sh IMPORTANT NOTE -The -.Nm -utility must be run as root. -.Sh SEE ALSO -.Xr mrinfo 8 , -.Xr mrouted 8 , -.Xr mtrace 8 -.Sh AUTHORS -.An Pavel Curtis diff --git a/usr.sbin/mrouted/map-mbone/Makefile b/usr.sbin/mrouted/map-mbone/Makefile deleted file mode 100644 index f99247b..0000000 --- a/usr.sbin/mrouted/map-mbone/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -PROG= map-mbone -MAN= map-mbone.8 -SRCS= mapper.c - -CFLAGS+= -I$S - -DPADD= ${LIBMROUTED} -LDADD= ${LIBMROUTED} - -.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c deleted file mode 100644 index 8fdbad0..0000000 --- a/usr.sbin/mrouted/mapper.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* Mapper for connections between MRouteD multicast routers. - * Written by Pavel Curtis <Pavel@PARC.Xerox.Com> - * - * mapper.c,v 3.8.4.3 1998/01/06 01:57:47 fenner Exp - */ - -/* - * Copyright (c) Xerox Corporation 1992. All rights reserved. - * - * License is granted to copy, to use, and to make and to use derivative - * works for research and evaluation purposes, provided that Xerox is - * acknowledged in all documentation pertaining to any such copy or derivative - * work. Xerox grants no other licenses expressed or implied. The Xerox trade - * name should not be used in any advertising without its written permission. - * - * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE - * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE - * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without - * express or implied warranty of any kind. - * - * These notices must be retained in any copies of any part of this software. - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include <err.h> -#include <string.h> -#include <netdb.h> -#include <sys/time.h> -#include "defs.h" -#include <arpa/inet.h> -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - -#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */ -#define DEFAULT_RETRIES 1 /* How many times to ask each router */ - - -/* All IP addresses are stored in the data structure in NET order. */ - -typedef struct neighbor { - struct neighbor *next; - u_int32 addr; /* IP address in NET order */ - u_char metric; /* TTL cost of forwarding */ - u_char threshold; /* TTL threshold to forward */ - u_short flags; /* flags on connection */ -#define NF_PRESENT 0x8000 /* True if flags are meaningful */ -} Neighbor; - -typedef struct interface { - struct interface *next; - u_int32 addr; /* IP address of the interface in NET order */ - Neighbor *neighbors; /* List of neighbors' IP addresses */ -} Interface; - -typedef struct node { - u_int32 addr; /* IP address of this entry in NET order */ - u_int32 version; /* which mrouted version is running */ - int tries; /* How many requests sent? -1 for aliases */ - union { - struct node *alias; /* If alias, to what? */ - struct interface *interfaces; /* Else, neighbor data */ - } u; - struct node *left, *right; -} Node; - - -Node *routers = 0; -u_int32 our_addr, target_addr = 0; /* in NET order */ -int debug = 0; -int retries = DEFAULT_RETRIES; -int timeout = DEFAULT_TIMEOUT; -int show_names = TRUE; -vifi_t numvifs; /* to keep loader happy */ - /* (see COPY_TABLES macro called in kern.c) */ - -Node * find_node __P((u_int32 addr, Node **ptr)); -Interface * find_interface __P((u_int32 addr, Node *node)); -Neighbor * find_neighbor __P((u_int32 addr, Node *node)); -int main __P((int argc, char *argv[])); -void ask __P((u_int32 dst)); -void ask2 __P((u_int32 dst)); -int retry_requests __P((Node *node)); -char * inet_name __P((u_int32 addr)); -void print_map __P((Node *node)); -char * graph_name __P((u_int32 addr, char *buf, int len)); -void graph_edges __P((Node *node)); -void elide_aliases __P((Node *node)); -void graph_map __P((void)); -int get_number __P((int *var, int deflt, char ***pargv, - int *pargc)); -u_int32 host_addr __P((char *name)); -static void usage __P((void)); - - -Node *find_node(addr, ptr) - u_int32 addr; - Node **ptr; -{ - Node *n = *ptr; - - if (!n) { - *ptr = n = (Node *) malloc(sizeof(Node)); - n->addr = addr; - n->version = 0; - n->tries = 0; - n->u.interfaces = 0; - n->left = n->right = 0; - return n; - } else if (addr == n->addr) - return n; - else if (addr < n->addr) - return find_node(addr, &(n->left)); - else - return find_node(addr, &(n->right)); -} - - -Interface *find_interface(addr, node) - u_int32 addr; - Node *node; -{ - Interface *ifc; - - for (ifc = node->u.interfaces; ifc; ifc = ifc->next) - if (ifc->addr == addr) - return ifc; - - ifc = (Interface *) malloc(sizeof(Interface)); - ifc->addr = addr; - ifc->next = node->u.interfaces; - node->u.interfaces = ifc; - ifc->neighbors = 0; - - return ifc; -} - - -Neighbor *find_neighbor(addr, node) - u_int32 addr; - Node *node; -{ - Interface *ifc; - - for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { - Neighbor *nb; - - for (nb = ifc->neighbors; nb; nb = nb->next) - if (nb->addr == addr) - return nb; - } - - return 0; -} - - -/* - * Log errors and other messages to stderr, according to the severity of the - * message and the current debug level. For errors of severity LOG_ERR or - * worse, terminate the program. - */ -#ifdef __STDC__ -void -log(int severity, int syserr, char *format, ...) -{ - va_list ap; - char fmt[100]; - - va_start(ap, format); -#else -/*VARARGS3*/ -void -log(severity, syserr, format, va_alist) - int severity, syserr; - char *format; - va_dcl -{ - va_list ap; - char fmt[100]; - - va_start(ap); -#endif - - switch (debug) { - case 0: if (severity > LOG_WARNING) return; - case 1: if (severity > LOG_NOTICE ) return; - case 2: if (severity > LOG_INFO ) return; - default: - fmt[0] = '\0'; - if (severity == LOG_WARNING) - strcpy(fmt, "warning - "); - strncat(fmt, format, sizeof(fmt)-strlen(fmt)); - fmt[sizeof(fmt)-1]='\0'; - vfprintf(stderr, fmt, ap); - if (syserr == 0) - fprintf(stderr, "\n"); - else if (syserr < sys_nerr) - fprintf(stderr, ": %s\n", sys_errlist[syserr]); - else - fprintf(stderr, ": errno %d\n", syserr); - } - - if (severity <= LOG_ERR) - exit(1); -} - - -/* - * Send a neighbors-list request. - */ -void ask(dst) - u_int32 dst; -{ - send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS, - htonl(MROUTED_LEVEL), 0); -} - -void ask2(dst) - u_int32 dst; -{ - send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, - htonl(MROUTED_LEVEL), 0); -} - - -/* - * Process an incoming group membership report. - */ -void accept_group_report(src, dst, group, r_type) - u_int32 src, dst, group; - int r_type; -{ - log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Process an incoming neighbor probe message. - */ -void accept_probe(src, dst, p, datalen, level) - u_int32 src, dst, level; - char *p; - int datalen; -{ - log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Process an incoming route report message. - */ -void accept_report(src, dst, p, datalen, level) - u_int32 src, dst, level; - char *p; - int datalen; -{ - log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Process an incoming neighbor-list request message. - */ -void accept_neighbor_request(src, dst) - u_int32 src, dst; -{ - if (src != our_addr) - log(LOG_INFO, 0, - "ignoring spurious DVMRP neighbor request from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - -void accept_neighbor_request2(src, dst) - u_int32 src, dst; -{ - if (src != our_addr) - log(LOG_INFO, 0, - "ignoring spurious DVMRP neighbor request2 from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Process an incoming neighbor-list message. - */ -void accept_neighbors(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - Node *node = find_node(src, &routers); - - if (node->tries == 0) /* Never heard of 'em; must have hit them at */ - node->tries = 1; /* least once, though...*/ - else if (node->tries == -1) /* follow alias link */ - node = node->u.alias; - -#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\ - a += ((u_int32)*p++ << 8), a += *p++) - - /* if node is running a recent mrouted, ask for additional info */ - if (level != 0) { - node->version = level; - node->tries = 1; - ask2(src); - return; - } - - if (debug > 3) { - int i; - - fprintf(stderr, " datalen = %d\n", datalen); - for (i = 0; i < datalen; i++) { - if ((i & 0xF) == 0) - fprintf(stderr, " "); - fprintf(stderr, " %02x", p[i]); - if ((i & 0xF) == 0xF) - fprintf(stderr, "\n"); - } - if ((datalen & 0xF) != 0xF) - fprintf(stderr, "\n"); - } - - while (datalen > 0) { /* loop through interfaces */ - u_int32 ifc_addr; - u_char metric, threshold, ncount; - Node *ifc_node; - Interface *ifc; - Neighbor *old_neighbors; - - if (datalen < 4 + 3) { - log(LOG_WARNING, 0, "received truncated interface record from %s", - inet_fmt(src, s1)); - return; - } - - GET_ADDR(ifc_addr); - ifc_addr = htonl(ifc_addr); - metric = *p++; - threshold = *p++; - ncount = *p++; - datalen -= 4 + 3; - - /* Fix up any alias information */ - ifc_node = find_node(ifc_addr, &routers); - if (ifc_node->tries == 0) { /* new node */ - ifc_node->tries = -1; - ifc_node->u.alias = node; - } else if (ifc_node != node - && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { - /* must merge two hosts' nodes */ - Interface *ifc_i, *next_ifc_i; - - if (ifc_node->tries == -1) { - Node *tmp = ifc_node->u.alias; - - ifc_node->u.alias = node; - ifc_node = tmp; - } - - /* Merge ifc_node (foo_i) into node (foo_n) */ - - if (ifc_node->tries > node->tries) - node->tries = ifc_node->tries; - - for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { - Neighbor *nb_i, *next_nb_i, *nb_n; - Interface *ifc_n = find_interface(ifc_i->addr, node); - - old_neighbors = ifc_n->neighbors; - for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { - next_nb_i = nb_i->next; - for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) - if (nb_i->addr == nb_n->addr) { - if (nb_i->metric != nb_n->metric - || nb_i->threshold != nb_n->threshold) - log(LOG_WARNING, 0, - "inconsistent %s for neighbor %s of %s", - "metric/threshold", - inet_fmt(nb_i->addr, s1), - inet_fmt(node->addr, s2)); - free(nb_i); - break; - } - if (!nb_n) { /* no match for this neighbor yet */ - nb_i->next = ifc_n->neighbors; - ifc_n->neighbors = nb_i; - } - } - - next_ifc_i = ifc_i->next; - free(ifc_i); - } - - ifc_node->tries = -1; - ifc_node->u.alias = node; - } - - ifc = find_interface(ifc_addr, node); - old_neighbors = ifc->neighbors; - - /* Add the neighbors for this interface */ - while (ncount--) { - u_int32 neighbor; - Neighbor *nb; - Node *n_node; - - if (datalen < 4) { - log(LOG_WARNING, 0, "received truncated neighbor list from %s", - inet_fmt(src, s1)); - return; - } - - GET_ADDR(neighbor); - neighbor = htonl(neighbor); - datalen -= 4; - - for (nb = old_neighbors; nb; nb = nb->next) - if (nb->addr == neighbor) { - if (metric != nb->metric || threshold != nb->threshold) - log(LOG_WARNING, 0, - "inconsistent %s for neighbor %s of %s", - "metric/threshold", - inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2)); - goto next_neighbor; - } - - nb = (Neighbor *) malloc(sizeof(Neighbor)); - nb->next = ifc->neighbors; - ifc->neighbors = nb; - nb->addr = neighbor; - nb->metric = metric; - nb->threshold = threshold; - nb->flags = 0; - - n_node = find_node(neighbor, &routers); - if (n_node->tries == 0 && !target_addr) { /* it's a new router */ - ask(neighbor); - n_node->tries = 1; - } - - next_neighbor: ; - } - } -} - -void accept_neighbors2(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - Node *node = find_node(src, &routers); - u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */ - /* well, only possibly_broken_cisco, but that's too long to type. */ - - if (node->tries == 0) /* Never heard of 'em; must have hit them at */ - node->tries = 1; /* least once, though...*/ - else if (node->tries == -1) /* follow alias link */ - node = node->u.alias; - - while (datalen > 0) { /* loop through interfaces */ - u_int32 ifc_addr; - u_char metric, threshold, ncount, flags; - Node *ifc_node; - Interface *ifc; - Neighbor *old_neighbors; - - if (datalen < 4 + 4) { - log(LOG_WARNING, 0, "received truncated interface record from %s", - inet_fmt(src, s1)); - return; - } - - ifc_addr = *(u_int32*)p; - p += 4; - metric = *p++; - threshold = *p++; - flags = *p++; - ncount = *p++; - datalen -= 4 + 4; - - if (broken_cisco && ncount == 0) /* dumb Ciscos */ - ncount = 1; - if (broken_cisco && ncount > 15) /* dumb Ciscos */ - ncount = ncount & 0xf; - - /* Fix up any alias information */ - ifc_node = find_node(ifc_addr, &routers); - if (ifc_node->tries == 0) { /* new node */ - ifc_node->tries = -1; - ifc_node->u.alias = node; - } else if (ifc_node != node - && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { - /* must merge two hosts' nodes */ - Interface *ifc_i, *next_ifc_i; - - if (ifc_node->tries == -1) { - Node *tmp = ifc_node->u.alias; - - ifc_node->u.alias = node; - ifc_node = tmp; - } - - /* Merge ifc_node (foo_i) into node (foo_n) */ - - if (ifc_node->tries > node->tries) - node->tries = ifc_node->tries; - - for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { - Neighbor *nb_i, *next_nb_i, *nb_n; - Interface *ifc_n = find_interface(ifc_i->addr, node); - - old_neighbors = ifc_n->neighbors; - for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { - next_nb_i = nb_i->next; - for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) - if (nb_i->addr == nb_n->addr) { - if (nb_i->metric != nb_n->metric - || nb_i->threshold != nb_i->threshold) - log(LOG_WARNING, 0, - "inconsistent %s for neighbor %s of %s", - "metric/threshold", - inet_fmt(nb_i->addr, s1), - inet_fmt(node->addr, s2)); - free(nb_i); - break; - } - if (!nb_n) { /* no match for this neighbor yet */ - nb_i->next = ifc_n->neighbors; - ifc_n->neighbors = nb_i; - } - } - - next_ifc_i = ifc_i->next; - free(ifc_i); - } - - ifc_node->tries = -1; - ifc_node->u.alias = node; - } - - ifc = find_interface(ifc_addr, node); - old_neighbors = ifc->neighbors; - - /* Add the neighbors for this interface */ - while (ncount-- && datalen > 0) { - u_int32 neighbor; - Neighbor *nb; - Node *n_node; - - if (datalen < 4) { - log(LOG_WARNING, 0, "received truncated neighbor list from %s", - inet_fmt(src, s1)); - return; - } - - neighbor = *(u_int32*)p; - p += 4; - datalen -= 4; - if (neighbor == 0) - /* make leaf nets point to themselves */ - neighbor = ifc_addr; - - for (nb = old_neighbors; nb; nb = nb->next) - if (nb->addr == neighbor) { - if (metric != nb->metric || threshold != nb->threshold) - log(LOG_WARNING, 0, - "inconsistent %s for neighbor %s of %s", - "metric/threshold", - inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2)); - goto next_neighbor; - } - - nb = (Neighbor *) malloc(sizeof(Neighbor)); - nb->next = ifc->neighbors; - ifc->neighbors = nb; - nb->addr = neighbor; - nb->metric = metric; - nb->threshold = threshold; - nb->flags = flags | NF_PRESENT; - - n_node = find_node(neighbor, &routers); - if (n_node->tries == 0 && !target_addr) { /* it's a new router */ - ask(neighbor); - n_node->tries = 1; - } - - next_neighbor: ; - } - } -} - - -void check_vif_state() -{ - log(LOG_NOTICE, 0, "network marked down..."); -} - - -int retry_requests(node) - Node *node; -{ - int result; - - if (node) { - result = retry_requests(node->left); - if (node->tries > 0 && node->tries < retries) { - if (node->version) - ask2(node->addr); - else - ask(node->addr); - node->tries++; - result = 1; - } - return retry_requests(node->right) || result; - } else - return 0; -} - - -char *inet_name(addr) - u_int32 addr; -{ - struct hostent *e; - - e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); - - return e ? e->h_name : 0; -} - - -void print_map(node) - Node *node; -{ - if (node) { - char *name, *addr; - - print_map(node->left); - - addr = inet_fmt(node->addr, s1); - if (!target_addr - || (node->tries >= 0 && node->u.interfaces) - || (node->tries == -1 - && node->u.alias->tries >= 0 - && node->u.alias->u.interfaces)) { - if (show_names && (name = inet_name(node->addr))) - printf("%s (%s):", addr, name); - else - printf("%s:", addr); - if (node->tries < 0) - printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1)); - else if (!node->u.interfaces) - printf(" no response to query\n\n"); - else { - Interface *ifc; - - if (node->version) - printf(" <v%d.%d>", node->version & 0xff, - (node->version >> 8) & 0xff); - printf("\n"); - for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { - Neighbor *nb; - char *ifc_name = inet_fmt(ifc->addr, s1); - int ifc_len = strlen(ifc_name); - int count = 0; - - printf(" %s:", ifc_name); - for (nb = ifc->neighbors; nb; nb = nb->next) { - if (count > 0) - printf("%*s", ifc_len + 5, ""); - printf(" %s", inet_fmt(nb->addr, s1)); - if (show_names && (name = inet_name(nb->addr))) - printf(" (%s)", name); - printf(" [%d/%d", nb->metric, nb->threshold); - if (nb->flags) { - u_short flags = nb->flags; - if (flags & DVMRP_NF_TUNNEL) - printf("/tunnel"); - if (flags & DVMRP_NF_SRCRT) - printf("/srcrt"); - if (flags & DVMRP_NF_QUERIER) - printf("/querier"); - if (flags & DVMRP_NF_DISABLED) - printf("/disabled"); - if (flags & DVMRP_NF_DOWN) - printf("/down"); - } - printf("]\n"); - count++; - } - } - printf("\n"); - } - } - print_map(node->right); - } -} - - -char *graph_name(addr, buf, len) - u_int32 addr; - char *buf; - int len; -{ - char *name; - - if (len < sizeof("255.255.255.255")) { - fprintf(stderr, -"Buffer too small in graph_name, provided %d bytes, but needed %d.\n", - len, sizeof("255.255.255.255")); - return NULL; - } - if (show_names && (name = inet_name(addr))) { - strncpy(buf, name, len - 1); - buf[len - 1] = '\0'; - } else - inet_fmt(addr, buf); - - return buf; -} - - -void graph_edges(node) - Node *node; -{ - Interface *ifc; - Neighbor *nb; - char name[100]; - - if (node) { - graph_edges(node->left); - if (node->tries >= 0) { - printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n", - (int) node->addr, - node->addr & 0xFF, (node->addr >> 8) & 0xFF, - graph_name(node->addr, name, sizeof(name)), - node->u.interfaces ? "" : "*"); - for (ifc = node->u.interfaces; ifc; ifc = ifc->next) - for (nb = ifc->neighbors; nb; nb = nb->next) { - Node *nb_node = find_node(nb->addr, &routers); - Neighbor *nb2; - - if (nb_node->tries < 0) - nb_node = nb_node->u.alias; - - if (node != nb_node && - (!(nb2 = find_neighbor(node->addr, nb_node)) - || node->addr < nb_node->addr)) { - printf(" %d \"%d/%d", - nb_node->addr, nb->metric, nb->threshold); - if (nb2 && (nb2->metric != nb->metric - || nb2->threshold != nb->threshold)) - printf(",%d/%d", nb2->metric, nb2->threshold); - if (nb->flags & NF_PRESENT) - printf("%s%s", - nb->flags & DVMRP_NF_SRCRT ? "" : - nb->flags & DVMRP_NF_TUNNEL ? "E" : "P", - nb->flags & DVMRP_NF_DOWN ? "D" : ""); - printf("\"\n"); - } - } - printf(" ;\n"); - } - graph_edges(node->right); - } -} - -void elide_aliases(node) - Node *node; -{ - if (node) { - elide_aliases(node->left); - if (node->tries >= 0) { - Interface *ifc; - - for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { - Neighbor *nb; - - for (nb = ifc->neighbors; nb; nb = nb->next) { - Node *nb_node = find_node(nb->addr, &routers); - - if (nb_node->tries < 0) - nb->addr = nb_node->u.alias->addr; - } - } - } - elide_aliases(node->right); - } -} - -void graph_map() -{ - time_t now = time(0); - char *nowstr = ctime(&now); - - nowstr[24] = '\0'; /* Kill the newline at the end */ - elide_aliases(routers); - printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n", - nowstr); - graph_edges(routers); - printf("END\n"); -} - - -int get_number(var, deflt, pargv, pargc) - int *var, *pargc, deflt; - char ***pargv; -{ - if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */ - if (*pargc > 1 && isdigit((*pargv)[1][0])) { - (*pargv)++, (*pargc)--; - *var = atoi((*pargv)[0]); - return 1; - } else if (deflt >= 0) { - *var = deflt; - return 1; - } else - return 0; - } else { /* Get value from the rest of this argument */ - if (isdigit((*pargv)[0][2])) { - *var = atoi((*pargv)[0] + 2); - return 1; - } else { - return 0; - } - } -} - - -u_int32 host_addr(name) - char *name; -{ - struct hostent *e = gethostbyname(name); - int addr; - - if (e && e->h_length == sizeof(addr)) - memcpy(&addr, e->h_addr_list[0], e->h_length); - else { - addr = inet_addr(name); - if (addr == -1) - addr = 0; - } - - return addr; -} - - -int main(argc, argv) - int argc; - char *argv[]; -{ - int flood = FALSE, graph = FALSE; - - if (geteuid() != 0) - errx(1, "must be root"); - - init_igmp(); - setuid(getuid()); - - setlinebuf(stderr); - - argv++, argc--; - while (argc > 0 && argv[0][0] == '-') { - switch (argv[0][1]) { - case 'd': - if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc)) - usage(); - break; - case 'f': - flood = TRUE; - break; - case 'g': - graph = TRUE; - break; - case 'n': - show_names = FALSE; - break; - case 'r': - if (!get_number(&retries, -1, &argv, &argc)) - usage(); - break; - case 't': - if (!get_number(&timeout, -1, &argv, &argc)) - usage(); - break; - default: - usage(); - } - argv++, argc--; - } - - if (argc > 1) { - usage(); - } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) - errx(2, "unknown host: %s", argv[0]); - - if (debug) - fprintf(stderr, "Debug level %u\n", debug); - - { /* Find a good local address for us. */ - int udp; - struct sockaddr_in addr; - int addrlen = sizeof(addr); - - addr.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - addr.sin_len = sizeof addr; -#endif - addr.sin_addr.s_addr = dvmrp_group; - addr.sin_port = htons(2000); /* any port over 1024 will do... */ - if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 - || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 - || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) - err(-1, "determining local address"); - close(udp); - our_addr = addr.sin_addr.s_addr; - } - - /* Send initial seed message to all local routers */ - ask(target_addr ? target_addr : allhosts_group); - - if (target_addr) { - Node *n = find_node(target_addr, &routers); - - n->tries = 1; - - if (flood) - target_addr = 0; - } - - /* Main receive loop */ - for(;;) { - fd_set fds; - struct timeval tv; - int count, recvlen, dummy = 0; - - if (igmp_socket >= FD_SETSIZE) - log(LOG_ERR, 0, "descriptor too big"); - FD_ZERO(&fds); - FD_SET(igmp_socket, &fds); - - tv.tv_sec = timeout; - tv.tv_usec = 0; - - count = select(igmp_socket + 1, &fds, 0, 0, &tv); - - if (count < 0) { - if (errno != EINTR) - warn("select"); - continue; - } else if (count == 0) { - log(LOG_DEBUG, 0, "Timed out receiving neighbor lists"); - if (retry_requests(routers)) - continue; - else - break; - } - - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, NULL, &dummy); - if (recvlen >= 0) - accept_igmp(recvlen); - else if (errno != EINTR) - warn("recvfrom"); - } - - printf("\n"); - - if (graph) - graph_map(); - else { - if (!target_addr) - printf("Multicast Router Connectivity:\n\n"); - print_map(routers); - } - - exit(0); -} - -static void -usage() -{ - fprintf(stderr, "%s\n%s\n", - "usage: map-mbone [-f] [-g] [-n] [-t timeout] [-r retries]", - " [-d [debug-level]] [router]"); - exit(1); -} - -/* dummies */ -void accept_prune(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void accept_graft(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void accept_g_ack(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void add_table_entry(origin, mcastgrp) - u_int32 origin, mcastgrp; -{ -} -void accept_leave_message(src, dst, group) - u_int32 src, dst, group; -{ -} -void accept_mtrace(src, dst, group, data, no, datalen) - u_int32 src, dst, group; - char *data; - u_int no; - int datalen; -{ -} -void accept_membership_query(src, dst, group, tmo) - u_int32 src, dst, group; - int tmo; -{ -} -void accept_info_request(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ -} -void accept_info_reply(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ -} diff --git a/usr.sbin/mrouted/mrinfo.8 b/usr.sbin/mrouted/mrinfo.8 deleted file mode 100644 index 94f8f0a1..0000000 --- a/usr.sbin/mrouted/mrinfo.8 +++ /dev/null @@ -1,91 +0,0 @@ -.\" $FreeBSD$ -.\" -.Dd May 8, 1995 -.Dt MRINFO 8 -.Os -.Sh NAME -.Nm mrinfo -.Nd display configuration info from a multicast router -.Sh SYNOPSIS -.Nm -.Op Fl d Ar debug_level -.Op Fl r Ar retry_count -.Op Fl t Ar timeout_count -.Ar multicast_router -.Sh DESCRIPTION -The -.Nm -utility -attempts to display the configuration information from the multicast router -.Ar multicast_router . -.Pp -The -.Nm -utility uses the ASK_NEIGHBORS IGMP message to the specified multicast router. -If this -multicast router responds, the version number and a list of their neighboring -multicast router addresses is part of that response. -If the responding router -has a recent multicast version number, then -.Nm -requests additional information such as metrics, thresholds, and flags from the -multicast router. -Once the specified multicast router responds, the -configuration is displayed to the standard output. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl d Ar debug_level -Set the debug level. -When the debug level is greater than the -default value of 0, addition debugging messages are printed. -Regardless of -the debug level, an error condition, will always write an error message and will -cause -.Nm -to terminate. -Non-zero debug levels have the following effects: -.Bl -tag -width indent -.It "level 1" -packet warnings are printed to stderr. -.It "level 2" -all level 1 messages plus notifications down networks are printed to stderr. -.It "level 3" -all level 2 messages plus notifications of all packet -timeouts are printed to stderr. -.El -.It Fl r Ar retry_count -Set the neighbor query retry limit. -Default is 3 retries. -.It Fl t Ar timeout_count -Set the number of seconds to wait for a neighbor query -reply. -Default timeout is 4 seconds. -.El -.Sh SAMPLE OUTPUT -.Bd -literal -$ mrinfo mbone.phony.dom.net -127.148.176.10 (mbone.phony.dom.net) [version 3.3]: - 127.148.176.10 -> 0.0.0.0 (?) [1/1/querier] - 127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel] - 127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down] - 127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel] -.Ed -.Pp -For each neighbor of the queried multicast router, the IP of the queried router -is displayed, followed by the IP and name of the neighbor. -In square brackets -the metric (cost of connection), the threshold (multicast ttl) is displayed. -If -the queried multicast router has a newer version number, the type (tunnel, -srcrt) and status (disabled, down) of the connection is displayed. -.Sh IMPORTANT NOTE -The -.Nm -utility must be run as root. -.Sh SEE ALSO -.Xr map-mbone 8 , -.Xr mrouted 8 , -.Xr mtrace 8 -.Sh AUTHORS -.An Van Jacobson diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c deleted file mode 100644 index 1df6577..0000000 --- a/usr.sbin/mrouted/mrinfo.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * This tool requests configuration info from a multicast router - * and prints the reply (if any). Invoke it as: - * - * mrinfo router-name-or-address - * - * Written Wed Mar 24 1993 by Van Jacobson (adapted from the - * multicast mapper written by Pavel Curtis). - * - * The lawyers insist we include the following UC copyright notice. - * The mapper from which this is derived contained a Xerox copyright - * notice which follows the UC one. Try not to get depressed noting - * that the legal gibberish is larger than the program. - * - * Copyright (c) 1993 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the Computer Systems - * Engineering Group at Lawrence Berkeley Laboratory. - * 4. Neither the name of the University nor of the Laboratory may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * --------------------------------- - * Copyright (c) Xerox Corporation 1992. All rights reserved. - * - * License is granted to copy, to use, and to make and to use derivative works - * for research and evaluation purposes, provided that Xerox is acknowledged - * in all documentation pertaining to any such copy or derivative work. Xerox - * grants no other licenses expressed or implied. The Xerox trade name should - * not be used in any advertising without its written permission. - * - * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE - * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR - * ANY PARTICULAR PURPOSE. The software is provided "as is" without express - * or implied warranty of any kind. - * - * These notices must be retained in any copies of any part of this software. - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -/* original rcsid: - "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)"; -*/ -#endif - -#include <err.h> -#include <netdb.h> -#include <sys/time.h> -#include "defs.h" -#include <arpa/inet.h> -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - -#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */ -#define DEFAULT_RETRIES 3 /* How many times to ask each router */ - -u_int32 our_addr, target_addr = 0; /* in NET order */ -int debug = 0; -int nflag = 0; -int retries = DEFAULT_RETRIES; -int timeout = DEFAULT_TIMEOUT; -int target_level = 0; -vifi_t numvifs; /* to keep loader happy */ - /* (see COPY_TABLES macro called in kern.c) */ - -char * inet_name __P((u_int32 addr)); -void ask __P((u_int32 dst)); -void ask2 __P((u_int32 dst)); -int get_number __P((int *var, int deflt, char ***pargv, - int *pargc)); -u_int32 host_addr __P((char *name)); -static void usage __P((void)); - -/* to shut up -Wstrict-prototypes */ -int main __P((int argc, char *argv[])); - - -char * -inet_name(addr) - u_int32 addr; -{ - struct hostent *e; - struct in_addr in; - - if (addr == 0) - return "local"; - - if (nflag || - (e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) { - in.s_addr = addr; - return (inet_ntoa(in)); - } - return (e->h_name); -} - -/* - * Log errors and other messages to stderr, according to the severity of the - * message and the current debug level. For errors of severity LOG_ERR or - * worse, terminate the program. - */ -#ifdef __STDC__ -void -log(int severity, int syserr, char *format, ...) -{ - va_list ap; - char fmt[100]; - - va_start(ap, format); -#else -void -log(severity, syserr, format, va_alist) - int severity, syserr; - char *format; - va_dcl -{ - va_list ap; - char fmt[100]; - - va_start(ap); -#endif - switch (debug) { - case 0: - if (severity > LOG_WARNING) - return; - case 1: - if (severity > LOG_NOTICE) - return; - case 2: - if (severity > LOG_INFO) - return; - default: - fmt[0] = '\0'; - if (severity == LOG_WARNING) - strcpy(fmt, "warning - "); - strncat(fmt, format, sizeof(fmt)-strlen(fmt)); - fmt[sizeof(fmt)-1]='\0'; - vfprintf(stderr, fmt, ap); - if (syserr == 0) - fprintf(stderr, "\n"); - else if (syserr < sys_nerr) - fprintf(stderr, ": %s\n", sys_errlist[syserr]); - else - fprintf(stderr, ": errno %d\n", syserr); - } - - if (severity <= LOG_ERR) - exit(1); -} - -/* - * Send a neighbors-list request. - */ -void -ask(dst) - u_int32 dst; -{ - send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS, - htonl(MROUTED_LEVEL), 0); -} - -void -ask2(dst) - u_int32 dst; -{ - send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, - htonl(MROUTED_LEVEL), 0); -} - -/* - * Process an incoming neighbor-list message. - */ -void -accept_neighbors(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - u_char *ep = p + datalen; -#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\ - a += ((u_int32)*p++ << 8), a += *p++) - - printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src)); - while (p < ep) { - register u_int32 laddr; - register u_char metric; - register u_char thresh; - register int ncount; - - GET_ADDR(laddr); - laddr = htonl(laddr); - metric = *p++; - thresh = *p++; - ncount = *p++; - while (--ncount >= 0) { - register u_int32 neighbor; - GET_ADDR(neighbor); - neighbor = htonl(neighbor); - printf(" %s -> ", inet_fmt(laddr, s1)); - printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1), - inet_name(neighbor), metric, thresh); - } - } -} - -void -accept_neighbors2(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - u_char *ep = p + datalen; - u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */ - /* well, only possibly_broken_cisco, but that's too long to type. */ - u_int majvers = level & 0xff; - u_int minvers = (level >> 8) & 0xff; - - printf("%s (%s) [", inet_fmt(src, s1), inet_name(src)); - if (majvers == 3 && minvers == 0xff) - printf("DVMRPv3 compliant"); - else - printf("version %d.%d", majvers, minvers); - printf ("]:\n"); - - while (p < ep) { - register u_char metric; - register u_char thresh; - register u_char flags; - register int ncount; - register u_int32 laddr = *(u_int32*)p; - - p += 4; - metric = *p++; - thresh = *p++; - flags = *p++; - ncount = *p++; - if (broken_cisco && ncount == 0) /* dumb Ciscos */ - ncount = 1; - if (broken_cisco && ncount > 15) /* dumb Ciscos */ - ncount = ncount & 0xf; - while (--ncount >= 0 && p < ep) { - register u_int32 neighbor = *(u_int32*)p; - p += 4; - printf(" %s -> ", inet_fmt(laddr, s1)); - printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1), - inet_name(neighbor), metric, thresh); - if (flags & DVMRP_NF_TUNNEL) - printf("/tunnel"); - if (flags & DVMRP_NF_SRCRT) - printf("/srcrt"); - if (flags & DVMRP_NF_PIM) - printf("/pim"); - if (flags & DVMRP_NF_QUERIER) - printf("/querier"); - if (flags & DVMRP_NF_DISABLED) - printf("/disabled"); - if (flags & DVMRP_NF_DOWN) - printf("/down"); - if (flags & DVMRP_NF_LEAF) - printf("/leaf"); - printf("]\n"); - } - } -} - -int -get_number(var, deflt, pargv, pargc) - int *var, *pargc, deflt; - char ***pargv; -{ - if ((*pargv)[0][2] == '\0') { /* Get the value from the next - * argument */ - if (*pargc > 1 && isdigit((*pargv)[1][0])) { - (*pargv)++, (*pargc)--; - *var = atoi((*pargv)[0]); - return 1; - } else if (deflt >= 0) { - *var = deflt; - return 1; - } else - return 0; - } else { /* Get value from the rest of this argument */ - if (isdigit((*pargv)[0][2])) { - *var = atoi((*pargv)[0] + 2); - return 1; - } else { - return 0; - } - } -} - -static void -usage() -{ - fprintf(stderr, - "usage: mrinfo [-n] [-t timeout] [-r retries] [router]\n"); - exit(1); -} - -int -main(argc, argv) - int argc; - char *argv[]; -{ - int tries; - int trynew; - struct timeval et; - struct hostent *hp; - struct hostent bogus; - char *host; - int curaddr; - - if (geteuid() != 0) - errx(1, "must be root"); - - init_igmp(); - setuid(getuid()); - - setlinebuf(stderr); - - argv++, argc--; - while (argc > 0 && argv[0][0] == '-') { - switch (argv[0][1]) { - case 'd': - if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc)) - usage(); - break; - case 'n': - ++nflag; - break; - case 'r': - if (!get_number(&retries, -1, &argv, &argc)) - usage(); - break; - case 't': - if (!get_number(&timeout, -1, &argv, &argc)) - usage(); - break; - default: - usage(); - } - argv++, argc--; - } - if (argc > 1) - usage(); - if (argc == 1) - host = argv[0]; - else - host = "127.0.0.1"; - - if ((target_addr = inet_addr(host)) != -1) { - hp = &bogus; - hp->h_length = sizeof(target_addr); - hp->h_addr_list = (char **)malloc(2 * sizeof(char *)); - hp->h_addr_list[0] = malloc(hp->h_length); - memcpy(hp->h_addr_list[0], &target_addr, hp->h_length); - hp->h_addr_list[1] = 0; - } else - hp = gethostbyname(host); - - if (hp == NULL || hp->h_length != sizeof(target_addr)) - errx(1, "%s: no such host", argv[0]); - if (debug) - fprintf(stderr, "Debug level %u\n", debug); - - /* Check all addresses; mrouters often have unreachable interfaces */ - for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) { - memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length); - { /* Find a good local address for us. */ - int udp; - struct sockaddr_in addr; - int addrlen = sizeof(addr); - - addr.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - addr.sin_len = sizeof addr; -#endif - addr.sin_addr.s_addr = target_addr; - addr.sin_port = htons(2000); /* any port over 1024 will - * do... */ - if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 - || connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0 - || getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) - err(-1, "determining local address"); - close(udp); - our_addr = addr.sin_addr.s_addr; - } - - tries = 0; - trynew = 1; - /* - * New strategy: send 'ask2' for two timeouts, then fall back - * to 'ask', since it's not very likely that we are going to - * find someone who only responds to 'ask' these days - */ - ask2(target_addr); - - gettimeofday(&et, 0); - et.tv_sec += timeout; - - /* Main receive loop */ - for (;;) { - fd_set fds; - struct timeval tv, now; - int count, recvlen, dummy = 0; - register u_int32 src, dst, group; - struct ip *ip; - struct igmp *igmp; - int ipdatalen, iphdrlen, igmpdatalen; - - if (igmp_socket >= FD_SETSIZE) - log(LOG_ERR, 0, "descriptor too big"); - FD_ZERO(&fds); - FD_SET(igmp_socket, &fds); - - gettimeofday(&now, 0); - tv.tv_sec = et.tv_sec - now.tv_sec; - tv.tv_usec = et.tv_usec - now.tv_usec; - - if (tv.tv_usec < 0) { - tv.tv_usec += 1000000L; - --tv.tv_sec; - } - if (tv.tv_sec < 0) - tv.tv_sec = tv.tv_usec = 0; - - count = select(igmp_socket + 1, &fds, 0, 0, &tv); - - if (count < 0) { - if (errno != EINTR) - warn("select"); - continue; - } else if (count == 0) { - log(LOG_DEBUG, 0, "Timed out receiving neighbor lists"); - if (++tries > retries) - break; - /* If we've tried ASK_NEIGHBORS2 twice with - * no response, fall back to ASK_NEIGHBORS - */ - if (tries == 2 && target_level == 0) - trynew = 0; - if (target_level == 0 && trynew == 0) - ask(target_addr); - else - ask2(target_addr); - gettimeofday(&et, 0); - et.tv_sec += timeout; - continue; - } - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, NULL, &dummy); - if (recvlen <= 0) { - if (recvlen && errno != EINTR) - warn("recvfrom"); - continue; - } - - if (recvlen < sizeof(struct ip)) { - log(LOG_WARNING, 0, - "packet too short (%u bytes) for IP header", - recvlen); - continue; - } - ip = (struct ip *) recv_buf; - if (ip->ip_p == 0) - continue; /* Request to install cache entry */ - src = ip->ip_src.s_addr; - dst = ip->ip_dst.s_addr; - iphdrlen = ip->ip_hl << 2; -#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len) - iphdrlen; -#else - ipdatalen = ip->ip_len; -#endif - if (iphdrlen + ipdatalen != recvlen) { - log(LOG_WARNING, 0, - "packet shorter (%u bytes) than hdr+data length (%u+%u)", - recvlen, iphdrlen, ipdatalen); - continue; - } - igmp = (struct igmp *) (recv_buf + iphdrlen); - group = igmp->igmp_group.s_addr; - igmpdatalen = ipdatalen - IGMP_MINLEN; - if (igmpdatalen < 0) { - log(LOG_WARNING, 0, - "IP data field too short (%u bytes) for IGMP, from %s", - ipdatalen, inet_fmt(src, s1)); - continue; - } - if (igmp->igmp_type != IGMP_DVMRP) - continue; - - switch (igmp->igmp_code) { - case DVMRP_NEIGHBORS: - case DVMRP_NEIGHBORS2: - if (src != target_addr) { - warnx("got reply from %s instead of %s", - inet_fmt(src, s1), inet_fmt(target_addr, s1)); - /*continue;*/ - } - break; - default: - continue; /* ignore all other DVMRP messages */ - } - - switch (igmp->igmp_code) { - - case DVMRP_NEIGHBORS: - if (group) { - /* knows about DVMRP_NEIGHBORS2 msg */ - if (target_level == 0) { - target_level = ntohl(group); - ask2(target_addr); - } - } else { - accept_neighbors(src, dst, (u_char *)(igmp + 1), - igmpdatalen, ntohl(group)); - exit(0); - } - break; - - case DVMRP_NEIGHBORS2: - accept_neighbors2(src, dst, (u_char *)(igmp + 1), - igmpdatalen, ntohl(group)); - exit(0); - } - } - } - exit(1); -} - -/* dummies */ -void accept_probe(src, dst, p, datalen, level) - u_int32 src, dst, level; - char *p; - int datalen; -{ -} -void accept_group_report(src, dst, group, r_type) - u_int32 src, dst, group; - int r_type; -{ -} -void accept_neighbor_request2(src, dst) - u_int32 src, dst; -{ -} -void accept_report(src, dst, p, datalen, level) - u_int32 src, dst, level; - char *p; - int datalen; -{ -} -void accept_neighbor_request(src, dst) - u_int32 src, dst; -{ -} -void accept_prune(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void accept_graft(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void accept_g_ack(src, dst, p, datalen) - u_int32 src, dst; - char *p; - int datalen; -{ -} -void add_table_entry(origin, mcastgrp) - u_int32 origin, mcastgrp; -{ -} -void check_vif_state() -{ -} -void accept_leave_message(src, dst, group) - u_int32 src, dst, group; -{ -} -void accept_mtrace(src, dst, group, data, no, datalen) - u_int32 src, dst, group; - char *data; - u_int no; - int datalen; -{ -} -void accept_membership_query(src, dst, group, tmo) - u_int32 src, dst, group; - int tmo; -{ -} -void accept_info_request(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ -} -void accept_info_reply(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ -} diff --git a/usr.sbin/mrouted/mrinfo/Makefile b/usr.sbin/mrouted/mrinfo/Makefile deleted file mode 100644 index f111aa9..0000000 --- a/usr.sbin/mrouted/mrinfo/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -PROG= mrinfo -MAN= mrinfo.8 -BINOWN= root -BINMODE= 4555 - -CFLAGS+= -I$S - -DPADD= ${LIBMROUTED} -LDADD= ${LIBMROUTED} - -.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8 deleted file mode 100644 index 5713914..0000000 --- a/usr.sbin/mrouted/mrouted.8 +++ /dev/null @@ -1,665 +0,0 @@ -.\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University. -.\" -.\" $FreeBSD$ -.\" -.Dd May 8, 1995 -.Dt MROUTED 8 -.Os -.Sh NAME -.Nm mrouted -.Nd IP multicast routing daemon -.Sh SYNOPSIS -.Nm -.Op Fl c Ar config_file -.Op Fl d Op Ar debug_level -.Op Fl p -.Sh DESCRIPTION -The -.Nm -utility is an implementation of the Distance-Vector Multicast Routing -Protocol (DVMRP), an earlier version of which is specified in RFC-1075. -It maintains topological knowledge via a distance-vector routing protocol -(like RIP, described in RFC-1058), upon which it implements a multicast -datagram forwarding algorithm called Reverse Path Multicasting. -.Pp -The -.Nm -utility forwards a multicast datagram along a shortest (reverse) path tree -rooted at the subnet on which the datagram originates. -The multicast -delivery tree may be thought of as a broadcast delivery tree that has -been pruned back so that it does not extend beyond those subnetworks -that have members of the destination group. -Hence, datagrams -are not forwarded along those branches which have no listeners of the -multicast group. -The IP time-to-live of a multicast datagram can be -used to limit the range of multicast datagrams. -.Pp -In order to support multicasting among subnets that are separated by (unicast) -routers that do not support IP multicasting, -.Nm -includes support for -"tunnels", which are virtual point-to-point links between pairs of -multicast routers -located anywhere in an internet. -IP multicast packets are encapsulated for -transmission through tunnels, so that they look like normal unicast datagrams -to intervening routers and subnets. -The encapsulation -is added on entry to a tunnel, and stripped off -on exit from a tunnel. -The packets are encapsulated using the IP-in-IP protocol -(IP protocol number 4). -Older versions of -.Nm -tunneled using IP source routing, which puts a heavy load on some -types of routers. -This version does not support IP source route tunnelling. -.Pp -The tunnelling mechanism allows -.Nm -to establish a virtual internet, for -the purpose of multicasting only, which is independent of the physical -internet, and which may span multiple Autonomous Systems. -This capability -is intended for experimental support of internet multicasting only, pending -widespread support for multicast routing by the regular (unicast) routers. -The -.Nm -utility suffers from the well-known scaling problems of any distance-vector -routing protocol, and does not (yet) support hierarchical multicast routing. -.Pp -The -.Nm -utility -handles multicast routing only; there may or may not be unicast routing -software running on the same machine as -.Nm . -With the use of tunnels, it -is not necessary for -.Nm -to have access to more than one physical subnet -in order to perform multicast forwarding. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl c Ar config_file -Specify an alternative file for configuration commands. -Default is -.Pa /etc/mrouted.conf . -.It Fl d Op Ar debug_level -If no -.Fl d -option is given, or if the debug level is specified as 0, -.Nm -detaches from the invoking terminal. -Otherwise, it remains attached to the -invoking terminal and responsive to signals from that terminal. -Regardless of the debug level, -.Nm -always writes warning and error messages to the system -log daemon. -The -.Fl debug-level -argument is a comma-separated list of any of the following: -.Bl -tag -width indent -.It "packet" -Display the type, source and destination of all packets sent or received. -.It "pruning" -Display more information about prunes sent or received. -.It "routing" -Display more information about routing update packets sent or received. -.It "route_detail" -Display routing updates in excruciating detail. -This is generally way too -much information. -.It "neighbors" -Display information about neighbor discovery. -.It "cache" -Display insertions, deletions and refreshes of entries in -the kernel forwarding cache. -.It "timeout" -Debug timeouts and periodic processes. -.It "interface" -Display information about interfaces and their configuration. -.It "membership" -Display information about group memberships on physical interfaces. -.It "traceroute" -Display information about multicast traceroute requests -passing through this router. -.It "igmp" -Display IGMP operation including group membership and querier election. -.It "icmp" -Monitor ICMP handling. -.It "rsrr" -Monitor RSRR operation. -.El -.Pp -Upon startup, -.Nm -writes its pid to the file -.Pa /var/run/mrouted.pid . -.El -.Sh CONFIGURATION -The -.Nm -utility automatically configures itself to forward on all multicast-capable -interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding -the loopback "interface"), and it finds other DVMRP routers directly reachable -via those interfaces. -To override the default configuration, or to add -tunnel links to other multicast routers, -configuration commands may be placed in -.Pa /etc/mrouted.conf -(or an alternative file, specified by the -.Fl c -option). -.Pp -The file format is free-form; whitespace (including newlines) is not -significant. -The file begins with commands that apply to -.Nm Ns 's -overall operation or set defaults. -.Bl -tag -width indent -.It cache_lifetime Ar secs -Specifies, in seconds, the lifetime of a multicast forwarding cache -entry in the kernel. -Multicast forwarding cache entries in the kernel -are checked every -.Ar secs -seconds, and are refreshed if the source is still -active or deleted if not. -Care should be taken when setting this value, -as a low value can keep the kernel cache small at the cost of "thrashing" -the cache for periodic senders, but high values can cause the kernel -cache to grow unacceptably large. -The default is 300 seconds (5 minutes). -.It prune_lifetime Ar secs -Specifies, in seconds, the average lifetime of prunes that are sent towards -parents. -The actual lifetimes will be randomized in the range -[.5\fIsecs\fP,1.5\fIsecs\fP]. -The default is 7200 (2 hours). -Smaller values -cause less state to be kept both at this router and the parent, at the -cost of more frequent broadcasts. -However, some routers (e.g.\& -.Nm -<3.3 -and all currently known versions of cisco's IOS) do not use the -DVMRP generation ID to determine that a neighbor has rebooted. -Prunes -sent towards these neighbors should be kept short, in order to shorten -the time to recover from a reboot. -For use in this situation, the -prune_lifetime keyword may be specified on an interface as described -below. -.It noflood -The -.Nm -utility -uses a DVMRP optimization to prevent having to keep individual routing tables -for each neighbor; part of this optimization is that -.Nm -assumes that it is the forwarder for each of its attached subnets on -startup. -This can cause duplicates for a short period (approximately -one full route report interval), since both the router that just -started up and the proper forwarder will be forwarding traffic. -This -behavior can be turned off with the noflood keyword; -.Nm -will not assume that it is the forwarder on startup. -Turning on noflood can cause black holes on restart, which will generally -last approximately one full route report interval. -The noflood keyword can also be specified on individual interfaces. -.It rexmit_prunes Ar [on|off] -Default is to retransmit prunes on all point-to-point interfaces -(including tunnels) but no multi-access interfaces. -This option -may be used to make the default on (or off) for all interfaces. -The rexmit_prunes keyword can also be specified on individual interfaces. -.It name Ar "boundary-name scoped-addr/mask-len" -Associates -.Ar boundary-name -with the boundary described by -.Ar scoped-addr/mask-len , -to help make interface configurations -more readable and reduce repetition in the configuration file. -.El -.Pp -The second section of the configuration file, which may optionally -be empty, describes options that apply to physical interfaces. -.Bl -tag -width indent -.It phyint Ar "local-addr|ifname" -The phyint command does nothing by itself; it is simply a place holder -which interface-specific commands may follow. -An interface address or -name may be specified. -.It disable -Disables multicast forwarding on this interface. -By default, -.Nm -discovers all locally attached multicast capable interfaces and forwards -on all of them. -.It netmask Ar netmask -If the kernel's netmask does not accurately reflect -the subnet (e.g.\& you are using proxy-ARP in lieu of IP subnetting), use the -netmask command to describe the real netmask. -.It altnet Ar network/mask-len -If a phyint is attached to multiple IP subnets, describe each additional subnet -with the altnet keyword. -This command may be specified multiple times -to describe multiple subnets. -.It igmpv1 -If there are any IGMPv1 routers on the phyint, use the \fBigmpv1\fP -keyword to force -.Nm -into IGMPv1 mode. -All routers on the phyint -must use the same version of IGMP. -.It force_leaf -Force -.Nm -to ignore other routers on this interface. -.Nm -will never send or accept neighbor probes or -route reports on this interface. -.El -.Pp -In addition, the common vif commands described later may all be used on -a phyint. -.Pp -The third section of the configuration file, also optional, describes -the configuration of any DVMRP tunnels this router might have. -.Bl -tag -width indent -.It tunnel Ar "local-addr|ifname" Ar "remote-addr|remote-hostname" -This command establishes a DVMRP tunnel between this host (on the interface -described by -.Ar local-addr -or -.Ar ifname ) -and a remote host (identified by -.Ar remote-addr -or -.Ar remote-hostname ) . -A remote hostname may only be used if -it maps to a single IP address. -A tunnel must be configured on both routers before it can be used. -.Pp -Be careful that the unicast route to the remote address goes out the -interface specified by the -.Ar "local-addr|ifname" -argument. -Some UNIX -kernels rewrite the source address of -.Nm Ns 's -packets on their way out to contain the address of the transmission -interface. -This is best assured via a static host route. -.El -.Pp -The common vif commands described below -may all be used on tunnels or phyints. -.Bl -tag -width indent -.It metric Ar m -The metric is the "cost" associated with receiving a datagram on the given -interface or tunnel; it may be used to influence the choice of routes. -The metric defaults to 1. -Metrics should be kept as small as possible, -because DVMRP cannot route along paths with a sum of metrics greater -than 31. -.It advert_metric Ar m -The advert_metric is the "cost" associated with sending a datagram -on the given interface or tunnel; it may be used to influence the choice -of routes. -The advert_metric defaults to 0. -Note that the effective -metric of a link is one end's metric plus the other end's advert_metric. -.It threshold Ar t -The threshold is the minimum IP time-to-live required for a multicast datagram -to be forwarded to the given interface or tunnel. -It is used to control the -scope of multicast datagrams. -(The TTL of forwarded packets is only compared -to the threshold, it is not decremented by the threshold. -Every multicast -router decrements the TTL by exactly 1.) -The default threshold is 1. -.Pp -In general, all multicast routers -connected to a particular subnet or tunnel should -use the same metric and threshold for that subnet or tunnel. -.It rate_limit Ar r -The rate_limit option allows the network administrator to specify a -certain bandwidth in Kbits/second which would be allocated to multicast -traffic. -It defaults 0 (unlimited). -.It boundary Ar "boundary-name|scoped-addr/mask-len" -The boundary option allows an interface -to be configured as an administrative boundary for the specified -scoped address. -Packets belonging to this address will not -be forwarded on a scoped interface. -The boundary option accepts either -a name or a boundary spec. -This command may be specified several times -on an interface in order to describe multiple boundaries. -.It passive -No packets will be sent on this link or tunnel until we hear from the other -end. -This is useful for the "server" end of a tunnel that goes over -a dial-on-demand link; configure the "server" end as passive and -it will not send its periodic probes until it hears one from the other -side, so will not keep the link up. -If this option is specified on both -ends of a tunnel, the tunnel will never come up. -.It noflood -As described above, but only applicable to this interface/tunnel. -.It prune_lifetime Ar secs -As described above, but only applicable to this interface/tunnel. -.It rexmit_prunes Ar "[on|off]" -As described above, but only applicable to this interface/tunnel. -Recall that prune retransmission -defaults to on for point-to-point links and tunnels, and to off for -multi-access links. -.It allow_nonpruners -By default, -.Nm -refuses to peer with DVMRP neighbors that -do not claim to support pruning. -This option allows such peerings -on this interface. -.It notransit -A specialized case of route filtering; no route learned from an interface -marked "notransit" will be advertised on another interface marked -"notransit". -Marking only a single interface "notransit" has no meaning. -.It accept|deny Ar "(route/mask-len [exact])+" Op bidir -The -.Li accept -and -.Li deny -commands allow rudimentary route filtering. -The -.Li accept -command causes -.Nm -to accept only the listed routes on the configured interface; the -.Li deny -command causes -.Nm -to accept all but the listed routes. -Only one of -.Li accept -or -.Li deny -commands may be used on a given interface. -.Pp -The list of routes follows the -.Li accept -or -.Li deny -keyword. -If the keyword -.Ar exact -follows a route, then only that route is matched; otherwise, that route -and any more specific route is matched. -For example, -.Li deny 0/0 -denys all routes, while -.Li deny 0/0 exact -denys only the default route. -The default route may also be specified -with the -.Li default -keyword. -.Pp -The -.Ar bidir -keyword enables bidirectional route filtering; the filter will be applied -to routes on both output and input. -Without the -.Ar bidir -keyword, -.Li accept -and -.Li deny -filters are only applied on input. -Poison reverse routes are never -filtered out. -.El -.Pp -The -.Nm -utility will not initiate execution if it has fewer than two enabled vifs, -where a vif (virtual interface) is either a physical multicast-capable -interface or a tunnel. -It will log a warning if all of its vifs are -tunnels; such an -.Nm -configuration would be better replaced by more -direct tunnels (i.e., eliminate the middle man). -.Sh "EXAMPLE CONFIGURATION" -This is an example configuration for a mythical multicast router at a big -school. -.Pp -.Bd -literal -# -# mrouted.conf example -# -# Name our boundaries to make it easier -name LOCAL 239.255.0.0/16 -name EE 239.254.0.0/16 -# -# le1 is our gateway to compsci, don't forward our -# local groups to them -phyint le1 boundary EE -# -# le2 is our interface on the classroom net, it has four -# different length subnets on it. -# note that you can use either an ip address or an -# interface name -phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26 - altnet 172.16.15.128/26 altnet 172.16.48.0/24 -# -# atm0 is our ATM interface, which doesn't properly -# support multicasting. -phyint atm0 disable -# -# This is an internal tunnel to another EE subnet -# Remove the default tunnel rate limit, since this -# tunnel is over ethernets -tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1 - rate_limit 0 -# -# This is our tunnel to the outside world. -# Careful with those boundaries, Eugene. -tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32 - boundary LOCAL boundary EE -.Ed -.Sh SIGNALS -The -.Nm -utility responds to the following signals: -.Bl -tag -width indent -.It HUP -Restarts -.Nm . -The configuration file is reread every time this signal is evoked. -.It INT -Terminate execution gracefully (i.e., by sending -good-bye messages to all neighboring routers). -.It TERM -Same as INT. -.It USR1 -Dump the internal routing tables to -.Pa /var/tmp/mrouted.dump . -.It USR2 -Dump the internal cache tables to -.Pa /var/tmp/mrouted.cache . -.It QUIT -Dump the internal routing tables to stderr (only if -.Nm -was invoked with a non-zero debug level). -.El -.Pp -For convenience in sending signals, -.Nm -writes its pid to -.Pa /var/run/mrouted.pid -upon startup. -.Sh FILES -.Bl -tag -width /var/tmp/mrouted.cache -compact -.It Pa /etc/mrouted.conf -.It Pa /var/run/mrouted.pid -.It Pa /var/tmp/mrouted.dump -.It Pa /var/tmp/mrouted.cache -.El -.Sh EXAMPLES -The routing tables look like this: -.Pp -.Bd -literal -Virtual Interface Table - Vif Local-Address Metric Thresh Flags - 0 36.2.0.8 subnet: 36.2/16 1 1 querier - groups: 224.0.2.1 - 224.0.0.4 - pkts in: 3456 - pkts out: 2322323 - - 1 36.11.0.1 subnet: 36.11/16 1 1 querier - groups: 224.0.2.1 - 224.0.1.0 - 224.0.0.4 - pkts in: 345 - pkts out: 3456 - - 2 36.2.0.8 tunnel: 36.8.0.77 3 1 - peers: 36.8.0.77 (3.255) - boundaries: 239.0.1/24 - : 239.1.2/24 - pkts in: 34545433 - pkts out: 234342 - - 3 36.2.0.8 tunnel: 36.6.8.23 3 16 - -Multicast Routing Table (1136 entries) - Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs - 36.2 1 45 0 1* 2 3* - 36.8 36.8.0.77 4 15 2 0* 1* 3* - 36.11 1 20 1 0* 2 3* - . - . - . -.Ed -.Pp -In this example, there are four vifs connecting to two subnets and two -tunnels. -The vif 3 tunnel is not in use (no peer address). -The vif 0 and -vif 1 subnets have some groups present; tunnels never have any groups. -This -instance of -.Nm -is the one responsible for sending periodic group -membership queries on the vif 0 and vif 1 subnets, as indicated by the -"querier" flags. -The list of boundaries indicate the scoped addresses on that -interface. -A count of the no. -of incoming and outgoing packets is also -shown at each interface. -.Pp -Associated with each subnet from which a multicast datagram can originate -is the address of the previous hop router (unless the subnet is directly- -connected), the metric of the path back to the origin, the amount of time -since we last received an update for this subnet, the incoming vif for -multicasts from that origin, and a list of outgoing vifs. -"*" means that -the outgoing vif is connected to a leaf of the broadcast tree rooted at the -origin, and a multicast datagram from that origin will be forwarded on that -outgoing vif only if there are members of the destination group on that leaf. -.Pp -The -.Nm -utility also maintains a copy of the kernel forwarding cache table. -Entries -are created and deleted by -.Nm . -.Pp -The cache tables look like this: -.Pp -.Bd -literal -Multicast Routing Cache Table (147 entries) - Origin Mcast-group CTmr Age Ptmr IVif Forwvifs - 13.2.116/22 224.2.127.255 3m 2m - 0 1 ->13.2.116.19 ->13.2.116.196 - 138.96.48/21 224.2.127.255 5m 2m - 0 1 ->138.96.48.108 - 128.9.160/20 224.2.127.255 3m 2m - 0 1 ->128.9.160.45 - 198.106.194/24 224.2.135.190 9m 28s 9m 0P ->198.106.194.22 -.Ed -.Pp -Each entry is characterized by the origin subnet number and mask and the -destination multicast group. -.Pp -The 'CTmr' field indicates the lifetime -of the entry. -The entry is deleted from the cache table -(or refreshed, if traffic is flowing) -when the timer decrements to zero. -The 'Age' field is the time since -this cache entry was originally created. -Since cache entries get refreshed -if traffic is flowing, routing entries can grow very old. -.Pp -The 'Ptmr' field is simply a dash if no prune was sent upstream, or the -amount of time until the upstream prune will time out. -.Pp -The 'Ivif' field indicates the -incoming vif for multicast packets from that origin. -Each router also -maintains a record of the number of prunes received from neighboring -routers for a particular source and group. -If there are no members of -a multicast group on any downward link of the multicast tree for a -subnet, a prune message is sent to the upstream router. -They are -indicated by a "P" after the vif number. -.Pp -The Forwvifs field shows the -interfaces along which datagrams belonging to the source-group are -forwarded. -A "p" indicates that no datagrams are being forwarded along -that interface. -An unlisted interface is a leaf subnet with no -members of the particular group on that subnet. -A "b" on an interface -indicates that it is a boundary interface, i.e., traffic will not be -forwarded on the scoped address on that interface. -.Pp -An additional line with a ">" as the first character is printed for -each source on the subnet. -Note that there can be many sources in -one subnet. -An additional line with a "<" as the first character is printed -describing any prunes received from downstream dependent neighbors -for this subnet and group. -.Sh SEE ALSO -.Xr map-mbone 8 , -.Xr mrinfo 8 , -.Xr mtrace 8 -.Pp -DVMRP is described, along with other multicast routing algorithms, in the -paper "Multicast Routing in Internetworks and Extended LANs" by -.An S. Deering , -in the Proceedings of the ACM SIGCOMM '88 Conference. -.Sh AUTHORS -.An Steve Deering , -.An Ajit Thyagarajan , -.An Bill Fenner . diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf deleted file mode 100644 index e9cb04c..0000000 --- a/usr.sbin/mrouted/mrouted.conf +++ /dev/null @@ -1,44 +0,0 @@ -# $FreeBSD$ -# mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel -# -# This is the configuration file for "mrouted", an IP multicast router. -# mrouted looks for it in "/etc/mrouted.conf". -# -# Command formats: -# -# name <boundname> <scoped-addr>/<mask-len> -# cache_lifetime 3600 # seconds -# pruning on -# -# phyint <local-addr> [disable] [metric <m>] [threshold <t>] [rate_limit <b>] -# [boundary (<boundname>|<scoped-addr>/<mask-len>)] -# [altnet (<subnet>/<mask-len>|<subnet>)] -# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] -# [threshold <t>] [rate_limit <b>] -# [boundary (<boundname>|<scoped-addr>/<mask-len>)] -# -# NOTE: any phyint commands MUST precede any tunnel commands -# NOTE: the mask-len is the no. of leading 1's in the mask -# NOTE: rate_limit is in kilobits, and defaults to 500 for tunnels -# -# Example of named bounary: -#name LOCAL 239.255.0.0/16 -#name EE 239.254.0.0/16 # i.e. the EE dept wants local groups -# -# Example of use of named boundary -#phyint le1 boundary EE # le1 is our interface to comp sci, -# # keep them away from our local groups -# -# -# Template tunnel for mcast_install -tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate_limit 500 # <-- REPLACE -# boundary LOCAL -# -# You might want to specify a boundary on your tunnel to the outside world, -# as above. -# -# NOTE: ONLY uncomment the following if you are running mrouted.snmp! -#sysName "mymrouter" -#sysContact "Me <me@me.com> +x.yyy.zzz-zzzz" -#sysVersion "MyOS 4.1.3 and mrouted" -#sysLocation "The MBONE" diff --git a/usr.sbin/mrouted/mrouted/Makefile b/usr.sbin/mrouted/mrouted/Makefile deleted file mode 100644 index afd3af8..0000000 --- a/usr.sbin/mrouted/mrouted/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -PROG= mrouted -MAN= mrouted.8 -SRCS= config.c cfparse.y main.c route.c vif.c prune.c callout.c rsrr.c \ - ipip.c icmp.c vers.c igmp.c inet.c kern.c -CLEANFILES+= vers.c - -CFLAGS+= -I$S -YFLAGS= - -vers.c: $S/VERSION - rm -f vers.c ; \ - sed 's/.*/char todaysversion[] = "&";/' $S/VERSION > vers.c - -.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8 deleted file mode 100644 index cd8d67d..0000000 --- a/usr.sbin/mrouted/mtrace.8 +++ /dev/null @@ -1,589 +0,0 @@ -.\" Copyright (c) 1995 by the University of Southern California -.\" All rights reserved. -.\" -.\" Permission to use, copy, modify, and distribute this software and its -.\" documentation in source and binary forms for non-commercial purposes -.\" and without fee is hereby granted, provided that the above copyright -.\" notice appear in all copies and that both the copyright notice and -.\" this permission notice appear in supporting documentation, and that -.\" any documentation, advertising materials, and other materials related -.\" to such distribution and use acknowledge that the software was -.\" developed by the University of Southern California, Information -.\" Sciences Institute. The name of the University may not be used to -.\" endorse or promote products derived from this software without -.\" specific prior written permission. -.\" -.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about -.\" the suitability of this software for any purpose. THIS SOFTWARE IS -.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, -.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -.\" -.\" Other copyrights might apply to parts of this software and are so -.\" noted when applicable. -.\" -.\" This manual page (but not the software) was derived from the -.\" manual page for the traceroute program which bears the following -.\" copyright notice: -.\" -.\" Copyright (c) 1988 The Regents of the University of California. -.\" All rights reserved. -.\" -.\" $FreeBSD$ -.\" -.Dd May 8, 1995 -.Dt MTRACE 8 -.Os -.Sh NAME -.Nm mtrace -.Nd print multicast path from a source to a receiver -.Sh SYNOPSIS -.Nm -.Op Fl e Ar extrahops -.Op Fl g Ar gateway -.Op Fl i Ar if_addr -.Op Fl l -.Op Fl M -.Op Fl m Ar max_hops -.Op Fl n -.Op Fl O -.Op Fl p -.Op Fl P -.Op Fl q Ar nqueries -.Op Fl r Ar resp_dest -.Op Fl s -.Op Fl S Ar stat_int -.Op Fl t Ar ttl -.Op Fl T -.Op Fl U -.Op Fl v -.Op Fl w Ar waittime -.Ar source -.Op Ar receiver -.Op Ar group -.Sh DESCRIPTION -Assessing problems in the distribution of IP multicast traffic -can be difficult. -The -.Nm -utility utilizes a tracing feature implemented in multicast routers that is -accessed via an extension to the IGMP protocol. -A trace query is -passed hop-by-hop along the reverse path from the -.Ar receiver -to the -.Ar source , -collecting hop addresses, packet counts, and routing error conditions -along the path, and then the response is returned to the requestor. -.Pp -The only required parameter is the -.Ar source -host name or address. -The default -.Ar receiver -is the host running mtrace, and the default -.Ar group -is 0.0.0.0, which is sufficient if packet loss -statistics for a particular multicast group are not needed. -These two -optional parameters may be specified to test the path to some other -receiver in a particular group, subject to some constraints as -detailed below. -The two parameters can be distinguished because the -.Ar receiver -is a unicast address and the -.Ar group -is a multicast address. -If the -.Fl g -flag is specified, the source address defaults to the host running -.Nm , -and the receiver defaults to the router being addressed with -the -.Fl g -flag. -In this case, there are no required parameters. -.Pp -NOTE: For Solaris 2.4/2.5, if the multicast interface is not the default -interface, the -.Fl i -option must be used to set the local address. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl e Ar extrahops -Try tracing -.Ar extrahops -hops past a non-responding router. -.It Fl g Ar gwy -Send the trace query via unicast directly to the multicast router -.Ar gwy -rather than multicasting the query. -This must be the last-hop router on the path from the intended -.Ar source -to the -.Ar receiver . -.Pp -.Em CAUTION ! ! -Versions 3.3 and 3.5 of -.Nm mrouted -will crash if a trace query is received via a -unicast packet and -.Nm mrouted -has no route for the -.Ar source -address. -Therefore, do not use the -.Fl g -option unless the target -.Nm mrouted -has been verified to be 3.4 or newer than 3.5. -.It Fl i Ar addr -Use -.Ar addr -as the local interface address (on a multi-homed host) for sending the -trace query and as the default for the -.Ar receiver -and the response destination. -.It Fl l -Loop indefinitely printing packet rate and loss statistics for the -multicast path every 10 seconds (see -.Fl S Ar stat_int ) . -.It Fl M -Always request the response using multicast rather than attempting -unicast for the last half of the tries. -.It Fl m Ar n -Set to -.Ar n -the maximum number of hops that will be traced from the -.Ar receiver -back toward the -.Ar source . -The default is 32 hops (infinity for the DVMRP routing protocol). -.It Fl n -Print hop addresses numerically rather than symbolically and numerically -(saves a nameserver address-to-name lookup for each router found on the -path). -.It Fl q Ar n -Set the maximum number of query attempts for any hop to -.Ar n . -The default is 3. -.It Fl O -Do not use the Router-Alert IP option on those requests which need it. -Some versions of Cisco's IOS cannot handle -multicast traceroutes with IP options, so it may be necessary to use the -.Fl O -flag if the last-hop router is a Cisco. -.It Fl p -Listen passively for multicast responses from traces initiated by -others. -This works best when run on a multicast router. -.It Fl P -Loop indefinitely collecting the path every 10 seconds (see -.Fl S Ar stat_int ) -and printing it when it changes. -Do not print any statistics. -.It Fl r Ar host -Send the trace response to -.Ar host -rather than to the host on which -.Nm -is being run, or to a multicast address other than the one registered -for this purpose (224.0.1.32). -.It Fl s -Print a short form output including only the multicast path and not -the packet rate and loss statistics. -.It Fl S Ar n -Change the interval between statistics gathering traces to -.Ar n -seconds (default 10 seconds). -.It Fl t Ar ttl -Set the -.Ar ttl -(time-to-live, or number of hops) for multicast trace queries and -responses. -The default is 127, except for local queries to the "all -routers" multicast group which use ttl 1. -.It Fl T -"Tunnel statistics" mode; show loss rates for overall traffic. -These statistics can be extremely misleading. -.It Fl U -Always request the response using unicast rather than attempting -multicast first. -.It Fl v -Verbose mode; show hop times on the initial trace and statistics display. -Also show the route that was used to forward the initial trace. -.It Fl w Ar n -Set the time to wait for a trace response to -.Ar n -seconds (default 3 seconds). -.El -.Sh USAGE -.Ss "How It Works" -The technique used by the -.Nm traceroute -utility to trace unicast network paths will not work for IP multicast -because ICMP responses are specifically forbidden for multicast traffic. -Instead, a tracing feature has been built into the multicast routers. -This technique has the advantage that additional information about -packet rates and losses can be accumulated while the number of packets -sent is minimized. -.Pp -Since multicast uses -reverse path forwarding, the trace is run backwards from the -.Ar receiver -to the -.Ar source . -A trace query packet is sent to the last -hop multicast router (the leaf router for the desired -.Ar receiver -address). -The last hop router builds a trace response packet, fills in -a report for its hop, and forwards the trace packet using unicast to -the router it believes is the previous hop for packets originating -from the specified -.Ar source . -Each router along the path adds its report and forwards the packet. -When the trace response packet reaches the first hop router (the router -that is directly connected to the source's net), that router sends the -completed response to the response destination address specified in -the trace query. -.Pp -If some multicast router along the path does not implement the -multicast traceroute feature or if there is some outage, then no -response will be returned. -To solve this problem, the trace query -includes a maximum hop count field to limit the number of hops traced -before the response is returned. -That allows a partial path to be -traced. -.Pp -The reports inserted by each router contain not only the address of -the hop, but also the ttl required to forward and some flags to indicate -routing errors, plus counts of the total number of packets on the -incoming and outgoing interfaces and those forwarded for the specified -.Ar group . -Taking differences in these counts for two traces separated in time -and comparing the output packet counts from one hop with the input -packet counts of the next hop allows the calculation of packet rate -and packet loss statistics for each hop to isolate congestion -problems. -.Ss Finding the Last-Hop Router -The trace query must be sent to the multicast router which is the -last hop on the path from the -.Ar source -to the -.Ar receiver . -If the receiver is on the local subnet (as determined using the subnet -mask), then the default method is to multicast the trace query to -all-routers.mcast.net (224.0.0.2) with a ttl of 1. -Otherwise, the -trace query is multicast to the -.Ar group -address since the last hop router will be a member of that group if -the receiver is. -Therefore it is necessary to specify a group that -the intended receiver has joined. -This multicast is sent with a -default ttl of 127, which may not be sufficient for all cases (changed -with the -.Fl t -option). -If the last hop router is known, it may also be addressed directly -using the -.Fl g -option). -Alternatively, if it is desired to trace a group that the -receiver has not joined, but it is known that the last-hop router is a -member of another group, the -.Fl g -option may also be used to specify a different multicast address for the -trace query. -.Pp -When tracing from a multihomed host or router, the default receiver -address may not be the desired interface for the path from the source. -In that case, the desired interface should be specified explicitly as -the -.Ar receiver . -.Ss Directing the Response -By default, -.Nm -first attempts to trace the full reverse path, unless the number of -hops to trace is explicitly set with the -.Fl m -option. -If there is no response within a 3 second timeout interval -(changed with the -.Fl w -option), a "*" is printed and the probing switches to hop-by-hop mode. -Trace queries are issued starting with a maximum hop count of one and -increasing by one until the full path is traced or no response is -received. -At each hop, multiple probes are sent (default is three, -changed with -.Fl q -option). -The first half of the attempts (default is two) are made with -the reply address set to standard multicast address, mtrace.mcast.net -(224.0.1.32) with the ttl set to 32 more than what is needed to pass the -thresholds seen so far along the path to the receiver. -For each -additional attempt, the ttl is increased by another 32 each time up to -a maximum of 192. -Since the desired router may not be able to send a -multicast reply, the remainder of the attempts request that the -response be sent via unicast to the host running -.Nm . -Alternatively, the multicast ttl may be set explicitly with the -.Fl t -option, the initial multicast attempts can be forced to use unicast -instead with the -.Fl U -option, the final unicast attempts can be forced to use multicast -instead with the -.Fl M -option, or if you specify -.Fl UM , -.Nm -will first attempt using unicast and then multicast. -For each attempt, -if no response is received within the timeout, a "*" is printed. -After -the specified number of attempts have failed, -.Nm -will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2 -request (as used by the -.Nm mrinfo -program) to see what kind of router it is. -The -.Nm -utility will try to query three (changed with the -.Fl e -option) hops past a non-responding router, in the hopes that even -though it is not capable of sending a response, it might be capable of -forwarding the request on. -.Sh EXAMPLES -The output of -.Nm -is in two sections. -The first section is a short listing of the hops -in the order they are queried, that is, in the reverse of the order -from the -.Ar source -to the -.Ar receiver . -For each hop, a line is printed showing the hop number (counted -negatively to indicate that this is the reverse path); the multicast -routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to -forward data (to the previous hop in the listing as indicated by the -up-arrow character); and the cumulative delay for the query to reach -that hop (valid only if the clocks are synchronized). -This first -section ends with a line showing the round-trip time which measures -the interval from when the query is issued until the response is -received, both derived from the local system clock, and the total -ttl required for a packet to travel along this path. -A sample use and -output might be: -.Pp -.Bd -literal -oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3 -Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3 -Querying full reverse path... - 0 oak.isi.edu (128.9.160.100) - -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms - -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms - -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms - -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms - -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms - -6 caraway.lcs.mit.edu (18.26.0.170) -Round trip time 124 ms; total ttl of 6 required. -.Ed -.Pp -If a hop reports that it is using the default route to forward packets, -the word -.Em [default] -is printed after that hop. -If the -.Fl v -flag is supplied, the route being used to forward packets is printed -in the form -.Em [18.26.0/24] . -.Pp -The second section provides a pictorial view of the path in the -forward direction with data flow indicated by arrows pointing downward -and the query path indicated by arrows pointing upward. -For each hop, -both the entry and exit addresses of the router are shown if -different, along with the initial ttl required on the packet in order -to be forwarded at this hop and the propagation delay across the hop -assuming that the routers at both ends have synchronized clocks. -The right half of this section is composed of two sets of statistics. -The first column contains the average packet rate for all traffic at -each hop. -The remaining columns are the -number of packets lost, the number of packets sent, the percentage -lost, and the average packet rate at each hop. -These statistics are -calculated from differences between traces and from hop to hop as -explained above. -The first group shows the statistics for all traffic -flowing out the interface at one hop and in the interface at the next -hop. -The second group shows the statistics only for traffic forwarded -from the specified -.Ar source -to the specified -.Ar group . -The first group of statistics may be expanded to include loss rates -using the -.Fl T -option. -However, these numbers can be extremely misleading and require -detailed knowledge of the routers involved to be interpreted properly. -.Pp -These statistics are shown on one or two lines for each hop. -Without -any options, this second section of the output is printed only once, -approximately 10 seconds after the initial trace. -One line is shown -for each hop showing the statistics over that 10-second period. -If -the -.Fl l -option is given, the second section is repeated every 10 seconds and -two lines are shown for each hop. -The first line shows the statistics -for the last 10 seconds, and the second line shows the cumulative -statistics over the period since the initial trace, which is 101 -seconds in the example below. -The second section of the output is -omitted if the -.Fl s -option is set or if no multicast group is specified. -.Pp -.Bd -literal -Waiting to accumulate statistics... Results after 101 seconds: - - Source Response Dest Overall Packet Statistics For Traffic From -18.26.0.170 128.9.160.100 Packet 18.26.0.170 To 224.2.0.3 - | __/ rtt 125 ms Rate Lost/Sent = Pct Rate - v / hop 65 ms ------- --------------------- -18.26.0.144 -140.173.48.2 mit.dart.net - | ^ ttl 1 0 pps 0/2 = --% 0 pps - v | hop 8 ms 0 pps 0/18 = 0% 0 pps -140.173.48.1 -140.173.32.1 bbn.dart.net - | ^ ttl 2 0 pps 0/2 = --% 0 pps - v | hop 12 ms 0 pps 0/18 = 0% 0 pps -140.173.32.2 -140.173.64.1 dc.dart.net - | ^ ttl 3 27 pps 0/2 = --% 0 pps - v | hop 34 ms 26 pps 0/18 = 0% 0 pps -140.173.64.2 -140.173.128.1 la.dart.net - | ^ ttl 4 83 pps 0/2 = --% 0 pps - v | hop 11 ms 79 pps 0/18 = 0% 0 pps -140.173.128.2 -128.9.160.153 cub.isi.edu - | \\__ ttl 5 83 pps ?/2 0 pps - v \\ hop -8 ms 79 pps ?/18 0 pps -128.9.160.100 128.9.160.100 - Receiver Query Source -.Ed -.Pp -Because the packet counts may be changing as the trace query is -propagating, there may be small errors (off by 1 or 2) in these -statistics. -However, those errors should not accumulate, so the -cumulative statistics line should increase in accuracy as a new trace -is run every 10 seconds. -There are two sources of larger errors, both -of which show up as negative losses: -.Pp -If the input to a node is from a multi-access network with more than -one other node attached, then the input count will be (close to) the -sum of the output counts from all the attached nodes, but the output -count from the previous hop on the traced path will be only part of -that. -Hence the output count minus the input count will be negative. -.Pp -In release 3.3 of the DVMRP multicast forwarding software for SunOS -and other systems, a multicast packet generated on a router will be -counted as having come in an interface even though it did not. -This -creates the negative loss that can be seen in the example above. -.Pp -Note that these negative losses may mask positive losses. -.Pp -In the example, there is also one negative hop time. -This simply -indicates a lack of synchronization between the system clocks across -that hop. -This example also illustrates how the percentage loss is -shown as two dashes when the number of packets sent is less than 10 -because the percentage would not be statistically valid. -.Pp -A second example shows a trace to a receiver that is not local; the -query is sent to the last-hop router with the -.Fl g -option. -In this example, the trace of the full reverse path resulted -in no response because there was a node running an old version of -.Nm mrouted -that did not implement the multicast traceroute function, so -.Nm -switched to hop-by-hop mode. -The -.Dq Output pruned -error code -indicates that traffic for group 224.2.143.24 would not be forwarded. -.Pp -.Bd -literal -oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\ - butter.lcs.mit.edu 224.2.143.24 -Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24 -Querying full reverse path... * switching to hop-by-hop: - 0 butter.lcs.mit.edu (18.26.0.151) - -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Output pruned - -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms - -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms - -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms - -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond -Round trip time 95 ms -.Ed -.Sh SEE ALSO -.Xr map-mbone 8 , -.Xr mrinfo 8 , -.Xr mrouted 8 , -.Xr traceroute 8 -.Sh AUTHORS -.An -nosplit -Implemented by -.An Steve Casner -based on an initial prototype written by -.An Ajit Thyagarajan . -The multicast traceroute mechanism was designed by -.An Van Jacobson -with help from -.An Steve Casner , -.An Steve Deering , -.An Dino Farinacci , -and -.An Deb Agrawal ; -it was implemented in -.Nm mrouted -by -.An Ajit Thyagarajan -and -.An Bill Fenner . -The option syntax and the output format of -.Nm -are modeled after the unicast -.Nm traceroute -program written by -.An Van Jacobson . -.Sh BUGS -Statistics collection in passive mode does not always produce the same output -as when actively collecting data. diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c deleted file mode 100644 index 9cb53e3..0000000 --- a/usr.sbin/mrouted/mtrace.c +++ /dev/null @@ -1,3177 +0,0 @@ -/* - * mtrace.c - * - * This tool traces the branch of a multicast tree from a source to a - * receiver for a particular multicast group and gives statistics - * about packet rate and loss for each hop along the path. It can - * usually be invoked just as - * - * mtrace source - * - * to trace the route from that source to the local host for a default - * group when only the route is desired and not group-specific packet - * counts. See the usage line for more complex forms. - * - * - * Released 4 Apr 1995. This program was adapted by Steve Casner - * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and - * Xerox PARC). It attempts to parallel in command syntax and output - * format the unicast traceroute program written by Van Jacobson (LBL) - * for the parts where that makes sense. - * - * Copyright (c) 1995 by the University of Southern California - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation in source and binary forms for any purposes and without - * fee is hereby granted, provided that the above copyright notice - * appear in all copies and that both the copyright notice and this - * permission notice appear in supporting documentation, and that any - * documentation, advertising materials, and other materials related to - * such distribution and use acknowledge that the software was developed - * by the University of Southern California, Information Sciences - * Institute. The name of the University may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about - * the suitability of this software for any purpose. THIS SOFTWARE IS - * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Other copyrights might apply to parts of this software and are so - * noted when applicable. - * - * Parts of this software are derived from mrouted, which has the - * following license: - * - * The mrouted program is covered by the following license. Use of the - * mrouted program represents acceptance of these terms and conditions. - * - * 1. STANFORD grants to LICENSEE a nonexclusive and nontransferable - * license to use, copy and modify the computer software ``mrouted'' - * (hereinafter called the ``Program''), upon the terms and conditions - * hereinafter set out and until Licensee discontinues use of the Licensed - * Program. - * - * 2. LICENSEE acknowledges that the Program is a research tool still in - * the development state, that it is being supplied ``as is,'' without any - * accompanying services from STANFORD, and that this license is entered - * into in order to encourage scientific collaboration aimed at further - * development and application of the Program. - * - * 3. LICENSEE may copy the Program and may sublicense others to use - * object code copies of the Program or any derivative version of the - * Program. All copies must contain all copyright and other proprietary - * notices found in the Program as provided by STANFORD. Title to - * copyright to the Program remains with STANFORD. - * - * 4. LICENSEE may create derivative versions of the Program. LICENSEE - * hereby grants STANFORD a royalty-free license to use, copy, modify, - * distribute and sublicense any such derivative works. At the time - * LICENSEE provides a copy of a derivative version of the Program to a - * third party, LICENSEE shall provide STANFORD with one copy of the - * source code of the derivative version at no charge to STANFORD. - * - * 5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR - * IMPLIED. By way of example, but not limitation, STANFORD MAKES NO - * REPRESENTATION OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY - * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED PROGRAM WILL NOT - * INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD - * shall not be held liable for any liability nor for any direct, indirect - * or consequential damages with respect to any claim by LICENSEE or any - * third party on account of or arising from this Agreement or use of the - * Program. - * - * 6. This agreement shall be construed, interpreted and applied in - * accordance with the State of California and any legal action arising - * out of this Agreement or use of the Program shall be filed in a court - * in the State of California. - * - * 7. Nothing in this Agreement shall be construed as conferring rights to - * use in advertising, publicity or otherwise any trademark or the name - * of ``Stanford''. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * The mtrace program has been modified and improved by Xerox - * Corporation. Xerox grants to LICENSEE a non-exclusive and - * non-transferable license to use, copy, and modify the Xerox modified - * and improved mrouted software on the same terms and conditions which - * govern the license Stanford and ISI grant with respect to the mtrace - * program. These terms and conditions are incorporated in this grant - * by reference and shall be deemed to have been accepted by LICENSEE - * to cover its relationship with Xerox Corporation with respect to any - * use of the Xerox improved program. - * - * The mtrace program is COPYRIGHT 1998 by Xerox Corporation. - * - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <memory.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/igmp.h> -#include <sys/ioctl.h> -#ifdef SYSV -#include <sys/sockio.h> -#endif -#include <arpa/inet.h> -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif -#ifdef SUNOS5 -#include <sys/systeminfo.h> -#endif - -typedef unsigned int u_int32; /* XXX */ -#include "mtrace.h" - -#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */ -#define DEFAULT_RETRIES 3 /* How many times to try */ -#define DEFAULT_EXTRAHOPS 3 /* How many hops past a non-responding rtr */ -#define MAXHOPS 60 /* Don't need more hops than this */ -#define UNICAST_TTL 255 /* TTL for unicast response */ -#define MULTICAST_TTL1 127 /* Default TTL for multicast query/response */ -#define MULTICAST_TTL_INC 32 /* TTL increment for increase after timeout */ -#define MULTICAST_TTL_MAX 192 /* Maximum TTL allowed (protect low-BW links */ - -#define TRUE 1 -#define FALSE 0 -#define DVMRP_ASK_NEIGHBORS2 5 /* DVMRP msg requesting neighbors */ -#define DVMRP_NEIGHBORS2 6 /* reply to above */ -#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ -#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ -#define MAX_IP_PACKET_LEN 576 -#define MIN_IP_HEADER_LEN 20 -#define MAX_IP_HEADER_LEN 60 -#define MAX_DVMRP_DATA_LEN \ - ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN ) - -struct resp_buf { - u_long qtime; /* Time query was issued */ - u_long rtime; /* Time response was received */ - int len; /* Number of reports or length of data */ - struct igmp igmp; /* IGMP header */ - union { - struct { - struct tr_query q; /* Query/response header */ - struct tr_resp r[MAXHOPS]; /* Per-hop reports */ - } t; - char d[MAX_DVMRP_DATA_LEN]; /* Neighbor data */ - } u; -} base, incr[2]; - -#define qhdr u.t.q -#define resps u.t.r -#define ndata u.d - -char *names[MAXHOPS]; - -/* - * In mrouted 3.3 and 3.4 (and in some Cisco IOS releases), - * cache entries can get deleted even if there is traffic - * flowing, which will reset the per-source/group counters. - */ -#define BUG_RESET 0x01 - -/* - * Also in mrouted 3.3 and 3.4, there's a bug in neighbor - * version processing which can cause them to believe that - * the neighbor is constantly resetting. This causes them - * to constantly delete all their state. - */ -#define BUG_RESET2X 0x02 - -/* - * Pre-3.7 mrouted's forget to byte-swap their reports. - */ -#define BUG_SWAP 0x04 - -/* - * Pre-3.9 mrouted's forgot a parenthesis in the htonl() - * on the time calculation so supply bogus times. - */ -#define BUG_BOGUSTIME 0x08 - -#define BUG_NOPRINT (BUG_RESET | BUG_RESET2X) - -int bugs[MAXHOPS]; /* List of bugs noticed at each hop */ - -struct mtrace { - struct mtrace *next; - struct resp_buf base, incr[2]; - struct resp_buf *new, *prev; - int nresp; - struct timeval last; - int bugs[MAXHOPS]; - char *names[MAXHOPS]; - int lastqid; -}; - -int timeout = DEFAULT_TIMEOUT; -int nqueries = DEFAULT_RETRIES; -int numeric = FALSE; -int debug = 0; -int passive = FALSE; -int multicast = FALSE; -int unicast = FALSE; -int statint = 10; -int verbose = FALSE; -int tunstats = FALSE; -int weak = FALSE; -int extrahops = DEFAULT_EXTRAHOPS; -int printstats = TRUE; -int sendopts = TRUE; -int lossthresh = 0; -int fflag = FALSE; -int staticqid = 0; - -u_int32 defgrp; /* Default group if not specified */ -u_int32 query_cast; /* All routers multicast addr */ -u_int32 resp_cast; /* Mtrace response multicast addr */ - -u_int32 lcl_addr = 0; /* This host address, in NET order */ -u_int32 dst_netmask = 0; /* netmask to go with qdst */ - -/* - * Query/response parameters, all initialized to zero and set later - * to default values or from options. - */ -u_int32 qsrc = 0; /* Source address in the query */ -u_int32 qgrp = 0; /* Group address in the query */ -u_int32 qdst = 0; /* Destination (receiver) address in query */ -u_char qno = 0; /* Max number of hops to query */ -u_int32 raddr = 0; /* Address where response should be sent */ -int qttl = 0; /* TTL for the query packet */ -u_char rttl = 0; /* TTL for the response packet */ -u_int32 gwy = 0; /* User-supplied last-hop router address */ -u_int32 tdst = 0; /* Address where trace is sent (last-hop) */ - -char s1[19]; /* buffers to hold the string representations */ -char s2[19]; /* of IP addresses, to be passed to inet_fmt() */ -char s3[19]; /* or inet_fmts(). */ - -#if !(defined(BSD) && (BSD >= 199103)) -extern int errno; -extern int sys_nerr; -extern char * sys_errlist[]; -#endif - -#define RECV_BUF_SIZE 8192 -char *send_buf, *recv_buf; -int igmp_socket; -u_int32 allrtrs_group; -char router_alert[4]; /* Router Alert IP Option */ -#ifndef IPOPT_RA -#define IPOPT_RA 148 -#endif -#ifdef SUNOS5 -char eol[4]; /* EOL IP Option */ -int ip_addlen = 0; /* Workaround for Option bug #2 */ -#endif - -/* - * max macro, with weird case to avoid conflicts - */ -#define MaX(a,b) ((a) > (b) ? (a) : (b)) - -#ifndef __P -#ifdef __STDC__ -#define __P(x) x -#else -#define __P(x) () -#endif -#endif - -typedef int (*callback_t) __P((int, u_char *, int, struct igmp *, int, - struct sockaddr *, int *, struct timeval *)); - -void init_igmp __P((void)); -void send_igmp __P((u_int32 src, u_int32 dst, int type, - int code, u_int32 group, - int datalen)); -int inet_cksum __P((u_short *addr, u_int len)); -void k_set_rcvbuf __P((int bufsize)); -void k_hdr_include __P((int bool)); -void k_set_ttl __P((int t)); -void k_set_loop __P((int l)); -void k_set_if __P((u_int32 ifa)); -void k_join __P((u_int32 grp, u_int32 ifa)); -void k_leave __P((u_int32 grp, u_int32 ifa)); -char * inet_fmt __P((u_int32 addr, char *s)); -char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s)); -char * inet_name __P((u_int32 addr)); -u_int32 host_addr __P((char *name)); -/* u_int is promoted u_char */ -char * proto_type __P((u_int type)); -char * flag_type __P((u_int type)); - -u_int32 get_netmask __P((int s, u_int32 *dst)); -int get_ttl __P((struct resp_buf *buf)); -int t_diff __P((u_long a, u_long b)); -u_long byteswap __P((u_long v)); -int mtrace_callback __P((int, u_char *, int, struct igmp *, - int, struct sockaddr *, int *, - struct timeval *)); -int send_recv __P((u_int32 dst, int type, int code, - int tries, struct resp_buf *save, - callback_t callback)); -void passive_mode __P((void)); -char * print_host __P((u_int32 addr)); -char * print_host2 __P((u_int32 addr1, u_int32 addr2)); -void print_trace __P((int idx, struct resp_buf *buf, - char **names)); -int what_kind __P((struct resp_buf *buf, char *why)); -char * scale __P((int *hop)); -void stat_line __P((struct tr_resp *r, struct tr_resp *s, - int have_next, int *res)); -void fixup_stats __P((struct resp_buf *base, - struct resp_buf *prev, - struct resp_buf *new, - int *bugs)); -int check_thresh __P((int thresh, - struct resp_buf *base, - struct resp_buf *prev, - struct resp_buf *new)); -int print_stats __P((struct resp_buf *base, - struct resp_buf *prev, - struct resp_buf *new, - int *bugs, - char **names)); -int path_changed __P((struct resp_buf *base, - struct resp_buf *new)); -void check_vif_state __P((void)); - -int main __P((int argc, char *argv[])); -void log __P((int, int, char *, ...)); -static void usage __P((void)); - - -/* - * Open and initialize the igmp socket, and fill in the non-changing - * IP header fields in the output packet buffer. - */ -void -init_igmp() -{ - struct ip *ip; - - recv_buf = (char *)malloc(RECV_BUF_SIZE); - if (recv_buf == 0) - log(LOG_ERR, 0, "Out of memory allocating recv_buf!"); - send_buf = (char *)malloc(RECV_BUF_SIZE); - if (send_buf == 0) - log(LOG_ERR, 0, "Out of memory allocating send_buf!"); - - if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) - log(LOG_ERR, errno, "IGMP socket"); - - k_hdr_include(TRUE); /* include IP header when sending */ - k_set_rcvbuf(48*1024); /* lots of input buffering */ - k_set_ttl(1); /* restrict multicasts to one hop */ - k_set_loop(FALSE); /* disable multicast loopback */ - - ip = (struct ip *)send_buf; - ip->ip_hl = sizeof(struct ip) >> 2; - ip->ip_v = IPVERSION; - ip->ip_tos = 0; - ip->ip_off = 0; - ip->ip_p = IPPROTO_IGMP; - ip->ip_ttl = MAXTTL; /* applies to unicasts only */ - -#ifndef INADDR_ALLRTRS_GROUP -#define INADDR_ALLRTRS_GROUP 0xe0000002 /* 224.0.0.2 */ -#endif - allrtrs_group = htonl(INADDR_ALLRTRS_GROUP); - - router_alert[0] = IPOPT_RA; /* Router Alert */ - router_alert[1] = 4; /* 4 bytes */ - router_alert[2] = 0; - router_alert[3] = 0; -} - -#ifdef SUNOS5 -void -checkforsolarisbug() -{ - u_int32 localhost = htonl(0x7f000001); - - eol[0] = IPOPT_EOL; - eol[1] = IPOPT_EOL; - eol[2] = IPOPT_EOL; - eol[3] = IPOPT_EOL; - - setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, eol, sizeof(eol)); - /* - * Check if the kernel adds the options length to the packet - * length. Send myself an IGMP packet of type 0 (illegal), - * with 4 IPOPT_EOL options, my PID (for collision detection) - * and 4 bytes of zero (so that the checksum works whether - * the 4 bytes of zero get truncated or not). - */ - bzero(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN, 8); - *(int *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN) = getpid(); - send_igmp(localhost, localhost, 0, 0, 0, 8); - while (1) { - int recvlen, dummy = 0; - - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, NULL, &dummy); - /* 8 == 4 bytes of options and 4 bytes of PID */ - if (recvlen >= MIN_IP_HEADER_LEN + IGMP_MINLEN + 8) { - struct ip *ip = (struct ip *)recv_buf; - struct igmp *igmp; - int *p; - - if (ip->ip_hl != 6 || - ip->ip_p != IPPROTO_IGMP || - ip->ip_src.s_addr != localhost || - ip->ip_dst.s_addr != localhost) - continue; - - igmp = (struct igmp *)(recv_buf + (ip->ip_hl << 2)); - if (igmp->igmp_group.s_addr != 0) - continue; - if (igmp->igmp_type != 0 || igmp->igmp_code != 0) - continue; - - p = (int *)((char *)igmp + IGMP_MINLEN); - if (*p != getpid()) - continue; - -#ifdef RAW_INPUT_IS_RAW - ip->ip_len = ntohs(ip->ip_len); -#endif - if (ip->ip_len == IGMP_MINLEN + 4) - ip_addlen = 4; - else if (ip->ip_len == IGMP_MINLEN + 8) - ip_addlen = 0; - else - log(LOG_ERR, 0, "while checking for Solaris bug: Sent %d bytes and got back %d!", IGMP_MINLEN + 8, ip->ip_len); - - break; - } - } -} -#endif - -/* - * Construct an IGMP message in the output packet buffer. The caller may - * have already placed data in that buffer, of length 'datalen'. Then send - * the message from the interface with IP address 'src' to destination 'dst'. - */ -void -send_igmp(src, dst, type, code, group, datalen) - u_int32 src, dst; - int type, code; - u_int32 group; - int datalen; -{ - struct sockaddr_in sdst; - struct ip *ip; - struct igmp *igmp; - int setloop = 0; - static int raset = 0; - int sendra = 0; - int sendlen; - - ip = (struct ip *)send_buf; - ip->ip_src.s_addr = src; - ip->ip_dst.s_addr = dst; - ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; - sendlen = ip->ip_len; -#ifdef SUNOS5 - ip->ip_len += ip_addlen; -#endif -#ifdef RAW_OUTPUT_IS_RAW - ip->ip_len = htons(ip->ip_len); -#endif - - igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); - igmp->igmp_type = type; - igmp->igmp_code = code; - igmp->igmp_group.s_addr = group; - igmp->igmp_cksum = 0; - igmp->igmp_cksum = inet_cksum((u_short *)igmp, - IGMP_MINLEN + datalen); - - if (IN_MULTICAST(ntohl(dst))) { - k_set_if(src); - setloop = 1; - k_set_loop(TRUE); - if (dst != allrtrs_group) - sendra = 1; - } - - if (sendopts && sendra && !raset) { - setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, - router_alert, sizeof(router_alert)); - raset = 1; - } else if (!sendra && raset) { -#ifdef SUNOS5 - /* - * SunOS5 < 5.6 cannot properly reset the IP_OPTIONS "socket" - * option. Instead, set up a string of 4 EOL's. - */ - setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, - eol, sizeof(eol)); -#else - setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, - NULL, 0); -#endif - raset = 0; - } - - bzero(&sdst, sizeof(sdst)); - sdst.sin_family = AF_INET; -#if (defined(BSD) && (BSD >= 199103)) - sdst.sin_len = sizeof(sdst); -#endif - sdst.sin_addr.s_addr = dst; - if (sendto(igmp_socket, send_buf, sendlen, 0, - (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { - log(LOG_WARNING, errno, "sendto to %s on %s", - inet_fmt(dst, s1), inet_fmt(src, s2)); - } - - if (setloop) - k_set_loop(FALSE); - - log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", - type == IGMP_MTRACE ? "mtrace request" : "ask_neighbors", - src == INADDR_ANY ? "INADDR_ANY" : inet_fmt(src, s1), - inet_fmt(dst, s2)); -} - -/* - * inet_cksum extracted from: - * P I N G . C - * - * Author - - * Mike Muuss - * U. S. Army Ballistic Research Laboratory - * December, 1983 - * Modified at Uc Berkeley - * - * (ping.c) Status - - * Public Domain. Distribution Unlimited. - * - * I N _ C K S U M - * - * Checksum routine for Internet Protocol family headers (C Version) - * - */ -int -inet_cksum(addr, len) - u_short *addr; - u_int len; -{ - register int nleft = (int)len; - register u_short *w = addr; - u_short answer = 0; - register int sum = 0; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), - * we add sequential 16 bit words to it, and at the end, fold - * back all the carry bits from the top 16 bits into the lower - * 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) { - *(u_char *) (&answer) = *(u_char *)w ; - sum += answer; - } - - /* - * add back carry outs from top 16 bits to low 16 bits - */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return (answer); -} - -void -k_set_rcvbuf(bufsize) - int bufsize; -{ - if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, - (char *)&bufsize, sizeof(bufsize)) < 0) - log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize); -} - - -void -k_hdr_include(bool) - int bool; -{ -#ifdef IP_HDRINCL - if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, - (char *)&bool, sizeof(bool)) < 0) - log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool); -#endif -} - -void -k_set_ttl(t) - int t; -{ - u_char ttl; - - ttl = t; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, - (char *)&ttl, sizeof(ttl)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl); -} - - -void -k_set_loop(l) - int l; -{ - u_char loop; - - loop = l; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, - (char *)&loop, sizeof(loop)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop); -} - -void -k_set_if(ifa) - u_int32 ifa; -{ - struct in_addr adr; - - adr.s_addr = ifa; - if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&adr, sizeof(adr)) < 0) - log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s", - inet_fmt(ifa, s1)); -} - -void -k_join(grp, ifa) - u_int32 grp; - u_int32 ifa; -{ - struct ip_mreq mreq; - - mreq.imr_multiaddr.s_addr = grp; - mreq.imr_interface.s_addr = ifa; - - if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) < 0) - log(LOG_WARNING, errno, "can't join group %s on interface %s", - inet_fmt(grp, s1), inet_fmt(ifa, s2)); -} - - -void -k_leave(grp, ifa) - u_int32 grp; - u_int32 ifa; -{ - struct ip_mreq mreq; - - mreq.imr_multiaddr.s_addr = grp; - mreq.imr_interface.s_addr = ifa; - - if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) < 0) - log(LOG_WARNING, errno, "can't leave group %s on interface %s", - inet_fmt(grp, s1), inet_fmt(ifa, s2)); -} - -/* - * Convert an IP address in u_long (network) format into a printable string. - */ -char * -inet_fmt(addr, s) - u_int32 addr; - char *s; -{ - register u_char *a; - - a = (u_char *)&addr; - sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); - return (s); -} - - -/* - * Convert an IP subnet number in u_long (network) format into a printable - * string including the netmask as a number of bits. - */ -char * -inet_fmts(addr, mask, s) - u_int32 addr, mask; - char *s; -{ - register u_char *a, *m; - int bits; - - if ((addr == 0) && (mask == 0)) { - sprintf(s, "default"); - return (s); - } - a = (u_char *)&addr; - m = (u_char *)&mask; - bits = 33 - ffs(ntohl(mask)); - - if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3], - bits); - else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits); - else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits); - else sprintf(s, "%u/%d", a[0], bits); - - return (s); -} - -char * -inet_name(addr) - u_int32 addr; -{ - struct hostent *e; - - e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); - - return e ? e->h_name : "?"; -} - - -u_int32 -host_addr(name) - char *name; -{ - struct hostent *e = (struct hostent *)0; - u_int32 addr; - int i, dots = 3; - char buf[40]; - char *ip = name; - char *op = buf; - - /* - * Undo BSD's favor -- take fewer than 4 octets as net/subnet address - * if the name is all numeric. - */ - for (i = sizeof(buf) - 7; i > 0; --i) { - if (*ip == '.') --dots; - else if (*ip == '\0') break; - else if (!isdigit(*ip)) dots = 0; /* Not numeric, don't add zeroes */ - *op++ = *ip++; - } - for (i = 0; i < dots; ++i) { - *op++ = '.'; - *op++ = '0'; - } - *op = '\0'; - - if (dots <= 0) - e = gethostbyname(name); - if (e && (e->h_length == sizeof(addr))) { - memcpy((char *)&addr, e->h_addr_list[0], e->h_length); - if (e->h_addr_list[1]) - fprintf(stderr, "Warning: %s has multiple addresses, using %s\n", - name, inet_fmt(addr, s1)); - } else { - addr = inet_addr(buf); - if (addr == -1 || (IN_MULTICAST(addr) && dots)) { - addr = 0; - printf("Could not parse %s as host name or address\n", name); - } - } - return addr; -} - - -char * -proto_type(type) - u_int type; -{ - static char buf[80]; - - switch (type) { - case PROTO_DVMRP: - return ("DVMRP"); - case PROTO_MOSPF: - return ("MOSPF"); - case PROTO_PIM: - return ("PIM"); - case PROTO_CBT: - return ("CBT"); - case PROTO_PIM_SPECIAL: - return ("PIM/Special"); - case PROTO_PIM_STATIC: - return ("PIM/Static"); - case PROTO_DVMRP_STATIC: - return ("DVMRP/Static"); - case PROTO_PIM_BGP4PLUS: - return ("PIM/BGP4+"); - case PROTO_CBT_SPECIAL: - return ("CBT/Special"); - case PROTO_CBT_STATIC: - return ("CBT/Static"); - case PROTO_PIM_ASSERT: - return ("PIM/Assert"); - case 0: - return ("None"); - default: - (void) sprintf(buf, "Unknown protocol code %d", type); - return (buf); - } -} - - -char * -flag_type(type) - u_int type; -{ - static char buf[80]; - - switch (type) { - case TR_NO_ERR: - return (""); - case TR_WRONG_IF: - return ("Wrong interface"); - case TR_PRUNED: - return ("Prune sent upstream"); - case TR_OPRUNED: - return ("Output pruned"); - case TR_SCOPED: - return ("Hit scope boundary"); - case TR_NO_RTE: - return ("No route"); - case TR_NO_FWD: - return ("Not forwarding"); - case TR_HIT_RP: - return ("Reached RP/Core"); - case TR_RPF_IF: - return ("RPF Interface"); - case TR_NO_MULTI: - return ("Multicast disabled"); - case TR_OLD_ROUTER: - return ("Next router no mtrace"); - case TR_NO_SPACE: - return ("No space in packet"); - case TR_ADMIN_PROHIB: - return ("Admin. Prohibited"); - default: - (void) sprintf(buf, "Unknown error code %d", type); - return (buf); - } -} - -/* - * If destination is on a local net, get the netmask, else set the - * netmask to all ones. There are two side effects: if the local - * address was not explicitly set, and if the destination is on a - * local net, use that one; in either case, verify that the local - * address is valid. - */ -u_int32 -get_netmask(s, dst) - int s; - u_int32 *dst; -{ - unsigned int n; - struct ifconf ifc; - struct ifreq *ifrp, *ifend; - u_int32 if_addr, if_mask; - u_int32 retval = 0xFFFFFFFF; - int found = FALSE; - int num_ifreq = 32; - - ifc.ifc_len = num_ifreq * sizeof(struct ifreq); - ifc.ifc_buf = malloc(ifc.ifc_len); - while (ifc.ifc_buf) { - if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { - perror("ioctl SIOCGIFCONF"); - return retval; - } - - /* - * If the buffer was large enough to hold all the addresses - * then break out, otherwise increase the buffer size and - * try again. - * - * The only way to know that we definitely had enough space - * is to know that there was enough space for at least one - * more struct ifreq. ??? - */ - if ((num_ifreq * sizeof(struct ifreq)) >= - ifc.ifc_len + sizeof(struct ifreq)) - break; - - num_ifreq *= 2; - ifc.ifc_len = num_ifreq * sizeof(struct ifreq); - ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); - } - if (ifc.ifc_buf == NULL) { - fprintf(stderr, "getting interface list: ran out of memory"); - exit(1); - } - - ifrp = (struct ifreq *)ifc.ifc_buf; - ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); - /* - * Loop through all of the interfaces. - */ - for (; ifrp < ifend && !found; ifrp = (struct ifreq *)((char *)ifrp + n)) { -#if BSD >= 199006 - n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); - if (n < sizeof(*ifrp)) - n = sizeof(*ifrp); -#else - n = sizeof(*ifrp); -#endif - /* - * Ignore any interface for an address family other than IP. - */ - if (ifrp->ifr_addr.sa_family != AF_INET) - continue; - - if_addr = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr; - if (ioctl(s, SIOCGIFFLAGS, (char *)ifrp) < 0) { - fprintf(stderr, "SIOCGIFFLAGS on "); - perror(ifrp->ifr_name); - continue; - } - if ((ifrp->ifr_flags & (IFF_MULTICAST|IFF_UP|IFF_LOOPBACK)) != - (IFF_MULTICAST|IFF_UP)) - continue; - if (*dst == 0) - *dst = if_addr; - if (ioctl(s, SIOCGIFNETMASK, (char *)ifrp) >= 0) { - if_mask = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr; - if (if_mask != 0 && (*dst & if_mask) == (if_addr & if_mask)) { - retval = if_mask; - if (lcl_addr == 0) lcl_addr = if_addr; /* XXX what about aliases? */ - } - } - if (lcl_addr == if_addr) found = TRUE; - } - if (!found && lcl_addr != 0) { - printf("Interface address is not valid\n"); - exit(1); - } - return (retval); -} - - -/* - * Try to pick a TTL that will get past all the thresholds in the path. - */ -int -get_ttl(buf) - struct resp_buf *buf; -{ - int rno; - struct tr_resp *b; - u_int ttl; - - if (buf && (rno = buf->len) > 0) { - b = buf->resps + rno - 1; - ttl = b->tr_fttl; - - while (--rno > 0) { - --b; - if (ttl < b->tr_fttl) ttl = b->tr_fttl; - else ++ttl; - } - ttl += MULTICAST_TTL_INC; - if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1; - if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX; - return (ttl); - } else return(MULTICAST_TTL1); -} - -/* - * Calculate the difference between two 32-bit NTP timestamps and return - * the result in milliseconds. - */ -int -t_diff(a, b) - u_long a, b; -{ - int d = a - b; - - return ((d * 125) >> 13); -} - -/* - * Swap bytes for poor little-endian machines that don't byte-swap - */ -u_long -byteswap(v) - u_long v; -{ - return ((v << 24) | ((v & 0xff00) << 8) | - ((v >> 8) & 0xff00) | (v >> 24)); -} - -#if 0 -/* - * XXX incomplete - need private callback data, too? - * XXX since dst doesn't get passed through? - */ -int -neighbors_callback(tmo, buf, buflen, igmp, igmplen, addr, addrlen, ts) - int tmo; - u_char *buf; - int buflen; - struct igmp *igmp; - int igmplen; - struct sockaddr *addr; - int *addrlen; - struct timeval *ts; -{ - int len; - u_int32 dst; - struct ip *ip = (struct ip *)buf; - - if (tmo) - return 0; - - if (igmp->igmp_code != DVMRP_NEIGHBORS2) - return 0; - len = igmplen; - /* - * Accept DVMRP_NEIGHBORS2 response if it comes from the - * address queried or if that address is one of the local - * addresses in the response. - */ - if (ip->ip_src.s_addr != dst) { - u_int32 *p = (u_int32 *)(igmp + 1); - u_int32 *ep = p + (len >> 2); - while (p < ep) { - u_int32 laddr = *p++; - int n = ntohl(*p++) & 0xFF; - if (laddr == dst) { - ep = p + 1; /* ensure p < ep after loop */ - break; - } - p += n; - } - if (p >= ep) - return 0; - } - return buflen; -} -#endif - -int -mtrace_callback(tmo, buf, buflen, igmp, igmplen, addr, addrlen, ts) - int tmo; - u_char *buf; - int buflen; - struct igmp *igmp; - int igmplen; - struct sockaddr *addr; - int *addrlen; - struct timeval *ts; -{ - static u_char *savbuf = NULL; - static int savbuflen; - static struct sockaddr *savaddr; - static int savaddrlen; - static struct timeval savts; - - int len = (igmplen - QLEN) / RLEN; - struct tr_resp *r = (struct tr_resp *)((struct tr_query *)(igmp + 1) + 1); - - if (tmo == 1) { - /* - * If we timed out with a packet saved, then return that packet. - * send_recv won't send this same packet to the callback again. - */ - if (savbuf) { - bcopy(savbuf, buf, savbuflen); - free(savbuf); - savbuf = NULL; - bcopy(savaddr, addr, savaddrlen); - free(savaddr); - *addrlen = savaddrlen; - bcopy(&savts, ts, sizeof(savts)); - return savbuflen; - } - return 0; - } - if (savbuf) { - free(savbuf); - savbuf = NULL; - free(savaddr); - } - /* - * Check for IOS bug described in CSCdi68628, where a router that does - * not have multicast enabled responds to an mtrace request with a 1-hop - * error packet. - * Heuristic is: - * If there is only one hop reported in the packet, - * And the protocol code is 0, - * And there is no previous hop, - * And the forwarding information is "Not Forwarding", - * And the router is not on the same subnet as the destination of the - * trace, - * then drop this packet. The "#if 0"'d code saves it and returns - * it on timeout, but timeouts are too common (e.g. routers with - * limited unicast routing tables, etc). - */ - if (len == 1 && r->tr_rproto == 0 && r->tr_rmtaddr == 0 && - r->tr_rflags == TR_NO_FWD) { - u_int32 smask; - - VAL_TO_MASK(smask, r->tr_smask); - if ((r->tr_outaddr & smask) != (qdst & smask)) { -#if 0 - /* XXX should do this silently? */ - fprintf(stderr, "mtrace: probably IOS-buggy packet from %s\n", - inet_fmt(((struct sockaddr_in *)addr)->sin_addr.s_addr, s1)); - /* Save the packet to return if a timeout occurs. */ - savbuf = (u_char *)malloc(buflen); - if (savbuf != NULL) { - bcopy(buf, savbuf, buflen); - savbuflen = buflen; - savaddr = (struct sockaddr *)malloc(*addrlen); - if (savaddr != NULL) { - bcopy(addr, savaddr, *addrlen); - savaddrlen = *addrlen; - bcopy(ts, &savts, sizeof(savts)); - } else { - free(savbuf); - savbuf = NULL; - } - } -#endif - return 0; - } - } - return buflen; -} - -int -send_recv(dst, type, code, tries, save, callback) - u_int32 dst; - int type, code, tries; - struct resp_buf *save; - callback_t callback; -{ - fd_set fds; - struct timeval tq, tr, tv; - struct ip *ip; - struct igmp *igmp; - struct tr_query *query, *rquery; - struct tr_resp *r; - struct sockaddr_in recvaddr; - u_int32 local, group; - int ipdatalen, iphdrlen, igmpdatalen; - int datalen; - int count, recvlen, socklen = sizeof(recvaddr); - int len; - int i; - - if (type == IGMP_MTRACE) { - group = qgrp; - datalen = sizeof(struct tr_query); - } else { - group = htonl(0xff03); - datalen = 0; - } - if (IN_MULTICAST(ntohl(dst))) local = lcl_addr; - else local = INADDR_ANY; - - /* - * If the reply address was not explictly specified, start off - * with the standard multicast reply address, or the unicast - * address of this host if the unicast flag was specified. - * Then, if there is no response after trying half the tries - * with multicast, switch to the unicast address of this host - * if the multicast flag was not specified. If the TTL was - * also not specified, set a multicast TTL and increase it - * for every try. - */ - query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - query->tr_raddr = raddr ? raddr : unicast ? lcl_addr : resp_cast; - TR_SETTTL(query->tr_rttlqid, rttl ? rttl : - IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL); - query->tr_src = qsrc; - query->tr_dst = qdst; - - for (i = tries ; i > 0; --i) { - int oqid; - - if (tries == nqueries && raddr == 0) { - if (i == (nqueries >> 1)) { - if (multicast && unicast) { - query->tr_raddr = resp_cast; - if (!rttl) - TR_SETTTL(query->tr_rttlqid, get_ttl(save)); - } else if (!multicast) { - query->tr_raddr = lcl_addr; - TR_SETTTL(query->tr_rttlqid, UNICAST_TTL); - } - } - if (i < tries && IN_MULTICAST(ntohl(query->tr_raddr)) && - rttl == 0) { - TR_SETTTL(query->tr_rttlqid, - TR_GETTTL(query->tr_rttlqid) + MULTICAST_TTL_INC); - if (TR_GETTTL(query->tr_rttlqid) > MULTICAST_TTL_MAX) - TR_SETTTL(query->tr_rttlqid, MULTICAST_TTL_MAX); - } - } - - /* - * Change the qid for each request sent to avoid being confused - * by duplicate responses - */ - oqid = TR_GETQID(query->tr_rttlqid); - if (staticqid) - TR_SETQID(query->tr_rttlqid, staticqid); - else -#ifdef SYSV - TR_SETQID(query->tr_rttlqid, ((u_int32)lrand48() >> 8)); -#else - TR_SETQID(query->tr_rttlqid, ((u_int32)arc4random() >> 8)); -#endif - - /* - * Set timer to calculate delays, then send query - */ - gettimeofday(&tq, 0); - send_igmp(local, dst, type, code, group, datalen); - - /* - * Wait for response, discarding false alarms - */ - while (TRUE) { - if (igmp_socket >= FD_SETSIZE) - log(LOG_ERR, 0, "descriptor too big"); - FD_ZERO(&fds); - FD_SET(igmp_socket, &fds); - gettimeofday(&tv, 0); - tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec; - tv.tv_usec = tq.tv_usec - tv.tv_usec; - if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec; - if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0; - - count = select(igmp_socket + 1, &fds, (fd_set *)0, (fd_set *)0, - &tv); - - if (count < 0) { - if (errno != EINTR) warn("select"); - continue; - } else if (count == 0) { - /* - * Timed out. Notify the callback. - */ - if (!callback || (recvlen = (callback)(1, recv_buf, 0, NULL, 0, (struct sockaddr *)&recvaddr, &socklen, &tr)) == 0) { - printf("* "); - fflush(stdout); - break; - } - } else { - /* - * Data is available on the socket, so read it. - */ - gettimeofday(&tr, 0); - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, (struct sockaddr *)&recvaddr, &socklen); - } - - if (recvlen <= 0) { - if (recvlen && errno != EINTR) warn("recvfrom"); - continue; - } - - if (recvlen < sizeof(struct ip)) { - warnx("packet too short (%u bytes) for IP header", recvlen); - continue; - } - ip = (struct ip *) recv_buf; - if (ip->ip_p == 0) /* ignore cache creation requests */ - continue; - - iphdrlen = ip->ip_hl << 2; -#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len); -#else - ipdatalen = ip->ip_len; -#endif - if (iphdrlen + ipdatalen != recvlen) { - warnx("packet shorter (%u bytes) than hdr+data len (%u+%u)", - recvlen, iphdrlen, ipdatalen); - continue; - } - - igmp = (struct igmp *) (recv_buf + iphdrlen); - igmpdatalen = ipdatalen - IGMP_MINLEN; - if (igmpdatalen < 0) { - warnx("IP data field too short (%u bytes) for IGMP from %s", - ipdatalen, inet_fmt(ip->ip_src.s_addr, s1)); - continue; - } - - switch (igmp->igmp_type) { - - case IGMP_DVMRP: - if (type != IGMP_DVMRP || code != DVMRP_ASK_NEIGHBORS2) - continue; - if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue; - len = igmpdatalen; - /* - * Accept DVMRP_NEIGHBORS2 response if it comes from the - * address queried or if that address is one of the local - * addresses in the response. - */ - if (ip->ip_src.s_addr != dst) { - u_int32 *p = (u_int32 *)(igmp + 1); - u_int32 *ep = p + (len >> 2); - while (p < ep) { - u_int32 laddr = *p++; - int n = ntohl(*p++) & 0xFF; - if (laddr == dst) { - ep = p + 1; /* ensure p < ep after loop */ - break; - } - p += n; - } - if (p >= ep) continue; - } - break; - - case IGMP_MTRACE: /* For backward compatibility with 3.3 */ - case IGMP_MTRACE_RESP: - if (type != IGMP_MTRACE) continue; - if (igmpdatalen <= QLEN) continue; - if ((igmpdatalen - QLEN)%RLEN) { - printf("packet with incomplete responses (%d bytes)\n", - igmpdatalen); - continue; - } - - /* - * Ignore responses that don't match query. - */ - rquery = (struct tr_query *)(igmp + 1); - if (rquery->tr_src != qsrc || rquery->tr_dst != qdst) - continue; - if (TR_GETQID(rquery->tr_rttlqid) != - TR_GETQID(query->tr_rttlqid)) { - if (verbose && TR_GETQID(rquery->tr_rttlqid) == oqid) - printf("[D]"); - continue; - } - len = (igmpdatalen - QLEN)/RLEN; - r = (struct tr_resp *)(rquery+1) + len - 1; - - /* - * Ignore trace queries passing through this node when - * mtrace is run on an mrouter that is in the path - * (needed only because IGMP_MTRACE is accepted above - * for backward compatibility with multicast release 3.3). - */ - if (igmp->igmp_type == IGMP_MTRACE) { - u_int32 smask; - - VAL_TO_MASK(smask, r->tr_smask); - if (len < code && (r->tr_inaddr & smask) != (qsrc & smask) - && r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80)) - continue; - } - /* - * Some routers will return error messages without - * filling in their addresses. We fill in the address - * for them. - */ - if (r->tr_outaddr == 0) - r->tr_outaddr = recvaddr.sin_addr.s_addr; - - /* - * A match, we'll keep this one. - */ - if (len > code) { - warnx("num hops received (%d) exceeds request (%d)", - len, code); - } - rquery->tr_raddr = query->tr_raddr; /* Insure these are */ - TR_SETTTL(rquery->tr_rttlqid, TR_GETTTL(query->tr_rttlqid)); - /* as we sent them */ - break; - - default: - continue; - } - - /* - * We're pretty sure we want to use this packet now, - * but if the caller gave a callback function, it might - * want to handle it instead. Give the callback a chance, - * unless the select timed out (in which case the only way - * to get here is because the callback returned a packet). - */ - if (callback && (count != 0) && ((callback)(0, recv_buf, recvlen, igmp, igmpdatalen, (struct sockaddr*)&recvaddr, &socklen, &tr)) == 0) { - /* - * The callback function didn't like this packet. - * Go try receiving another one. - */ - continue; - } - - /* - * Most of the sanity checking done at this point. - * Return this packet we have been waiting for. - */ - if (save) { - save->qtime = ((tq.tv_sec + JAN_1970) << 16) + - (tq.tv_usec << 10) / 15625; - save->rtime = ((tr.tv_sec + JAN_1970) << 16) + - (tr.tv_usec << 10) / 15625; - save->len = len; - bcopy((char *)igmp, (char *)&save->igmp, ipdatalen); - } - return (recvlen); - } - } - return (0); -} - -/* - * Most of this code is duplicated elsewhere. I'm not sure if - * the duplication is absolutely required or not. - * - * Ideally, this would keep track of ongoing statistics - * collection and print out statistics. (& keep track - * of h-b-h traces and only print the longest) For now, - * it just snoops on what traces it can. - */ -void -passive_mode() -{ - struct timeval tr; - time_t tr_sec; - struct ip *ip; - struct igmp *igmp; - struct tr_resp *r; - struct sockaddr_in recvaddr; - struct tm *now; - char timebuf[32]; - int socklen; - int ipdatalen, iphdrlen, igmpdatalen; - int len, recvlen; - int qid; - u_int32 smask; - struct mtrace *remembered = NULL, *m, *n, **nn; - int pc = 0; - - if (raddr) { - if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr); - } else k_join(htonl(0xE0000120), lcl_addr); - - while (1) { - fflush(stdout); /* make sure previous trace is flushed */ - - socklen = sizeof(recvaddr); - recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, - 0, (struct sockaddr *)&recvaddr, &socklen); - gettimeofday(&tr,0); - - if (recvlen <= 0) { - if (recvlen && errno != EINTR) warn("recvfrom"); - continue; - } - - if (recvlen < sizeof(struct ip)) { - warnx("packet too short (%u bytes) for IP header", recvlen); - continue; - } - ip = (struct ip *) recv_buf; - if (ip->ip_p == 0) /* ignore cache creation requests */ - continue; - - iphdrlen = ip->ip_hl << 2; -#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len); -#else - ipdatalen = ip->ip_len; -#endif - if (iphdrlen + ipdatalen != recvlen) { - warnx("packet shorter (%u bytes) than hdr+data len (%u+%u)", - recvlen, iphdrlen, ipdatalen); - continue; - } - - igmp = (struct igmp *) (recv_buf + iphdrlen); - igmpdatalen = ipdatalen - IGMP_MINLEN; - if (igmpdatalen < 0) { - warnx("IP data field too short (%u bytes) for IGMP from %s", - ipdatalen, inet_fmt(ip->ip_src.s_addr, s1)); - continue; - } - - switch (igmp->igmp_type) { - - case IGMP_MTRACE: /* For backward compatibility with 3.3 */ - case IGMP_MTRACE_RESP: - if (igmpdatalen < QLEN) continue; - if ((igmpdatalen - QLEN)%RLEN) { - printf("packet with incorrect datalen\n"); - continue; - } - - len = (igmpdatalen - QLEN)/RLEN; - - break; - - default: - continue; - } - - base.qtime = ((tr.tv_sec + JAN_1970) << 16) + - (tr.tv_usec << 10) / 15625; - base.rtime = ((tr.tv_sec + JAN_1970) << 16) + - (tr.tv_usec << 10) / 15625; - base.len = len; - bcopy((char *)igmp, (char *)&base.igmp, ipdatalen); - /* - * If the user specified which traces to monitor, - * only accept traces that correspond to the - * request - */ - if ((qsrc != 0 && qsrc != base.qhdr.tr_src) || - (qdst != 0 && qdst != base.qhdr.tr_dst) || - (qgrp != 0 && qgrp != igmp->igmp_group.s_addr)) - continue; - - /* XXX This should be a hash table */ - /* XXX garbage-collection should be more efficient */ - for (nn = &remembered, n = *nn, m = 0; n; n = *nn) { - if ((n->base.qhdr.tr_src == base.qhdr.tr_src) && - (n->base.qhdr.tr_dst == base.qhdr.tr_dst) && - (n->base.igmp.igmp_group.s_addr == igmp->igmp_group.s_addr)) { - m = n; - m->last = tr; - } - if (tr.tv_sec - n->last.tv_sec > 500) { /* XXX don't hardcode */ - *nn = n->next; - free(n); - } else { - nn = &n->next; - } - } - - tr_sec = tr.tv_sec; - now = localtime(&tr_sec); - strftime(timebuf, sizeof(timebuf), "%b %e %k:%M:%S", now); - printf("Mtrace %s at %s", - len == 0 ? "query" : - igmp->igmp_type == IGMP_MTRACE_RESP ? "response" : - "in transit", - timebuf); - if (len == 0) - printf(" by %s", inet_fmt(recvaddr.sin_addr.s_addr, s1)); - if (!IN_MULTICAST(base.qhdr.tr_raddr)) - printf(", resp to %s", (len == 0 && recvaddr.sin_addr.s_addr == base.qhdr.tr_raddr) ? "same" : inet_fmt(base.qhdr.tr_raddr, s1)); - else - printf(", respttl %d", TR_GETTTL(base.qhdr.tr_rttlqid)); - printf(", qid %06x\n", qid = TR_GETQID(base.qhdr.tr_rttlqid)); - printf("packet from %s to %s\n", - inet_fmt(ip->ip_src.s_addr, s1), - inet_fmt(ip->ip_dst.s_addr, s2)); - - printf("from %s to %s via group %s (mxhop=%d)\n", - inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2), - inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code); - if (len == 0) { - printf("\n"); - continue; - } - r = base.resps + base.len - 1; - /* - * Some routers will return error messages without - * filling in their addresses. We fill in the address - * for them. - */ - if (r->tr_outaddr == 0) - r->tr_outaddr = recvaddr.sin_addr.s_addr; - - /* - * If there was a previous trace, it see if this is a - * statistics candidate. - */ - if (m && base.len == m->base.len && - !(pc = path_changed(&m->base, &base))) { - /* - * Some mtrace responders send multiple copies of the same - * reply. Skip this packet if it's got the same query-id - * as the last one. - */ - if (m->lastqid == qid) { - printf("Skipping duplicate reply\n"); - continue; - } - - m->lastqid = qid; - - ++m->nresp; - - bcopy(&base, m->new, sizeof(base)); - - printf("Results after %d seconds:\n\n", - (int)((m->new->qtime - m->base.qtime) >> 16)); - fixup_stats(&m->base, m->prev, m->new, m->bugs); - print_stats(&m->base, m->prev, m->new, m->bugs, m->names); - m->prev = m->new; - m->new = &m->incr[(m->nresp & 1)]; - - continue; - } - - if (m == NULL) { - m = (struct mtrace *)malloc(sizeof(struct mtrace)); - if (m == NULL) { - fprintf(stderr, "Out of memory!\n"); - continue; - } - bzero(m, sizeof(struct mtrace)); - m->next = remembered; - remembered = m; - bcopy(&tr, &m->last, sizeof(tr)); - } - - /* Either it's a hop-by-hop in progress, or the path changed. */ - if (pc) { - printf("[Path Changed...]\n"); - bzero(m->bugs, sizeof(m->bugs)); - } - bcopy(&base, &m->base, sizeof(base)); - m->prev = &m->base; - m->new = &m->incr[0]; - m->nresp = 0; - - printf(" 0 "); - print_host(base.qhdr.tr_dst); - printf("\n"); - print_trace(1, &base, m->names); - VAL_TO_MASK(smask, r->tr_smask); - if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) { - printf("%3d ", -(base.len+1)); - print_host(base.qhdr.tr_src); - printf("\n"); - } else if (r->tr_rmtaddr != 0) { - printf("%3d ", -(base.len+1)); - print_host(r->tr_rmtaddr); - printf(" %s\n", r->tr_rflags == TR_OLD_ROUTER ? - "doesn't support mtrace" - : "is the next hop"); - } - printf("\n"); - } -} - -char * -print_host(addr) - u_int32 addr; -{ - return print_host2(addr, 0); -} - -/* - * On some routers, one interface has a name and the other doesn't. - * We always print the address of the outgoing interface, but can - * sometimes get the name from the incoming interface. This might be - * confusing but should be slightly more helpful than just a "?". - */ -char * -print_host2(addr1, addr2) - u_int32 addr1, addr2; -{ - char *name; - - if (numeric) { - printf("%s", inet_fmt(addr1, s1)); - return (""); - } - name = inet_name(addr1); - if (*name == '?' && *(name + 1) == '\0' && addr2 != 0) - name = inet_name(addr2); - printf("%s (%s)", name, inet_fmt(addr1, s1)); - return (name); -} - -/* - * Print responses as received (reverse path from dst to src) - */ -void -print_trace(idx, buf, names) - int idx; - struct resp_buf *buf; - char **names; -{ - struct tr_resp *r; - char *name; - int i; - int hop; - char *ms; - - i = abs(idx); - r = buf->resps + i - 1; - - for (; i <= buf->len; ++i, ++r) { - if (idx > 0) printf("%3d ", -i); - name = print_host2(r->tr_outaddr, r->tr_inaddr); - if (r->tr_rflags != TR_NO_RTE) - printf(" %s thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl); - if (verbose) { - hop = t_diff(ntohl(r->tr_qarr), buf->qtime); - ms = scale(&hop); - printf(" %d%s", hop, ms); - } - printf(" %s", flag_type(r->tr_rflags)); - if (i > 1 && r->tr_outaddr != (r-1)->tr_rmtaddr) { - printf(" !RPF!"); - print_host((r-1)->tr_rmtaddr); - } - if (r->tr_rflags != TR_NO_RTE) { - if (r->tr_smask <= 1) /* MASK_TO_VAL() returns 1 for default */ - printf(" [default]"); - else if (verbose) { - u_int32 smask; - - VAL_TO_MASK(smask, r->tr_smask); - printf(" [%s]", inet_fmts(buf->qhdr.tr_src & smask, - smask, s1)); - } - } - printf("\n"); - if (names[i-1]) - free(names[i-1]); - names[i-1]=malloc(strlen(name) + 1); - strcpy(names[i-1], name); - } -} - -/* - * See what kind of router is the next hop - */ -int -what_kind(buf, why) - struct resp_buf *buf; - char *why; -{ - u_int32 smask; - int retval; - int hops = buf->len; - struct tr_resp *r = buf->resps + hops - 1; - u_int32 next = r->tr_rmtaddr; - - retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0], NULL); - print_host(next); - if (retval) { - u_int32 version = ntohl(incr[0].igmp.igmp_group.s_addr); - u_int32 *p = (u_int32 *)incr[0].ndata; - u_int32 *ep = p + (incr[0].len >> 2); - char *type = "version "; - - retval = 0; - switch (version & 0xFF) { - case 1: - type = "proteon/mrouted "; - retval = 1; - break; - - case 10: - case 11: - type = "cisco "; - } - printf(" [%s%d.%d] %s\n", - type, version & 0xFF, (version >> 8) & 0xFF, - why); - VAL_TO_MASK(smask, r->tr_smask); - while (p < ep) { - u_int32 laddr = *p++; - int flags = (ntohl(*p) & 0xFF00) >> 8; - int n = ntohl(*p++) & 0xFF; - if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) && - (laddr & smask) == (qsrc & smask)) { - printf("%3d ", -(hops+2)); - print_host(qsrc); - printf("\n"); - return 1; - } - p += n; - } - return retval; - } - printf(" %s\n", why); - return 0; -} - - -char * -scale(hop) - int *hop; -{ - if (*hop > -1000 && *hop < 10000) return (" ms"); - *hop /= 1000; - if (*hop > -1000 && *hop < 10000) return (" s "); - return ("s "); -} - -/* - * Calculate and print one line of packet loss and packet rate statistics. - * Checks for count of all ones from mrouted 2.3 that doesn't have counters. - */ -#define NEITHER 0 -#define INS 1 -#define OUTS 2 -#define BOTH 3 -void -stat_line(r, s, have_next, rst) - struct tr_resp *r, *s; - int have_next; - int *rst; -{ - int timediff = (ntohl(s->tr_qarr) - ntohl(r->tr_qarr)) >> 16; - int v_lost, v_pct; - int g_lost, g_pct; - int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout); - int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt); - int v_pps, g_pps; - char v_str[8], g_str[8]; - int vhave = NEITHER; - int ghave = NEITHER; - int gmissing = NEITHER; - char whochar; - int badtime = 0; - - if (timediff == 0) { - badtime = 1; - /* Might be 32 bits of int seconds instead of 16int+16frac */ - timediff = ntohl(s->tr_qarr) - ntohl(r->tr_qarr); - if (timediff == 0 || abs(timediff - statint) > statint) - timediff = 1; - } - v_pps = v_out / timediff; - g_pps = g_out / timediff; - -#define STATS_MISSING(x) ((x) == 0xFFFFFFFF) - - if (!STATS_MISSING(s->tr_vifout) && !STATS_MISSING(r->tr_vifout)) - vhave |= OUTS; - if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt)) - gmissing |= OUTS; - if (!(*rst & BUG_NOPRINT)) - ghave |= OUTS; - - if (have_next) { - --r, --s, --rst; - if (!STATS_MISSING(s->tr_vifin) && !STATS_MISSING(r->tr_vifin)) - vhave |= INS; - if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt)) - gmissing |= INS; - if (!(*rst & BUG_NOPRINT)) - ghave |= INS; - } - - /* - * Stats can be missing for any number of reasons: - * - The hop may not be capable of collecting stats - * - Traffic may be getting dropped at the previous hop - * and so this hop may not have any state - * - * We need a stronger heuristic to tell between these - * two cases; in case 1 we don't want to print the stats - * and in case 2 we want to print 100% loss. We used to - * err on the side of not printing, which is less useful - * than printing 100% loss and dealing with it. - */ -#if 0 - /* - * If both hops report as missing, then it's likely that there's just - * no traffic flowing. - * - * If just one hop is missing, then we really don't have it. - */ - if (gmissing != BOTH) - ghave &= ~gmissing; -#endif - - whochar = have_next ? '^' : ' '; - switch (vhave) { - case BOTH: - v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin)); - if (v_out) v_pct = v_lost * 100 / v_out; - else v_pct = 0; - if (-20 < v_pct && v_pct < 101 && v_out > 10) - sprintf(v_str, "%3d%%", v_pct); - else if (v_pct < -900 && v_out > 10) - sprintf(v_str, "%3dx", (int)(-v_pct / 100. + 1.)); - else if (v_pct <= -20 && v_out > 10) - sprintf(v_str, "%1.1fx", -v_pct / 100. + 1.); - else - memcpy(v_str, " -- ", 5); - - if (tunstats) - printf("%6d/%-5d=%s", v_lost, v_out, v_str); - else - printf(" "); - printf("%4d pps", v_pps); - if (v_pps && badtime) - printf("?"); - - break; - - case INS: - v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin); - v_pps = v_out / timediff; - whochar = 'v'; - /* FALLTHROUGH */ - - case OUTS: - if (tunstats) - printf(" %c%-5d ", whochar, v_out); - else - printf(" %c", whochar); - printf("%4d pps", v_pps); - if (v_pps && badtime) - printf("?"); - - break; - - case NEITHER: - if (ghave != NEITHER) - if (tunstats) - printf(" "); - else - printf(" "); - - break; - } - - whochar = have_next ? '^' : ' '; - switch (ghave) { - case BOTH: - g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt)); - if (g_out) g_pct = g_lost * 100 / g_out; - else g_pct = 0; - if (-20 < g_pct && g_pct < 101 && g_out > 10) - sprintf(g_str, "%3d%%", g_pct); - else if (g_pct < -900 && g_out > 10) - sprintf(g_str, "%3dx", (int)(-g_pct / 100. + 1.)); - else if (g_pct <= -20 && g_out > 10) - sprintf(g_str, "%1.1fx", -g_pct / 100. + 1.); - else - memcpy(g_str, " -- ", 5); - - printf("%s%6d/%-5d=%s%4d pps", - tunstats ? "" : " ", g_lost, g_out, g_str, g_pps); - if (g_pps && badtime) - printf("?"); - printf("\n"); - break; - -#if 0 - case INS: - g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt); - g_pps = g_out / timediff; - whochar = 'v'; - /* FALLTHROUGH */ -#endif - - case OUTS: - printf("%s ?/%-5d %4d pps", - tunstats ? "" : " ", g_out, g_pps); - if (badtime) - printf("?"); - printf("\n"); - break; - - case INS: - case NEITHER: - printf("\n"); - break; - } - - - if (debug > 2) { - printf("\t\t\t\tv_in: %ld ", (long)ntohl(s->tr_vifin)); - printf("v_out: %ld ", (long)ntohl(s->tr_vifout)); - printf("pkts: %ld\n", (long)ntohl(s->tr_pktcnt)); - printf("\t\t\t\tv_in: %ld ", (long)ntohl(r->tr_vifin)); - printf("v_out: %ld ", (long)ntohl(r->tr_vifout)); - printf("pkts: %ld\n", (long)ntohl(r->tr_pktcnt)); - printf("\t\t\t\tv_in: %ld ", - (long)(ntohl(s->tr_vifin) - ntohl(r->tr_vifin))); - printf("v_out: %ld ", - (long)(ntohl(s->tr_vifout) - ntohl(r->tr_vifout))); - printf("pkts: %ld ", (long)(ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt))); - printf("time: %d\n", timediff); - printf("\t\t\t\treset: %x hoptime: %lx\n", *rst, ntohl(s->tr_qarr)); - } -} - -/* - * A fixup to check if any pktcnt has been reset, and to fix the - * byteorder bugs in mrouted 3.6 on little-endian machines. - * - * XXX Since periodic traffic sources are likely to have their - * pktcnt periodically reset, should we save old values when - * the reset occurs to keep slightly better statistics over - * the long term? (e.g. SAP) - */ -void -fixup_stats(base, prev, new, bugs) - struct resp_buf *base, *prev, *new; - int *bugs; -{ - int rno = base->len; - struct tr_resp *b = base->resps + rno; - struct tr_resp *p = prev->resps + rno; - struct tr_resp *n = new->resps + rno; - int *r = bugs + rno; - int res; - int cleanup = 0; - - /* Check for byte-swappers. Only check on the first trace, - * since long-running traces can wrap around and falsely trigger. */ - while (--rno >= 0) { -#ifdef TEST_ONLY - u_int32 nvifout = ntohl(n->tr_vifout); - u_int32 pvifout = ntohl(p->tr_vifout); -#endif - --n; --p; --b; -#ifdef TEST_ONLY /*XXX this is still buggy, so disable it for release */ - if ((*r & BUG_SWAP) || - ((base == prev) && - (nvifout - pvifout) > (byteswap(nvifout) - byteswap(pvifout)))) { - if (1 || debug > 2) { - printf("ip %s swaps; b %08x p %08x n %08x\n", - inet_fmt(n->tr_inaddr, s1), - ntohl(b->tr_vifout), pvifout, nvifout); - } - /* This host sends byteswapped reports; swap 'em */ - if (!(*r & BUG_SWAP)) { - *r |= BUG_SWAP; - b->tr_qarr = byteswap(b->tr_qarr); - b->tr_vifin = byteswap(b->tr_vifin); - b->tr_vifout = byteswap(b->tr_vifout); - b->tr_pktcnt = byteswap(b->tr_pktcnt); - } - - n->tr_qarr = byteswap(n->tr_qarr); - n->tr_vifin = byteswap(n->tr_vifin); - n->tr_vifout = byteswap(n->tr_vifout); - n->tr_pktcnt = byteswap(n->tr_pktcnt); - } -#endif - /* - * A missing parenthesis in mrouted 3.5-3.8's prune.c - * causes extremely bogus time diff's. - * One half of the time calculation was - * inside an htonl() and one half wasn't. Therefore, on - * a little-endian machine, both halves of the calculation - * would get added together in the little end. Thus, the - * low-order 2 bytes are either 0000 (no overflow) or - * 0100 (overflow from the addition). - * - * Odds are against these particular bit patterns - * happening in both prev and new for actual time values. - */ - if ((*r & BUG_BOGUSTIME) || (((ntohl(n->tr_qarr) & 0xfeff) == 0x0000) && - ((ntohl(p->tr_qarr) & 0xfeff) == 0x0000))) { - *r |= BUG_BOGUSTIME; - n->tr_qarr = new->rtime; - p->tr_qarr = prev->rtime; - b->tr_qarr = base->rtime; - } - } - - rno = base->len; - b = base->resps + rno; - p = prev->resps + rno; - n = new->resps + rno; - r = bugs + rno; - - while (--rno >= 0) { - --n; --p; --b; --r; - /* - * This hop has reset if: - * - There were statistics in the base AND previous pass, AND - * - There are less packets this time than the first time and - * we didn't reset last time, OR - * - There are less packets this time than last time, OR - * - There are no statistics on this pass. - * - * The "and we didn't reset last time" is necessary in the - * first branch of the OR because if the base is large and - * we reset last time but the constant-resetter-avoidance - * code kicked in so we delayed the copy of prev to base, - * new could still be below base so we trigger the - * constant-resetter code even though it was really only - * a single reset. - */ - res = ((b->tr_pktcnt != 0xFFFFFFFF) && (p->tr_pktcnt != 0xFFFFFFFF) && - ((!(*r & BUG_RESET) && ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) || - (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)) || - (n->tr_pktcnt == 0xFFFFFFFF))); - if (debug > 2) { - printf("\t\tip=%s, r=%d, res=%d\n", inet_fmt(b->tr_inaddr, s1), *r, res); - if (res) - printf("\t\tbase=%ld, prev=%ld, new=%ld\n", ntohl(b->tr_pktcnt), - ntohl(p->tr_pktcnt), ntohl(n->tr_pktcnt)); - } - if (*r & BUG_RESET) { - if (res || (*r & BUG_RESET2X)) { - /* - * This router appears to be a 3.4 with that nasty ol' - * neighbor version bug, which causes it to constantly - * reset. Just nuke the statistics for this node, and - * don't even bother giving it the benefit of the - * doubt from now on. - */ - p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt; - *r |= BUG_RESET2X; - } else { - /* - * This is simply the situation that the original - * fixup_stats was meant to deal with -- that a - * 3.3 or 3.4 router deleted a cache entry while - * traffic was still active. - */ - *r &= ~BUG_RESET; - cleanup = 1; - } - } else - if (res) - *r |= BUG_RESET; - } - - if (cleanup == 0) return; - - /* - * If some hop reset its counters and didn't continue to - * reset, then we pretend that the previous - * trace was the first one. - */ - rno = base->len; - b = base->resps + rno; - p = prev->resps + rno; - - while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt; - base->qtime = prev->qtime; - base->rtime = prev->rtime; -} - -/* - * Check per-source losses along path and compare with threshold. - */ -int -check_thresh(thresh, base, prev, new) - int thresh; - struct resp_buf *base, *prev, *new; -{ - int rno = base->len - 1; - struct tr_resp *b = base->resps + rno; - struct tr_resp *p = prev->resps + rno; - struct tr_resp *n = new->resps + rno; - int g_out, g_lost; - - while (TRUE) { - if ((n->tr_inaddr != b->tr_inaddr) || - (n->tr_outaddr != b->tr_outaddr) || - (n->tr_rmtaddr != b->tr_rmtaddr)) - return 1; /* Route changed */ - - if (rno-- < 1) break; - g_out = ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt); - b--; n--; p--; - g_lost = g_out - (ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt)); - if (g_out && ((g_lost * 100 + (g_out >> 1))/ g_out) > thresh) { - return TRUE; - } - } - return FALSE; -} - -/* - * Print responses with statistics for forward path (from src to dst) - */ -int -print_stats(base, prev, new, bugs, names) - struct resp_buf *base, *prev, *new; - int *bugs; - char **names; -{ - int rtt, hop; - char *ms; - u_int32 smask; - int rno = base->len - 1; - struct tr_resp *b = base->resps + rno; - struct tr_resp *p = prev->resps + rno; - struct tr_resp *n = new->resps + rno; - int *r = bugs + rno; - u_long resptime = new->rtime; - u_long qarrtime = ntohl(n->tr_qarr); - u_int ttl = MaX(1, n->tr_fttl) + 1; - int first = (base == prev); - - VAL_TO_MASK(smask, b->tr_smask); - printf(" Source Response Dest "); - if (tunstats) - printf("Packet Statistics For Only For Traffic\n"); - else - printf("Overall Packet Statistics For Traffic From\n"); - (void)inet_fmt(base->qhdr.tr_src, s1); - printf("%-15s %-15s ", - ((b->tr_inaddr & smask) == (base->qhdr.tr_src & smask)) ? - s1 : " * * * ", - inet_fmt(base->qhdr.tr_raddr, s2)); - (void)inet_fmt(base->igmp.igmp_group.s_addr, s2); - if (tunstats) - printf("All Multicast Traffic From %s\n", s1); - else - printf("Packet %s To %s\n", s1, s2); - rtt = t_diff(resptime, new->qtime); - ms = scale(&rtt); - printf(" %c __/ rtt%5d%s ", - (first && !verbose) ? 'v' : '|', rtt, ms); - if (tunstats) - printf("Lost/Sent = Pct Rate To %s\n", s2); - else - printf(" Rate Lost/Sent = Pct Rate\n"); - if (!first || verbose) { - hop = t_diff(resptime, qarrtime); - ms = scale(&hop); - printf(" v / hop%5d%s ", hop, ms); - if (tunstats) - printf("--------------------- --------------------\n"); - else - printf("------- ---------------------\n"); - } - if ((b->tr_inaddr & smask) != (base->qhdr.tr_src & smask) && - b->tr_rmtaddr != 0) { - printf("%-15s %-14s is the previous hop\n", inet_fmt(b->tr_rmtaddr, s1), - inet_name(b->tr_rmtaddr)); - printf(" v ^\n"); - } - if (debug > 2) { - printf("\t\t\t\tv_in: %ld ", (long)ntohl(n->tr_vifin)); - printf("v_out: %ld ", (long)ntohl(n->tr_vifout)); - printf("pkts: %ld\n", (long)ntohl(n->tr_pktcnt)); - printf("\t\t\t\tv_in: %ld ", (long)ntohl(b->tr_vifin)); - printf("v_out: %ld ", (long)ntohl(b->tr_vifout)); - printf("pkts: %ld\n", (long)ntohl(b->tr_pktcnt)); - printf("\t\t\t\tv_in: %ld ", - (long)(ntohl(n->tr_vifin) - ntohl(b->tr_vifin))); - printf("v_out: %ld ", - (long)(ntohl(n->tr_vifout) - ntohl(b->tr_vifout))); - printf("pkts: %ld\n", - (long)(ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt))); - printf("\t\t\t\treset: %x hoptime: %lx\n", *r, (long)ntohl(n->tr_qarr)); - } - - while (TRUE) { - if ((n->tr_inaddr != b->tr_inaddr) || - (n->tr_outaddr != b->tr_outaddr) || - (n->tr_rmtaddr != b->tr_rmtaddr)) - return 1; /* Route changed */ - - if ((n->tr_inaddr != n->tr_outaddr) && n->tr_inaddr) - printf("%-15s\n", inet_fmt(n->tr_inaddr, s1)); - printf("%-15s %-14s %s%s\n", inet_fmt(n->tr_outaddr, s1), names[rno], - flag_type(n->tr_rflags), - (*r & BUG_NOPRINT) ? " [reset counters]" : ""); - - if (rno-- < 1) break; - - printf(" %c ^ ttl%5d ", (first && !verbose) ? 'v' : '|', - ttl); - stat_line(p, n, TRUE, r); - if (!first || verbose) { - resptime = qarrtime; - qarrtime = ntohl((n-1)->tr_qarr); - hop = t_diff(resptime, qarrtime); - ms = scale(&hop); - printf(" v | hop%5d%s", hop, ms); - if (first) - printf("\n"); - else - stat_line(b, n, TRUE, r); - } - - --b, --p, --n, --r; - ttl = MaX(ttl, MaX(1, n->tr_fttl) + base->len - rno); - } - - printf(" %c \\__ ttl%5d ", (first && !verbose) ? 'v' : '|', - ttl); - stat_line(p, n, FALSE, r); - if (!first || verbose) { - hop = t_diff(qarrtime, new->qtime); - ms = scale(&hop); - printf(" v \\ hop%5d%s", hop, ms); - if (first) - printf("\n"); - else - stat_line(b, n, FALSE, r); - } - printf("%-15s %s\n", inet_fmt(base->qhdr.tr_dst, s1), - !passive ? inet_fmt(lcl_addr, s2) : " * * * "); - printf(" Receiver Query Source\n\n"); - return 0; -} - -/* - * Determine whether or not the path has changed. - */ -int -path_changed(base, new) - struct resp_buf *base, *new; -{ - int rno = base->len - 1; - struct tr_resp *b = base->resps + rno; - struct tr_resp *n = new->resps + rno; - - while (rno-- >= 0) { - if ((n->tr_inaddr != b->tr_inaddr) || - (n->tr_outaddr != b->tr_outaddr) || - (n->tr_rmtaddr != b->tr_rmtaddr)) - return 1; /* Route changed */ - if ((b->tr_rflags == TR_NO_RTE) && - (n->tr_rflags != TR_NO_RTE)) - return 1; /* Route got longer? */ - --n; - --b; - } - return 0; -} - - -/*************************************************************************** - * main - ***************************************************************************/ - -int -main(argc, argv) -int argc; -char *argv[]; -{ - int udp; - struct sockaddr_in addr; - int addrlen = sizeof(addr); - int recvlen; - struct timeval tv; - struct resp_buf *prev, *new; - struct tr_resp *r; - u_int32 smask; - int rno; - int hops, nexthop, tries; - u_int32 lastout = 0; - int numstats = 1; - int waittime; - int seed; - int hopbyhop; - int i; - int printed = 1; - - if (geteuid() != 0) - errx(1, "must be root"); - - /* - * We might get spawned by vat with the audio device open. - * Close everything but stdin, stdout, stderr. - */ - for (i = 3; i < 255; i++) - close(i); - - init_igmp(); - setuid(getuid()); - - argv++, argc--; - if (argc == 0) usage(); - - while (argc > 0 && *argv[0] == '-') { - char *p = *argv++; argc--; - p++; - do { - char c = *p++; - char *arg = (char *) 0; - if (isdigit(*p)) { - arg = p; - p = ""; - } else if (argc > 0) arg = argv[0]; - switch (c) { - case 'd': /* Unlisted debug print option */ - if (arg && isdigit(*arg)) { - debug = atoi(arg); - if (debug < 0) debug = 0; - if (debug > 3) debug = 3; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'M': /* Use multicast for reponse */ - multicast = TRUE; - break; - case 'U': /* Use unicast for response */ - unicast = TRUE; - break; - case 'L': /* Trace w/ loss threshold */ - if (arg && isdigit(*arg)) { - lossthresh = atoi(arg); - if (lossthresh < 0) - lossthresh = 0; - numstats = 3153600; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - break; - case 'O': /* Don't use IP options */ - sendopts = FALSE; - break; - case 'P': /* Just watch the path */ - printstats = FALSE; - numstats = 3153600; - break; - case 'Q': /* (undoc.) always use this QID */ - if (arg && isdigit(*arg)) { - staticqid = atoi(arg); - if (staticqid < 0) - staticqid = 0; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - break; - case 'T': /* Print confusing tunnel stats */ - tunstats = TRUE; - break; - case 'W': /* Cisco's "weak" mtrace */ - weak = TRUE; - break; - case 'V': /* Print version and exit */ - /* - * FreeBSD wants to have its own Id string, so - * determination of the version number has to change. - * XXX Note that this must be changed by hand on importing - * XXX new versions! - */ - { - char *r = strdup(rcsid); - char *s = strchr(r, ','); - - while (s && *(s+1) != 'v') - s = strchr(s + 1, ','); - - if (s) { - char *q; - - s += 3; /* , v sp */ - q = strchr(s, ' '); - if (q) - *q = '\0'; - fprintf(stderr, "mtrace version 5.2/%s\n", s); - } else { - fprintf(stderr, "mtrace could not determine version number!?\n"); - } - exit(1); - } - break; - case 'l': /* Loop updating stats indefinitely */ - numstats = 3153600; - break; - case 'n': /* Don't reverse map host addresses */ - numeric = TRUE; - break; - case 'p': /* Passive listen for traces */ - passive = TRUE; - break; - case 'v': /* Verbosity */ - verbose = TRUE; - break; - case 's': /* Short form, don't wait for stats */ - numstats = 0; - break; - case 'w': /* Time to wait for packet arrival */ - if (arg && isdigit(*arg)) { - timeout = atoi(arg); - if (timeout < 1) timeout = 1; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'f': /* first hop */ - if (arg && isdigit(*arg)) { - qno = atoi(arg); - if (qno > MAXHOPS) qno = MAXHOPS; - else if (qno < 1) qno = 0; - if (arg == argv[0]) argv++, argc--; - fflag++; - break; - } else - usage(); - case 'm': /* Max number of hops to trace */ - if (arg && isdigit(*arg)) { - qno = atoi(arg); - if (qno > MAXHOPS) qno = MAXHOPS; - else if (qno < 1) qno = 0; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'q': /* Number of query retries */ - if (arg && isdigit(*arg)) { - nqueries = atoi(arg); - if (nqueries < 1) nqueries = 1; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'g': /* Last-hop gateway (dest of query) */ - if (arg && (gwy = host_addr(arg))) { - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 't': /* TTL for query packet */ - if (arg && isdigit(*arg)) { - qttl = atoi(arg); - if (qttl < 1) qttl = 1; - rttl = qttl; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'e': /* Extra hops past non-responder */ - if (arg && isdigit(*arg)) { - extrahops = atoi(arg); - if (extrahops < 0) extrahops = 0; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'r': /* Dest for response packet */ - if (arg && (raddr = host_addr(arg))) { - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'i': /* Local interface address */ - if (arg && (lcl_addr = host_addr(arg))) { - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - case 'S': /* Stat accumulation interval */ - if (arg && isdigit(*arg)) { - statint = atoi(arg); - if (statint < 1) statint = 1; - if (arg == argv[0]) argv++, argc--; - break; - } else - usage(); - default: - usage(); - } - } while (*p); - } - - if (argc > 0 && (qsrc = host_addr(argv[0]))) { /* Source of path */ - if (IN_MULTICAST(ntohl(qsrc))) { - if (gwy) { - /* Should probably rewrite arg parsing at some point, as - * this makes "mtrace -g foo 224.1.2.3 224.2.3.4" valid!... */ - qgrp = qsrc; - qsrc = 0; - } else { - usage(); - } - } - argv++, argc--; - if (argc > 0 && (qdst = host_addr(argv[0]))) { /* Dest of path */ - argv++, argc--; - if (argc > 0 && (qgrp = host_addr(argv[0]))) { /* Path via group */ - argv++, argc--; - } - if (IN_MULTICAST(ntohl(qdst))) { - u_int32 temp = qdst; - qdst = qgrp; - qgrp = temp; - if (IN_MULTICAST(ntohl(qdst))) usage(); - } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) usage(); - } - } - - if (passive) { - passive_mode(); - return(0); - } - - if (argc > 0) { - usage(); - } - -#ifdef SUNOS5 - if (sendopts) - checkforsolarisbug(); -#endif - - /* - * Set useful defaults for as many parameters as possible. - */ - - defgrp = 0; /* Default to no group */ - query_cast = htonl(0xE0000002); /* All routers multicast addr */ - resp_cast = htonl(0xE0000120); /* Mtrace response multicast addr */ - if (qgrp == 0) { - if (!weak) - qgrp = defgrp; - if (printstats && numstats != 0 && !tunstats) { - /* Stats are useless without a group */ - warnx( - "WARNING: no multicast group specified, so no statistics printed"); - numstats = 0; - } - } else { - if (weak) - warnx( - "WARNING: group was specified so not performing \"weak\" mtrace"); - } - - /* - * Get default local address for multicasts to use in setting defaults. - */ - addr.sin_family = AF_INET; -#if (defined(BSD) && (BSD >= 199103)) - addr.sin_len = sizeof(addr); -#endif - addr.sin_addr.s_addr = qgrp ? qgrp : query_cast; - addr.sin_port = htons(2000); /* Any port above 1024 will do */ - - /* - * Note that getsockname() can return 0 on some systems - * (notably SunOS 5.x, x < 6). This is taken care of in - * get_netmask(). If the default multicast interface (set - * with the route for 224.0.0.0) is not the same as the - * hostname, mtrace -i [if_addr] will have to be used. - */ - if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) || - (connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) || - getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) - err(-1, "determining local address"); - -#ifdef SUNOS5 - /* - * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket. - * This call to sysinfo will return the hostname. - * If the default multicast interfface (set with the route - * for 224.0.0.0) is not the same as the hostname, - * mtrace -i [if_addr] will have to be used. - */ - if (addr.sin_addr.s_addr == 0) { - char myhostname[MAXHOSTNAMELEN]; - struct hostent *hp; - int error; - - error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname)); - if (error == -1) - err(1, "getting my hostname"); - - hp = gethostbyname(myhostname); - if (hp == NULL || hp->h_addrtype != AF_INET || - hp->h_length != sizeof(addr.sin_addr)) - err(1, "finding IP address for my hostname"); - - memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length); - } -#endif - - /* - * Default destination for path to be queried is the local host. - * When gateway specified, default destination is that gateway - * and default source is local host. - */ - if (qdst == 0) { - qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr; - dst_netmask = get_netmask(udp, &qdst); - if (gwy && (gwy & dst_netmask) != (qdst & dst_netmask) && - !IN_MULTICAST(ntohl(gwy))) - qdst = gwy; - } - if (qsrc == 0 && gwy) - qsrc = lcl_addr ? lcl_addr : addr.sin_addr.s_addr; - if (qsrc == 0) - usage(); - if (!dst_netmask) - dst_netmask = get_netmask(udp, &qdst); - close(udp); - if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr; - - /* - * Initialize the seed for random query identifiers. - */ - gettimeofday(&tv, 0); - seed = tv.tv_usec ^ lcl_addr; -#ifdef SYSV - srand48(seed); -#endif - - /* - * Protect against unicast queries to mrouted versions that might crash. - * Also use the obsolete "can mtrace" neighbor bit to warn about - * older implementations. - */ - if (gwy && !IN_MULTICAST(ntohl(gwy))) - if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0], NULL)) { - int flags = ntohl(incr[0].igmp.igmp_group.s_addr); - int version = flags & 0xFFFF; - int info = (flags & 0xFF0000) >> 16; - - if (version == 0x0303 || version == 0x0503) { - printf("Don't use -g to address an mrouted 3.%d, it might crash\n", - (version >> 8) & 0xFF); - exit(0); - } - if ((info & 0x08) == 0) { - printf("mtrace: "); - print_host(gwy); - printf(" probably doesn't support mtrace, trying anyway...\n"); - } - } - - printf("Mtrace from %s to %s via group %s\n", - inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3)); - - if ((qdst & dst_netmask) == (qsrc & dst_netmask)) - fprintf(stderr, "mtrace: Source & receiver appear to be directly connected\n"); - - /* - * If the response is to be a multicast address, make sure we - * are listening on that multicast address. - */ - if (raddr) { - if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr); - } else k_join(resp_cast, lcl_addr); - - memset(&base, 0, sizeof(base)); - - /* - * If the destination is on the local net, the last-hop router can - * be found by multicast to the all-routers multicast group. - * Otherwise, use the group address that is the subject of the - * query since by definition the last-hop router will be a member. - * Set default TTLs for local remote multicasts. - */ - if (gwy == 0) - if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast; - else tdst = qgrp; - else tdst = gwy; - if (tdst == 0 && qgrp == 0) - errx(1, "mtrace: weak mtrace requires -g if destination is not local.\n"); - - if (IN_MULTICAST(ntohl(tdst))) { - k_set_loop(1); /* If I am running on a router, I need to hear this */ - if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1); - else k_set_ttl(qttl ? qttl : MULTICAST_TTL1); - } - - /* - * Try a query at the requested number of hops or MAXHOPS if unspecified. - */ - if (qno == 0) { - hops = MAXHOPS; - tries = 1; - printf("Querying full reverse path... "); - fflush(stdout); - } else { - hops = qno; - tries = nqueries; - if (fflag) - printf("Querying full reverse path, starting at hop %d...", qno); - else - printf("Querying reverse path, maximum %d hops... ", qno); - fflush(stdout); - } - base.rtime = 0; - base.len = 0; - hopbyhop = FALSE; - - recvlen = send_recv(tdst, IGMP_MTRACE, hops, tries, &base, mtrace_callback); - - /* - * If the initial query was successful, print it. Otherwise, if - * the query max hop count is the default of zero, loop starting - * from one until there is no response for extrahops more hops. The - * extra hops allow getting past an mtrace-capable mrouter that can't - * send multicast packets because all phyints are disabled. - */ - if (recvlen) { - printf("\n 0 "); - print_host(qdst); - printf("\n"); - print_trace(1, &base, names); - r = base.resps + base.len - 1; - if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE || - (qno != 0 && r->tr_rmtaddr != 0 && !fflag)) { - printf("%3d ", -(base.len+1)); - what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ? - "doesn't support mtrace" - : "is the next hop"); - } else { - if (fflag) { - nexthop = hops = qno; - goto continuehop; - } - VAL_TO_MASK(smask, r->tr_smask); - if ((r->tr_inaddr & smask) == (qsrc & smask)) { - printf("%3d ", -(base.len+1)); - print_host(qsrc); - printf("\n"); - } - } - } else if (qno == 0) { - hopbyhop = TRUE; - printf("switching to hop-by-hop:\n 0 "); - print_host(qdst); - printf("\n"); - - for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) { - printf("%3d ", -hops); - fflush(stdout); - - /* - * After a successful first hop, try switching to the unicast - * address of the last-hop router instead of multicasting the - * trace query. This should be safe for mrouted versions 3.3 - * and 3.5 because there is a long route timeout with metric - * infinity before a route disappears. Switching to unicast - * reduces the amount of multicast traffic and avoids a bug - * with duplicate suppression in mrouted 3.5. - */ - if (hops == 2 && gwy == 0 && lastout != 0 && - (recvlen = send_recv(lastout, IGMP_MTRACE, hops, 1, &base, mtrace_callback))) - tdst = lastout; - else recvlen = send_recv(tdst, IGMP_MTRACE, hops, nqueries, &base, mtrace_callback); - - if (recvlen == 0) { - /*if (hops == 1) break;*/ - if (hops == nexthop) { - if (hops == 1) { - printf("\n"); - } else if (what_kind(&base, "didn't respond")) { - /* the ask_neighbors determined that the - * not-responding router is the first-hop. */ - break; - } - if (extrahops == 0) - break; - } else if (hops < nexthop + extrahops) { - printf("\n"); - } else { - printf("...giving up\n"); - break; - } - continue; - } - if (base.len == hops && - (hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) { - if (hops == nexthop) { - print_trace(-hops, &base, names); - } else { - printf("\nResuming...\n"); - print_trace(nexthop, &base, names); - } - } else { - if (base.len < hops) { - /* - * A shorter trace than requested means a fatal error - * occurred along the path, or that the route changed - * to a shorter one. - * - * If the trace is longer than the last one we received, - * then we are resuming from a skipped router (but there - * is still probably a problem). - * - * If the trace is shorter than the last one we - * received, then the route must have changed (and - * there is still probably a problem). - */ - if (nexthop <= base.len) { - printf("\nResuming...\n"); - print_trace(nexthop, &base, names); - } else if (nexthop > base.len + 1) { - hops = base.len; - printf("\nRoute must have changed...\n"); - print_trace(1, &base, names); - } - } else { - /* - * The last hop address is not the same as it was. - * If we didn't know the last hop then we just - * got the first response from a hop-by-hop trace; - * if we did know the last hop then - * the route probably changed underneath us. - */ - hops = base.len; - if (lastout != 0) - printf("\nRoute must have changed...\n"); - else - printf("\nResuming...\n"); - print_trace(1, &base, names); - } - } -continuehop: - r = base.resps + base.len - 1; - lastout = r->tr_outaddr; - - if (base.len < hops || - r->tr_rmtaddr == 0 || - (r->tr_rflags & 0x80)) { - VAL_TO_MASK(smask, r->tr_smask); - if (r->tr_rmtaddr) { - if (hops != nexthop) { - printf("\n%3d ", -(base.len+1)); - } - what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ? - "doesn't support mtrace" : - "would be the next hop"); - /* XXX could do segmented trace if TR_NO_SPACE */ - } else if (r->tr_rflags == TR_NO_ERR && - (r->tr_inaddr & smask) == (qsrc & smask)) { - printf("%3d ", -(hops + 1)); - print_host(qsrc); - printf("\n"); - } - break; - } - - nexthop = hops + 1; - } - } - - if (base.rtime == 0) { - printf("Timed out receiving responses\n"); - if (IN_MULTICAST(ntohl(tdst))) - if (tdst == query_cast) - printf("Perhaps no local router has a route for source %s\n", - inet_fmt(qsrc, s1)); - else - printf("Perhaps receiver %s is not a member of group %s,\n\ -or no router local to it has a route for source %s,\n\ -or multicast at ttl %d doesn't reach its last-hop router for that source\n", - inet_fmt(qdst, s2), inet_fmt(qgrp, s3), inet_fmt(qsrc, s1), - qttl ? qttl : MULTICAST_TTL1); - exit(1); - } - - printf("Round trip time %d ms; ", t_diff(base.rtime, base.qtime)); - { - struct tr_resp *n = base.resps + base.len - 1; - u_int ttl = n->tr_fttl + 1; - - rno = base.len - 1; - while (--rno > 0) { - --n; - ttl = MaX(ttl, MaX(1, n->tr_fttl) + base.len - rno); - } - printf("total ttl of %d required.\n\n",ttl); - } - - /* - * Use the saved response which was the longest one received, - * and make additional probes after delay to measure loss. - */ - raddr = base.qhdr.tr_raddr; - rttl = TR_GETTTL(base.qhdr.tr_rttlqid); - gettimeofday(&tv, 0); - waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16)); - prev = &base; - new = &incr[numstats&1]; - - /* - * Zero out bug-avoidance counters - */ - memset(bugs, 0, sizeof(bugs)); - - if (!printstats) - printf("Monitoring path.."); - - while (numstats--) { - if (waittime < 1) printf("\n"); - else { - if (printstats && (lossthresh == 0 || printed)) { - printf("Waiting to accumulate statistics..."); - } else { - printf("."); - } - fflush(stdout); - sleep((unsigned)waittime); - } - printed = 0; - rno = hopbyhop ? base.len : qno ? qno : MAXHOPS; - recvlen = send_recv(tdst, IGMP_MTRACE, rno, nqueries, new, mtrace_callback); - - if (recvlen == 0) { - printf("Timed out.\n"); - if (numstats) { - numstats++; - continue; - } else - exit(1); - } - - if (base.len != new->len || path_changed(&base, new)) { - printf("%s", base.len == new->len ? "Route changed" : - "Trace length doesn't match"); - if (!printstats) - printf(" after %d seconds", - (int)((new->qtime - base.qtime) >> 16)); - printf(":\n"); -printandcontinue: - print_trace(1, new, names); - numstats++; - bcopy(new, &base, sizeof(base)); - nexthop = hops = new->len; - printf("Continuing with hop-by-hop...\n"); - goto continuehop; - } - - if (printstats) { - if (new->igmp.igmp_group.s_addr != qgrp || - new->qhdr.tr_src != qsrc || new->qhdr.tr_dst != qdst) - printf("\nWARNING: trace modified en route; statistics may be incorrect\n"); - fixup_stats(&base, prev, new, bugs); - if ((lossthresh == 0) || check_thresh(lossthresh, &base, prev, new)) { - printf("Results after %d seconds", - (int)((new->qtime - base.qtime) >> 16)); - if (lossthresh) - printf(" (this trace %d seconds)", - (int)((new->qtime - prev->qtime) >> 16)); - if (verbose) { - time_t t = time(0); - struct tm *qr = localtime(&t); - - printf(" qid 0x%06x at %2d:%02d:%02d", - TR_GETQID(base.qhdr.tr_rttlqid), - qr->tm_hour, qr->tm_min, qr->tm_sec); - } - printf(":\n\n"); - printed = 1; - if (print_stats(&base, prev, new, bugs, names)) { - printf("This should have been detected earlier, but "); - printf("Route changed:\n"); - goto printandcontinue; - } - } - } - prev = new; - new = &incr[numstats&1]; - waittime = statint; - } - - /* - * If the response was multicast back, leave the group - */ - if (raddr) { - if (IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr); - } else k_leave(resp_cast, lcl_addr); - - return (0); -} - -static void -usage() -{ - fprintf(stderr, "%s\n%s\n%s\n", - "usage: mtrace [-MUOPTWVlnpvs] [-e extra_hops] [-f first_hop] [-i if_addr]", - " [-g gateway] [-m max_hops] [-q nqueries] [-r resp_dest]", - " [-S statint] [-t ttl] [-w wait] source [receiver] [group]"); - exit(1); -} - -void -check_vif_state() -{ - log(LOG_WARNING, errno, "sendto"); -} - -/* - * Log errors and other messages to stderr, according to the severity - * of the message and the current debug level. For errors of severity - * LOG_ERR or worse, terminate the program. - */ -#ifdef __STDC__ -void -log(int severity, int syserr, char *format, ...) -{ - va_list ap; - char fmt[100]; - - va_start(ap, format); -#else -/*VARARGS3*/ -void -log(severity, syserr, format, va_alist) - int severity, syserr; - char *format; - va_dcl -{ - va_list ap; - char fmt[100]; - - va_start(ap); -#endif - - switch (debug) { - case 0: if (severity > LOG_WARNING) return; - case 1: if (severity > LOG_NOTICE) return; - case 2: if (severity > LOG_INFO ) return; - default: - fmt[0] = '\0'; - if (severity == LOG_WARNING) - strcpy(fmt, "warning - "); - strncat(fmt, format, sizeof(fmt)-strlen(fmt)); - fmt[sizeof(fmt)-1]='\0'; - vfprintf(stderr, fmt, ap); - if (syserr == 0) - fprintf(stderr, "\n"); - else if (syserr < sys_nerr) - fprintf(stderr, ": %s\n", sys_errlist[syserr]); - else - fprintf(stderr, ": errno %d\n", syserr); - } - if (severity <= LOG_ERR) exit(1); -} diff --git a/usr.sbin/mrouted/mtrace.h b/usr.sbin/mrouted/mtrace.h deleted file mode 100644 index e67dbd0..0000000 --- a/usr.sbin/mrouted/mtrace.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Multicast traceroute related definitions - * - * mtrace.h,v 5.2 1998/12/04 04:48:21 fenner Exp - */ - -/* - * NetBSD renamed the mtrace packet types. - */ -#if !defined(IGMP_MTRACE_RESP) && defined(IGMP_MTRACE_REPLY) -#define IGMP_MTRACE_RESP IGMP_MTRACE_REPLY -#define IGMP_MTRACE IGMP_MTRACE_QUERY -#endif - -/* - * The packet format for a traceroute request. - */ -struct tr_query { - u_int32 tr_src; /* traceroute source */ - u_int32 tr_dst; /* traceroute destination */ - u_int32 tr_raddr; /* traceroute response address */ - u_int32 tr_rttlqid; /* response ttl and qid */ -}; - -#define TR_SETTTL(x, ttl) (x = (x & 0x00ffffff) | ((ttl) << 24)) -#define TR_GETTTL(x) (((x) >> 24) & 0xff) -#define TR_SETQID(x, qid) (x = (x & 0xff000000) | ((qid) & 0x00ffffff)) -#define TR_GETQID(x) ((x) & 0x00ffffff) - -/* - * Traceroute response format. A traceroute response has a tr_query at the - * beginning, followed by one tr_resp for each hop taken. - */ -struct tr_resp { - u_int32 tr_qarr; /* query arrival time */ - u_int32 tr_inaddr; /* incoming interface address */ - u_int32 tr_outaddr; /* outgoing interface address */ - u_int32 tr_rmtaddr; /* parent address in source tree */ - u_int32 tr_vifin; /* input packet count on interface */ - u_int32 tr_vifout; /* output packet count on interface */ - u_int32 tr_pktcnt; /* total incoming packets for src-grp */ - u_char tr_rproto; /* routing protocol deployed on router */ - u_char tr_fttl; /* ttl required to forward on outvif */ - u_char tr_smask; /* subnet mask for src addr */ - u_char tr_rflags; /* forwarding error codes */ -}; - -/* defs within mtrace */ -#define QLEN sizeof(struct tr_query) -#define RLEN sizeof(struct tr_resp) - -/* fields for tr_rflags (forwarding error codes) */ -#define TR_NO_ERR 0 -#define TR_WRONG_IF 1 -#define TR_PRUNED 2 -#define TR_OPRUNED 3 -#define TR_SCOPED 4 -#define TR_NO_RTE 5 -#define TR_NO_FWD 7 -#define TR_HIT_RP 8 -#define TR_RPF_IF 9 -#define TR_NO_MULTI 10 -#define TR_NO_SPACE 0x81 -#define TR_OLD_ROUTER 0x82 -#define TR_ADMIN_PROHIB 0x83 - -/* fields for tr_rproto (routing protocol) */ -#define PROTO_DVMRP 1 -#define PROTO_MOSPF 2 -#define PROTO_PIM 3 -#define PROTO_CBT 4 -#define PROTO_PIM_SPECIAL 5 -#define PROTO_PIM_STATIC 6 -#define PROTO_DVMRP_STATIC 7 -#define PROTO_PIM_BGP4PLUS 8 -#define PROTO_CBT_SPECIAL 9 -#define PROTO_CBT_STATIC 10 -#define PROTO_PIM_ASSERT 11 - -#define VAL_TO_MASK(x, i) { \ - x = htonl(~((1 << (32 - (i))) - 1)); \ - }; - -#if defined(__STDC__) || defined(__GNUC__) -#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ -#else -#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */ -#define const /**/ -#endif diff --git a/usr.sbin/mrouted/mtrace/Makefile b/usr.sbin/mrouted/mtrace/Makefile deleted file mode 100644 index ee9adb7..0000000 --- a/usr.sbin/mrouted/mtrace/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -PROG= mtrace -MAN= mtrace.8 -BINOWN= root -BINMODE= 4555 - -CFLAGS+= -I$S - -.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h deleted file mode 100644 index d4fb01d..0000000 --- a/usr.sbin/mrouted/pathnames.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * pathnames.h,v 3.8 1995/11/29 22:36:57 fenner Rel - */ - -#define _PATH_MROUTED_CONF "/etc/mrouted.conf" - -#if (defined(BSD) && (BSD >= 199103)) -#define _PATH_MROUTED_PID "/var/run/mrouted.pid" -#define _PATH_MROUTED_GENID "/var/run/mrouted.genid" -#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump" -#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache" -#else -#define _PATH_MROUTED_PID "/etc/mrouted.pid" -#define _PATH_MROUTED_GENID "/etc/mrouted.genid" -#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump" -#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache" -#endif diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c deleted file mode 100644 index acefaf9..0000000 --- a/usr.sbin/mrouted/prune.c +++ /dev/null @@ -1,2619 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * prune.c,v 3.8.4.59 1998/03/01 02:06:32 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -extern int cache_lifetime; -extern int prune_lifetime; -extern struct rtentry *routing_table; - -extern int phys_vif; - -extern int allow_black_holes; - -/* - * randomize value to obtain a value between .5x and 1.5x - * in order to prevent synchronization - */ -#ifdef SYSV -#define JITTERED_VALUE(x) ((x)/2 + (lrand48() % (x))) -#else -#define JITTERED_VALUE(x) ((x)/2 + (arc4random() % (x))) -#endif -#define CACHE_LIFETIME(x) JITTERED_VALUE(x) /* XXX */ - -struct gtable *kernel_table; /* ptr to list of kernel grp entries*/ -static struct gtable *kernel_no_route; /* list of grp entries w/o routes */ -struct gtable *gtp; /* pointer for kernel rt entries */ -unsigned int kroutes; /* current number of cache entries */ - -/**************************************************************************** - Functions that are local to prune.c -****************************************************************************/ -static int scoped_addr __P((vifi_t vifi, u_int32 addr)); -static void prun_add_ttls __P((struct gtable *gt)); -static int pruning_neighbor __P((vifi_t vifi, u_int32 addr)); -static int can_mtrace __P((vifi_t vifi, u_int32 addr)); -static struct ptable * find_prune_entry __P((u_int32 vr, struct ptable *pt)); -static void remove_sources __P((struct gtable *gt)); -static void rexmit_prune __P((void *arg)); -static void expire_prune __P((vifi_t vifi, struct gtable *gt)); -static void send_prune __P((struct gtable *gt)); -static void send_graft __P((struct gtable *gt)); -static void send_graft_ack __P((u_int32 src, u_int32 dst, - u_int32 origin, u_int32 grp, - vifi_t vifi)); -static void update_kernel __P((struct gtable *g)); - -/* - * Updates the ttl values for each vif. - */ -static void -prun_add_ttls(gt) - struct gtable *gt; -{ - struct uvif *v; - vifi_t vifi; - - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (VIFM_ISSET(vifi, gt->gt_grpmems)) - gt->gt_ttls[vifi] = v->uv_threshold; - else - gt->gt_ttls[vifi] = 0; - } -} - -/* - * checks for scoped multicast addresses - * XXX I want to make the check of allow_black_holes based on ALLOW_BLACK_HOLES - * but macros are not functions. - */ -#define GET_SCOPE(gt) { \ - register vifi_t _i; \ - VIFM_CLRALL((gt)->gt_scope); \ - if (allow_black_holes || \ - (ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \ - for (_i = 0; _i < numvifs; _i++) \ - if (scoped_addr(_i, (gt)->gt_mcastgrp)) \ - VIFM_SET(_i, (gt)->gt_scope); \ - } \ - if ((gt)->gt_route == NULL || ((gt)->gt_route->rt_parent != NO_VIF && \ - VIFM_ISSET((gt)->gt_route->rt_parent, (gt)->gt_scope))) \ - VIFM_SETALL((gt)->gt_scope); - -#define APPLY_SCOPE(gt) VIFM_CLR_MASK((gt)->gt_grpmems, (gt)->gt_scope) - -#define GET_MEMBERSHIP(gt, vifi) { \ - if ((gt)->gt_route && \ - VIFM_ISSET((vifi), (gt)->gt_route->rt_children) && \ - (!SUBS_ARE_PRUNED((gt)->gt_route->rt_subordinates, \ - uvifs[vifi].uv_nbrmap, (gt)->gt_prunes) || \ - grplst_mem((vifi), (gt)->gt_mcastgrp))) \ - VIFM_SET((vifi), (gt)->gt_grpmems); \ - } - -static int -scoped_addr(vifi, addr) - vifi_t vifi; - u_int32 addr; -{ - struct vif_acl *acl; - - for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next) - if ((addr & acl->acl_mask) == acl->acl_addr) - return 1; - - return 0; -} - -/* - * Determine the list of outgoing vifs, based upon - * route subordinates, prunes received, and group - * memberships. - */ -void -determine_forwvifs(gt) - struct gtable *gt; -{ - vifi_t i; - - VIFM_CLRALL(gt->gt_grpmems); - for (i = 0; i < numvifs; i++) { - GET_MEMBERSHIP(gt, i); - } - GET_SCOPE(gt); - APPLY_SCOPE(gt); -} - -/* - * Send a prune or a graft if necessary. - */ -void -send_prune_or_graft(gt) - struct gtable *gt; -{ - if (VIFM_ISEMPTY(gt->gt_grpmems)) - send_prune(gt); - else if (gt->gt_prsent_timer) - send_graft(gt); -} - -/* - * Determine if mcastgrp has a listener on vifi - */ -int -grplst_mem(vifi, mcastgrp) - vifi_t vifi; - u_int32 mcastgrp; -{ - register struct listaddr *g; - register struct uvif *v; - - v = &uvifs[vifi]; - - for (g = v->uv_groups; g != NULL; g = g->al_next) - if (mcastgrp == g->al_addr) - return 1; - - return 0; -} - -/* - * Finds the group entry with the specified source and netmask. - * If netmask is 0, it uses the route's netmask. - * - * Returns TRUE if found a match, and the global variable gtp is left - * pointing to entry before the found entry. - * Returns FALSE if no exact match found, gtp is left pointing to before - * the entry in question belongs, or is NULL if the it belongs at the - * head of the list. - */ -int -find_src_grp(src, mask, grp) - u_int32 src; - u_int32 mask; - u_int32 grp; -{ - struct gtable *gt; - - gtp = NULL; - gt = kernel_table; - while (gt != NULL) { - if (grp == gt->gt_mcastgrp && - (mask ? (gt->gt_route->rt_origin == src && - gt->gt_route->rt_originmask == mask) : - ((src & gt->gt_route->rt_originmask) == - gt->gt_route->rt_origin))) - return TRUE; - if (ntohl(grp) > ntohl(gt->gt_mcastgrp) || - (grp == gt->gt_mcastgrp && - (ntohl(mask) < ntohl(gt->gt_route->rt_originmask) || - (mask == gt->gt_route->rt_originmask && - (ntohl(src) > ntohl(gt->gt_route->rt_origin)))))) { - gtp = gt; - gt = gt->gt_gnext; - } - else break; - } - return FALSE; -} - -/* - * Check if the neighbor supports pruning - */ -static int -pruning_neighbor(vifi, addr) - vifi_t vifi; - u_int32 addr; -{ - struct listaddr *n = neighbor_info(vifi, addr); - int vers; - - if (n == NULL) - return 0; - - vers = NBR_VERS(n); - return (vers >= 0x0300 && ((vers & 0xff00) != 0x0a00)); -} - -/* - * Can the neighbor in question handle multicast traceroute? - */ -static int -can_mtrace(vifi, addr) - vifi_t vifi; - u_int32 addr; -{ - struct listaddr *n = neighbor_info(vifi, addr); - int vers; - - if (n == NULL) - return 1; /* fail "safe" */ - - vers = NBR_VERS(n); - return (vers >= 0x0303 && ((vers & 0xff00) != 0x0a00)); -} - -/* - * Returns the prune entry of the router, or NULL if none exists - */ -static struct ptable * -find_prune_entry(vr, pt) - u_int32 vr; - struct ptable *pt; -{ - while (pt) { - if (pt->pt_router == vr) - return pt; - pt = pt->pt_next; - } - - return NULL; -} - -/* - * Remove all the sources hanging off the group table entry from the kernel - * cache. Remember the packet counts wherever possible, to keep the mtrace - * counters consistent. This prepares for possible prune retransmission, - * either on a multi-access network or when a prune that we sent upstream - * has expired. - */ -static void -remove_sources(gt) - struct gtable *gt; -{ - struct stable *st; - struct sioc_sg_req sg_req; - - sg_req.grp.s_addr = gt->gt_mcastgrp; - - /* - * call k_del_rg() on every one of the gt->gt_srctbl entries - * but first save the packet count so that the mtrace packet - * counters can remain approximately correct. There's a race - * here but it's minor. - */ - for (st = gt->gt_srctbl; st; st = st->st_next) { - if (st->st_ctime == 0) - continue; - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "rexmit_prune deleting (%s %s) (next is %d sec)", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_prune_rexmit); - sg_req.src.s_addr = st->st_origin; - if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) { - sg_req.pktcnt = 0; - } - k_del_rg(st->st_origin, gt); - st->st_ctime = 0; /* flag that it's not in the kernel any more */ - st->st_savpkt += sg_req.pktcnt; - kroutes--; - } - - /* - * Now, add_table_entry will prune when asked to add a cache entry. - */ -} - -/* - * Prepare for possible prune retransmission - */ -static void -rexmit_prune(arg) - void *arg; -{ - struct gtable *gt = *(struct gtable **)arg; - - free(arg); - - gt->gt_rexmit_timer = 0; - - /* Make sure we're still not forwarding traffic */ - if (!VIFM_ISEMPTY(gt->gt_grpmems)) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "rexmit_prune (%s %s): gm:%x", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_grpmems); - return; - } - - remove_sources(gt); -} - -/* - * Send a prune message to the dominant router for - * this source. - * - * Record an entry that a prune was sent for this group - */ -static void -send_prune(gt) - struct gtable *gt; -{ - struct ptable *pt; - char *p; - int i; - int datalen; - u_int32 dst; - u_int32 tmp; - int rexmitting = 0; - struct uvif *v; - - /* - * Can't process a prune if we don't have an associated route - * or if the route points to a local interface. - */ - if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF || - gt->gt_route->rt_gateway == 0) - return; - - /* Don't send a prune to a non-pruning router */ - if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway)) - return; - - v = &uvifs[gt->gt_route->rt_parent]; - /* - * sends a prune message to the router upstream. - */ -#if 0 - dst = v->uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/ -#else - dst = gt->gt_route->rt_gateway; -#endif - - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - datalen = 0; - - /* - * determine prune lifetime, if this isn't a retransmission. - * - * Use interface-specified lifetime if there is one. - */ - if (gt->gt_prsent_timer == 0) { - int l = prune_lifetime; - - if (v->uv_prune_lifetime != 0) - l = v->uv_prune_lifetime; - - gt->gt_prsent_timer = JITTERED_VALUE(l); - for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) - if (pt->pt_timer < gt->gt_prsent_timer) - gt->gt_prsent_timer = pt->pt_timer; - } else if (gt->gt_prsent_timer < 0) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "asked to rexmit? (%s,%s)/%d on vif %d to %s with negative time", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_prsent_timer, gt->gt_route->rt_parent, - inet_fmt(gt->gt_route->rt_gateway, s3)); - return; - } else - rexmitting = 1; - - if (rexmitting && !(v->uv_flags & VIFF_REXMIT_PRUNES)) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "not rexmitting prune for (%s %s)/%d on vif %d to %s", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_prsent_timer, gt->gt_route->rt_parent, - inet_fmt(gt->gt_route->rt_gateway, s3)); - return; - } - if (gt->gt_prsent_timer <= MIN_PRUNE_LIFE) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "not bothering to send prune for (%s,%s)/%d on vif %d to %s because it's too short", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_prsent_timer, gt->gt_route->rt_parent, - inet_fmt(gt->gt_route->rt_gateway, s3)); - return; - } - - /* - * If we have a graft pending, cancel graft retransmission - */ - gt->gt_grftsnt = 0; - - for (i = 0; i < 4; i++) - *p++ = ((char *)&(gt->gt_route->rt_origin))[i]; - for (i = 0; i < 4; i++) - *p++ = ((char *)&(gt->gt_mcastgrp))[i]; - tmp = htonl(gt->gt_prsent_timer); - for (i = 0; i < 4; i++) - *p++ = ((char *)&(tmp))[i]; - datalen += 12; - - send_on_vif(v, dst, DVMRP_PRUNE, datalen); - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s prune for (%s %s)/%d on vif %d to %s", - rexmitting ? "rexmitted" : "sent", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - gt->gt_prsent_timer, gt->gt_route->rt_parent, - inet_fmt(gt->gt_route->rt_gateway, s3)); - - if ((v->uv_flags & VIFF_REXMIT_PRUNES) && - gt->gt_rexmit_timer == 0 && - gt->gt_prsent_timer > gt->gt_prune_rexmit) { - struct gtable **arg = - (struct gtable **)malloc(sizeof (struct gtable **)); - - *arg = gt; - gt->gt_rexmit_timer = timer_setTimer( - JITTERED_VALUE(gt->gt_prune_rexmit), - rexmit_prune, arg); - gt->gt_prune_rexmit *= 2; - } -} - -/* - * a prune was sent upstream - * so, a graft has to be sent to annul the prune - * set up a graft timer so that if an ack is not - * heard within that time, another graft request - * is sent out. - */ -static void -send_graft(gt) - struct gtable *gt; -{ - register char *p; - register int i; - int datalen; - u_int32 dst; - - /* Can't send a graft without an associated route */ - if (gt->gt_route == NULL || gt->gt_route->rt_parent == NO_VIF) { - gt->gt_grftsnt = 0; - return; - } - - gt->gt_prsent_timer = 0; - gt->gt_prune_rexmit = PRUNE_REXMIT_VAL; - if (gt->gt_rexmit_timer) - timer_clearTimer(gt->gt_rexmit_timer); - - if (gt->gt_grftsnt == 0) - gt->gt_grftsnt = 1; - -#if 0 - dst = uvifs[gt->gt_route->rt_parent].uv_flags & VIFF_TUNNEL ? dvmrp_group : gt->gt_route->rt_gateway; /*XXX*/ -#else - dst = gt->gt_route->rt_gateway; -#endif - - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - datalen = 0; - - for (i = 0; i < 4; i++) - *p++ = ((char *)&(gt->gt_route->rt_origin))[i]; - for (i = 0; i < 4; i++) - *p++ = ((char *)&(gt->gt_mcastgrp))[i]; - datalen += 8; - - send_on_vif(&uvifs[gt->gt_route->rt_parent], dst, DVMRP_GRAFT, datalen); - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "sent graft for (%s %s) to %s on vif %d", - RT_FMT(gt->gt_route, s1), inet_fmt(gt->gt_mcastgrp, s2), - inet_fmt(gt->gt_route->rt_gateway, s3), gt->gt_route->rt_parent); -} - -/* - * Send an ack that a graft was received - */ -static void -send_graft_ack(src, dst, origin, grp, vifi) - u_int32 src; - u_int32 dst; - u_int32 origin; - u_int32 grp; - vifi_t vifi; -{ - register char *p; - register int i; - int datalen; - - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - datalen = 0; - - for (i = 0; i < 4; i++) - *p++ = ((char *)&(origin))[i]; - for (i = 0; i < 4; i++) - *p++ = ((char *)&(grp))[i]; - datalen += 8; - - if (vifi == NO_VIF) - send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK, - htonl(MROUTED_LEVEL), datalen); - else { -#if 0 - if (uvifs[vifi].uv_flags & VIFF_TUNNEL) - dst = dvmrp_group; /* XXX */ -#endif - send_on_vif(&uvifs[vifi], dst, DVMRP_GRAFT_ACK, datalen); - } - - IF_DEBUG(DEBUG_PRUNE) - if (vifi == NO_VIF) - log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s", - inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3)); - else - log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s on vif %d", - inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3), vifi); -} - -/* - * Update the kernel cache with all the routes hanging off the group entry - */ -static void -update_kernel(g) - struct gtable *g; -{ - struct stable *st; - - for (st = g->gt_srctbl; st; st = st->st_next) - if (st->st_ctime != 0) - k_add_rg(st->st_origin, g); -} - -/**************************************************************************** - Functions that are used externally -****************************************************************************/ - -#ifdef SNMP -#include <sys/types.h> -#include "snmp.h" - -/* - * Find a specific group entry in the group table - */ -struct gtable * -find_grp(grp) - u_int32 grp; -{ - struct gtable *gt; - - for (gt = kernel_table; gt; gt = gt->gt_gnext) { - if (ntohl(grp) < ntohl(gt->gt_mcastgrp)) - break; - if (gt->gt_mcastgrp == grp) - return gt; - } - return NULL; -} - -/* - * Given a group entry and source, find the corresponding source table - * entry - */ -struct stable * -find_grp_src(gt, src) - struct gtable *gt; - u_int32 src; -{ - struct stable *st; - u_long grp = gt->gt_mcastgrp; - struct gtable *gtcurr; - - for (gtcurr = gt; gtcurr->gt_mcastgrp == grp; gtcurr = gtcurr->gt_gnext) { - for (st = gtcurr->gt_srctbl; st; st = st->st_next) - if (st->st_origin == src) - return st; - } - return NULL; -} - -/* - * Find next entry > specification - */ -int -next_grp_src_mask(gtpp, stpp, grp, src, mask) - struct gtable **gtpp; /* ordered by group */ - struct stable **stpp; /* ordered by source */ - u_int32 grp; - u_int32 src; - u_int32 mask; -{ - struct gtable *gt, *gbest = NULL; - struct stable *st, *sbest = NULL; - - /* Find first group entry >= grp spec */ - (*gtpp) = kernel_table; - while ((*gtpp) && ntohl((*gtpp)->gt_mcastgrp) < ntohl(grp)) - (*gtpp)=(*gtpp)->gt_gnext; - if (!(*gtpp)) - return 0; /* no more groups */ - - for (gt = kernel_table; gt; gt=gt->gt_gnext) { - /* Since grps are ordered, we can stop when group changes from gbest */ - if (gbest && gbest->gt_mcastgrp != gt->gt_mcastgrp) - break; - for (st = gt->gt_srctbl; st; st=st->st_next) { - - /* Among those entries > spec, find "lowest" one */ - if (((ntohl(gt->gt_mcastgrp)> ntohl(grp)) - || (ntohl(gt->gt_mcastgrp)==ntohl(grp) - && ntohl(st->st_origin)> ntohl(src)) - || (ntohl(gt->gt_mcastgrp)==ntohl(grp) - && ntohl(st->st_origin)==src && 0xFFFFFFFF>ntohl(mask))) - && (!gbest - || (ntohl(gt->gt_mcastgrp)< ntohl(gbest->gt_mcastgrp)) - || (ntohl(gt->gt_mcastgrp)==ntohl(gbest->gt_mcastgrp) - && ntohl(st->st_origin)< ntohl(sbest->st_origin)))) { - gbest = gt; - sbest = st; - } - } - } - (*gtpp) = gbest; - (*stpp) = sbest; - return (*gtpp)!=0; -} - -/* - * Ensure that sg contains current information for the given group,source. - * This is fetched from the kernel as a unit so that counts for the entry - * are consistent, i.e. packet and byte counts for the same entry are - * read at the same time. - */ -void -refresh_sg(sg, gt, st) - struct sioc_sg_req *sg; - struct gtable *gt; - struct stable *st; -{ - static int lastq = -1; - - if (quantum != lastq || sg->src.s_addr!=st->st_origin - || sg->grp.s_addr!=gt->gt_mcastgrp) { - lastq = quantum; - sg->src.s_addr = st->st_origin; - sg->grp.s_addr = gt->gt_mcastgrp; - ioctl(udp_socket, SIOCGETSGCNT, (char *)sg); - } -} - -/* - * Given a routing table entry, and a vifi, find the next entry - * equal to or greater than those - */ -int -next_child(gtpp, stpp, grp, src, mask, vifi) - struct gtable **gtpp; - struct stable **stpp; - u_int32 grp; - u_int32 src; - u_int32 mask; - vifi_t *vifi; /* vif at which to start looking */ -{ - /* Get (G,S,M) entry */ - if (mask!=0xFFFFFFFF - || !((*gtpp) = find_grp(grp)) - || !((*stpp) = find_grp_src((*gtpp),src))) - if (!next_grp_src_mask(gtpp, stpp, grp, src, mask)) - return 0; - - /* Continue until we get one with a valid next vif */ - do { - for (; (*gtpp)->gt_route->rt_children && *vifi<numvifs; (*vifi)++) - if (VIFM_ISSET(*vifi, (*gtpp)->gt_route->rt_children)) - return 1; - *vifi = 0; - } while (next_grp_src_mask(gtpp, stpp, (*gtpp)->gt_mcastgrp, - (*stpp)->st_origin, 0xFFFFFFFF) ); - - return 0; -} -#endif /* SNMP */ - -/* - * Initialize the kernel table structure - */ -void -init_ktable() -{ - kernel_table = NULL; - kernel_no_route = NULL; - kroutes = 0; -} - -/* - * Add a new table entry for (origin, mcastgrp) - */ -void -add_table_entry(origin, mcastgrp) - u_int32 origin; - u_int32 mcastgrp; -{ - struct rtentry *r; - struct gtable *gt,**gtnp,*prev_gt; - struct stable *st,**stnp; - - /* - * Since we have to enable mrouting to get the version number, - * some cache creation requests can sneak through. Ignore them - * since we're not going to do useful stuff until we've performed - * final initialization. - */ - if (!did_final_init) - return; - -#ifdef DEBUG_MFC - md_log(MD_MISS, origin, mcastgrp); -#endif - - r = determine_route(origin); - prev_gt = NULL; - if (r == NULL) { - /* - * Look for it on the no_route table; if it is found then - * it will be detected as a duplicate below. - */ - for (gt = kernel_no_route; gt; gt = gt->gt_next) - if (mcastgrp == gt->gt_mcastgrp && - gt->gt_srctbl && gt->gt_srctbl->st_origin == origin) - break; - gtnp = &kernel_no_route; - } else { - gtnp = &r->rt_groups; - while ((gt = *gtnp) != NULL) { - if (gt->gt_mcastgrp >= mcastgrp) - break; - gtnp = >->gt_next; - prev_gt = gt; - } - } - - if (gt == NULL || gt->gt_mcastgrp != mcastgrp) { - gt = (struct gtable *)malloc(sizeof(struct gtable)); - if (gt == NULL) - log(LOG_ERR, 0, "ran out of memory"); - - gt->gt_mcastgrp = mcastgrp; - gt->gt_timer = CACHE_LIFETIME(cache_lifetime); - time(>->gt_ctime); - gt->gt_prsent_timer = 0; - gt->gt_grftsnt = 0; - gt->gt_srctbl = NULL; - gt->gt_pruntbl = NULL; - gt->gt_route = r; - gt->gt_rexmit_timer = 0; - NBRM_CLRALL(gt->gt_prunes); - gt->gt_prune_rexmit = PRUNE_REXMIT_VAL; -#ifdef RSRR - gt->gt_rsrr_cache = NULL; -#endif - - /* Calculate forwarding vifs */ - determine_forwvifs(gt); - - /* update ttls */ - prun_add_ttls(gt); - - gt->gt_next = *gtnp; - *gtnp = gt; - if (gt->gt_next) - gt->gt_next->gt_prev = gt; - gt->gt_prev = prev_gt; - - if (r) { - if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) { - struct gtable *g; - - g = gtp ? gtp->gt_gnext : kernel_table; - log(LOG_WARNING, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), - r, g->gt_route); - } else { - if (gtp) { - gt->gt_gnext = gtp->gt_gnext; - gt->gt_gprev = gtp; - gtp->gt_gnext = gt; - } else { - gt->gt_gnext = kernel_table; - gt->gt_gprev = NULL; - kernel_table = gt; - } - if (gt->gt_gnext) - gt->gt_gnext->gt_gprev = gt; - } - } else { - gt->gt_gnext = gt->gt_gprev = NULL; - } - } - - stnp = >->gt_srctbl; - while ((st = *stnp) != NULL) { - if (ntohl(st->st_origin) >= ntohl(origin)) - break; - stnp = &st->st_next; - } - - if (st == NULL || st->st_origin != origin) { - st = (struct stable *)malloc(sizeof(struct stable)); - if (st == NULL) - log(LOG_ERR, 0, "ran out of memory"); - - st->st_origin = origin; - st->st_pktcnt = 0; - st->st_savpkt = 0; - time(&st->st_ctime); - st->st_next = *stnp; - *stnp = st; - } else { - if (st->st_ctime == 0) { - /* An old source which we're keeping around for statistics */ - time(&st->st_ctime); - } else { -#ifdef DEBUG_MFC - md_log(MD_DUPE, origin, mcastgrp); -#endif - /* Ignore kernel->mrouted retransmissions */ - if (time(0) - st->st_ctime > 5) - log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)", - inet_fmt(origin, s1), inet_fmt(mcastgrp, s2)); - k_add_rg(origin, gt); - return; - } - } - - kroutes++; - k_add_rg(origin, gt); - - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d", - inet_fmt(origin, s1), - inet_fmt(mcastgrp, s2), - gt->gt_grpmems, r ? r->rt_parent : -1); - - /* - * If there are no downstream routers that want traffic for - * this group, send (or retransmit) a prune upstream. - */ - if (VIFM_ISEMPTY(gt->gt_grpmems)) - send_prune(gt); -} - -/* - * A router has gone down. Remove prune state pertinent to that router. - */ -void -reset_neighbor_state(vifi, addr) - vifi_t vifi; - u_int32 addr; -{ - struct rtentry *r; - struct gtable *g; - struct ptable *pt, **ptnp; - struct stable *st; - - for (g = kernel_table; g; g = g->gt_gnext) { - r = g->gt_route; - - /* - * If neighbor was the parent, remove the prune sent state - * and all of the source cache info so that prunes get - * regenerated. - */ - if (vifi == r->rt_parent) { - if (addr == r->rt_gateway) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2)); - - g->gt_prsent_timer = 0; - g->gt_grftsnt = 0; - while ((st = g->gt_srctbl) != NULL) { - g->gt_srctbl = st->st_next; - if (st->st_ctime != 0) { - k_del_rg(st->st_origin, g); - kroutes--; - } - free(st); - } - } - } else { - /* - * Remove any prunes that this router has sent us. - */ - ptnp = &g->gt_pruntbl; - while ((pt = *ptnp) != NULL) { - if (pt->pt_vifi == vifi && pt->pt_router == addr) { - NBRM_CLR(pt->pt_index, g->gt_prunes); - *ptnp = pt->pt_next; - free(pt); - } else - ptnp = &pt->pt_next; - } - - /* - * And see if we want to forward again. - */ - if (!VIFM_ISSET(vifi, g->gt_grpmems)) { - GET_MEMBERSHIP(g, vifi); - APPLY_SCOPE(g); - prun_add_ttls(g); - - /* Update kernel state */ - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - - /* - * If removing this prune causes us to start forwarding - * (e.g. the neighbor rebooted), and we sent a prune upstream, - * send a graft to cancel the prune. - */ - if (!VIFM_ISEMPTY(g->gt_grpmems) && g->gt_prsent_timer) - send_graft(g); - - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "reset neighbor state (%s %s) gm:%x", - RT_FMT(r, s1), - inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems); - } - } - } -} - -/* - * Delete table entry from the kernel - * del_flag determines how many entries to delete - */ -void -del_table_entry(r, mcastgrp, del_flag) - struct rtentry *r; - u_int32 mcastgrp; - u_int del_flag; -{ - struct gtable *g, *prev_g; - struct stable *st, *prev_st; - struct ptable *pt, *prev_pt; - - if (del_flag == DEL_ALL_ROUTES) { - g = r->rt_groups; - while (g) { - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2)); - st = g->gt_srctbl; - while (st) { - if (st->st_ctime != 0) { - if (k_del_rg(st->st_origin, g) < 0) { - log(LOG_WARNING, errno, - "del_table_entry trying to delete (%s, %s)", - inet_fmt(st->st_origin, s1), - inet_fmt(g->gt_mcastgrp, s2)); - } - kroutes--; - } - prev_st = st; - st = st->st_next; - free(prev_st); - } - g->gt_srctbl = NULL; - - pt = g->gt_pruntbl; - while (pt) { - prev_pt = pt; - pt = pt->pt_next; - free(prev_pt); - } - g->gt_pruntbl = NULL; - - if (g->gt_gnext) - g->gt_gnext->gt_gprev = g->gt_gprev; - if (g->gt_gprev) - g->gt_gprev->gt_gnext = g->gt_gnext; - else - kernel_table = g->gt_gnext; - -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,0); - rsrr_cache_clean(g); -#endif /* RSRR */ - if (g->gt_rexmit_timer) - timer_clearTimer(g->gt_rexmit_timer); - - prev_g = g; - g = g->gt_next; - free(prev_g); - } - r->rt_groups = NULL; - } - - /* - * Dummy routine - someday this may be needed, so it is just there - */ - if (del_flag == DEL_RTE_GROUP) { - prev_g = (struct gtable *)&r->rt_groups; - for (g = r->rt_groups; g; g = g->gt_next) { - if (g->gt_mcastgrp == mcastgrp) { - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2)); - st = g->gt_srctbl; - while (st) { - if (st->st_ctime != 0) { - if (k_del_rg(st->st_origin, g) < 0) { - log(LOG_WARNING, errno, - "del_table_entry trying to delete (%s, %s)", - inet_fmt(st->st_origin, s1), - inet_fmt(g->gt_mcastgrp, s2)); - } - kroutes--; - } - prev_st = st; - st = st->st_next; - free(prev_st); - } - g->gt_srctbl = NULL; - - pt = g->gt_pruntbl; - while (pt) { - prev_pt = pt; - pt = pt->pt_next; - free(prev_pt); - } - g->gt_pruntbl = NULL; - - if (g->gt_gnext) - g->gt_gnext->gt_gprev = g->gt_gprev; - if (g->gt_gprev) - g->gt_gprev->gt_gnext = g->gt_gnext; - else - kernel_table = g->gt_gnext; - - if (prev_g != (struct gtable *)&r->rt_groups) - g->gt_next->gt_prev = prev_g; - else - g->gt_next->gt_prev = NULL; - prev_g->gt_next = g->gt_next; - - if (g->gt_rexmit_timer) - timer_clearTimer(g->gt_rexmit_timer); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,0); - rsrr_cache_clean(g); -#endif /* RSRR */ - free(g); - g = prev_g; - } else { - prev_g = g; - } - } - } -} - -/* - * update kernel table entry when a route entry changes - */ -void -update_table_entry(r, old_parent_gw) - struct rtentry *r; - u_int32 old_parent_gw; -{ - struct gtable *g; - struct ptable *pt, **ptnp; - - for (g = r->rt_groups; g; g = g->gt_next) { - ptnp = &g->gt_pruntbl; - /* - * Delete prune entries from non-children, or non-subordinates. - */ - while ((pt = *ptnp)) { - if (!VIFM_ISSET(pt->pt_vifi, r->rt_children) || - !NBRM_ISSET(pt->pt_index, r->rt_subordinates)) { - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "update_table_entry deleting prune for (%s %s) from %s on vif %d -%s%s", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), - inet_fmt(pt->pt_router, s3), pt->pt_vifi, - VIFM_ISSET(pt->pt_vifi, r->rt_children) ? "" : " not a child", - NBRM_ISSET(pt->pt_index, r->rt_subordinates) ? "" : " not a subordinate"); - - if (!NBRM_ISSET(pt->pt_index, g->gt_prunes)) { - log(LOG_WARNING, 0, - "gt_prunes lost track of (%s %s) from %s on vif %d", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), - inet_fmt(pt->pt_router, s3), pt->pt_vifi); - } - - NBRM_CLR(pt->pt_index, g->gt_prunes); - *ptnp = pt->pt_next; - free(pt); - continue; - } - ptnp = &((*ptnp)->pt_next); - } - - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "updating cache entries (%s %s) old gm:%x", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), - g->gt_grpmems); - - /* - * Forget about a prune or graft that we sent previously if we - * have a new parent router (since the new parent router will - * know nothing about what I sent to the previous parent). The - * old parent will forget any prune state it is keeping for us. - */ - if (old_parent_gw != r->rt_gateway) { - g->gt_prsent_timer = 0; - g->gt_grftsnt = 0; - } - - /* Recalculate membership */ - determine_forwvifs(g); - /* send a prune or graft if needed. */ - send_prune_or_graft(g); - - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "updating cache entries (%s %s) new gm:%x", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), - g->gt_grpmems); - - /* update ttls and add entry into kernel */ - prun_add_ttls(g); - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - } -} - -/* - * set the forwarding flag for all mcastgrps on this vifi - */ -void -update_lclgrp(vifi, mcastgrp) - vifi_t vifi; - u_int32 mcastgrp; -{ - struct rtentry *r; - struct gtable *g; - - IF_DEBUG(DEBUG_MEMBER) - log(LOG_DEBUG, 0, "group %s joined on vif %d", - inet_fmt(mcastgrp, s1), vifi); - - for (g = kernel_table; g; g = g->gt_gnext) { - if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp)) - break; - - r = g->gt_route; - if (g->gt_mcastgrp == mcastgrp && - VIFM_ISSET(vifi, r->rt_children)) { - - VIFM_SET(vifi, g->gt_grpmems); - APPLY_SCOPE(g); - if (VIFM_ISEMPTY(g->gt_grpmems)) - continue; - - prun_add_ttls(g); - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "update lclgrp (%s %s) gm:%x", - RT_FMT(r, s1), - inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems); - - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - } - } -} - -/* - * reset forwarding flag for all mcastgrps on this vifi - */ -void -delete_lclgrp(vifi, mcastgrp) - vifi_t vifi; - u_int32 mcastgrp; -{ - struct gtable *g; - - IF_DEBUG(DEBUG_MEMBER) - log(LOG_DEBUG, 0, "group %s left on vif %d", - inet_fmt(mcastgrp, s1), vifi); - - for (g = kernel_table; g; g = g->gt_gnext) { - if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp)) - break; - - if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, g->gt_grpmems)) { - if (g->gt_route == NULL || - SUBS_ARE_PRUNED(g->gt_route->rt_subordinates, - uvifs[vifi].uv_nbrmap, g->gt_prunes)) { - VIFM_CLR(vifi, g->gt_grpmems); - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "delete lclgrp (%s %s) gm:%x", - RT_FMT(g->gt_route, s1), - inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems); - - prun_add_ttls(g); - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - - /* - * If there are no more members of this particular group, - * send prune upstream - */ - if (VIFM_ISEMPTY(g->gt_grpmems) && g->gt_route->rt_gateway) - send_prune(g); - } - } - } -} - -/* - * Takes the prune message received and then strips it to - * determine the (src, grp) pair to be pruned. - * - * Adds the router to the (src, grp) entry then. - * - * Determines if further packets have to be sent down that vif - * - * Determines if a corresponding prune message has to be generated - */ -void -accept_prune(src, dst, p, datalen) - u_int32 src; - u_int32 dst; - char *p; - int datalen; -{ - u_int32 prun_src; - u_int32 prun_grp; - u_int32 prun_tmr; - vifi_t vifi; - int i; - struct rtentry *r; - struct gtable *g; - struct ptable *pt; - - if ((vifi = find_vif(src, dst)) == NO_VIF) { - log(LOG_INFO, 0, - "ignoring prune report from non-neighbor %s", - inet_fmt(src, s1)); - return; - } - - /* Check if enough data is present */ - if (datalen < 12) - { - log(LOG_WARNING, 0, - "non-decipherable prune from %s", - inet_fmt(src, s1)); - return; - } - - for (i = 0; i< 4; i++) - ((char *)&prun_src)[i] = *p++; - for (i = 0; i< 4; i++) - ((char *)&prun_grp)[i] = *p++; - for (i = 0; i< 4; i++) - ((char *)&prun_tmr)[i] = *p++; - prun_tmr = ntohl(prun_tmr); - - if (prun_tmr <= MIN_PRUNE_LIFE) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "ignoring prune from %s on vif %d for (%s %s)/%d because its lifetime is too short", - inet_fmt(src, s1), vifi, - inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr); - return; - } - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d", - inet_fmt(src, s1), vifi, - inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr); - - /* - * Find the subnet for the prune - */ - if (find_src_grp(prun_src, 0, prun_grp)) { - g = gtp ? gtp->gt_gnext : kernel_table; - r = g->gt_route; - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "found grp state, (%s %s), metric is %d, children are %x, subords are %08x%08x", - RT_FMT(r, s1), inet_fmt(g->gt_mcastgrp, s2), r->rt_metric, - r->rt_children, r->rt_subordinates.hi, r->rt_subordinates.lo); - if (!VIFM_ISSET(vifi, r->rt_children)) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_WARNING, 0, "prune received from non-child %s for (%s %s) (dominant on vif %d is %s)", - inet_fmt(src, s1), inet_fmt(prun_src, s2), - inet_fmt(prun_grp, s3), vifi, - inet_fmt(r->rt_dominants[vifi], s4)); -#ifdef RINGBUFFER - printringbuf(); -#endif - return; - } - if (VIFM_ISSET(vifi, g->gt_scope)) { - log(LOG_WARNING, 0, "prune received from %s on scoped grp (%s %s)", - inet_fmt(src, s1), inet_fmt(prun_src, s2), - inet_fmt(prun_grp, s3)); - return; - } - if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x", - "duplicate prune received on vif", - vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2), - inet_fmt(prun_grp, s3), prun_tmr, - "old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems); - pt->pt_timer = prun_tmr; - } else { - struct listaddr *n = neighbor_info(vifi, src); - - if (!n) { - log(LOG_WARNING, 0, "Prune from non-neighbor %s on vif %d!?", - inet_fmt(src, s1), vifi); - return; - } - - /* allocate space for the prune structure */ - pt = (struct ptable *)(malloc(sizeof(struct ptable))); - if (pt == NULL) - log(LOG_ERR, 0, "pt: ran out of memory"); - - pt->pt_vifi = vifi; - pt->pt_router = src; - pt->pt_timer = prun_tmr; - - pt->pt_next = g->gt_pruntbl; - g->gt_pruntbl = pt; - - if (n) { - pt->pt_index = n->al_index; - NBRM_SET(n->al_index, g->gt_prunes); - } - } - - /* - * check if any more packets need to be sent on the - * vif which sent this message - */ - if (SUBS_ARE_PRUNED(r->rt_subordinates, - uvifs[vifi].uv_nbrmap, g->gt_prunes) && - !grplst_mem(vifi, prun_grp)) { - nbrbitmap_t tmp; - - VIFM_CLR(vifi, g->gt_grpmems); - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "vifnbrs=0x%08x%08x, subord=0x%08x%08x prunes=0x%08x%08x", - uvifs[vifi].uv_nbrmap.hi,uvifs[vifi].uv_nbrmap.lo, - r->rt_subordinates.hi, r->rt_subordinates.lo, - g->gt_prunes.hi, g->gt_prunes.lo); - /* XXX debugging */ - NBRM_COPY(r->rt_subordinates, tmp); - NBRM_MASK(tmp, uvifs[vifi].uv_nbrmap); - if (!NBRM_ISSETALLMASK(g->gt_prunes, tmp)) - log(LOG_WARNING, 0, "subordinate error"); - /* XXX end debugging */ - IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) - log(LOG_DEBUG, 0, "prune (%s %s), stop sending on vif %d, gm:%x", - RT_FMT(r, s1), - inet_fmt(g->gt_mcastgrp, s2), vifi, g->gt_grpmems); - - prun_add_ttls(g); - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - } - - /* - * check if all the child routers have expressed no interest - * in this group and if this group does not exist in the - * interface - * Send a prune message then upstream - */ - if (VIFM_ISEMPTY(g->gt_grpmems) && r->rt_gateway) { - send_prune(g); - } - } else { - /* - * There is no kernel entry for this group. Therefore, we can - * simply ignore the prune, as we are not forwarding this traffic - * downstream. - */ - IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) - log(LOG_DEBUG, 0, "%s (%s %s)/%d from %s", - "prune message received with no kernel entry for", - inet_fmt(prun_src, s1), inet_fmt(prun_grp, s2), - prun_tmr, inet_fmt(src, s3)); - return; - } -} - -/* - * Checks if this mcastgrp is present in the kernel table - * If so and if a prune was sent, it sends a graft upwards - */ -void -chkgrp_graft(vifi, mcastgrp) - vifi_t vifi; - u_int32 mcastgrp; -{ - struct rtentry *r; - struct gtable *g; - - for (g = kernel_table; g; g = g->gt_gnext) { - if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp)) - break; - - r = g->gt_route; - if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children)) - if (g->gt_prsent_timer) { - VIFM_SET(vifi, g->gt_grpmems); - - /* - * If the vif that was joined was a scoped vif, - * ignore it ; don't graft back - */ - APPLY_SCOPE(g); - if (VIFM_ISEMPTY(g->gt_grpmems)) - continue; - - /* send graft upwards */ - send_graft(g); - - /* update cache timer*/ - g->gt_timer = CACHE_LIFETIME(cache_lifetime); - - IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) - log(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x", - RT_FMT(r, s1), - inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems); - - prun_add_ttls(g); - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - } - } -} - -/* determine the multicast group and src - * - * if it does, then determine if a prune was sent - * upstream. - * if prune sent upstream, send graft upstream and send - * ack downstream. - * - * if no prune sent upstream, change the forwarding bit - * for this interface and send ack downstream. - * - * if no entry exists for this group send ack downstream. - */ -void -accept_graft(src, dst, p, datalen) - u_int32 src; - u_int32 dst; - char *p; - int datalen; -{ - vifi_t vifi; - u_int32 graft_src; - u_int32 graft_grp; - int i; - struct rtentry *r; - struct gtable *g; - struct ptable *pt, **ptnp; - - if (datalen < 8) { - log(LOG_WARNING, 0, - "received non-decipherable graft from %s", - inet_fmt(src, s1)); - return; - } - - for (i = 0; i< 4; i++) - ((char *)&graft_src)[i] = *p++; - for (i = 0; i< 4; i++) - ((char *)&graft_grp)[i] = *p++; - - vifi = find_vif(src, dst); - send_graft_ack(dst, src, graft_src, graft_grp, vifi); - - if (vifi == NO_VIF) { - log(LOG_INFO, 0, - "ignoring graft for (%s %s) from non-neighbor %s", - inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3), - inet_fmt(src, s1)); - return; - } - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)", - inet_fmt(src, s1), vifi, - inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3)); - - /* - * Find the subnet for the graft - */ - if (find_src_grp(graft_src, 0, graft_grp)) { - g = gtp ? gtp->gt_gnext : kernel_table; - r = g->gt_route; - - if (VIFM_ISSET(vifi, g->gt_scope)) { - log(LOG_WARNING, 0, "graft received from %s on scoped grp (%s %s)", - inet_fmt(src, s1), inet_fmt(graft_src, s2), - inet_fmt(graft_grp, s3)); - return; - } - - ptnp = &g->gt_pruntbl; - while ((pt = *ptnp) != NULL) { - if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) { - NBRM_CLR(pt->pt_index, g->gt_prunes); - *ptnp = pt->pt_next; - free(pt); - - VIFM_SET(vifi, g->gt_grpmems); - IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) - log(LOG_DEBUG, 0, "accept graft (%s %s) gm:%x", - RT_FMT(r, s1), - inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems); - - prun_add_ttls(g); - update_kernel(g); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(g,1); -#endif /* RSRR */ - break; - } else { - ptnp = &pt->pt_next; - } - } - - g->gt_timer = CACHE_LIFETIME(cache_lifetime); - - if (g->gt_prsent_timer) - /* send graft upwards */ - send_graft(g); - } else { - /* - * We have no state for the source and group in question. - * This is fine, since we know that we have no prune state, and - * grafts are requests to remove prune state. - */ - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s (%s %s) from %s", - "graft received with no kernel entry for", - inet_fmt(graft_src, s1), inet_fmt(graft_grp, s2), - inet_fmt(src, s3)); - return; - } -} - -/* - * find out which group is involved first of all - * then determine if a graft was sent. - * if no graft sent, ignore the message - * if graft was sent and the ack is from the right - * source, remove the graft timer so that we don't - * have send a graft again - */ -void -accept_g_ack(src, dst, p, datalen) - u_int32 src; - u_int32 dst; - char *p; - int datalen; -{ - struct gtable *g; - vifi_t vifi; - u_int32 grft_src; - u_int32 grft_grp; - int i; - - if ((vifi = find_vif(src, dst)) == NO_VIF) { - log(LOG_INFO, 0, - "ignoring graft ack from non-neighbor %s", - inet_fmt(src, s1)); - return; - } - - if (datalen < 0 || datalen > 8) { - log(LOG_WARNING, 0, - "received non-decipherable graft ack from %s", - inet_fmt(src, s1)); - return; - } - - for (i = 0; i< 4; i++) - ((char *)&grft_src)[i] = *p++; - for (i = 0; i< 4; i++) - ((char *)&grft_grp)[i] = *p++; - - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)", - inet_fmt(src, s1), vifi, - inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3)); - - /* - * Find the subnet for the graft ack - */ - if (find_src_grp(grft_src, 0, grft_grp)) { - g = gtp ? gtp->gt_gnext : kernel_table; - g->gt_grftsnt = 0; - } else { - log(LOG_WARNING, 0, "%s (%s, %s) from %s", - "rcvd graft ack with no kernel entry for", - inet_fmt(grft_src, s1), inet_fmt(grft_grp, s2), - inet_fmt(src, s3)); -#ifdef RINGBUFFER - printringbuf(); -#endif - return; - } -} - - -/* - * free all prune entries and kernel routes - * normally, this should inform the kernel that all of its routes - * are going away, but this is only called by restart(), which is - * about to call MRT_DONE which does that anyway. - */ -void -free_all_prunes() -{ - register struct rtentry *r; - register struct gtable *g, *prev_g; - register struct stable *s, *prev_s; - register struct ptable *p, *prev_p; - - for (r = routing_table; r; r = r->rt_next) { - g = r->rt_groups; - while (g) { - s = g->gt_srctbl; - while (s) { - prev_s = s; - s = s->st_next; - free(prev_s); - } - - p = g->gt_pruntbl; - while (p) { - prev_p = p; - p = p->pt_next; - free(prev_p); - } - - prev_g = g; - g = g->gt_next; - if (prev_g->gt_rexmit_timer) - timer_clearTimer(prev_g->gt_rexmit_timer); - free(prev_g); - } - r->rt_groups = NULL; - } - kernel_table = NULL; - - g = kernel_no_route; - while (g) { - if (g->gt_srctbl) - free(g->gt_srctbl); - - prev_g = g; - g = g->gt_next; - if (prev_g->gt_rexmit_timer) - timer_clearTimer(prev_g->gt_rexmit_timer); - free(prev_g); - } - kernel_no_route = NULL; -} - -/* - * When a new route is created, search - * a) The less-specific part of the routing table - * b) The route-less kernel table - * for sources that the new route might want to handle. - * - * "Inheriting" these sources might be cleanest, but simply deleting - * them is easier, and letting the kernel re-request them. - */ -void -steal_sources(rt) - struct rtentry *rt; -{ - register struct rtentry *rp; - register struct gtable *gt, **gtnp; - register struct stable *st, **stnp; - - for (rp = rt->rt_next; rp; rp = rp->rt_next) { - if (rp->rt_groups == NULL) - continue; - if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "Route for %s stealing sources from %s", - RT_FMT(rt, s1), RT_FMT(rp, s2)); - for (gt = rp->rt_groups; gt; gt = gt->gt_next) { - stnp = >->gt_srctbl; - while ((st = *stnp) != NULL) { - if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s", - RT_FMT(rt, s1), - inet_fmt(st->st_origin, s3), - inet_fmt(gt->gt_mcastgrp, s4), - RT_FMT(rp, s2)); - if (st->st_ctime != 0) { - if (k_del_rg(st->st_origin, gt) < 0) { - log(LOG_WARNING, errno, "%s (%s, %s)", - "steal_sources trying to delete", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - } - kroutes--; - } - *stnp = st->st_next; - free(st); - } else { - stnp = &st->st_next; - } - } - } - } - } - - gtnp = &kernel_no_route; - while ((gt = *gtnp) != NULL) { - if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask) - == rt->rt_origin)) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s", - RT_FMT(rt, s1), - inet_fmt(gt->gt_srctbl->st_origin, s3), - inet_fmt(gt->gt_mcastgrp, s4), - "no_route table"); - if (gt->gt_srctbl->st_ctime != 0) { - if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) { - log(LOG_WARNING, errno, "%s (%s %s)", - "steal_sources trying to delete", - inet_fmt(gt->gt_srctbl->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - } - kroutes--; - } - free(gt->gt_srctbl); - *gtnp = gt->gt_next; - if (gt->gt_next) - gt->gt_next->gt_prev = gt->gt_prev; - if (gt->gt_rexmit_timer) - timer_clearTimer(gt->gt_rexmit_timer); - free(gt); - } else { - gtnp = >->gt_next; - } - } -} - -/* - * Advance the timers on all the cache entries. - * If there are any entries whose timers have expired, - * remove these entries from the kernel cache. - */ -void -age_table_entry() -{ - struct rtentry *r; - struct gtable *gt, **gtnptr; - struct stable *st, **stnp; - struct ptable *pt, **ptnp; - struct sioc_sg_req sg_req; - - IF_DEBUG(DEBUG_PRUNE|DEBUG_CACHE) - log(LOG_DEBUG, 0, "aging forwarding cache entries"); - - gtnptr = &kernel_table; - while ((gt = *gtnptr) != NULL) { - vifi_t i; /* XXX Debugging */ - int fixit = 0; /* XXX Debugging */ - - r = gt->gt_route; - - /* XXX Debugging... */ - for (i = 0; i < numvifs; i++) { - /* - * If we're not sending on this vif, - * And this group isn't scoped on this vif, - * And I'm the parent for this route on this vif, - * And there are subordinates on this vif, - * And all of the subordinates haven't pruned, - * YELL LOUDLY - * and remember to fix it up later - */ - if (!VIFM_ISSET(i, gt->gt_grpmems) && - !VIFM_ISSET(i, gt->gt_scope) && - VIFM_ISSET(i, r->rt_children) && - NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates) && - !SUBS_ARE_PRUNED(r->rt_subordinates, uvifs[i].uv_nbrmap, gt->gt_prunes)) { - log(LOG_WARNING, 0, "(%s %s) is blackholing on vif %d", - RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), i); - fixit = 1; - } - } - if (fixit) { - log(LOG_WARNING, 0, "fixing membership for (%s %s) gm:%x", - RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems); - determine_forwvifs(gt); - send_prune_or_graft(gt); - log(LOG_WARNING, 0, "fixed membership for (%s %s) gm:%x", - RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems); -#ifdef RINGBUFFER - printringbuf(); -#endif - } - /*DEBUG2*/ - /* If there are group members, - * and there are recent sources, - * and we have a route, - * and it's not directly connected, - * and we haven't sent a prune, - * if there are any cache entries in the kernel - * [if there aren't we're probably waiting to rexmit], - * YELL LOUDLY - * and send a prune - */ - if (VIFM_ISEMPTY(gt->gt_grpmems) && gt->gt_srctbl && r && r->rt_gateway && gt->gt_prsent_timer == 0) { - for (st = gt->gt_srctbl; st; st = st->st_next) - if (st->st_ctime != 0) - break; - if (st != NULL) { - log(LOG_WARNING, 0, "grpmems for (%s %s) is empty but no prune state!", RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2)); - send_prune_or_graft(gt); -#ifdef RINGBUFFER - printringbuf(); -#endif - } - } - /* XXX ...Debugging */ - - /* advance the timer for the kernel entry */ - gt->gt_timer -= TIMER_INTERVAL; - - /* decrement prune timer if need be */ - if (gt->gt_prsent_timer > 0) { - gt->gt_prsent_timer -= TIMER_INTERVAL; - if (gt->gt_prsent_timer <= 0) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "upstream prune tmo (%s %s)", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - gt->gt_prsent_timer = -1; - /* Reset the prune retransmission timer to its initial value */ - gt->gt_prune_rexmit = PRUNE_REXMIT_VAL; - } - } - - /* retransmit graft with exponential backoff */ - if (gt->gt_grftsnt) { - register int y; - - y = ++gt->gt_grftsnt; - while (y && !(y & 1)) - y >>= 1; - if (y == 1) - send_graft(gt); - } - - /* - * Age prunes - * - * If a prune expires, forward again on that vif. - */ - ptnp = >->gt_pruntbl; - while ((pt = *ptnp) != NULL) { - if ((pt->pt_timer -= TIMER_INTERVAL) <= 0) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "expire prune (%s %s) from %s on vif %d", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2), - inet_fmt(pt->pt_router, s3), - pt->pt_vifi); - if (gt->gt_prsent_timer > 0) { - log(LOG_WARNING, 0, "prune (%s %s) from %s on vif %d expires with %d left on prsent timer", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2), - inet_fmt(pt->pt_router, s3), - pt->pt_vifi, gt->gt_prsent_timer); - /* Send a graft to heal the tree. */ - send_graft(gt); - } - - NBRM_CLR(pt->pt_index, gt->gt_prunes); - expire_prune(pt->pt_vifi, gt); - - /* remove the router's prune entry and await new one */ - *ptnp = pt->pt_next; - free(pt); - } else { - ptnp = &pt->pt_next; - } - } - - /* - * If the cache entry has expired, delete source table entries for - * silent sources. If there are no source entries left, and there - * are no downstream prunes, then the entry is deleted. - * Otherwise, the cache entry's timer is refreshed. - */ - if (gt->gt_timer <= 0) { - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "(%s %s) timed out, checking for traffic", - RT_FMT(gt->gt_route, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - /* Check for traffic before deleting source entries */ - sg_req.grp.s_addr = gt->gt_mcastgrp; - stnp = >->gt_srctbl; - while ((st = *stnp) != NULL) { - /* - * Source entries with no ctime are not actually in the - * kernel; they have been removed by rexmit_prune() so - * are safe to remove from the list at this point. - */ - if (st->st_ctime) { - sg_req.src.s_addr = st->st_origin; - if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) { - log(LOG_WARNING, errno, "%s (%s %s)", - "age_table_entry: SIOCGETSGCNT failing for", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - /* Make sure it gets deleted below */ - sg_req.pktcnt = st->st_pktcnt; - } - } else { - sg_req.pktcnt = st->st_pktcnt; - } - if (sg_req.pktcnt == st->st_pktcnt) { - *stnp = st->st_next; - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - if (st->st_ctime != 0) { - if (k_del_rg(st->st_origin, gt) < 0) { - log(LOG_WARNING, errno, - "age_table_entry trying to delete (%s %s)", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - } - kroutes--; - } - free(st); - } else { - st->st_pktcnt = sg_req.pktcnt; - stnp = &st->st_next; - } - } - - /* - * Retain the group entry if we have downstream prunes or if - * there is at least one source in the list that still has - * traffic, or if our upstream prune timer or graft - * retransmission timer is running. - */ - if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL || - gt->gt_prsent_timer > 0 || gt->gt_grftsnt > 0) { - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "refresh lifetim of cache entry %s%s%s%s(%s, %s)", - gt->gt_pruntbl ? "(dstrm prunes) " : "", - gt->gt_srctbl ? "(trfc flow) " : "", - gt->gt_prsent_timer > 0 ? "(upstrm prune) " : "", - gt->gt_grftsnt > 0 ? "(grft rexmit) " : "", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - gt->gt_timer = CACHE_LIFETIME(cache_lifetime); - if (gt->gt_prsent_timer == -1) { - /* - * The upstream prune timed out. Remove any kernel - * state. - */ - gt->gt_prsent_timer = 0; - if (gt->gt_pruntbl) { - log(LOG_WARNING, 0, "upstream prune for (%s %s) expires with downstream prunes active", - RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2)); - } - remove_sources(gt); - } - gtnptr = >->gt_gnext; - continue; - } - - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - - if (gt->gt_prev) - gt->gt_prev->gt_next = gt->gt_next; - else - gt->gt_route->rt_groups = gt->gt_next; - if (gt->gt_next) - gt->gt_next->gt_prev = gt->gt_prev; - - if (gt->gt_gprev) { - gt->gt_gprev->gt_gnext = gt->gt_gnext; - gtnptr = >->gt_gprev->gt_gnext; - } else { - kernel_table = gt->gt_gnext; - gtnptr = &kernel_table; - } - if (gt->gt_gnext) - gt->gt_gnext->gt_gprev = gt->gt_gprev; - -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(gt,0); - rsrr_cache_clean(gt); -#endif /* RSRR */ - if (gt->gt_rexmit_timer) - timer_clearTimer(gt->gt_rexmit_timer); - - free((char *)gt); - } else { - if (gt->gt_prsent_timer == -1) { - /* - * The upstream prune timed out. Remove any kernel - * state. - */ - gt->gt_prsent_timer = 0; - if (gt->gt_pruntbl) { - log(LOG_WARNING, 0, "upstream prune for (%s %s) expires with downstream prunes active", - RT_FMT(r, s1), inet_fmt(gt->gt_mcastgrp, s2)); - } - remove_sources(gt); - } - gtnptr = >->gt_gnext; - } - } - - /* - * When traversing the no_route table, the decision is much easier. - * Just delete it if it has timed out. - */ - gtnptr = &kernel_no_route; - while ((gt = *gtnptr) != NULL) { - /* advance the timer for the kernel entry */ - gt->gt_timer -= TIMER_INTERVAL; - - if (gt->gt_timer < 0) { - if (gt->gt_srctbl) { - if (gt->gt_srctbl->st_ctime != 0) { - if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) { - log(LOG_WARNING, errno, "%s (%s %s)", - "age_table_entry trying to delete no-route", - inet_fmt(gt->gt_srctbl->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - } - kroutes--; - } - free(gt->gt_srctbl); - } - *gtnptr = gt->gt_next; - if (gt->gt_next) - gt->gt_next->gt_prev = gt->gt_prev; - - if (gt->gt_rexmit_timer) - timer_clearTimer(gt->gt_rexmit_timer); - - free((char *)gt); - } else { - gtnptr = >->gt_next; - } - } -} - -/* - * Modify the kernel to forward packets when one or multiple prunes that - * were received on the vif given by vifi, for the group given by gt, - * have expired. - */ -static void -expire_prune(vifi, gt) - vifi_t vifi; - struct gtable *gt; -{ - /* - * No need to send a graft, any prunes that we sent - * will expire before any prunes that we have received. - * However, in the case that we did make a mistake, - * send a graft to compensate. - */ - if (gt->gt_prsent_timer >= MIN_PRUNE_LIFE) { - IF_DEBUG(DEBUG_PRUNE) - log(LOG_DEBUG, 0, "prune expired with %d left on %s", - gt->gt_prsent_timer, "prsent_timer"); - gt->gt_prsent_timer = 0; - send_graft(gt); - } - - /* modify the kernel entry to forward packets */ - if (!VIFM_ISSET(vifi, gt->gt_grpmems)) { - struct rtentry *rt = gt->gt_route; - VIFM_SET(vifi, gt->gt_grpmems); - IF_DEBUG(DEBUG_CACHE) - log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d", - RT_FMT(rt, s1), - inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi); - - prun_add_ttls(gt); - update_kernel(gt); -#ifdef RSRR - /* Send route change notification to reservation protocol. */ - rsrr_cache_send(gt,1); -#endif /* RSRR */ - } -} - -/* - * Print the contents of the cache table on file 'fp2'. - */ -void -dump_cache(fp2) - FILE *fp2; -{ - register struct rtentry *r; - register struct gtable *gt; - register struct stable *st; - register struct ptable *pt; - register vifi_t i; - char c; - register time_t thyme = time(0); - - fprintf(fp2, - "Multicast Routing Cache Table (%d entries)\n%s", kroutes, - " Origin Mcast-group CTmr Age Ptmr Rx IVif Forwvifs\n"); - fprintf(fp2, - "<(prunesrc:vif[idx]/tmr) prunebitmap\n%s", - ">Source Lifetime SavPkt Pkts Bytes RPFf\n"); - - for (gt = kernel_no_route; gt; gt = gt->gt_next) { - if (gt->gt_srctbl) { - fprintf(fp2, " %-18s %-15s %-8s %-8s - -1 (no route)\n", - inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1), - inet_fmt(gt->gt_mcastgrp, s2), scaletime(gt->gt_timer), - scaletime(thyme - gt->gt_ctime)); - fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin, s1)); - } - } - - for (gt = kernel_table; gt; gt = gt->gt_gnext) { - r = gt->gt_route; - fprintf(fp2, " %-18s %-15s", - RT_FMT(r, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - - fprintf(fp2, " %-8s", scaletime(gt->gt_timer)); - - fprintf(fp2, " %-8s %-8s ", scaletime(thyme - gt->gt_ctime), - gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) : - " -"); - - if (gt->gt_prune_rexmit) { - int i = gt->gt_prune_rexmit; - int n = 0; - - while (i > PRUNE_REXMIT_VAL) { - n++; - i /= 2; - } - if (n == 0 && gt->gt_prsent_timer == 0) - fprintf(fp2, " -"); - else - fprintf(fp2, "%2d", n); - } else { - fprintf(fp2, " -"); - } - - fprintf(fp2, " %2u%c%c", r->rt_parent, - gt->gt_prsent_timer ? 'P' : - gt->gt_grftsnt ? 'G' : ' ', - VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' '); - - for (i = 0; i < numvifs; ++i) { - if (VIFM_ISSET(i, gt->gt_grpmems)) - fprintf(fp2, " %u ", i); - else if (VIFM_ISSET(i, r->rt_children) && - NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates)) - fprintf(fp2, " %u%c", i, - VIFM_ISSET(i, gt->gt_scope) ? 'b' : - SUBS_ARE_PRUNED(r->rt_subordinates, - uvifs[i].uv_nbrmap, gt->gt_prunes) ? 'p' : '!'); - } - fprintf(fp2, "\n"); - if (gt->gt_pruntbl) { - fprintf(fp2, "<"); - c = '('; - for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) { - fprintf(fp2, "%c%s:%d[%d]/%d", c, inet_fmt(pt->pt_router, s1), - pt->pt_vifi, pt->pt_index, pt->pt_timer); - c = ','; - } - fprintf(fp2, ")"); - fprintf(fp2, " 0x%08lx%08lx\n",/*XXX*/ - gt->gt_prunes.hi, gt->gt_prunes.lo); - } - for (st = gt->gt_srctbl; st; st = st->st_next) { - fprintf(fp2, ">%-18s %-8s %6ld", inet_fmt(st->st_origin, s1), - st->st_ctime ? scaletime(thyme - st->st_ctime) : "-", - st->st_savpkt); - if (st->st_ctime) { - struct sioc_sg_req sg_req; - - sg_req.src.s_addr = st->st_origin; - sg_req.grp.s_addr = gt->gt_mcastgrp; - if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) { - log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)", - inet_fmt(st->st_origin, s1), - inet_fmt(gt->gt_mcastgrp, s2)); - } else { - fprintf(fp2, " %8ld %8ld %4ld", sg_req.pktcnt, - sg_req.bytecnt, sg_req.wrong_if); - } - } - fprintf(fp2, "\n"); - } - } -} - -/* - * Traceroute function which returns traceroute replies to the requesting - * router. Also forwards the request to downstream routers. - */ -void -accept_mtrace(src, dst, group, data, no, datalen) - u_int32 src; - u_int32 dst; - u_int32 group; - char *data; - u_int no; /* promoted u_char */ - int datalen; -{ - u_char type; - struct rtentry *rt; - struct gtable *gt; - struct tr_query *qry; - struct tr_resp *resp; - int vifi; - char *p; - int rcount; - int errcode = TR_NO_ERR; - int resptype; - struct timeval tp; - struct sioc_vif_req v_req; - struct sioc_sg_req sg_req; - - /* Remember qid across invocations */ - static u_int32 oqid = 0; - - /* timestamp the request/response */ - gettimeofday(&tp, 0); - - /* - * Check if it is a query or a response - */ - if (datalen == QLEN) { - type = QUERY; - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); - } - else if ((datalen - QLEN) % RLEN == 0) { - type = RESP; - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); - if (IN_MULTICAST(ntohl(dst))) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Dropping multicast response"); - return; - } - } - else { - log(LOG_WARNING, 0, "%s from %s to %s", - "Non decipherable traceroute request recieved", - inet_fmt(src, s1), inet_fmt(dst, s2)); - return; - } - - qry = (struct tr_query *)data; - - /* - * if it is a packet with all reports filled, drop it - */ - if ((rcount = (datalen - QLEN)/RLEN) == no) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "packet with all reports filled in"); - return; - } - - IF_DEBUG(DEBUG_TRACE) { - log(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1), - inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3)); - log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl, - inet_fmt(qry->tr_raddr, s1)); - log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid); - } - - /* determine the routing table entry for this traceroute */ - rt = determine_route(qry->tr_src); - IF_DEBUG(DEBUG_TRACE) - if (rt) { - log(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d", - rt->rt_parent, inet_fmt(rt->rt_gateway, s1), rt->rt_metric); - log(LOG_DEBUG, 0, "rt origin %s", - RT_FMT(rt, s1)); - } else - log(LOG_DEBUG, 0, "...no route"); - - /* - * Query type packet - check if rte exists - * Check if the query destination is a vif connected to me. - * and if so, whether I should start response back - */ - if (type == QUERY) { - if (oqid == qry->tr_qid) { - /* - * If the multicast router is a member of the group being - * queried, and the query is multicasted, then the router can - * recieve multiple copies of the same query. If we have already - * replied to this traceroute, just ignore it this time. - * - * This is not a total solution, but since if this fails you - * only get N copies, N <= the number of interfaces on the router, - * it is not fatal. - */ - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet"); - return; - } - - if (rt == NULL) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s", - inet_fmt(qry->tr_src, s1)); - if (IN_MULTICAST(ntohl(dst))) - return; - } - vifi = find_vif(qry->tr_dst, 0); - - if (vifi == NO_VIF) { - /* The traceroute destination is not on one of my subnet vifs. */ - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Destination %s not an interface", - inet_fmt(qry->tr_dst, s1)); - if (IN_MULTICAST(ntohl(dst))) - return; - errcode = TR_WRONG_IF; - } else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", - inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2)); - if (IN_MULTICAST(ntohl(dst))) - return; - errcode = TR_WRONG_IF; - } - } - else { - /* - * determine which interface the packet came in on - * RESP packets travel hop-by-hop so this either traversed - * a tunnel or came from a directly attached mrouter. - */ - if ((vifi = find_vif(src, dst)) == NO_VIF) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Wrong interface for packet"); - errcode = TR_WRONG_IF; - } - } - - /* Now that we've decided to send a response, save the qid */ - oqid = qry->tr_qid; - - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Sending traceroute response"); - - /* copy the packet to the sending buffer */ - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - - bcopy(data, p, datalen); - - p += datalen; - - /* - * If there is no room to insert our reply, coopt the previous hop - * error indication to relay this fact. - */ - if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE) { - resp = (struct tr_resp *)p - 1; - resp->tr_rflags = TR_NO_SPACE; - rt = NULL; - goto sendit; - } - - /* - * fill in initial response fields - */ - resp = (struct tr_resp *)p; - bzero(resp, sizeof(struct tr_resp)); - datalen += RLEN; - - resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) + - ((tp.tv_usec << 10) / 15625)); - - resp->tr_rproto = PROTO_DVMRP; - resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr; - resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold; - resp->tr_rflags = errcode; - - /* - * obtain # of packets out on interface - */ - v_req.vifi = vifi; - if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) - resp->tr_vifout = htonl(v_req.ocount); - else - resp->tr_vifout = 0xffffffff; - - /* - * fill in scoping & pruning information - */ - if (rt) - for (gt = rt->rt_groups; gt; gt = gt->gt_next) { - if (gt->gt_mcastgrp >= group) - break; - } - else - gt = NULL; - - if (gt && gt->gt_mcastgrp == group) { - struct stable *st; - - for (st = gt->gt_srctbl; st; st = st->st_next) - if (qry->tr_src == st->st_origin) - break; - - sg_req.src.s_addr = qry->tr_src; - sg_req.grp.s_addr = group; - if (st && st->st_ctime != 0 && - ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0) - resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt); - else - resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff); - - if (VIFM_ISSET(vifi, gt->gt_scope)) - resp->tr_rflags = TR_SCOPED; - else if (gt->gt_prsent_timer) - resp->tr_rflags = TR_PRUNED; - else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) - if (!NBRM_ISEMPTY(uvifs[vifi].uv_nbrmap) && - SUBS_ARE_PRUNED(rt->rt_subordinates, - uvifs[vifi].uv_nbrmap, gt->gt_prunes)) - resp->tr_rflags = TR_OPRUNED; - else - resp->tr_rflags = TR_NO_FWD; - } else { - if ((vifi != NO_VIF && scoped_addr(vifi, group)) || - (rt && scoped_addr(rt->rt_parent, group))) - resp->tr_rflags = TR_SCOPED; - else if (rt && !VIFM_ISSET(vifi, rt->rt_children)) - resp->tr_rflags = TR_NO_FWD; - } - - /* - * if no rte exists, set NO_RTE error - */ - if (rt == NULL) { - src = dst; /* the dst address of resp. pkt */ - resp->tr_inaddr = 0; - resp->tr_rflags = TR_NO_RTE; - resp->tr_rmtaddr = 0; - } else { - /* get # of packets in on interface */ - v_req.vifi = rt->rt_parent; - if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) - resp->tr_vifin = htonl(v_req.icount); - else - resp->tr_vifin = 0xffffffff; - - MASK_TO_VAL(rt->rt_originmask, resp->tr_smask); - src = uvifs[rt->rt_parent].uv_lcl_addr; - resp->tr_inaddr = src; - resp->tr_rmtaddr = rt->rt_gateway; - if (!VIFM_ISSET(vifi, rt->rt_children)) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", - inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2)); - resp->tr_rflags = TR_WRONG_IF; - } - if (rt->rt_metric >= UNREACHABLE) { - resp->tr_rflags = TR_NO_RTE; - /* Hack to send reply directly */ - rt = NULL; - } - } - -sendit: - /* - * if metric is 1 or no. of reports is 1, send response to requestor - * else send to upstream router. If the upstream router can't handle - * mtrace, set an error code and send to requestor anyway. - */ - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no); - - if ((rcount + 1 == no) || (rt == NULL) || (rt->rt_metric == 1)) { - resptype = IGMP_MTRACE_RESP; - dst = qry->tr_raddr; - } else - if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) { - dst = qry->tr_raddr; - resp->tr_rflags = TR_OLD_ROUTER; - resptype = IGMP_MTRACE_RESP; - } else { - dst = rt->rt_gateway; - resptype = IGMP_MTRACE; - } - - if (IN_MULTICAST(ntohl(dst))) { - /* - * Send the reply on a known multicast capable vif. - * If we don't have one, we can't source any multicasts anyway. - */ - if (phys_vif != -1) { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Sending reply to %s from %s", - inet_fmt(dst, s1), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2)); - k_set_ttl(qry->tr_rttl); - send_igmp(uvifs[phys_vif].uv_lcl_addr, dst, - resptype, no, group, - datalen); - k_set_ttl(1); - } else - log(LOG_INFO, 0, "No enabled phyints -- %s", - "dropping traceroute reply"); - } else { - IF_DEBUG(DEBUG_TRACE) - log(LOG_DEBUG, 0, "Sending %s to %s from %s", - resptype == IGMP_MTRACE_RESP ? "reply" : "request on", - inet_fmt(dst, s1), inet_fmt(src, s2)); - - send_igmp(src, dst, - resptype, no, group, - datalen); - } - return; -} diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h deleted file mode 100644 index 375fada..0000000 --- a/usr.sbin/mrouted/prune.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * prune.h,v 3.8.4.5 1998/02/27 22:45:43 fenner Exp - */ - -/* - * Group table - * - * Each group entry is a member of two doubly-linked lists: - * - * a) A list hanging off of the routing table entry for this source (rt_groups) - * sorted by group address under the routing entry (gt_next, gt_prev) - * b) An independent list pointed to by kernel_table, which is a list of - * active source,group's (gt_gnext, gt_gprev). - * - */ -struct gtable { - struct gtable *gt_next; /* pointer to the next entry */ - struct gtable *gt_prev; /* back pointer for linked list */ - struct gtable *gt_gnext; /* fwd pointer for group list */ - struct gtable *gt_gprev; /* rev pointer for group list */ - u_int32 gt_mcastgrp; /* multicast group associated */ - vifbitmap_t gt_scope; /* scoped interfaces */ - u_char gt_ttls[MAXVIFS]; /* ttl vector for forwarding */ - vifbitmap_t gt_grpmems; /* forw. vifs for src, grp */ - int gt_prsent_timer; /* prune timer for this group */ - int gt_timer; /* timer for this group entry */ - time_t gt_ctime; /* time of entry creation */ - u_char gt_grftsnt; /* graft sent/retransmit timer */ - nbrbitmap_t gt_prunes; /* bitmap of neighbors who pruned */ - struct stable *gt_srctbl; /* source table */ - struct ptable *gt_pruntbl; /* prune table */ - struct rtentry *gt_route; /* parent route */ - int gt_rexmit_timer; /* timer for prune retransmission */ - int gt_prune_rexmit; /* time til prune retransmission */ -#ifdef RSRR - struct rsrr_cache *gt_rsrr_cache; /* RSRR cache */ -#endif /* RSRR */ -}; - -/* - * Source table - * - * When source-based prunes exist, there will be a struct ptable here as well. - */ -struct stable -{ - struct stable *st_next; /* pointer to the next entry */ - u_int32 st_origin; /* host origin of multicasts */ - u_long st_pktcnt; /* packet count for src-grp entry */ - u_long st_savpkt; /* saved pkt cnt when no krnl entry */ - time_t st_ctime; /* kernel entry creation time */ -}; - -/* - * structure to store incoming prunes. Can hang off of either group or source. - */ -struct ptable -{ - struct ptable *pt_next; /* pointer to the next entry */ - u_int32 pt_router; /* router that sent this prune */ - vifi_t pt_vifi; /* vif prune received on */ - int pt_index; /* neighbor index of router */ - int pt_timer; /* timer for prune */ -}; - -#define MIN_PRUNE_LIFE TIMER_INTERVAL /* min prune lifetime to bother with */ - -/* - * The packet format for a traceroute request. - */ -struct tr_query { - u_int32 tr_src; /* traceroute source */ - u_int32 tr_dst; /* traceroute destination */ - u_int32 tr_raddr; /* traceroute response address */ -#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) - struct { - u_int qid : 24; /* traceroute query id */ - u_int ttl : 8; /* traceroute response ttl */ - } q; -#else - struct { - u_int ttl : 8; /* traceroute response ttl */ - u_int qid : 24; /* traceroute query id */ - } q; -#endif /* BYTE_ORDER */ -}; - -#define tr_rttl q.ttl -#define tr_qid q.qid - -/* - * Traceroute response format. A traceroute response has a tr_query at the - * beginning, followed by one tr_resp for each hop taken. - */ -struct tr_resp { - u_int32 tr_qarr; /* query arrival time */ - u_int32 tr_inaddr; /* incoming interface address */ - u_int32 tr_outaddr; /* outgoing interface address */ - u_int32 tr_rmtaddr; /* parent address in source tree */ - u_int32 tr_vifin; /* input packet count on interface */ - u_int32 tr_vifout; /* output packet count on interface */ - u_int32 tr_pktcnt; /* total incoming packets for src-grp */ - u_char tr_rproto; /* routing protocol deployed on router */ - u_char tr_fttl; /* ttl required to forward on outvif */ - u_char tr_smask; /* subnet mask for src addr */ - u_char tr_rflags; /* forwarding error codes */ -}; - -/* defs within mtrace */ -#define QUERY 1 -#define RESP 2 -#define QLEN sizeof(struct tr_query) -#define RLEN sizeof(struct tr_resp) - -/* fields for tr_rflags (forwarding error codes) */ -#define TR_NO_ERR 0 -#define TR_WRONG_IF 1 -#define TR_PRUNED 2 -#define TR_OPRUNED 3 -#define TR_SCOPED 4 -#define TR_NO_RTE 5 -#define TR_NO_FWD 7 -#define TR_NO_SPACE 0x81 -#define TR_OLD_ROUTER 0x82 - -/* fields for tr_rproto (routing protocol) */ -#define PROTO_DVMRP 1 -#define PROTO_MOSPF 2 -#define PROTO_PIM 3 -#define PROTO_CBT 4 - -#define MASK_TO_VAL(x, i) { \ - u_int32 _x = ntohl(x); \ - (i) = 1; \ - while ((_x) <<= 1) \ - (i)++; \ - }; - -#define VAL_TO_MASK(x, i) { \ - x = i ? htonl(~((1 << (32 - (i))) - 1)) : 0; \ - }; - -#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv) diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c deleted file mode 100644 index b269539..0000000 --- a/usr.sbin/mrouted/route.c +++ /dev/null @@ -1,1475 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * route.c,v 3.8.4.41 1998/01/15 00:08:34 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" - -/* - * This define statement saves a lot of space later - */ -#define RT_ADDR (struct rtentry *)&routing_table - -/* - * Exported variables. - */ -int routes_changed; /* 1=>some routes have changed */ -int delay_change_reports; /* 1=>postpone change reports */ - - -/* - * The routing table is shared with prune.c , so must not be static. - */ -struct rtentry *routing_table; /* pointer to list of route entries */ - -/* - * Private variables. - */ -static struct rtentry *rtp; /* pointer to a route entry */ -static struct rtentry *rt_end; /* pointer to last route entry */ -unsigned int nroutes; /* current number of route entries */ - -/* - * Private functions. - */ -static int init_children_and_leaves __P((struct rtentry *r, - vifi_t parent, int first)); -static int find_route __P((u_int32 origin, u_int32 mask)); -static void create_route __P((u_int32 origin, u_int32 mask)); -static void discard_route __P((struct rtentry *prev_r)); -static int compare_rts __P((const void *rt1, const void *rt2)); -static int report_chunk __P((int, struct rtentry *start_rt, vifi_t vifi, - u_int32 dst)); -static void queue_blaster_report __P((vifi_t, u_int32, u_int32, char *, - int, u_int32)); -static void process_blaster_report __P((void *)); - -#ifdef SNMP -#include <sys/types.h> -#include "snmp.h" - -/* - * Return pointer to a specific route entry. This must be a separate - * function from find_route() which modifies rtp. - */ -struct rtentry * -snmp_find_route(src, mask) - register u_int32 src, mask; -{ - register struct rtentry *rt; - - for (rt = routing_table; rt; rt = rt->rt_next) { - if (src == rt->rt_origin && mask == rt->rt_originmask) - return rt; - } - return NULL; -} - -/* - * Find next route entry > specification - */ -int -next_route(rtpp, src, mask) - struct rtentry **rtpp; - u_int32 src; - u_int32 mask; -{ - struct rtentry *rt, *rbest = NULL; - - /* Among all entries > spec, find "lowest" one in order */ - for (rt = routing_table; rt; rt=rt->rt_next) { - if ((ntohl(rt->rt_origin) > ntohl(src) - || (ntohl(rt->rt_origin) == ntohl(src) - && ntohl(rt->rt_originmask) > ntohl(mask))) - && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin)) - || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin) - && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask)))) - rbest = rt; - } - (*rtpp) = rbest; - return (*rtpp)!=0; -} - -/* - * Given a routing table entry, and a vifi, find the next vifi/entry - */ -int -next_route_child(rtpp, src, mask, vifi) - struct rtentry **rtpp; - u_int32 src; - u_int32 mask; - vifi_t *vifi; /* vif at which to start looking */ -{ - /* Get (S,M) entry */ - if (!((*rtpp) = snmp_find_route(src,mask))) - if (!next_route(rtpp, src, mask)) - return 0; - - /* Continue until we get one with a valid next vif */ - do { - for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++) - if (VIFM_ISSET(*vifi, (*rtpp)->rt_children)) - return 1; - *vifi = 0; - } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) ); - - return 0; -} -#endif - -/* - * Initialize the routing table and associated variables. - */ -void -init_routes() -{ - routing_table = NULL; - rt_end = RT_ADDR; - nroutes = 0; - routes_changed = FALSE; - delay_change_reports = FALSE; -} - - -/* - * Initialize the children bits for route 'r', along with the - * associated dominant and subordinate data structures. - * If first is set, initialize dominants, otherwise keep old - * dominants on non-parent interfaces. - * XXX Does this need a return value? - */ -static int -init_children_and_leaves(r, parent, first) - register struct rtentry *r; - register vifi_t parent; - int first; -{ - register vifi_t vifi; - register struct uvif *v; - vifbitmap_t old_children; - nbrbitmap_t old_subords; - - VIFM_COPY(r->rt_children, old_children); - NBRM_COPY(r->rt_subordinates, old_subords); - - VIFM_CLRALL(r->rt_children); - - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (first || vifi == parent) - r->rt_dominants [vifi] = 0; - if (vifi == parent || uvifs[vifi].uv_flags & VIFF_NOFLOOD || - AVOID_TRANSIT(vifi, r) || (!first && r->rt_dominants[vifi])) - NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - else - NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - - if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) && - !(!first && r->rt_dominants[vifi])) { - VIFM_SET(vifi, r->rt_children); - } - } - - return (!VIFM_SAME(r->rt_children, old_children) || - !NBRM_SAME(r->rt_subordinates, old_subords)); -} - - -/* - * A new vif has come up -- update the children bitmaps in all route - * entries to take that into account. - */ -void -add_vif_to_routes(vifi) - register vifi_t vifi; -{ - register struct rtentry *r; - register struct uvif *v; - - v = &uvifs[vifi]; - for (r = routing_table; r != NULL; r = r->rt_next) { - if (r->rt_metric != UNREACHABLE && - !VIFM_ISSET(vifi, r->rt_children)) { - VIFM_SET(vifi, r->rt_children); - r->rt_dominants [vifi] = 0; - /*XXX isn't uv_nbrmap going to be empty?*/ - NBRM_CLRMASK(r->rt_subordinates, v->uv_nbrmap); - update_table_entry(r, r->rt_gateway); - } - } -} - - -/* - * A vif has gone down -- expire all routes that have that vif as parent, - * and update the children bitmaps in all other route entries to take into - * account the failed vif. - */ -void -delete_vif_from_routes(vifi) - register vifi_t vifi; -{ - register struct rtentry *r; - - for (r = routing_table; r != NULL; r = r->rt_next) { - if (r->rt_metric != UNREACHABLE) { - if (vifi == r->rt_parent) { - del_table_entry(r, 0, DEL_ALL_ROUTES); - r->rt_timer = ROUTE_EXPIRE_TIME; - r->rt_metric = UNREACHABLE; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } - else if (VIFM_ISSET(vifi, r->rt_children)) { - VIFM_CLR(vifi, r->rt_children); - NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - update_table_entry(r, r->rt_gateway); - } - else { - r->rt_dominants[vifi] = 0; - } - } - } -} - - -/* - * A new neighbor has come up. If we're flooding on the neighbor's - * vif, mark that neighbor as subordinate for all routes whose parent - * is not this vif. - */ -void -add_neighbor_to_routes(vifi, index) - register vifi_t vifi; - register int index; -{ - register struct rtentry *r; - register struct uvif *v; - - v = &uvifs[vifi]; - if (v->uv_flags & VIFF_NOFLOOD) - return; - for (r = routing_table; r != NULL; r = r->rt_next) { - if (r->rt_metric != UNREACHABLE && r->rt_parent != vifi && - !AVOID_TRANSIT(vifi, r)) { - NBRM_SET(index, r->rt_subordinates); - update_table_entry(r, r->rt_gateway); - } - } -} - - -/* - * A neighbor has failed or become unreachable. If that neighbor was - * considered a dominant or subordinate router in any route entries, - * take appropriate action. Expire all routes this neighbor advertised - * to us. - */ -void -delete_neighbor_from_routes(addr, vifi, index) - register u_int32 addr; - register vifi_t vifi; - int index; -{ - register struct rtentry *r; - register struct uvif *v; - - v = &uvifs[vifi]; - for (r = routing_table; r != NULL; r = r->rt_next) { - if (r->rt_metric != UNREACHABLE) { - if (r->rt_parent == vifi && r->rt_gateway == addr) { - del_table_entry(r, 0, DEL_ALL_ROUTES); - r->rt_timer = ROUTE_EXPIRE_TIME; - r->rt_metric = UNREACHABLE; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } else if (r->rt_dominants[vifi] == addr) { - VIFM_SET(vifi, r->rt_children); - r->rt_dominants[vifi] = 0; - if ((uvifs[vifi].uv_flags & VIFF_NOFLOOD) || - AVOID_TRANSIT(vifi, r)) - NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - else - NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - update_table_entry(r, r->rt_gateway); - } else if (NBRM_ISSET(index, r->rt_subordinates)) { - NBRM_CLR(index, r->rt_subordinates); - update_table_entry(r, r->rt_gateway); - } - } - } -} - - -/* - * Prepare for a sequence of ordered route updates by initializing a pointer - * to the start of the routing table. The pointer is used to remember our - * position in the routing table in order to avoid searching from the - * beginning for each update; this relies on having the route reports in - * a single message be in the same order as the route entries in the routing - * table. - */ -void -start_route_updates() -{ - rtp = RT_ADDR; -} - - -/* - * Starting at the route entry following the one to which 'rtp' points, - * look for a route entry matching the specified origin and mask. If a - * match is found, return TRUE and leave 'rtp' pointing at the found entry. - * If no match is found, return FALSE and leave 'rtp' pointing to the route - * entry preceding the point at which the new origin should be inserted. - * This code is optimized for the normal case in which the first entry to - * be examined is the matching entry. - */ -static int -find_route(origin, mask) - register u_int32 origin, mask; -{ - register struct rtentry *r; - - r = rtp->rt_next; - while (r != NULL) { - if (origin == r->rt_origin && mask == r->rt_originmask) { - rtp = r; - return (TRUE); - } - if (ntohl(mask) < ntohl(r->rt_originmask) || - (mask == r->rt_originmask && - ntohl(origin) < ntohl(r->rt_origin))) { - rtp = r; - r = r->rt_next; - } - else break; - } - return (FALSE); -} - -/* - * Create a new routing table entry for the specified origin and link it into - * the routing table. The shared variable 'rtp' is assumed to point to the - * routing entry after which the new one should be inserted. It is left - * pointing to the new entry. - * - * Only the origin, originmask, originwidth and flags fields are initialized - * in the new route entry; the caller is responsible for filling in the the - * rest. - */ -static void -create_route(origin, mask) - u_int32 origin, mask; -{ - register struct rtentry *r; - - if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) + - (numvifs * sizeof(u_int32)))) == NULL) { - log(LOG_ERR, 0, "ran out of memory"); /* fatal */ - } - r->rt_origin = origin; - r->rt_originmask = mask; - if (((char *)&mask)[3] != 0) r->rt_originwidth = 4; - else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3; - else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2; - else r->rt_originwidth = 1; - r->rt_flags = 0; - r->rt_dominants = (u_int32 *)(r + 1); - bzero(r->rt_dominants, numvifs * sizeof(u_int32)); - r->rt_groups = NULL; - VIFM_CLRALL(r->rt_children); - NBRM_CLRALL(r->rt_subordinates); - NBRM_CLRALL(r->rt_subordadv); - - r->rt_next = rtp->rt_next; - rtp->rt_next = r; - r->rt_prev = rtp; - if (r->rt_next != NULL) - (r->rt_next)->rt_prev = r; - else - rt_end = r; - rtp = r; - ++nroutes; -} - - -/* - * Discard the routing table entry following the one to which 'prev_r' points. - */ -static void -discard_route(prev_r) - register struct rtentry *prev_r; -{ - register struct rtentry *r; - - r = prev_r->rt_next; - uvifs[r->rt_parent].uv_nroutes--; - /*???nbr???.al_nroutes--;*/ - prev_r->rt_next = r->rt_next; - if (prev_r->rt_next != NULL) - (prev_r->rt_next)->rt_prev = prev_r; - else - rt_end = prev_r; - free((char *)r); - --nroutes; -} - - -/* - * Process a route report for a single origin, creating or updating the - * corresponding routing table entry if necessary. 'src' is either the - * address of a neighboring router from which the report arrived, or zero - * to indicate a change of status of one of our own interfaces. - */ -void -update_route(origin, mask, metric, src, vifi, n) - u_int32 origin, mask; - u_int metric; - u_int32 src; - vifi_t vifi; - struct listaddr *n; -{ - register struct rtentry *r; - u_int adj_metric; - - /* - * Compute an adjusted metric, taking into account the cost of the - * subnet or tunnel over which the report arrived, and normalizing - * all unreachable/poisoned metrics into a single value. - */ - if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) { - log(LOG_WARNING, 0, - "%s reports out-of-range metric %u for origin %s", - inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2)); - return; - } - adj_metric = metric + uvifs[vifi].uv_metric; - if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE; - - /* - * Look up the reported origin in the routing table. - */ - if (!find_route(origin, mask)) { - /* - * Not found. - * Don't create a new entry if the report says it's unreachable, - * or if the reported origin and mask are invalid. - */ - if (adj_metric == UNREACHABLE) { - return; - } - if (src != 0 && !inet_valid_subnet(origin, mask)) { - log(LOG_WARNING, 0, - "%s reports an invalid origin (%s) and/or mask (%08x)", - inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask)); - return; - } - - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s advertises new route %s", - inet_fmt(src, s1), inet_fmts(origin, mask, s2)); - - /* - * OK, create the new routing entry. 'rtp' will be left pointing - * to the new entry. - */ - create_route(origin, mask); - uvifs[vifi].uv_nroutes++; - /*n->al_nroutes++;*/ - - rtp->rt_metric = UNREACHABLE; /* temporary; updated below */ - } - - /* - * We now have a routing entry for the reported origin. Update it? - */ - r = rtp; - if (r->rt_metric == UNREACHABLE) { - /* - * The routing entry is for a formerly-unreachable or new origin. - * If the report claims reachability, update the entry to use - * the reported route. - */ - if (adj_metric == UNREACHABLE) - return; - - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s advertises %s with adj_metric %d (ours was %d)", - inet_fmt(src, s1), inet_fmts(origin, mask, s2), - adj_metric, r->rt_metric); - - /* - * Now "steal away" any sources that belong under this route - * by deleting any cache entries they might have created - * and allowing the kernel to re-request them. - * - * If we haven't performed final initialization yet and are - * just collecting the routing table, we can't have any - * sources so we don't perform this step. - */ - if (did_final_init) - steal_sources(rtp); - - r->rt_parent = vifi; - r->rt_gateway = src; - init_children_and_leaves(r, vifi, 1); - - r->rt_timer = 0; - r->rt_metric = adj_metric; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - update_table_entry(r, r->rt_gateway); - } - else if (src == r->rt_gateway) { - /* - * The report has come either from the interface directly-connected - * to the origin subnet (src and r->rt_gateway both equal zero) or - * from the gateway we have chosen as the best first-hop gateway back - * towards the origin (src and r->rt_gateway not equal zero). Reset - * the route timer and, if the reported metric has changed, update - * our entry accordingly. - */ - r->rt_timer = 0; - - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s (current parent) advertises %s with adj_metric %d (ours was %d)", - inet_fmt(src, s1), inet_fmts(origin, mask, s2), - adj_metric, r->rt_metric); - - if (adj_metric == r->rt_metric) - return; - - if (adj_metric == UNREACHABLE) { - del_table_entry(r, 0, DEL_ALL_ROUTES); - r->rt_timer = ROUTE_EXPIRE_TIME; - } - r->rt_metric = adj_metric; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } - else if (src == 0 || - (r->rt_gateway != 0 && - (adj_metric < r->rt_metric || - (adj_metric == r->rt_metric && - (ntohl(src) < ntohl(r->rt_gateway) || - r->rt_timer >= ROUTE_SWITCH_TIME))))) { - /* - * The report is for an origin we consider reachable; the report - * comes either from one of our own interfaces or from a gateway - * other than the one we have chosen as the best first-hop gateway - * back towards the origin. If the source of the update is one of - * our own interfaces, or if the origin is not a directly-connected - * subnet and the reported metric for that origin is better than - * what our routing entry says, update the entry to use the new - * gateway and metric. We also switch gateways if the reported - * metric is the same as the one in the route entry and the gateway - * associated with the route entry has not been heard from recently, - * or if the metric is the same but the reporting gateway has a lower - * IP address than the gateway associated with the route entry. - * Did you get all that? - */ - u_int32 old_gateway; - vifi_t old_parent; - old_gateway = r->rt_gateway; - old_parent = r->rt_parent; - r->rt_gateway = src; - r->rt_parent = vifi; - - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s (new parent) on vif %d advertises %s with adj_metric %d (old parent was %s on vif %d, metric %d)", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - adj_metric, inet_fmt(old_gateway, s3), old_parent, - r->rt_metric); - - if (old_parent != vifi) { - init_children_and_leaves(r, vifi, 0); - uvifs[old_parent].uv_nroutes--; - uvifs[vifi].uv_nroutes++; - } - if (old_gateway != src) { - update_table_entry(r, old_gateway); - /*???old_gateway???->al_nroutes--;*/ - /*n->al_nroutes++;*/ - } - r->rt_timer = 0; - r->rt_metric = adj_metric; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } - else if (vifi != r->rt_parent) { - /* - * The report came from a vif other than the route's parent vif. - * Update the children info, if necessary. - */ - if (AVOID_TRANSIT(vifi, r)) { - /* - * The route's parent is a vif from which we're not supposed - * to transit onto this vif. Simply ignore the update. - */ - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored due to NOTRANSIT)", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric); - } else if (VIFM_ISSET(vifi, r->rt_children)) { - /* - * Vif is a child vif for this route. - */ - if (metric < r->rt_metric || - (metric == r->rt_metric && - ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) { - /* - * Neighbor has lower metric to origin (or has same metric - * and lower IP address) -- it becomes the dominant router, - * and vif is no longer a child for me. - */ - VIFM_CLR(vifi, r->rt_children); - r->rt_dominants [vifi] = src; - /* XXX - * We don't necessarily want to forget about subordinateness - * so that we can become the dominant quickly if the current - * dominant fails. - */ - NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - update_table_entry(r, r->rt_gateway); - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d becomes dominant for %s with metric %d", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric); - } - else if (metric > UNREACHABLE) { /* "poisoned reverse" */ - /* - * Neighbor considers this vif to be on path to route's - * origin; record this neighbor as subordinate - */ - if (!NBRM_ISSET(n->al_index, r->rt_subordinates)) { - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d becomes subordinate for %s with poison-reverse metric %d", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric - UNREACHABLE); - NBRM_SET(n->al_index, r->rt_subordinates); - update_table_entry(r, r->rt_gateway); - } else { - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d confirms subordinateness for %s with poison-reverse metric %d", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric - UNREACHABLE); - } - NBRM_SET(n->al_index, r->rt_subordadv); - } - else if (NBRM_ISSET(n->al_index, r->rt_subordinates)) { - /* - * Current subordinate no longer considers this vif to be on - * path to route's origin; it is no longer a subordinate - * router. - */ - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d is no longer a subordinate for %s with metric %d", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric); - NBRM_CLR(n->al_index, r->rt_subordinates); - update_table_entry(r, r->rt_gateway); - } - - } - else if (src == r->rt_dominants[vifi] && - (metric > r->rt_metric || - (metric == r->rt_metric && - ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) { - /* - * Current dominant no longer has a lower metric to origin - * (or same metric and lower IP address); we adopt the vif - * as our own child. - */ - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s (current dominant) on vif %d is no longer dominant for %s with metric %d", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric); - VIFM_SET(vifi, r->rt_children); - r->rt_dominants[vifi] = 0; - if (uvifs[vifi].uv_flags & VIFF_NOFLOOD) - NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - else - NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap); - if (metric > UNREACHABLE) { - NBRM_SET(n->al_index, r->rt_subordinates); - NBRM_SET(n->al_index, r->rt_subordadv); - } - update_table_entry(r, r->rt_gateway); - } else { - IF_DEBUG(DEBUG_RTDETAIL) - log(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored)", - inet_fmt(src, s1), vifi, inet_fmts(origin, mask, s2), - metric); - } - } -} - - -/* - * On every timer interrupt, advance the timer in each routing entry. - */ -void -age_routes() -{ - register struct rtentry *r; - register struct rtentry *prev_r; - extern u_long virtual_time; /* from main.c */ - - for (prev_r = RT_ADDR, r = routing_table; - r != NULL; - prev_r = r, r = r->rt_next) { - - if ((r->rt_timer += TIMER_INTERVAL) >= ROUTE_DISCARD_TIME) { - /* - * Time to garbage-collect the route entry. - */ - del_table_entry(r, 0, DEL_ALL_ROUTES); - discard_route(prev_r); - r = prev_r; - } - else if (r->rt_timer >= ROUTE_EXPIRE_TIME && - r->rt_metric != UNREACHABLE) { - /* - * Time to expire the route entry. If the gateway is zero, - * i.e., it is a route to a directly-connected subnet, just - * set the timer back to zero; such routes expire only when - * the interface to the subnet goes down. - */ - if (r->rt_gateway == 0) { - r->rt_timer = 0; - } - else { - del_table_entry(r, 0, DEL_ALL_ROUTES); - r->rt_metric = UNREACHABLE; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } - } - else if (virtual_time % (ROUTE_REPORT_INTERVAL * 2) == 0) { - /* - * Time out subordinateness that hasn't been reported in - * the last 2 intervals. - */ - if (!NBRM_SAME(r->rt_subordinates, r->rt_subordadv)) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "rt %s sub 0x%08x%08x subadv 0x%08x%08x metric %d", - RT_FMT(r, s1), - r->rt_subordinates.hi, r->rt_subordinates.lo, - r->rt_subordadv.hi, r->rt_subordadv.lo, r->rt_metric); - NBRM_MASK(r->rt_subordinates, r->rt_subordadv); - update_table_entry(r, r->rt_gateway); - } - NBRM_CLRALL(r->rt_subordadv); - } - } -} - - -/* - * Mark all routes as unreachable. This function is called only from - * hup() in preparation for informing all neighbors that we are going - * off the air. For consistency, we ought also to delete all reachable - * route entries from the kernel, but since we are about to exit we rely - * on the kernel to do its own cleanup -- no point in making all those - * expensive kernel calls now. - */ -void -expire_all_routes() -{ - register struct rtentry *r; - - for (r = routing_table; r != NULL; r = r->rt_next) { - r->rt_metric = UNREACHABLE; - r->rt_flags |= RTF_CHANGED; - routes_changed = TRUE; - } -} - - -/* - * Delete all the routes in the routing table. - */ -void -free_all_routes() -{ - register struct rtentry *r; - - r = RT_ADDR; - - while (r->rt_next) - discard_route(r); -} - - -/* - * Process an incoming neighbor probe message. - */ -void -accept_probe(src, dst, p, datalen, level) - u_int32 src; - u_int32 dst; - char *p; - int datalen; - u_int32 level; -{ - vifi_t vifi; - static struct listaddr *unknowns = NULL; - - if ((vifi = find_vif(src, dst)) == NO_VIF) { - struct listaddr *a, **prev; - struct listaddr *match = NULL; - time_t now = time(0); - - for (prev = &unknowns, a = *prev; a; a = *prev) { - if (a->al_addr == src) - match = a; - if (a->al_ctime + 2 * a->al_timer < now) { - /* We haven't heard from it in a long time */ - *prev = a->al_next; - free(a); - } else { - prev = &a->al_next; - } - } - if (match == NULL) { - match = *prev = (struct listaddr *)malloc(sizeof(struct listaddr)); - match->al_next = NULL; - match->al_addr = src; - match->al_timer = OLD_NEIGHBOR_EXPIRE_TIME; - match->al_ctime = now - match->al_timer; - } - - if (match->al_ctime + match->al_timer <= now) { - log(LOG_WARNING, 0, - "ignoring probe from non-neighbor %s, check for misconfigured tunnel or routing on %s", - inet_fmt(src, s1), s1); - match->al_timer *= 2; - } else - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, - "ignoring probe from non-neighbor %s (%d seconds until next warning)", inet_fmt(src, s1), match->al_ctime + match->al_timer - now); - return; - } - - update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level); -} - -struct newrt { - u_int32 mask; - u_int32 origin; - int metric; - int pad; -}; - -static int -compare_rts(rt1, rt2) - const void *rt1; - const void *rt2; -{ - register struct newrt *r1 = (struct newrt *)rt1; - register struct newrt *r2 = (struct newrt *)rt2; - register u_int32 m1 = ntohl(r1->mask); - register u_int32 m2 = ntohl(r2->mask); - register u_int32 o1, o2; - - if (m1 > m2) - return (-1); - if (m1 < m2) - return (1); - - /* masks are equal */ - o1 = ntohl(r1->origin); - o2 = ntohl(r2->origin); - if (o1 > o2) - return (-1); - if (o1 < o2) - return (1); - return (0); -} - -void -blaster_alloc(vifi) - vifi_t vifi; -{ - register struct uvif *v; - - v = &uvifs[vifi]; - if (v->uv_blasterbuf) - free(v->uv_blasterbuf); - - v->uv_blasterlen = 64*1024; - v->uv_blasterbuf = malloc(v->uv_blasterlen); - v->uv_blastercur = v->uv_blasterend = v->uv_blasterbuf; - if (v->uv_blastertimer) - timer_clearTimer(v->uv_blastertimer); - v->uv_blastertimer = 0; -} - -struct blaster_hdr { - u_int32 bh_src; - u_int32 bh_dst; - u_int32 bh_level; - int bh_datalen; -}; - -/* - * Queue a route report from a route-blaster. - * If the timer isn't running to process these reports, - * start it. - */ -static void -queue_blaster_report(vifi, src, dst, p, datalen, level) - vifi_t vifi; - u_int32 src, dst, level; - register char *p; - register int datalen; -{ - register struct blaster_hdr *bh; - register struct uvif *v; - int bblen = sizeof(*bh) + ((datalen + 3) & ~3); - - v = &uvifs[vifi]; - if (v->uv_blasterend - v->uv_blasterbuf + - bblen > v->uv_blasterlen) { - int end = v->uv_blasterend - v->uv_blasterbuf; - int cur = v->uv_blastercur - v->uv_blasterbuf; - - v->uv_blasterlen *= 2; - IF_DEBUG(DEBUG_IF) - log(LOG_DEBUG, 0, "increasing blasterbuf to %d bytes", - v->uv_blasterlen); - v->uv_blasterbuf = realloc(v->uv_blasterbuf, - v->uv_blasterlen); - if (v->uv_blasterbuf == NULL) { - log(LOG_WARNING, ENOMEM, "turning off blaster on vif %d", vifi); - v->uv_blasterlen = 0; - v->uv_blasterend = v->uv_blastercur = NULL; - v->uv_flags &= ~VIFF_BLASTER; - return; - } - v->uv_blasterend = v->uv_blasterbuf + end; - v->uv_blastercur = v->uv_blasterbuf + cur; - } - bh = (struct blaster_hdr *)v->uv_blasterend; - bh->bh_src = src; - bh->bh_dst = dst; - bh->bh_level = level; - bh->bh_datalen = datalen; - bcopy(p, (char *)(bh + 1), datalen); - v->uv_blasterend += bblen; - - if (v->uv_blastertimer == 0) { - int *i = (int *)malloc(sizeof(int *)); - - if (i == NULL) - log(LOG_ERR, 0, "out of memory"); - - *i = vifi; - - v->uv_blastertimer = timer_setTimer(5, - process_blaster_report, i); - } -} - -/* - * Periodic process; process up to 5 of the routes in the route-blaster - * queue. If there are more routes remaining, reschedule myself to run - * in 1 second. - */ -static void -process_blaster_report(vifip) - void *vifip; -{ - vifi_t vifi = *(int *)vifip; - register struct uvif *v; - register struct blaster_hdr *bh; - int i; - - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "processing vif %d blasted routes", vifi); - v = &uvifs[vifi]; - for (i = 0; i < 5; i++) { - if (v->uv_blastercur >= v->uv_blasterend) - break; - bh = (struct blaster_hdr *)v->uv_blastercur; - v->uv_blastercur += sizeof(*bh) + ((bh->bh_datalen + 3) & ~3); - accept_report(bh->bh_src, bh->bh_dst, (char *)(bh + 1), - -bh->bh_datalen, bh->bh_level); - } - - if (v->uv_blastercur >= v->uv_blasterend) { - v->uv_blastercur = v->uv_blasterbuf; - v->uv_blasterend = v->uv_blasterbuf; - v->uv_blastertimer = 0; - free(vifip); - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "finish processing vif %d blaster", vifi); - } else { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "more blasted routes to come on vif %d", vifi); - v->uv_blastertimer = timer_setTimer(1, - process_blaster_report, vifip); - } -} - -/* - * Process an incoming route report message. - * If the report arrived on a vif marked as a "blaster", then just - * queue it and return; queue_blaster_report() will schedule it for - * processing later. If datalen is negative, then this is actually - * a queued report so actually process it instead of queueing it. - */ -void -accept_report(src, dst, p, datalen, level) - u_int32 src, dst, level; - register char *p; - register int datalen; -{ - vifi_t vifi; - register int width, i, nrt = 0; - int metric; - u_int32 mask; - u_int32 origin; - struct newrt rt[4096]; - struct listaddr *nbr; - - if ((vifi = find_vif(src, dst)) == NO_VIF) { - log(LOG_INFO, 0, - "ignoring route report from non-neighbor %s", inet_fmt(src, s1)); - return; - } - - if (uvifs[vifi].uv_flags & VIFF_BLASTER) - if (datalen > 0) { - queue_blaster_report(vifi, src, dst, p, datalen, level); - return; - } else { - datalen = -datalen; - } - - if (!(nbr = update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level))) - return; - - if (datalen > 2*4096) { - log(LOG_INFO, 0, - "ignoring oversize (%d bytes) route report from %s", - datalen, inet_fmt(src, s1)); - return; - } - - while (datalen > 0) { /* Loop through per-mask lists. */ - - if (datalen < 3) { - log(LOG_WARNING, 0, - "received truncated route report from %s", - inet_fmt(src, s1)); - return; - } - ((u_char *)&mask)[0] = 0xff; width = 1; - if ((((u_char *)&mask)[1] = *p++) != 0) width = 2; - if ((((u_char *)&mask)[2] = *p++) != 0) width = 3; - if ((((u_char *)&mask)[3] = *p++) != 0) width = 4; - if (!inet_valid_mask(ntohl(mask))) { - log(LOG_WARNING, 0, - "%s reports bogus netmask 0x%08x (%s)", - inet_fmt(src, s1), ntohl(mask), inet_fmt(mask, s2)); - return; - } - datalen -= 3; - - do { /* Loop through (origin, metric) pairs */ - if (datalen < width + 1) { - log(LOG_WARNING, 0, - "received truncated route report from %s", - inet_fmt(src, s1)); - return; - } - origin = 0; - for (i = 0; i < width; ++i) - ((char *)&origin)[i] = *p++; - metric = *p++; - datalen -= width + 1; - rt[nrt].mask = mask; - rt[nrt].origin = origin; - rt[nrt].metric = (metric & 0x7f); - ++nrt; - } while (!(metric & 0x80)); - } - - qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts); - start_route_updates(); - /* - * If the last entry is default, change mask from 0xff000000 to 0 - */ - if (rt[nrt-1].origin == 0) - rt[nrt-1].mask = 0; - - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt, - inet_fmt(src, s1), inet_fmt(dst, s2)); - for (i = 0; i < nrt; ++i) { - if (i != 0 && rt[i].origin == rt[i-1].origin && - rt[i].mask == rt[i-1].mask) { - log(LOG_WARNING, 0, "%s reports duplicate route for %s", - inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2)); - continue; - } - /* Only filter non-poisoned updates. */ - if (uvifs[vifi].uv_filter && rt[i].metric < UNREACHABLE) { - struct vf_element *vfe; - int match = 0; - - for (vfe = uvifs[vifi].uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) { - if (vfe->vfe_flags & VFEF_EXACT) { - if ((vfe->vfe_addr == rt[i].origin) && - (vfe->vfe_mask == rt[i].mask)) { - match = 1; - break; - } - } else { - if ((rt[i].origin & vfe->vfe_mask) == vfe->vfe_addr) { - match = 1; - break; - } - } - } - if ((uvifs[vifi].uv_filter->vf_type == VFT_ACCEPT && match == 0) || - (uvifs[vifi].uv_filter->vf_type == VFT_DENY && match == 1)) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "%s skipped on vif %d because it %s %s", - inet_fmts(rt[i].origin, rt[i].mask, s1), - vifi, - match ? "matches" : "doesn't match", - match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2) : - "the filter"); -#if 0 - rt[i].metric += vfe->vfe_addmetric; - if (rt[i].metric > UNREACHABLE) -#endif - rt[i].metric = UNREACHABLE; - } - } - update_route(rt[i].origin, rt[i].mask, rt[i].metric, - src, vifi, nbr); - } - - if (routes_changed && !delay_change_reports) - report_to_all_neighbors(CHANGED_ROUTES); -} - - -/* - * Send a route report message to destination 'dst', via virtual interface - * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. - */ -void -report(which_routes, vifi, dst) - int which_routes; - vifi_t vifi; - u_int32 dst; -{ - register struct rtentry *r; - register int i; - - r = rt_end; - while (r != RT_ADDR) { - i = report_chunk(which_routes, r, vifi, dst); - while (i-- > 0) - r = r->rt_prev; - } -} - - -/* - * Send a route report message to all neighboring routers. - * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. - */ -void -report_to_all_neighbors(which_routes) - int which_routes; -{ - register vifi_t vifi; - register struct uvif *v; - register struct rtentry *r; - int routes_changed_before; - - /* - * Remember the state of the global routes_changed flag before - * generating the reports, and clear the flag. - */ - routes_changed_before = routes_changed; - routes_changed = FALSE; - - - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!NBRM_ISEMPTY(v->uv_nbrmap)) { - report(which_routes, vifi, v->uv_dst_addr); - } - } - - /* - * If there were changed routes before we sent the reports AND - * if no new changes occurred while sending the reports, clear - * the change flags in the individual route entries. If changes - * did occur while sending the reports, new reports will be - * generated at the next timer interrupt. - */ - if (routes_changed_before && !routes_changed) { - for (r = routing_table; r != NULL; r = r->rt_next) { - r->rt_flags &= ~RTF_CHANGED; - } - } - - /* - * Set a flag to inhibit further reports of changed routes until the - * next timer interrupt. This is to alleviate update storms. - */ - delay_change_reports = TRUE; -} - -/* - * Send a route report message to destination 'dst', via virtual interface - * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. - */ -static int -report_chunk(which_routes, start_rt, vifi, dst) - int which_routes; - register struct rtentry *start_rt; - vifi_t vifi; - u_int32 dst; -{ - register struct rtentry *r; - register char *p; - register int i; - register int nrt = 0; - struct uvif *v = &uvifs[vifi]; - int datalen = 0; - int width = 0; - u_int32 mask = 0; - u_int32 src; - int admetric = v->uv_admetric; - int metric; - - src = v->uv_lcl_addr; - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - - for (r = start_rt; r != RT_ADDR; r = r->rt_prev) { - if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) { - nrt++; - continue; - } - - /* - * Do not poison-reverse a route for a directly-connected - * subnetwork on that subnetwork. This can cause loops when - * some router on the subnetwork is misconfigured. - */ - if (r->rt_gateway == 0 && r->rt_parent == vifi) { - nrt++; - continue; - } - - if (v->uv_filter && v->uv_filter->vf_flags & VFF_BIDIR) { - struct vf_element *vfe; - int match = 0; - - for (vfe = v->uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) { - if (vfe->vfe_flags & VFEF_EXACT) { - if ((vfe->vfe_addr == r->rt_origin) && - (vfe->vfe_mask == r->rt_originmask)) { - match = 1; - break; - } - } else { - if ((r->rt_origin & vfe->vfe_mask) == vfe->vfe_addr) { - match = 1; - break; - } - } - } - if ((v->uv_filter->vf_type == VFT_ACCEPT && match == 0) || - (v->uv_filter->vf_type == VFT_DENY && match == 1)) { - IF_DEBUG(DEBUG_ROUTE) - log(LOG_DEBUG, 0, "%s not reported on vif %d because it %s %s", - RT_FMT(r, s1), vifi, - match ? "matches" : "doesn't match", - match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2) : - "the filter"); - nrt++; - continue; - } - } - - /* - * If there is no room for this route in the current message, - * send it & return how many routes we sent. - */ - if (datalen + ((r->rt_originmask == mask) ? - (width + 1) : - (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { - *(p-1) |= 0x80; - send_on_vif(v, 0, DVMRP_REPORT, datalen); - return (nrt); - } - - if (r->rt_originmask != mask || datalen == 0) { - mask = r->rt_originmask; - width = r->rt_originwidth; - if (datalen != 0) *(p-1) |= 0x80; - *p++ = ((char *)&mask)[1]; - *p++ = ((char *)&mask)[2]; - *p++ = ((char *)&mask)[3]; - datalen += 3; - } - for (i = 0; i < width; ++i) - *p++ = ((char *)&(r->rt_origin))[i]; - - metric = r->rt_metric + admetric; - if (metric > UNREACHABLE) - metric = UNREACHABLE; - if (r->rt_parent != vifi && AVOID_TRANSIT(vifi, r)) - metric = UNREACHABLE; - *p++ = (r->rt_parent == vifi && metric != UNREACHABLE) ? - (char)(metric + UNREACHABLE) : /* "poisoned reverse" */ - (char)(metric); - ++nrt; - datalen += width + 1; - } - if (datalen != 0) { - *(p-1) |= 0x80; - send_on_vif(v, 0, DVMRP_REPORT, datalen); - } - return (nrt); -} - -/* - * send the next chunk of our routing table to all neighbors. - * return the length of the smallest chunk we sent out. - */ -int -report_next_chunk() -{ - register vifi_t vifi; - register struct uvif *v; - register struct rtentry *sr; - register int i, n = 0, min = 20000; - static int start_rt; - - if (nroutes <= 0) - return (0); - - /* - * find this round's starting route. - */ - for (sr = rt_end, i = start_rt; --i >= 0; ) { - sr = sr->rt_prev; - if (sr == RT_ADDR) - sr = rt_end; - } - - /* - * send one chunk of routes starting at this round's start to - * all our neighbors. - */ - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!NBRM_ISEMPTY(v->uv_nbrmap)) { - n = report_chunk(ALL_ROUTES, sr, vifi, v->uv_dst_addr); - if (n < min) - min = n; - } - } - if (min == 20000) - min = 0; /* Neighborless router didn't send any routes */ - - n = min; - IF_DEBUG(DEBUG_ROUTE) - log(LOG_INFO, 0, "update %d starting at %d of %d", - n, (nroutes - start_rt), nroutes); - - start_rt = (start_rt + n) % nroutes; - return (n); -} - - -/* - * Print the contents of the routing table on file 'fp'. - */ -void -dump_routes(fp) - FILE *fp; -{ - register struct rtentry *r; - register vifi_t i; - - - fprintf(fp, - "Multicast Routing Table (%u %s)\n%s\n", - nroutes, (nroutes == 1) ? "entry" : "entries", - " Origin-Subnet From-Gateway Metric Tmr Fl In-Vif Out-Vifs"); - - for (r = routing_table; r != NULL; r = r->rt_next) { - - fprintf(fp, " %-18s %-15s ", - inet_fmts(r->rt_origin, r->rt_originmask, s1), - (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2)); - - fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ", - r->rt_metric); - - fprintf(fp, " %3u %c%c %3u ", r->rt_timer, - (r->rt_flags & RTF_CHANGED) ? 'C' : '.', - (r->rt_flags & RTF_HOLDDOWN) ? 'H' : '.', - r->rt_parent); - - for (i = 0; i < numvifs; ++i) { - struct listaddr *n; - char l = '['; - - if (VIFM_ISSET(i, r->rt_children)) { - if ((uvifs[i].uv_flags & VIFF_TUNNEL) && - !NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates)) - /* Don't print out parenthood of a leaf tunnel. */ - continue; - fprintf(fp, " %u", i); - if (!NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates)) - fprintf(fp, "*"); - for (n = uvifs[i].uv_neighbors; n; n = n->al_next) { - if (NBRM_ISSET(n->al_index, r->rt_subordinates)) { - fprintf(fp, "%c%d", l, n->al_index); - l = ','; - } - } - if (l == ',') - fprintf(fp, "]"); - } - } - fprintf(fp, "\n"); - } - fprintf(fp, "\n"); -} - -struct rtentry * -determine_route(src) - u_int32 src; -{ - struct rtentry *rt; - - for (rt = routing_table; rt != NULL; rt = rt->rt_next) { - if (rt->rt_origin == (src & rt->rt_originmask) && - rt->rt_metric != UNREACHABLE) - break; - } - return rt; -} diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h deleted file mode 100644 index 300202b..0000000 --- a/usr.sbin/mrouted/route.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * route.h,v 3.8.4.6 1997/07/01 23:02:35 fenner Exp - */ - -/* - * Routing Table Entry, one per subnet from which a multicast could originate. - * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) - * - * The Routing Table is stored as a doubly-linked list of these structures, - * ordered by decreasing value of rt_originmask and, secondarily, by - * decreasing value of rt_origin within each rt_originmask value. - * This data structure is efficient for generating route reports, whether - * full or partial, for processing received full reports, for clearing the - * CHANGED flags, and for periodically advancing the timers in all routes. - * It is not so efficient for updating a small number of routes in response - * to a partial report. In a stable topology, the latter are rare; if they - * turn out to be costing a lot, we can add an auxiliary hash table for - * faster access to arbitrary route entries. - */ -struct rtentry { - struct rtentry *rt_next; /* link to next entry MUST BE FIRST */ - u_int32 rt_origin; /* subnet origin of multicasts */ - u_int32 rt_originmask; /* subnet mask for origin */ - short rt_originwidth; /* # bytes of origin subnet number */ - u_char rt_metric; /* cost of route back to origin */ - u_char rt_flags; /* RTF_ flags defined below */ - u_int32 rt_gateway; /* first-hop gateway back to origin */ - vifi_t rt_parent; /* incoming vif (ie towards origin) */ - vifbitmap_t rt_children; /* outgoing children vifs */ - u_int32 *rt_dominants; /* per vif dominant gateways */ - nbrbitmap_t rt_subordinates; /* bitmap of subordinate gateways */ - nbrbitmap_t rt_subordadv; /* recently advertised subordinates */ - u_int rt_timer; /* for timing out the route entry */ - struct rtentry *rt_prev; /* link to previous entry */ - struct gtable *rt_groups; /* link to active groups */ -}; - -#define RTF_CHANGED 0x01 /* route changed but not reported */ -#define RTF_HOLDDOWN 0x04 /* this route is in holddown */ - -#define ALL_ROUTES 0 /* possible arguments to report() */ -#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */ - -#define RT_FMT(r, s) inet_fmts((r)->rt_origin, (r)->rt_originmask, s) diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c deleted file mode 100644 index 86d6e6e..0000000 --- a/usr.sbin/mrouted/rsrr.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright (c) 1993 by the University of Southern California - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation in source and binary forms for non-commercial purposes - * and without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both the copyright notice and - * this permission notice appear in supporting documentation. and that - * any documentation, advertising materials, and other materials related - * to such distribution and use acknowledge that the software was - * developed by the University of Southern California, Information - * Sciences Institute. The name of the University may not be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about - * the suitability of this software for any purpose. THIS SOFTWARE IS - * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Other copyrights might apply to parts of this software and are so - * noted when applicable. - */ - -/* RSRR code written by Daniel Zappala, USC Information Sciences Institute, - * April 1995. - */ - -/* May 1995 -- Added support for Route Change Notification */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#ifdef RSRR - -#include "defs.h" -#include <sys/param.h> -#ifdef HAVE_SA_LEN -#include <stddef.h> /* for offsetof */ -#endif - -/* - * Exported variables. - */ -int rsrr_socket; /* interface to reservation protocol */ - -/* - * Global RSRR variables. - */ -char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */ -char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */ - -struct sockaddr_un client_addr; -int client_length = sizeof(client_addr); - - -/* - * Procedure definitions needed internally. - */ -static void rsrr_accept __P((int recvlen)); -static void rsrr_accept_iq __P((void)); -static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags, - struct gtable *gt_notify)); -static void rsrr_read __P((int, fd_set *)); -static int rsrr_send __P((int sendlen)); -static void rsrr_cache __P((struct gtable *gt, - struct rsrr_rq *route_query)); - -/* Initialize RSRR socket */ -void -rsrr_init() -{ - int servlen; - struct sockaddr_un serv_addr; - - if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) - log(LOG_ERR, errno, "Can't create RSRR socket"); - - unlink(RSRR_SERV_PATH); - bzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sun_family = AF_UNIX; - strcpy(serv_addr.sun_path, RSRR_SERV_PATH); -#ifdef HAVE_SA_LEN - servlen = offsetof(struct sockaddr_un, sun_path) + - strlen(serv_addr.sun_path); - serv_addr.sun_len = servlen; -#else - servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path); -#endif - - if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0) - log(LOG_ERR, errno, "Can't bind RSRR socket"); - - if (register_input_handler(rsrr_socket, rsrr_read) < 0) - log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler"); -} - -/* Read a message from the RSRR socket */ -static void -rsrr_read(f, rfd) - int f; - fd_set *rfd; -{ - register int rsrr_recvlen; - - bzero((char *) &client_addr, sizeof(client_addr)); - rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf), - 0, (struct sockaddr *)&client_addr, &client_length); - if (rsrr_recvlen < 0) { - if (errno != EINTR) - log(LOG_ERR, errno, "RSRR recvfrom"); - return; - } - rsrr_accept(rsrr_recvlen); -} - -/* Accept a message from the reservation protocol and take - * appropriate action. - */ -static void -rsrr_accept(recvlen) - int recvlen; -{ - struct rsrr_header *rsrr; - struct rsrr_rq *route_query; - - if (recvlen < RSRR_HEADER_LEN) { - log(LOG_WARNING, 0, - "Received RSRR packet of %d bytes, which is less than min size", - recvlen); - return; - } - - rsrr = (struct rsrr_header *) rsrr_recv_buf; - - if (rsrr->version > RSRR_MAX_VERSION) { - log(LOG_WARNING, 0, - "Received RSRR packet version %d, which I don't understand", - rsrr->version); - return; - } - - switch (rsrr->version) { - case 1: - switch (rsrr->type) { - case RSRR_INITIAL_QUERY: - /* Send Initial Reply to client */ - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "Received Initial Query\n"); - rsrr_accept_iq(); - break; - case RSRR_ROUTE_QUERY: - /* Check size */ - if (recvlen < RSRR_RQ_LEN) { - log(LOG_WARNING, 0, - "Received Route Query of %d bytes, which is too small", - recvlen); - break; - } - /* Get the query */ - route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN); - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, - "Received Route Query for src %s grp %s notification %d", - inet_fmt(route_query->source_addr.s_addr, s1), - inet_fmt(route_query->dest_addr.s_addr,s2), - BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); - /* Send Route Reply to client */ - rsrr_accept_rq(route_query,rsrr->flags,NULL); - break; - default: - log(LOG_WARNING, 0, - "Received RSRR packet type %d, which I don't handle", - rsrr->type); - break; - } - break; - - default: - log(LOG_WARNING, 0, - "Received RSRR packet version %d, which I don't understand", - rsrr->version); - break; - } -} - -/* Send an Initial Reply to the reservation protocol. */ -static void -rsrr_accept_iq() -{ - struct rsrr_header *rsrr; - struct rsrr_vif *vif_list; - struct uvif *v; - int vifi, sendlen; - - /* Check for space. There should be room for plenty of vifs, - * but we should check anyway. - */ - if (numvifs > RSRR_MAX_VIFS) { - log(LOG_WARNING, 0, - "Can't send RSRR Route Reply because %d is too many vifs", - numvifs); - return; - } - - /* Set up message */ - rsrr = (struct rsrr_header *) rsrr_send_buf; - rsrr->version = 1; - rsrr->type = RSRR_INITIAL_REPLY; - rsrr->flags = 0; - rsrr->num = numvifs; - - vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN); - - /* Include the vif list. */ - for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) { - vif_list[vifi].id = vifi; - vif_list[vifi].status = 0; - if (v->uv_flags & VIFF_DISABLED) - BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT); - vif_list[vifi].threshold = v->uv_threshold; - vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr; - } - - /* Get the size. */ - sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN; - - /* Send it. */ - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "Send RSRR Initial Reply"); - rsrr_send(sendlen); -} - -/* Send a Route Reply to the reservation protocol. The Route Query - * contains the query to which we are responding. The flags contain - * the incoming flags from the query or, for route change - * notification, the flags that should be set for the reply. The - * kernel table entry contains the routing info to use for a route - * change notification. - */ -static int -rsrr_accept_rq(route_query,flags,gt_notify) - struct rsrr_rq *route_query; - int flags; - struct gtable *gt_notify; -{ - struct rsrr_header *rsrr; - struct rsrr_rr *route_reply; - struct gtable *gt,local_g; - struct rtentry *r; - int sendlen; - u_long mcastgrp; - - /* Set up message */ - rsrr = (struct rsrr_header *) rsrr_send_buf; - rsrr->version = 1; - rsrr->type = RSRR_ROUTE_REPLY; - rsrr->flags = 0; - rsrr->num = 0; - - route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN); - route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr; - route_reply->source_addr.s_addr = route_query->source_addr.s_addr; - route_reply->query_id = route_query->query_id; - - /* Blank routing entry for error. */ - route_reply->in_vif = 0; - route_reply->reserved = 0; - route_reply->out_vif_bm = 0; - - /* Get the size. */ - sendlen = RSRR_RR_LEN; - - /* If kernel table entry is defined, then we are sending a Route Reply - * due to a Route Change Notification event. Use the kernel table entry - * to supply the routing info. - */ - if (gt_notify) { - /* Set flags */ - rsrr->flags = flags; - /* Include the routing entry. */ - route_reply->in_vif = gt_notify->gt_route->rt_parent; - if (BIT_TST(flags,RSRR_NOTIFICATION_BIT)) - route_reply->out_vif_bm = gt_notify->gt_grpmems; - else - route_reply->out_vif_bm = 0; - } else if (find_src_grp(route_query->source_addr.s_addr, 0, - route_query->dest_addr.s_addr)) { - - /* Found kernel entry. Code taken from add_table_entry() */ - gt = gtp ? gtp->gt_gnext : kernel_table; - - /* Include the routing entry. */ - route_reply->in_vif = gt->gt_route->rt_parent; - route_reply->out_vif_bm = gt->gt_grpmems; - - /* Cache reply if using route change notification. */ - if BIT_TST(flags,RSRR_NOTIFICATION_BIT) { - rsrr_cache(gt,route_query); - BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT); - } - - } else { - /* No kernel entry; use routing table. */ - r = determine_route(route_query->source_addr.s_addr); - - if (r != NULL) { - /* We need to mimic what will happen if a data packet - * is forwarded by multicast routing -- the kernel will - * make an upcall and mrouted will install a route in the kernel. - * Our outgoing vif bitmap should reflect what that table - * will look like. Grab code from add_table_entry(). - * This is gross, but it's probably better to be accurate. - */ - - gt = &local_g; - mcastgrp = route_query->dest_addr.s_addr; - - gt->gt_mcastgrp = mcastgrp; - gt->gt_grpmems = 0; - gt->gt_scope = 0; - gt->gt_route = r; - - /* obtain the multicast group membership list */ - determine_forwvifs(gt); - - /* Include the routing entry. */ - route_reply->in_vif = gt->gt_route->rt_parent; - route_reply->out_vif_bm = gt->gt_grpmems; - - } else { - /* Set error bit. */ - BIT_SET(rsrr->flags,RSRR_ERROR_BIT); - } - } - - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n", - gt_notify ? "Route Change: " : "", - inet_fmt(route_reply->source_addr.s_addr,s1), - inet_fmt(route_reply->dest_addr.s_addr,s2), - route_reply->in_vif,route_reply->out_vif_bm); - - /* Send it. */ - return rsrr_send(sendlen); -} - -/* Send an RSRR message. */ -static int -rsrr_send(sendlen) - int sendlen; -{ - int error; - - /* Send it. */ - error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, - (struct sockaddr *)&client_addr, client_length); - - /* Check for errors. */ - if (error < 0) { - log(LOG_WARNING, errno, "Failed send on RSRR socket"); - } else if (error != sendlen) { - log(LOG_WARNING, 0, - "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen); - } - return error; -} - -/* Cache a message being sent to a client. Currently only used for - * caching Route Reply messages for route change notification. - */ -static void -rsrr_cache(gt,route_query) - struct gtable *gt; - struct rsrr_rq *route_query; -{ - struct rsrr_cache *rc, **rcnp; - struct rsrr_header *rsrr; - - rsrr = (struct rsrr_header *) rsrr_send_buf; - - rcnp = >->gt_rsrr_cache; - while ((rc = *rcnp) != NULL) { - if ((rc->route_query.source_addr.s_addr == - route_query->source_addr.s_addr) && - (rc->route_query.dest_addr.s_addr == - route_query->dest_addr.s_addr) && - (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) { - /* Cache entry already exists. - * Check if route notification bit has been cleared. - */ - if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) { - /* Delete cache entry. */ - *rcnp = rc->next; - free(rc); - } else { - /* Update */ - rc->route_query.query_id = route_query->query_id; - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, - "Update cached query id %ld from client %s\n", - rc->route_query.query_id, rc->client_addr.sun_path); - } - return; - } - rcnp = &rc->next; - } - - /* Cache entry doesn't already exist. Create one and insert at - * front of list. - */ - rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache)); - if (rc == NULL) - log(LOG_ERR, 0, "ran out of memory"); - rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr; - rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr; - rc->route_query.query_id = route_query->query_id; - strcpy(rc->client_addr.sun_path, client_addr.sun_path); - rc->client_length = client_length; - rc->next = gt->gt_rsrr_cache; - gt->gt_rsrr_cache = rc; - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n", - rc->route_query.query_id,rc->client_addr.sun_path); -} - -/* Send all the messages in the cache. Currently this is used to send - * all the cached Route Reply messages for route change notification. - */ -void -rsrr_cache_send(gt,notify) - struct gtable *gt; - int notify; -{ - struct rsrr_cache *rc, **rcnp; - int flags = 0; - - if (notify) - BIT_SET(flags,RSRR_NOTIFICATION_BIT); - - rcnp = >->gt_rsrr_cache; - while ((rc = *rcnp) != NULL) { - if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) { - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", - rc->route_query.query_id,rc->client_addr.sun_path); - /* Delete cache entry. */ - *rcnp = rc->next; - free(rc); - } else { - rcnp = &rc->next; - } - } -} - -/* Clean the cache by deleting all entries. */ -void -rsrr_cache_clean(gt) - struct gtable *gt; -{ - struct rsrr_cache *rc,*rc_next; - - IF_DEBUG(DEBUG_RSRR) - log(LOG_DEBUG, 0, "cleaning cache for group %s\n", - inet_fmt(gt->gt_mcastgrp, s1)); - rc = gt->gt_rsrr_cache; - while (rc) { - rc_next = rc->next; - free(rc); - rc = rc_next; - } - gt->gt_rsrr_cache = NULL; -} - -void -rsrr_clean() -{ - unlink(RSRR_SERV_PATH); -} - -#endif /* RSRR */ diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h deleted file mode 100644 index c88f8ce..0000000 --- a/usr.sbin/mrouted/rsrr.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 1993 by the University of Southern California - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation in source and binary forms for non-commercial purposes - * and without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both the copyright notice and - * this permission notice appear in supporting documentation. and that - * any documentation, advertising materials, and other materials related - * to such distribution and use acknowledge that the software was - * developed by the University of Southern California, Information - * Sciences Institute. The name of the University may not be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about - * the suitability of this software for any purpose. THIS SOFTWARE IS - * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Other copyrights might apply to parts of this software and are so - * noted when applicable. - */ - -#define RSRR_SERV_PATH "/var/run/rsrr_svr" -/* Note this needs to be 14 chars for 4.3 BSD compatibility */ -/* Note This appears to be unused */ -#define RSRR_CLI_PATH "/var/run/rsrr_cli" - -#define RSRR_MAX_LEN 2048 -#define RSRR_HEADER_LEN (sizeof(struct rsrr_header)) -#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq)) -#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr)) -#define RSRR_VIF_LEN (sizeof(struct rsrr_vif)) - -/* Current maximum number of vifs. */ -#define RSRR_MAX_VIFS 32 - -/* Maximum acceptable version */ -#define RSRR_MAX_VERSION 1 - -/* RSRR message types */ -#define RSRR_ALL_TYPES 0 -#define RSRR_INITIAL_QUERY 1 -#define RSRR_INITIAL_REPLY 2 -#define RSRR_ROUTE_QUERY 3 -#define RSRR_ROUTE_REPLY 4 - -/* RSRR Initial Reply (Vif) Status bits - * Each definition represents the position of the bit from right to left. - * - * Right-most bit is the disabled bit, set if the vif is administratively - * disabled. - */ -#define RSRR_DISABLED_BIT 0 -/* All other bits are zeroes */ - -/* RSRR Route Query/Reply flag bits - * Each definition represents the position of the bit from right to left. - * - * Right-most bit is the Route Change Notification bit, set if the - * reservation protocol wishes to receive notification of - * a route change for the source-destination pair listed in the query. - * Notification is in the form of an unsolicitied Route Reply. - */ -#define RSRR_NOTIFICATION_BIT 0 -/* Next bit indicates an error returning the Route Reply. */ -#define RSRR_ERROR_BIT 1 -/* All other bits are zeroes */ - -/* Definition of an RSRR message header. - * An Initial Query uses only the header, and an Initial Reply uses - * the header and a list of vifs. - */ -struct rsrr_header { - u_char version; /* RSRR Version, currently 1 */ - u_char type; /* type of message, as defined above */ - u_char flags; /* flags; defined by type */ - u_char num; /* number; defined by type */ -}; - -/* Definition of a vif as seen by the reservation protocol. - * - * Routing gives the reservation protocol a list of vifs in the - * Initial Reply. - * - * We explicitly list the ID because we can't assume that all routing - * protocols will use the same numbering scheme. - * - * The status is a bitmask of status flags, as defined above. It is the - * responsibility of the reservation protocol to perform any status checks - * if it uses the MULTICAST_VIF socket option. - * - * The threshold indicates the ttl an outgoing packet needs in order to - * be forwarded. The reservation protocol must perform this check itself if - * it uses the MULTICAST_VIF socket option. - * - * The local address is the address of the physical interface over which - * packets are sent. - */ -struct rsrr_vif { - u_char id; /* vif id */ - u_char threshold; /* vif threshold ttl */ - u_short status; /* vif status bitmask */ - struct in_addr local_addr; /* vif local address */ -}; - -/* Definition of an RSRR Route Query. - * - * The query asks routing for the forwarding entry for a particular - * source and destination. The query ID uniquely identifies the query - * for the reservation protocol. Thus, the combination of the client's - * address and the query ID forms a unique identifier for routing. - * Flags are defined above. - */ -struct rsrr_rq { - struct in_addr dest_addr; /* destination */ - struct in_addr source_addr; /* source */ - u_long query_id; /* query ID */ -}; - -/* Definition of an RSRR Route Reply. - * - * Routing uses the reply to give the reservation protocol the - * forwarding entry for a source-destination pair. Routing copies the - * query ID from the query and fills in the incoming vif and a bitmask - * of the outgoing vifs. - * Flags are defined above. - */ -struct rsrr_rr { - struct in_addr dest_addr; /* destination */ - struct in_addr source_addr; /* source */ - u_long query_id; /* query ID */ - u_short in_vif; /* incoming vif */ - u_short reserved; /* reserved */ - u_long out_vif_bm; /* outgoing vif bitmask */ -}; diff --git a/usr.sbin/mrouted/rsrr_var.h b/usr.sbin/mrouted/rsrr_var.h deleted file mode 100644 index 9b1c09c..0000000 --- a/usr.sbin/mrouted/rsrr_var.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1993 by the University of Southern California - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation in source and binary forms for non-commercial purposes - * and without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both the copyright notice and - * this permission notice appear in supporting documentation. and that - * any documentation, advertising materials, and other materials related - * to such distribution and use acknowledge that the software was - * developed by the University of Southern California, Information - * Sciences Institute. The name of the University may not be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about - * the suitability of this software for any purpose. THIS SOFTWARE IS - * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Other copyrights might apply to parts of this software and are so - * noted when applicable. - */ - -/* RSRR things that are only needed by mrouted. */ - -/* Cache of Route Query messages, distinguished by source, - * destination, and client addresses. Cache is flushed by RSRR client - * -- it sends notification when an unwanted Route Reply is received. - * Since this only happens during route changes, it is more likely - * that the cache will be flushed when the kernel table entry is - * deleted. */ -struct rsrr_cache { - struct rsrr_rq route_query; /* Cached Route Query */ - struct sockaddr_un client_addr; /* Client address */ - int client_length; /* Length of client */ - struct rsrr_cache *next; /* next cache item */ -}; - diff --git a/usr.sbin/mrouted/testrsrr/Makefile b/usr.sbin/mrouted/testrsrr/Makefile deleted file mode 100644 index 4f57dde..0000000 --- a/usr.sbin/mrouted/testrsrr/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# $FreeBSD$ - -S= ${.CURDIR}/.. -.PATH: $S - -PROG= testrsrr -NO_MAN= - -CFLAGS+= -I$S - -install: - -.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/testrsrr/testrsrr.c b/usr.sbin/mrouted/testrsrr/testrsrr.c deleted file mode 100644 index 6dfe831..0000000 --- a/usr.sbin/mrouted/testrsrr/testrsrr.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 1995 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#include <stddef.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <err.h> -#include <sysexits.h> - -#include <sys/param.h> -#include <sys/types.h> -#include <unistd.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -#include "rsrr.h" - -char sunpath[MAXPATHLEN]; -int s; - -void exitfn(void) { - close(s); - unlink(sunpath); -} - -int main(void) { - struct sockaddr_un sun; - char buf[RSRR_MAX_LEN]; - struct rsrr_header *rh; - struct rsrr_vif *rvp; - int i; - - s = socket(PF_LOCAL, SOCK_DGRAM, 0); - if (s < 0) { - err(EX_OSERR, "socket(PF_LOCAL, SOCK_DGRAM, 0)"); - } - - sun.sun_family = AF_LOCAL; - snprintf(sunpath, sizeof sun.sun_path, "/tmp/testrsrr.%lu", - (unsigned long)getpid()); - strcpy(sun.sun_path, sunpath); - sun.sun_len = (offsetof(struct sockaddr_un, sun_path) - + strlen(sunpath)); - - if (bind(s, (struct sockaddr *)&sun, sun.sun_len) < 0) { - err(EX_OSERR, "bind: %s", sunpath); - } - - atexit(exitfn); /* clean up if we exit on error */ - - strcpy(sun.sun_path, RSRR_SERV_PATH); - sun.sun_len = (offsetof(struct sockaddr_un, sun_path) - + strlen(sunpath)); - - if (connect(s, (struct sockaddr *)&sun, sun.sun_len) < 0) { - err(EX_OSERR, "connect: %s", RSRR_SERV_PATH); - } - - rh = (struct rsrr_header *)buf; - rh->version = RSRR_MAX_VERSION; - rh->type = RSRR_INITIAL_QUERY; - rh->flags = 0; - rh->num = 0; - - if (write(s, rh, sizeof *rh) == (ssize_t)-1) { - err(EX_OSERR, "write(initial query)"); - } - - if (read(s, buf, sizeof buf) == (ssize_t)-1) { - err(EX_OSERR, "read(initial reply)"); - } - - if (rh->version != RSRR_MAX_VERSION) { - errx(EX_PROTOCOL, "bad remote version %d", rh->version); - } - - if (rh->type != RSRR_INITIAL_REPLY) { - errx(EX_PROTOCOL, "remote returned unexpected message type %d", - rh->type); - } - - if (rh->flags) { - printf("confusing flags: %d\n", rh->flags); - } - - printf("There are %d vifs configured:\n", rh->num); - - printf(" Vif Thresh Status Local address\n"); - for(i = 0, rvp = (struct rsrr_vif *)(rh + 1); i < rh->num; i++,rvp++) { - printf(" %3d %6d %6d %s\n", rvp->id, rvp->threshold, - rvp->status, inet_ntoa(rvp->local_addr)); - } - exit(0); -} diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c deleted file mode 100644 index 423fa53..0000000 --- a/usr.sbin/mrouted/vif.c +++ /dev/null @@ -1,1862 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * vif.c,v 3.8.4.56.2.1 1999/01/20 05:18:50 fenner Exp - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include "defs.h" -#include <fcntl.h> - -/* - * Exported variables. - */ -struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */ -vifi_t numvifs; /* number of vifs in use */ -int vifs_down; /* 1=>some interfaces are down */ -int phys_vif; /* An enabled vif */ -int udp_socket; /* Since the honkin' kernel doesn't support */ - /* ioctls on raw IP sockets, we need a UDP */ - /* socket as well as our IGMP (raw) socket. */ - /* How dumb. */ -int vifs_with_neighbors; /* == 1 if I am a leaf */ - -/* - * Private variables. - */ -struct listaddr *nbrs[MAXNBRS]; /* array of neighbors */ - -typedef struct { - vifi_t vifi; - struct listaddr *g; - int q_time; -} cbk_t; - -/* - * Forward declarations. - */ -static void start_vif __P((vifi_t vifi)); -static void start_vif2 __P((vifi_t vifi)); -static void stop_vif __P((vifi_t vifi)); -static void age_old_hosts __P((void)); -static void send_probe_on_vif __P((struct uvif *v)); -static void send_query __P((struct uvif *v)); -static int info_version __P((char *p, int plen)); -static void DelVif __P((void *arg)); -static int SetTimer __P((int vifi, struct listaddr *g)); -static int DeleteTimer __P((int id)); -static void SendQuery __P((void *arg)); -static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire, - int q_time)); - - -/* - * Initialize the virtual interfaces, but do not install - * them in the kernel. Start routing on all vifs that are - * not down or disabled. - */ -void -init_vifs() -{ - vifi_t vifi; - struct uvif *v; - int enabled_vifs, enabled_phyints; - extern char *configfilename; - - numvifs = 0; - vifs_with_neighbors = 0; - vifs_down = FALSE; - - /* - * Configure the vifs based on the interface configuration of the - * the kernel and the contents of the configuration file. - * (Open a UDP socket for ioctl use in the config procedures if - * the kernel can't handle IOCTL's on the IGMP socket.) - */ -#ifdef IOCTL_OK_ON_RAW_SOCKET - udp_socket = igmp_socket; -#else - if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - log(LOG_ERR, errno, "UDP socket"); -#endif - log(LOG_INFO,0,"Getting vifs from kernel interfaces"); - config_vifs_from_kernel(); - log(LOG_INFO,0,"Getting vifs from %s",configfilename); - config_vifs_from_file(); - - /* - * Quit if there are fewer than two enabled vifs. - */ - enabled_vifs = 0; - enabled_phyints = 0; - phys_vif = -1; - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!(v->uv_flags & VIFF_DISABLED)) { - ++enabled_vifs; - if (!(v->uv_flags & VIFF_TUNNEL)) { - if (phys_vif == -1) - phys_vif = vifi; - ++enabled_phyints; - } - } - } - if (enabled_vifs < 2) - log(LOG_ERR, 0, "can't forward: %s", - enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif"); - - if (enabled_phyints == 0) - log(LOG_WARNING, 0, - "no enabled interfaces, forwarding via tunnels only"); - - log(LOG_INFO, 0, "Installing vifs in mrouted..."); - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!(v->uv_flags & VIFF_DISABLED)) { - if (!(v->uv_flags & VIFF_DOWN)) { - if (v->uv_flags & VIFF_TUNNEL) - log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi, - inet_fmt(v->uv_lcl_addr, s1), - inet_fmt(v->uv_rmt_addr, s2)); - else - log(LOG_INFO, 0, "vif #%d, phyint %s", vifi, - inet_fmt(v->uv_lcl_addr, s1)); - start_vif2(vifi); - } else log(LOG_INFO, 0, - "%s is not yet up; vif #%u not in service", - v->uv_name, vifi); - } - } -} - -/* - * Initialize the passed vif with all appropriate default values. - * "t" is true if a tunnel, or false if a phyint. - */ -void -zero_vif(v, t) - struct uvif *v; - int t; -{ - v->uv_flags = 0; - v->uv_metric = DEFAULT_METRIC; - v->uv_admetric = 0; - v->uv_threshold = DEFAULT_THRESHOLD; - v->uv_rate_limit = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT; - v->uv_lcl_addr = 0; - v->uv_rmt_addr = 0; - v->uv_dst_addr = t ? 0 : dvmrp_group; - v->uv_subnet = 0; - v->uv_subnetmask = 0; - v->uv_subnetbcast = 0; - v->uv_name[0] = '\0'; - v->uv_groups = NULL; - v->uv_neighbors = NULL; - NBRM_CLRALL(v->uv_nbrmap); - v->uv_querier = NULL; - v->uv_igmpv1_warn = 0; - v->uv_prune_lifetime = 0; - v->uv_leaf_timer = 0; - v->uv_acl = NULL; - v->uv_addrs = NULL; - v->uv_filter = NULL; - v->uv_blasterbuf = NULL; - v->uv_blastercur = NULL; - v->uv_blasterend = NULL; - v->uv_blasterlen = 0; - v->uv_blastertimer = 0; - v->uv_nbrup = 0; - v->uv_icmp_warn = 0; - v->uv_nroutes = 0; -} - -/* - * Start routing on all virtual interfaces that are not down or - * administratively disabled. - */ -void -init_installvifs() -{ - vifi_t vifi; - struct uvif *v; - - log(LOG_INFO, 0, "Installing vifs in kernel..."); - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!(v->uv_flags & VIFF_DISABLED)) { - if (!(v->uv_flags & VIFF_DOWN)) { - if (v->uv_flags & VIFF_TUNNEL) - log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi, - inet_fmt(v->uv_lcl_addr, s1), - inet_fmt(v->uv_rmt_addr, s2)); - else - log(LOG_INFO, 0, "vif #%d, phyint %s", vifi, - inet_fmt(v->uv_lcl_addr, s1)); - k_add_vif(vifi, &uvifs[vifi]); - } else log(LOG_INFO, 0, - "%s is not yet up; vif #%u not in service", - v->uv_name, vifi); - } - } -} - -/* - * See if any interfaces have changed from up state to down, or vice versa, - * including any non-multicast-capable interfaces that are in use as local - * tunnel end-points. Ignore interfaces that have been administratively - * disabled. - */ -void -check_vif_state() -{ - register vifi_t vifi; - register struct uvif *v; - struct ifreq ifr; - static int checking_vifs = 0; - - /* - * If we get an error while checking, (e.g. two interfaces go down - * at once, and we decide to send a prune out one of the failed ones) - * then don't go into an infinite loop! - */ - if (checking_vifs) - return; - - vifs_down = FALSE; - checking_vifs = 1; - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - - if (v->uv_flags & VIFF_DISABLED) continue; - - strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ); - if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) - log(LOG_ERR, errno, - "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); - - if (v->uv_flags & VIFF_DOWN) { - if (ifr.ifr_flags & IFF_UP) { - log(LOG_NOTICE, 0, - "%s has come up; vif #%u now in service", - v->uv_name, vifi); - v->uv_flags &= ~VIFF_DOWN; - start_vif(vifi); - } - else vifs_down = TRUE; - } - else { - if (!(ifr.ifr_flags & IFF_UP)) { - log(LOG_NOTICE, 0, - "%s has gone down; vif #%u taken out of service", - v->uv_name, vifi); - stop_vif(vifi); - v->uv_flags |= VIFF_DOWN; - vifs_down = TRUE; - } - } - } - checking_vifs = 0; -} - -/* - * Send a DVMRP message on the specified vif. If DVMRP messages are - * to be encapsulated and sent "inside" the tunnel, use the special - * encapsulator. If it's not a tunnel or DVMRP messages are to be - * sent "beside" the tunnel, as required by earlier versions of mrouted, - * then just send the message. - */ -void -send_on_vif(v, dst, code, datalen) - register struct uvif *v; - u_int32 dst; - int code; - int datalen; -{ - u_int32 group = htonl(MROUTED_LEVEL | - ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)); - - /* - * The UNIX kernel will not decapsulate unicasts. - * Therefore, we don't send encapsulated unicasts. - */ - if ((v->uv_flags & (VIFF_TUNNEL|VIFF_OTUNNEL)) == VIFF_TUNNEL && - ((dst == 0) || IN_MULTICAST(ntohl(dst)))) - send_ipip(v->uv_lcl_addr, dst ? dst : dvmrp_group, IGMP_DVMRP, - code, group, datalen, v); - else - send_igmp(v->uv_lcl_addr, dst ? dst : v->uv_dst_addr, IGMP_DVMRP, - code, group, datalen); -} - - -/* - * Send a probe message on vif v - */ -static void -send_probe_on_vif(v) - register struct uvif *v; -{ - register char *p; - register int datalen = 0; - struct listaddr *nbr; - int i; - - if ((v->uv_flags & VIFF_PASSIVE && v->uv_neighbors == NULL) || - (v->uv_flags & VIFF_FORCE_LEAF)) - return; - - p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; - - for (i = 0; i < 4; i++) - *p++ = ((char *)&(dvmrp_genid))[i]; - datalen += 4; - - /* - * add the neighbor list on the interface to the message - */ - nbr = v->uv_neighbors; - - while (nbr) { - for (i = 0; i < 4; i++) - *p++ = ((char *)&nbr->al_addr)[i]; - datalen +=4; - nbr = nbr->al_next; - } - - send_on_vif(v, 0, DVMRP_PROBE, datalen); -} - -static void -send_query(v) - register struct uvif *v; -{ - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "sending %squery on vif %d", - (v->uv_flags & VIFF_IGMPV1) ? "v1 " : "", - v - uvifs); - send_igmp(v->uv_lcl_addr, allhosts_group, - IGMP_MEMBERSHIP_QUERY, - (v->uv_flags & VIFF_IGMPV1) ? 0 : - IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); -} - -/* - * Add a vifi to the kernel and start routing on it. - */ -static void -start_vif(vifi) - vifi_t vifi; -{ - /* - * Install the interface in the kernel's vif structure. - */ - k_add_vif(vifi, &uvifs[vifi]); - - start_vif2(vifi); -} - -/* - * Add a vifi to all the user-level data structures but don't add - * it to the kernel yet. - */ -static void -start_vif2(vifi) - vifi_t vifi; -{ - struct uvif *v; - u_int32 src; - struct phaddr *p; - - v = &uvifs[vifi]; - src = v->uv_lcl_addr; - - /* - * Update the existing route entries to take into account the new vif. - */ - add_vif_to_routes(vifi); - - if (!(v->uv_flags & VIFF_TUNNEL)) { - /* - * Join the DVMRP multicast group on the interface. - * (This is not strictly necessary, since the kernel promiscuously - * receives IGMP packets addressed to ANY IP multicast group while - * multicast routing is enabled. However, joining the group allows - * this host to receive non-IGMP packets as well, such as 'pings'.) - */ - k_join(dvmrp_group, src); - - /* - * Join the ALL-ROUTERS multicast group on the interface. - * This allows mtrace requests to loop back if they are run - * on the multicast router. - */ - k_join(allrtrs_group, src); - - /* - * Install an entry in the routing table for the subnet to which - * the interface is connected. - */ - start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL); - for (p = v->uv_addrs; p; p = p->pa_next) { - start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL); - } - - /* - * Until neighbors are discovered, assume responsibility for sending - * periodic group membership queries to the subnet. Send the first - * query. - */ - v->uv_flags |= VIFF_QUERIER; - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "assuming querier duties on vif %d", vifi); - send_query(v); - } - - v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; - - /* - * Send a probe via the new vif to look for neighbors. - */ - send_probe_on_vif(v); -} - -/* - * Stop routing on the specified virtual interface. - */ -static void -stop_vif(vifi) - vifi_t vifi; -{ - struct uvif *v; - struct listaddr *a; - struct phaddr *p; - - v = &uvifs[vifi]; - - if (!(v->uv_flags & VIFF_TUNNEL)) { - /* - * Depart from the DVMRP multicast group on the interface. - */ - k_leave(dvmrp_group, v->uv_lcl_addr); - - /* - * Depart from the ALL-ROUTERS multicast group on the interface. - */ - k_leave(allrtrs_group, v->uv_lcl_addr); - - /* - * Update the entry in the routing table for the subnet to which - * the interface is connected, to take into account the interface - * failure. - */ - start_route_updates(); - update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL); - for (p = v->uv_addrs; p; p = p->pa_next) { - start_route_updates(); - update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL); - } - - /* - * Discard all group addresses. (No need to tell kernel; - * the k_del_vif() call, below, will clean up kernel state.) - */ - while (v->uv_groups != NULL) { - a = v->uv_groups; - v->uv_groups = a->al_next; - free((char *)a); - } - - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "releasing querier duties on vif %d", vifi); - v->uv_flags &= ~VIFF_QUERIER; - } - - /* - * Update the existing route entries to take into account the vif failure. - */ - delete_vif_from_routes(vifi); - - /* - * Delete the interface from the kernel's vif structure. - */ - k_del_vif(vifi); - - /* - * Discard all neighbor addresses. - */ - if (!NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors--; - - while (v->uv_neighbors != NULL) { - a = v->uv_neighbors; - v->uv_neighbors = a->al_next; - nbrs[a->al_index] = NULL; - free((char *)a); - } - NBRM_CLRALL(v->uv_nbrmap); -} - - -/* - * stop routing on all vifs - */ -void -stop_all_vifs() -{ - vifi_t vifi; - struct uvif *v; - struct listaddr *a; - struct vif_acl *acl; - - for (vifi = 0; vifi < numvifs; vifi++) { - v = &uvifs[vifi]; - while (v->uv_groups != NULL) { - a = v->uv_groups; - v->uv_groups = a->al_next; - free((char *)a); - } - while (v->uv_neighbors != NULL) { - a = v->uv_neighbors; - v->uv_neighbors = a->al_next; - nbrs[a->al_index] = NULL; - free((char *)a); - } - while (v->uv_acl != NULL) { - acl = v->uv_acl; - v->uv_acl = acl->acl_next; - free((char *)acl); - } - } -} - - -/* - * Find the virtual interface from which an incoming packet arrived, - * based on the packet's source and destination IP addresses. - */ -vifi_t -find_vif(src, dst) - register u_int32 src; - register u_int32 dst; -{ - register vifi_t vifi; - register struct uvif *v; - register struct phaddr *p; - - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { - if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { - if (v->uv_flags & VIFF_TUNNEL) { - if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr || - dst == dvmrp_group)) - return(vifi); - } - else { - if ((src & v->uv_subnetmask) == v->uv_subnet && - ((v->uv_subnetmask == 0xffffffff) || - (src != v->uv_subnetbcast))) - return(vifi); - for (p=v->uv_addrs; p; p=p->pa_next) { - if ((src & p->pa_subnetmask) == p->pa_subnet && - ((p->pa_subnetmask == 0xffffffff) || - (src != p->pa_subnetbcast))) - return(vifi); - } - } - } - } - return (NO_VIF); -} - -static void -age_old_hosts() -{ - register vifi_t vifi; - register struct uvif *v; - register struct listaddr *g; - - /* - * Decrement the old-hosts-present timer for each - * active group on each vif. - */ - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) - for (g = v->uv_groups; g != NULL; g = g->al_next) - if (g->al_old) - g->al_old--; -} - - -/* - * Send group membership queries on each interface for which I am querier. - * Note that technically, there should be a timer per interface, as the - * dynamics of querier election can cause the "right" time to send a - * query to be different on different interfaces. However, this simple - * implementation only ever sends queries sooner than the "right" time, - * so can not cause loss of membership (but can send more packets than - * necessary) - */ -void -query_groups() -{ - register vifi_t vifi; - register struct uvif *v; - - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { - if (v->uv_flags & VIFF_QUERIER) { - send_query(v); - } - } - age_old_hosts(); -} - -/* - * Process an incoming host membership query. Warn about - * IGMP version mismatches, perform querier election, and - * handle group-specific queries when we're not the querier. - */ -void -accept_membership_query(src, dst, group, tmo) - u_int32 src, dst, group; - int tmo; -{ - register vifi_t vifi; - register struct uvif *v; - - if ((vifi = find_vif(src, dst)) == NO_VIF || - (uvifs[vifi].uv_flags & VIFF_TUNNEL)) { - log(LOG_INFO, 0, - "ignoring group membership query from non-adjacent host %s", - inet_fmt(src, s1)); - return; - } - - v = &uvifs[vifi]; - - if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) || - (tmo != 0 && (v->uv_flags & VIFF_IGMPV1))) { - int i; - - /* - * Exponentially back-off warning rate - */ - i = ++v->uv_igmpv1_warn; - while (i && !(i & 1)) - i >>= 1; - if (i == 1) - log(LOG_WARNING, 0, "%s %s on vif %d, %s", - tmo == 0 ? "Received IGMPv1 report from" - : "Received IGMPv2 report from", - inet_fmt(src, s1), - vifi, - tmo == 0 ? "please configure vif for IGMPv1" - : "but I am configured for IGMPv1"); - } - - if (v->uv_querier == NULL || v->uv_querier->al_addr != src) { - /* - * This might be: - * - A query from a new querier, with a lower source address - * than the current querier (who might be me) - * - A query from a new router that just started up and doesn't - * know who the querier is. - */ - if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr) - : ntohl(v->uv_lcl_addr))) { - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "new querier %s (was %s) on vif %d", - inet_fmt(src, s1), - v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) : - "me", vifi); - if (!v->uv_querier) { - v->uv_querier = (struct listaddr *) - malloc(sizeof(struct listaddr)); - v->uv_flags &= ~VIFF_QUERIER; - } - time(&v->uv_querier->al_ctime); - v->uv_querier->al_addr = src; - } else { - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "ignoring query from %s; querier on vif %d is still %s", - inet_fmt(src, s1), vifi, - v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) : - "me"); - - return; - } - } - - /* - * Reset the timer since we've received a query. - */ - if (v->uv_querier && src == v->uv_querier->al_addr) - v->uv_querier->al_timer = 0; - - /* - * If this is a Group-Specific query which we did not source, - * we must set our membership timer to [Last Member Query Count] * - * the [Max Response Time] in the packet. - */ - if (!(v->uv_flags & (VIFF_IGMPV1|VIFF_QUERIER)) && group != 0 && - src != v->uv_lcl_addr) { - register struct listaddr *g; - - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, - "%s for %s from %s on vif %d, timer %d", - "Group-specific membership query", - inet_fmt(group, s2), inet_fmt(src, s1), vifi, tmo); - - for (g = v->uv_groups; g != NULL; g = g->al_next) { - if (group == g->al_addr && g->al_query == 0) { - /* setup a timeout to remove the group membership */ - if (g->al_timerid) - g->al_timerid = DeleteTimer(g->al_timerid); - g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT * - tmo / IGMP_TIMER_SCALE; - /* use al_query to record our presence in last-member state */ - g->al_query = -1; - g->al_timerid = SetTimer(vifi, g); - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, - "timer for grp %s on vif %d set to %d", - inet_fmt(group, s2), vifi, g->al_timer); - break; - } - } - } -} - -/* - * Process an incoming group membership report. - */ -void -accept_group_report(src, dst, group, r_type) - u_int32 src, dst, group; - int r_type; -{ - register vifi_t vifi; - register struct uvif *v; - register struct listaddr *g; - - if ((vifi = find_vif(src, dst)) == NO_VIF || - (uvifs[vifi].uv_flags & VIFF_TUNNEL)) { - log(LOG_INFO, 0, - "ignoring group membership report from non-adjacent host %s", - inet_fmt(src, s1)); - return; - } - - v = &uvifs[vifi]; - - /* - * Look for the group in our group list; if found, reset its timer. - */ - for (g = v->uv_groups; g != NULL; g = g->al_next) { - if (group == g->al_addr) { - if (r_type == IGMP_V1_MEMBERSHIP_REPORT) - g->al_old = OLD_AGE_THRESHOLD; - - g->al_reporter = src; - - /** delete old timers, set a timer for expiration **/ - g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; - if (g->al_query) - g->al_query = DeleteTimer(g->al_query); - if (g->al_timerid) - g->al_timerid = DeleteTimer(g->al_timerid); - g->al_timerid = SetTimer(vifi, g); - break; - } - } - - /* - * If not found, add it to the list and update kernel cache. - */ - if (g == NULL) { - g = (struct listaddr *)malloc(sizeof(struct listaddr)); - if (g == NULL) - log(LOG_ERR, 0, "ran out of memory"); /* fatal */ - - g->al_addr = group; - if (r_type == IGMP_V1_MEMBERSHIP_REPORT) - g->al_old = OLD_AGE_THRESHOLD; - else - g->al_old = 0; - - /** set a timer for expiration **/ - g->al_query = 0; - g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; - g->al_reporter = src; - g->al_timerid = SetTimer(vifi, g); - g->al_next = v->uv_groups; - v->uv_groups = g; - time(&g->al_ctime); - - update_lclgrp(vifi, group); - } - - /* - * Check if a graft is necessary for this group - */ - chkgrp_graft(vifi, group); -} - -/* - * Process an incoming IGMPv2 Leave Group message. - */ -void -accept_leave_message(src, dst, group) - u_int32 src, dst, group; -{ - register vifi_t vifi; - register struct uvif *v; - register struct listaddr *g; - - if ((vifi = find_vif(src, dst)) == NO_VIF || - (uvifs[vifi].uv_flags & VIFF_TUNNEL)) { - log(LOG_INFO, 0, - "ignoring group leave report from non-adjacent host %s", - inet_fmt(src, s1)); - return; - } - - v = &uvifs[vifi]; - - if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1)) - return; - - /* - * Look for the group in our group list in order to set up a short-timeout - * query. - */ - for (g = v->uv_groups; g != NULL; g = g->al_next) { - if (group == g->al_addr) { - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, - "[vif.c, _accept_leave_message] %d %d \n", - g->al_old, g->al_query); - - /* Ignore the leave message if there are old hosts present */ - if (g->al_old) - return; - - /* still waiting for a reply to a query, ignore the leave */ - if (g->al_query) - return; - - /** delete old timer set a timer for expiration **/ - if (g->al_timerid) - g->al_timerid = DeleteTimer(g->al_timerid); - -#if IGMP_LAST_MEMBER_QUERY_COUNT != 2 -This code needs to be updated to keep a counter of the number -of queries remaining. -#endif - /** send a group specific querry **/ - g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL * - (IGMP_LAST_MEMBER_QUERY_COUNT + 1); - send_igmp(v->uv_lcl_addr, g->al_addr, - IGMP_MEMBERSHIP_QUERY, - IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE, - g->al_addr, 0); - g->al_query = SetQueryTimer(g, vifi, - IGMP_LAST_MEMBER_QUERY_INTERVAL, - IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE); - g->al_timerid = SetTimer(vifi, g); - break; - } - } -} - - -/* - * Send a periodic probe on all vifs. - * Useful to determine one-way interfaces. - * Detect neighbor loss faster. - */ -void -probe_for_neighbors() -{ - register vifi_t vifi; - register struct uvif *v; - - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { - if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { - send_probe_on_vif(v); - } - } -} - - -/* - * Send a list of all of our neighbors to the requestor, `src'. - */ -void -accept_neighbor_request(src, dst) - u_int32 src, dst; -{ - vifi_t vifi; - struct uvif *v; - u_char *p, *ncount; - struct listaddr *la; - int datalen; - u_int32 temp_addr, them = src; - -#define PUT_ADDR(a) temp_addr = ntohl(a); \ - *p++ = temp_addr >> 24; \ - *p++ = (temp_addr >> 16) & 0xFF; \ - *p++ = (temp_addr >> 8) & 0xFF; \ - *p++ = temp_addr & 0xFF; - - p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - datalen = 0; - - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { - if (v->uv_flags & VIFF_DISABLED) - continue; - - ncount = 0; - - for (la = v->uv_neighbors; la; la = la->al_next) { - - /* Make sure that there's room for this neighbor... */ - if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { - send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, - htonl(MROUTED_LEVEL), datalen); - p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - datalen = 0; - ncount = 0; - } - - /* Put out the header for this neighbor list... */ - if (ncount == 0) { - PUT_ADDR(v->uv_lcl_addr); - *p++ = v->uv_metric; - *p++ = v->uv_threshold; - ncount = p; - *p++ = 0; - datalen += 4 + 3; - } - - PUT_ADDR(la->al_addr); - datalen += 4; - (*ncount)++; - } - } - - if (datalen != 0) - send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, - htonl(MROUTED_LEVEL), datalen); -} - -/* - * Send a list of all of our neighbors to the requestor, `src'. - */ -void -accept_neighbor_request2(src, dst) - u_int32 src, dst; -{ - vifi_t vifi; - struct uvif *v; - u_char *p, *ncount; - struct listaddr *la; - int datalen; - u_int32 them = src; - - p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - datalen = 0; - - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { - register u_short vflags = v->uv_flags; - register u_char rflags = 0; - if (vflags & VIFF_TUNNEL) - rflags |= DVMRP_NF_TUNNEL; - if (vflags & VIFF_SRCRT) - rflags |= DVMRP_NF_SRCRT; - if (vflags & VIFF_DOWN) - rflags |= DVMRP_NF_DOWN; - if (vflags & VIFF_DISABLED) - rflags |= DVMRP_NF_DISABLED; - if (vflags & VIFF_QUERIER) - rflags |= DVMRP_NF_QUERIER; - if (vflags & VIFF_LEAF) - rflags |= DVMRP_NF_LEAF; - ncount = 0; - la = v->uv_neighbors; - if (la == NULL) { - /* - * include down & disabled interfaces and interfaces on - * leaf nets. - */ - if (rflags & DVMRP_NF_TUNNEL) - rflags |= DVMRP_NF_DOWN; - if (datalen > MAX_DVMRP_DATA_LEN - 12) { - send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, - htonl(MROUTED_LEVEL), datalen); - p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - datalen = 0; - } - *(u_int*)p = v->uv_lcl_addr; - p += 4; - *p++ = v->uv_metric; - *p++ = v->uv_threshold; - *p++ = rflags; - *p++ = 1; - *(u_int*)p = v->uv_rmt_addr; - p += 4; - datalen += 12; - } else { - for ( ; la; la = la->al_next) { - /* Make sure that there's room for this neighbor... */ - if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { - send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, - htonl(MROUTED_LEVEL), datalen); - p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - datalen = 0; - ncount = 0; - } - /* Put out the header for this neighbor list... */ - if (ncount == 0) { - /* If it's a one-way tunnel, mark it down. */ - if (rflags & DVMRP_NF_TUNNEL && la->al_flags & NBRF_ONEWAY) - rflags |= DVMRP_NF_DOWN; - *(u_int*)p = v->uv_lcl_addr; - p += 4; - *p++ = v->uv_metric; - *p++ = v->uv_threshold; - *p++ = rflags; - ncount = p; - *p++ = 0; - datalen += 4 + 4; - } - /* Don't report one-way peering on phyint at all */ - if (!(rflags & DVMRP_NF_TUNNEL) && la->al_flags & NBRF_ONEWAY) - continue; - *(u_int*)p = la->al_addr; - p += 4; - datalen += 4; - (*ncount)++; - } - if (*ncount == 0) { - *(u_int*)p = v->uv_rmt_addr; - p += 4; - datalen += 4; - (*ncount)++; - } - } - } - if (datalen != 0) - send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, - htonl(MROUTED_LEVEL), datalen); -} - -void -accept_info_request(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ - u_char *q; - int len; - int outlen = 0; - - q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); - - /* To be general, this must deal properly with breaking up over-sized - * packets. That implies passing a length to each function, and - * allowing each function to request to be called again. Right now, - * we're only implementing the one thing we are positive will fit into - * a single packet, so we wimp out. - */ - while (datalen > 0) { - len = 0; - switch (*p) { - case DVMRP_INFO_VERSION: - len = info_version(q, RECV_BUF_SIZE-(q-(u_char *)send_buf)); - break; - - case DVMRP_INFO_NEIGHBORS: - default: - log(LOG_INFO, 0, "ignoring unknown info type %d", *p); - break; - } - *(q+1) = len++; - outlen += len * 4; - q += len * 4; - len = (*(p+1) + 1) * 4; - p += len; - datalen -= len; - } - - if (outlen != 0) - send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY, - htonl(MROUTED_LEVEL), outlen); -} - -/* - * Information response -- return version string - */ -static int -info_version(p, plen) - char *p; - int plen; -{ - int len; - extern char versionstring[]; - - *p++ = DVMRP_INFO_VERSION; - p++; /* skip over length */ - *p++ = 0; /* zero out */ - *p++ = 0; /* reserved fields */ - strncpy(p, versionstring, plen - 4); - p[plen-5] = '\0'; - - len = strlen(versionstring); - return ((len + 3) / 4); -} - -/* - * Process an incoming neighbor-list message. - */ -void -accept_neighbors(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Process an incoming neighbor-list message. - */ -void -accept_neighbors2(src, dst, p, datalen, level) - u_int32 src, dst, level; - u_char *p; - int datalen; -{ - IF_DEBUG(DEBUG_PKT) - log(LOG_DEBUG, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - -/* - * Process an incoming info reply message. - */ -void -accept_info_reply(src, dst, p, datalen) - u_int32 src, dst; - u_char *p; - int datalen; -{ - IF_DEBUG(DEBUG_PKT) - log(LOG_DEBUG, 0, "ignoring spurious DVMRP info reply from %s to %s", - inet_fmt(src, s1), inet_fmt(dst, s2)); -} - - -/* - * Update the neighbor entry for neighbor 'addr' on vif 'vifi'. - * 'msgtype' is the type of DVMRP message received from the neighbor. - * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise. - */ -struct listaddr * -update_neighbor(vifi, addr, msgtype, p, datalen, level) - vifi_t vifi; - u_int32 addr; - int msgtype; - char *p; - int datalen; - u_int32 level; -{ - register struct uvif *v; - register struct listaddr *n; - int pv = level & 0xff; - int mv = (level >> 8) & 0xff; - int has_genid = 0; - int in_router_list = 0; - int dvmrpspec = 0; - u_int32 genid; - u_int32 send_tables = 0; - int i; - int do_reset = FALSE; - - v = &uvifs[vifi]; - - /* - * Confirm that 'addr' is a valid neighbor address on vif 'vifi'. - * IT IS ASSUMED that this was preceded by a call to find_vif(), which - * checks that 'addr' is either a valid remote tunnel endpoint or a - * non-broadcast address belonging to a directly-connected subnet. - * Therefore, here we check only that 'addr' is not our own address - * (due to an impostor or erroneous loopback) or an address of the form - * {subnet,0} ("the unknown host"). These checks are not performed in - * find_vif() because those types of address are acceptable for some - * types of IGMP message (such as group membership reports). - */ - if (!(v->uv_flags & VIFF_TUNNEL) && - (addr == v->uv_lcl_addr || - addr == v->uv_subnet )) { - log(LOG_WARNING, 0, - "received DVMRP message from %s: %s", - (addr == v->uv_lcl_addr) ? "self (check device loopback)" : - "'the unknown host'", - inet_fmt(addr, s1)); - return NULL; - } - - /* - * Ignore all neighbors on vifs forced into leaf mode - */ - if (v->uv_flags & VIFF_FORCE_LEAF) { - return NULL; - } - - /* - * mrouted's version 3.3 and later include the generation ID - * and the list of neighbors on the vif in their probe messages. - */ - if (msgtype == DVMRP_PROBE && ((pv == 3 && mv > 2) || - (pv > 3 && pv < 10))) { - u_int32 router; - - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "checking probe from %s (%d.%d) on vif %d", - inet_fmt(addr, s1), pv, mv, vifi); - - if (datalen < 4) { - log(LOG_WARNING, 0, - "received truncated probe message from %s (len %d)", - inet_fmt(addr, s1), datalen); - return NULL; - } - - has_genid = 1; - - for (i = 0; i < 4; i++) - ((char *)&genid)[i] = *p++; - datalen -= 4; - - while (datalen > 0) { - if (datalen < 4) { - log(LOG_WARNING, 0, - "received truncated probe message from %s (len %d)", - inet_fmt(addr, s1), datalen); - return NULL; - } - for (i = 0; i < 4; i++) - ((char *)&router)[i] = *p++; - datalen -= 4; - - if (router == v->uv_lcl_addr) { - in_router_list = 1; - break; - } - } - } - - if ((pv == 3 && mv == 255) || (pv > 3 && pv < 10)) - dvmrpspec = 1; - - /* - * Look for addr in list of neighbors. - */ - for (n = v->uv_neighbors; n != NULL; n = n->al_next) { - if (addr == n->al_addr) { - break; - } - } - - if (n == NULL) { - /* - * New neighbor. - * - * If this neighbor follows the DVMRP spec, start the probe - * handshake. If not, then it doesn't require the probe - * handshake, so establish the peering immediately. - */ - if (dvmrpspec && (msgtype != DVMRP_PROBE)) - return NULL; - - for (i = 0; i < MAXNBRS; i++) - if (nbrs[i] == NULL) - break; - - if (i == MAXNBRS) { - /* XXX This is a severe new restriction. */ - /* XXX want extensible bitmaps! */ - log(LOG_ERR, 0, "Can't handle %dth neighbor %s on vif %d!", - MAXNBRS, inet_fmt(addr, s1), vifi); - /*NOTREACHED*/ - } - - /* - * Add it to our list of neighbors. - */ - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d", - inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, - (level >> 16) & 0xff, i); - - n = (struct listaddr *)malloc(sizeof(struct listaddr)); - if (n == NULL) - log(LOG_ERR, 0, "ran out of memory"); /* fatal */ - - n->al_addr = addr; - n->al_pv = pv; - n->al_mv = mv; - n->al_genid = has_genid ? genid : 0; - n->al_index = i; - nbrs[i] = n; - - time(&n->al_ctime); - n->al_timer = 0; - n->al_flags = has_genid ? NBRF_GENID : 0; - n->al_next = v->uv_neighbors; - v->uv_neighbors = n; - - /* - * If we are not configured to peer with non-pruning routers, - * check the deprecated "I-know-how-to-prune" bit. This bit - * was MBZ in early mrouted implementations (<3.5) and is required - * to be set by the DVMRPv3 specification. - */ - if (!(v->uv_flags & VIFF_ALLOW_NONPRUNERS) && - !((level & 0x020000) || (pv == 3 && mv < 5))) { - n->al_flags |= NBRF_TOOOLD; - } - - /* - * If this router implements the DVMRPv3 spec, then don't peer - * with him if we haven't yet established a bidirectional connection. - */ - if (dvmrpspec) { - if (!in_router_list) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "waiting for probe from %s with my addr", - inet_fmt(addr, s1)); - n->al_flags |= NBRF_WAITING; - return NULL; - } - } - - if (n->al_flags & NBRF_DONTPEER) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "not peering with %s on vif %d because %x", - inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER); - return NULL; - } - - /* - * If we thought that we had no neighbors on this vif, send a route - * report to the vif. If this is just a new neighbor on the same - * vif, send the route report just to the new neighbor. - */ - if (NBRM_ISEMPTY(v->uv_nbrmap)) { - send_tables = v->uv_dst_addr; - vifs_with_neighbors++; - } else { - send_tables = addr; - } - - - NBRM_SET(i, v->uv_nbrmap); - add_neighbor_to_routes(vifi, i); - } else { - /* - * Found it. Reset its timer. - */ - n->al_timer = 0; - - if (n->al_flags & NBRF_WAITING && msgtype == DVMRP_PROBE) { - n->al_flags &= ~NBRF_WAITING; - if (!in_router_list) { - log(LOG_WARNING, 0, "possible one-way peering with %s on vif %d", - inet_fmt(addr, s1), vifi); - n->al_flags |= NBRF_ONEWAY; - return NULL; - } else { - if (NBRM_ISEMPTY(v->uv_nbrmap)) { - send_tables = v->uv_dst_addr; - vifs_with_neighbors++; - } else { - send_tables = addr; - } - NBRM_SET(n->al_index, v->uv_nbrmap); - add_neighbor_to_routes(vifi, n->al_index); - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "%s on vif %d exits WAITING", - inet_fmt(addr, s1), vifi); - } - } - - if (n->al_flags & NBRF_ONEWAY && msgtype == DVMRP_PROBE) { - if (in_router_list) { - if (NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors++; - NBRM_SET(n->al_index, v->uv_nbrmap); - add_neighbor_to_routes(vifi, n->al_index); - log(LOG_NOTICE, 0, "peering with %s on vif %d is no longer one-way", - inet_fmt(addr, s1), vifi); - n->al_flags &= ~NBRF_ONEWAY; - } else { - /* XXX rate-limited warning message? */ - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "%s on vif %d is still ONEWAY", - inet_fmt(addr, s1), vifi); - } - } - - /* - * When peering with a genid-capable but pre-DVMRP spec peer, - * we might bring up the peering with a route report and not - * remember his genid. Assume that he doesn't send a route - * report and then reboot before sending a probe. - */ - if (has_genid && !(n->al_flags & NBRF_GENID)) { - n->al_flags |= NBRF_GENID; - n->al_genid = genid; - } - - /* - * update the neighbors version and protocol number and genid - * if changed => router went down and came up, - * so take action immediately. - */ - if ((n->al_pv != pv) || - (n->al_mv != mv) || - (has_genid && n->al_genid != genid)) { - - do_reset = TRUE; - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, - "version/genid change neighbor %s [old:%d.%d/%8x, new:%d.%d/%8x]", - inet_fmt(addr, s1), - n->al_pv, n->al_mv, n->al_genid, pv, mv, genid); - - n->al_pv = pv; - n->al_mv = mv; - n->al_genid = genid; - time(&n->al_ctime); - } - - if ((pv == 3 && mv > 2) || (pv > 3 && pv < 10)) { - if (!(n->al_flags & VIFF_ONEWAY) && has_genid && !in_router_list && - (time(NULL) - n->al_ctime > 20)) { - if (NBRM_ISSET(n->al_index, v->uv_nbrmap)) { - NBRM_CLR(n->al_index, v->uv_nbrmap); - if (NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors--; - } - delete_neighbor_from_routes(addr, vifi, n->al_index); - reset_neighbor_state(vifi, addr); - log(LOG_WARNING, 0, "peering with %s on vif %d is one-way", - inet_fmt(addr, s1), vifi); - n->al_flags |= NBRF_ONEWAY; - } - } - - if (n->al_flags & NBRF_DONTPEER) { - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "not peering with %s on vif %d because %x", - inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER); - return NULL; - } - - /* check "leaf" flag */ - } - if (do_reset) { - reset_neighbor_state(vifi, addr); - if (!send_tables) - send_tables = addr; - } - if (send_tables) { - send_probe_on_vif(v); - report(ALL_ROUTES, vifi, send_tables); - } - v->uv_leaf_timer = 0; - v->uv_flags &= ~VIFF_LEAF; - - return n; -} - - -/* - * On every timer interrupt, advance the timer in each neighbor and - * group entry on every vif. - */ -void -age_vifs() -{ - register vifi_t vifi; - register struct uvif *v; - register struct listaddr *a, *prev_a; - register u_int32 addr; - - for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { - if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) { - v->uv_flags |= VIFF_LEAF; - } - - for (prev_a = (struct listaddr *)&(v->uv_neighbors), - a = v->uv_neighbors; - a != NULL; - prev_a = a, a = a->al_next) { - int exp_time; - int idx; - - if (((a->al_pv == 3) && (a->al_mv >= 3)) || - ((a->al_pv > 3) && (a->al_pv < 10))) - exp_time = NEIGHBOR_EXPIRE_TIME; - else - exp_time = OLD_NEIGHBOR_EXPIRE_TIME; - - if ((a->al_timer += TIMER_INTERVAL) < exp_time) - continue; - - IF_DEBUG(DEBUG_PEER) - log(LOG_DEBUG, 0, "Neighbor %s (%d.%d) expired after %d seconds", - inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, exp_time); - - /* - * Neighbor has expired; delete it from the neighbor list, - * delete it from the 'dominants' and 'subordinates arrays of - * any route entries. - */ - NBRM_CLR(a->al_index, v->uv_nbrmap); - nbrs[a->al_index] = NULL; /* XXX is it a good idea to reuse indxs? */ - idx = a->al_index; - addr = a->al_addr; - prev_a->al_next = a->al_next; - free((char *)a); - a = prev_a;/*XXX use ** */ - - delete_neighbor_from_routes(addr, vifi, idx); - reset_neighbor_state(vifi, addr); - - if (NBRM_ISEMPTY(v->uv_nbrmap)) - vifs_with_neighbors--; - - v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; - } - - if (v->uv_querier && - (v->uv_querier->al_timer += TIMER_INTERVAL) > - IGMP_OTHER_QUERIER_PRESENT_INTERVAL) { - /* - * The current querier has timed out. We must become the - * querier. - */ - IF_DEBUG(DEBUG_IGMP) - log(LOG_DEBUG, 0, "querier %s timed out", - inet_fmt(v->uv_querier->al_addr, s1)); - free(v->uv_querier); - v->uv_querier = NULL; - v->uv_flags |= VIFF_QUERIER; - send_query(v); - } - } -} - -/* - * Returns the neighbor info struct for a given neighbor - */ -struct listaddr * -neighbor_info(vifi, addr) - vifi_t vifi; - u_int32 addr; -{ - struct listaddr *u; - - for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next) - if (u->al_addr == addr) - return u; - - return NULL; -} - -static struct vnflags { - int vn_flag; - char *vn_name; -} vifflags[] = { - { VIFF_DOWN, "down" }, - { VIFF_DISABLED, "disabled" }, - { VIFF_QUERIER, "querier" }, - { VIFF_ONEWAY, "one-way" }, - { VIFF_LEAF, "leaf" }, - { VIFF_IGMPV1, "IGMPv1" }, - { VIFF_REXMIT_PRUNES, "rexmit_prunes" }, - { VIFF_PASSIVE, "passive" }, - { VIFF_ALLOW_NONPRUNERS,"allow_nonpruners" }, - { VIFF_NOFLOOD, "noflood" }, - { VIFF_NOTRANSIT, "notransit" }, - { VIFF_BLASTER, "blaster" }, - { VIFF_FORCE_LEAF, "force_leaf" }, - { VIFF_OTUNNEL, "old-tunnel" }, -}; - -static struct vnflags nbrflags[] = { - { NBRF_LEAF, "leaf" }, - { NBRF_GENID, "have-genid" }, - { NBRF_WAITING, "waiting" }, - { NBRF_ONEWAY, "one-way" }, - { NBRF_TOOOLD, "too old" }, - { NBRF_TOOMANYROUTES, "too many routes" }, - { NBRF_NOTPRUNING, "not pruning?" }, -}; - -/* - * Print the contents of the uvifs array on file 'fp'. - */ -void -dump_vifs(fp) - FILE *fp; -{ - register vifi_t vifi; - register struct uvif *v; - register struct listaddr *a; - register struct phaddr *p; - register struct vif_acl *acl; - int i; - struct sioc_vif_req v_req; - time_t now; - char *label; - - time(&now); - fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors); - - if (vifs_with_neighbors == 1) - fprintf(fp,"[This host is a leaf]\n\n"); - - fprintf(fp, - "\nVirtual Interface Table\n%s", - "Vif Name Local-Address "); - fprintf(fp, - "M Thr Rate Flags\n"); - - for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { - - fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ", - vifi, - v->uv_name, - inet_fmt(v->uv_lcl_addr, s1), - (v->uv_flags & VIFF_TUNNEL) ? - "tunnel": - "subnet", - (v->uv_flags & VIFF_TUNNEL) ? - inet_fmt(v->uv_rmt_addr, s2) : - inet_fmts(v->uv_subnet, v->uv_subnetmask, s3), - v->uv_metric, - v->uv_threshold, - v->uv_rate_limit); - - for (i = 0; i < sizeof(vifflags) / sizeof(struct vnflags); i++) - if (v->uv_flags & vifflags[i].vn_flag) - fprintf(fp, " %s", vifflags[i].vn_name); - - fprintf(fp, "\n"); - /* - fprintf(fp, " #routes: %d\n", v->uv_nroutes); - */ - if (v->uv_admetric != 0) - fprintf(fp, " advert-metric %2u\n", - v->uv_admetric); - - label = "alternate subnets:"; - for (p = v->uv_addrs; p; p = p->pa_next) { - fprintf(fp, " %18s %s\n", label, - inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); - label = ""; - } - - label = "peers:"; - for (a = v->uv_neighbors; a != NULL; a = a->al_next) { - fprintf(fp, " %6s %s (%d.%d) [%d]", - label, inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, - a->al_index); - for (i = 0; i < sizeof(nbrflags) / sizeof(struct vnflags); i++) - if (a->al_flags & nbrflags[i].vn_flag) - fprintf(fp, " %s", nbrflags[i].vn_name); - fprintf(fp, " up %s\n", scaletime(now - a->al_ctime)); - /*fprintf(fp, " #routes %d\n", a->al_nroutes);*/ - label = ""; - } - - label = "group host (time left):"; - for (a = v->uv_groups; a != NULL; a = a->al_next) { - fprintf(fp, " %23s %-15s %-15s (%s)\n", - label, - inet_fmt(a->al_addr, s1), - inet_fmt(a->al_reporter, s2), - scaletime(timer_leftTimer(a->al_timerid))); - label = ""; - } - label = "boundaries:"; - for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) { - fprintf(fp, " %11s %-18s\n", label, - inet_fmts(acl->acl_addr, acl->acl_mask, s1)); - label = ""; - } - if (v->uv_filter) { - struct vf_element *vfe; - char lbuf[100]; - - sprintf(lbuf, "%5s %7s filter:", - v->uv_filter->vf_flags & VFF_BIDIR ? "bidir" - : " ", - v->uv_filter->vf_type == VFT_ACCEPT ? "accept" - : "deny"); - label = lbuf; - for (vfe = v->uv_filter->vf_filter; - vfe != NULL; vfe = vfe->vfe_next) { - fprintf(fp, " %23s %-18s%s\n", - label, - inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s1), - vfe->vfe_flags & VFEF_EXACT ? " (exact)" : ""); - label = ""; - } - } - if (!(v->uv_flags & (VIFF_TUNNEL|VIFF_DOWN|VIFF_DISABLED))) { - fprintf(fp, " IGMP querier: "); - if (v->uv_querier == NULL) - if (v->uv_flags & VIFF_QUERIER) - fprintf(fp, "%-18s (this system)\n", - inet_fmt(v->uv_lcl_addr, s1)); - else - fprintf(fp, "NONE - querier election failure?\n"); - else - fprintf(fp, "%-18s up %s last heard %s ago\n", - inet_fmt(v->uv_querier->al_addr, s1), - scaletime(now - v->uv_querier->al_ctime), - scaletime(v->uv_querier->al_timer)); - } - if (v->uv_flags & VIFF_BLASTER) - fprintf(fp, " blasterbuf size: %dk\n", - v->uv_blasterlen / 1024); - fprintf(fp, " Nbr bitmaps: 0x%08lx%08lx\n",/*XXX*/ - v->uv_nbrmap.hi, v->uv_nbrmap.lo); - if (v->uv_prune_lifetime != 0) - fprintf(fp, " Prune Lifetime: %d seconds\n", - v->uv_prune_lifetime); - - v_req.vifi = vifi; - if (did_final_init) - if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { - log(LOG_WARNING, errno, - "SIOCGETVIFCNT fails on vif %d", vifi); - } else { - fprintf(fp, " pkts/bytes in : %lu/%lu\n", - v_req.icount, v_req.ibytes); - fprintf(fp, " pkts/bytes out: %lu/%lu\n", - v_req.ocount, v_req.obytes); - } - fprintf(fp, "\n"); - } - fprintf(fp, "\n"); -} - -/* - * Time out record of a group membership on a vif - */ -static void -DelVif(arg) - void *arg; -{ - cbk_t *cbk = (cbk_t *)arg; - vifi_t vifi = cbk->vifi; - struct uvif *v = &uvifs[vifi]; - struct listaddr *a, **anp, *g = cbk->g; - - /* - * Group has expired - * delete all kernel cache entries with this group - */ - if (g->al_query) - DeleteTimer(g->al_query); - - delete_lclgrp(vifi, g->al_addr); - - anp = &(v->uv_groups); - while ((a = *anp) != NULL) { - if (a == g) { - *anp = a->al_next; - free((char *)a); - } else { - anp = &a->al_next; - } - } - - free(cbk); -} - -/* - * Set a timer to delete the record of a group membership on a vif. - */ -static int -SetTimer(vifi, g) - vifi_t vifi; - struct listaddr *g; -{ - cbk_t *cbk; - - cbk = (cbk_t *) malloc(sizeof(cbk_t)); - cbk->g = g; - cbk->vifi = vifi; - return timer_setTimer(g->al_timer, DelVif, cbk); -} - -/* - * Delete a timer that was set above. - */ -static int -DeleteTimer(id) - int id; -{ - timer_clearTimer(id); - return 0; -} - -/* - * Send a group-specific query. - */ -static void -SendQuery(arg) - void *arg; -{ - cbk_t *cbk = (cbk_t *)arg; - register struct uvif *v = &uvifs[cbk->vifi]; - - send_igmp(v->uv_lcl_addr, cbk->g->al_addr, - IGMP_MEMBERSHIP_QUERY, - cbk->q_time, cbk->g->al_addr, 0); - cbk->g->al_query = 0; - free(cbk); -} - -/* - * Set a timer to send a group-specific query. - */ -static int -SetQueryTimer(g, vifi, to_expire, q_time) - struct listaddr *g; - vifi_t vifi; - int to_expire, q_time; -{ - cbk_t *cbk; - - cbk = (cbk_t *) malloc(sizeof(cbk_t)); - cbk->g = g; - cbk->q_time = q_time; - cbk->vifi = vifi; - return timer_setTimer(to_expire, SendQuery, cbk); -} diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h deleted file mode 100644 index 5be618d..0000000 --- a/usr.sbin/mrouted/vif.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * The mrouted program is covered by the license in the accompanying file - * named "LICENSE". Use of the mrouted program represents acceptance of - * the terms and conditions listed in that file. - * - * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of - * Leland Stanford Junior University. - * - * - * $FreeBSD$ - * vif.h,v 3.8.4.26 1998/01/14 21:21:19 fenner Exp - */ - - -/* - * Bitmap handling functions. - * These should be fast but generic. bytes can be slow to zero and compare, - * words are hard to make generic. Thus two sets of macros (yuk). - */ - -/* - * The VIFM_ functions should migrate out of <netinet/ip_mroute.h>, since - * the kernel no longer uses vifbitmaps. - */ -#ifndef VIFM_SET -typedef u_long vifbitmap_t; - -#define VIFM_SET(n, m) ((m) |= (1 << (n))) -#define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) -#define VIFM_ISSET(n, m) ((m) & (1 << (n))) -#define VIFM_CLRALL(m) ((m) = 0x00000000) -#define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) -#define VIFM_SAME(m1, m2) ((m1) == (m2)) -#endif -/* - * And <netinet/ip_mroute.h> was missing some required functions anyway - */ -#ifndef VIFM_SETALL -#define VIFM_SETALL(m) ((m) = ~0) -#endif -#define VIFM_ISSET_ONLY(n, m) ((m) == (1 << (n))) -#define VIFM_ISEMPTY(m) ((m) == 0) -#define VIFM_CLR_MASK(m, mask) ((m) &= ~(mask)) -#define VIFM_SET_MASK(m, mask) ((m) |= (mask)) - -/* - * Neighbor bitmaps are, for efficiency, implemented as a struct - * containing two variables of a native machine type. If you - * have a native type that's bigger than a long, define it below. - */ -#define NBRTYPE u_long -#define NBRBITS sizeof(NBRTYPE) * 8 - -typedef struct { - NBRTYPE hi; - NBRTYPE lo; -} nbrbitmap_t; -#define MAXNBRS 2 * NBRBITS -#define NO_NBR MAXNBRS - -#define NBRM_SET(n, m) (((n) < NBRBITS) ? ((m).lo |= (1 << (n))) : \ - ((m).hi |= (1 << (n - NBRBITS)))) -#define NBRM_CLR(n, m) (((n) < NBRBITS) ? ((m).lo &= ~(1 << (n))) : \ - ((m).hi &= ~(1 << (n - NBRBITS)))) -#define NBRM_ISSET(n, m) (((n) < NBRBITS) ? ((m).lo & (1 << (n))) : \ - ((m).hi & (1 << ((n) - NBRBITS)))) -#define NBRM_CLRALL(m) ((m).lo = (m).hi = 0) -#define NBRM_COPY(mfrom, mto) ((mto).lo = (mfrom).lo, (mto).hi = (mfrom).hi) -#define NBRM_SAME(m1, m2) (((m1).lo == (m2).lo) && ((m1).hi == (m2).hi)) -#define NBRM_ISEMPTY(m) (((m).lo == 0) && ((m).hi == 0)) -#define NBRM_SETMASK(m, mask) (((m).lo |= (mask).lo),((m).hi |= (mask).hi)) -#define NBRM_CLRMASK(m, mask) (((m).lo &= ~(mask).lo),((m).hi &= ~(mask).hi)) -#define NBRM_MASK(m, mask) (((m).lo &= (mask).lo),((m).hi &= (mask).hi)) -#define NBRM_ISSETMASK(m, mask) (((m).lo & (mask).lo) || ((m).hi & (mask).hi)) -#define NBRM_ISSETALLMASK(m, mask)\ - ((((m).lo & (mask).lo) == (mask).lo) && \ - (((m).hi & (mask).hi) == (mask).hi)) -/* - * This macro is TRUE if all the subordinates have been pruned, or if - * there are no subordinates on this vif. - * The arguments is the map of subordinates, the map of neighbors on the - * vif, and the map of received prunes. - */ -#define SUBS_ARE_PRUNED(sub, vifmask, prunes) \ - (((sub).lo & (vifmask).lo) == ((prunes).lo & (vifmask).lo & (sub).lo) && \ - ((sub).hi & (vifmask).hi) == ((prunes).hi & (vifmask).hi & (sub).hi)) - -struct blastinfo { - char * bi_buf; /* Pointer to malloced storage */ - char * bi_cur; /* The update to process next */ - char * bi_end; /* The place to put the next update */ - int bi_len; /* Size of malloced storage */ - int bi_timer; /* Timer to run process_blaster_report */ -}; - -/* - * User level Virtual Interface structure - * - * A "virtual interface" is either a physical, multicast-capable interface - * (called a "phyint") or a virtual point-to-point link (called a "tunnel"). - * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) - */ -struct uvif { - u_int uv_flags; /* VIFF_ flags defined below */ - u_char uv_metric; /* cost of this vif */ - u_char uv_admetric; /* advertised cost of this vif */ - u_char uv_threshold; /* min ttl required to forward on vif */ - u_int uv_rate_limit; /* rate limit on this vif */ - u_int32 uv_lcl_addr; /* local address of this vif */ - u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */ - u_int32 uv_dst_addr; /* destination for DVMRP messages */ - u_int32 uv_subnet; /* subnet number (phyints only) */ - u_int32 uv_subnetmask; /* subnet mask (phyints only) */ - u_int32 uv_subnetbcast;/* subnet broadcast addr (phyints only) */ - char uv_name[IFNAMSIZ]; /* interface name */ - struct listaddr *uv_groups; /* list of local groups (phyints only) */ - struct listaddr *uv_neighbors; /* list of neighboring routers */ - nbrbitmap_t uv_nbrmap; /* bitmap of active neighboring routers */ - struct listaddr *uv_querier; /* IGMP querier on vif */ - int uv_igmpv1_warn;/* To rate-limit IGMPv1 warnings */ - int uv_prune_lifetime; /* Prune lifetime or 0 for default */ - struct vif_acl *uv_acl; /* access control list of groups */ - int uv_leaf_timer; /* time until this vif is considrd leaf */ - struct phaddr *uv_addrs; /* Additional subnets on this vif */ - struct vif_filter *uv_filter; /* Route filters on this vif */ - struct blastinfo uv_blaster; /* Info about route blasters */ - int uv_nbrup; /* Counter for neighbor up events */ - int uv_icmp_warn; /* To rate-limit ICMP warnings */ - u_int uv_nroutes; /* # of routes with this vif as parent */ - struct ip *uv_encap_hdr; /* Pre-formed header to encapsulate msgs*/ -}; - -#define uv_blasterbuf uv_blaster.bi_buf -#define uv_blastercur uv_blaster.bi_cur -#define uv_blasterend uv_blaster.bi_end -#define uv_blasterlen uv_blaster.bi_len -#define uv_blastertimer uv_blaster.bi_timer - -#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT) -#define VIFF_DOWN 0x000100 /* kernel state of interface */ -#define VIFF_DISABLED 0x000200 /* administratively disabled */ -#define VIFF_QUERIER 0x000400 /* I am the subnet's querier */ -#define VIFF_ONEWAY 0x000800 /* Maybe one way interface */ -#define VIFF_LEAF 0x001000 /* all neighbors are leaves */ -#define VIFF_IGMPV1 0x002000 /* Act as an IGMPv1 Router */ -#define VIFF_REXMIT_PRUNES 0x004000 /* retransmit prunes */ -#define VIFF_PASSIVE 0x008000 /* passive tunnel */ -#define VIFF_ALLOW_NONPRUNERS 0x010000 /* ok to peer with nonprunrs */ -#define VIFF_NOFLOOD 0x020000 /* don't flood on this vif */ -#define VIFF_NOTRANSIT 0x040000 /* don't transit these vifs */ -#define VIFF_BLASTER 0x080000 /* nbr on vif blasts routes */ -#define VIFF_FORCE_LEAF 0x100000 /* ignore nbrs on this vif */ -#define VIFF_OTUNNEL 0x200000 /* DVMRP msgs "beside" tunnel*/ - -#define AVOID_TRANSIT(v, r) \ - (((r)->rt_parent != NO_VIF) && \ - ((r)->rt_gateway != 0) && \ - (uvifs[(v)].uv_flags & VIFF_NOTRANSIT) && \ - (uvifs[(r)->rt_parent].uv_flags & VIFF_NOTRANSIT)) - -struct phaddr { - struct phaddr *pa_next; - u_int32 pa_subnet; /* extra subnet */ - u_int32 pa_subnetmask; /* netmask of extra subnet */ - u_int32 pa_subnetbcast; /* broadcast of extra subnet */ -}; - -struct vif_acl { - struct vif_acl *acl_next; /* next acl member */ - u_int32 acl_addr; /* Group address */ - u_int32 acl_mask; /* Group addr. mask */ -}; - -struct vif_filter { - int vf_type; -#define VFT_ACCEPT 1 -#define VFT_DENY 2 - int vf_flags; -#define VFF_BIDIR 1 - struct vf_element *vf_filter; -}; - -struct vf_element { - struct vf_element *vfe_next; - u_int32 vfe_addr; - u_int32 vfe_mask; - int vfe_flags; -#define VFEF_EXACT 0x0001 -}; - -struct listaddr { - struct listaddr *al_next; /* link to next addr, MUST BE FIRST */ - u_int32 al_addr; /* local group or neighbor address */ - u_long al_timer; /* for timing out group or neighbor */ - time_t al_ctime; /* entry creation time */ - union { - struct { - u_int32 alur_genid; /* generation id for neighbor */ - u_int alur_nroutes; /* # of routes w/ nbr as parent */ - u_char alur_pv; /* router protocol version */ - u_char alur_mv; /* router mrouted version */ - u_char alur_index; /* neighbor index */ - } alu_router; - struct { - u_int32 alug_reporter; /* a host which reported membership */ - u_long alug_timerid; /* timer for group membership */ - u_long alug_query; /* timer for repeated leave query */ - u_char alug_old; /* time since heard old report */ - } alu_group; - } al_alu; - u_short al_flags; /* flags related to this neighbor */ -}; -#define al_genid al_alu.alu_router.alur_genid -#define al_nroutes al_alu.alu_router.alur_nroutes -#define al_pv al_alu.alu_router.alur_pv -#define al_mv al_alu.alu_router.alur_mv -#define al_index al_alu.alu_router.alur_index -#define al_reporter al_alu.alu_group.alug_reporter -#define al_old al_alu.alu_group.alug_old -#define al_timerid al_alu.alu_group.alug_timerid -#define al_query al_alu.alu_group.alug_query - -#define NBRF_LEAF 0x0001 /* This neighbor is a leaf */ -#define NBRF_GENID 0x0100 /* I know this neighbor's genid */ -#define NBRF_WAITING 0x0200 /* Waiting for peering to come up */ -#define NBRF_ONEWAY 0x0400 /* One-way peering */ -#define NBRF_TOOOLD 0x0800 /* Too old (policy decision) */ -#define NBRF_TOOMANYROUTES 0x1000 /* Neighbor is spouting routes */ -#define NBRF_NOTPRUNING 0x2000 /* Neighbor doesn't appear to prune */ - -/* - * Don't peer with neighbors with any of these flags set - */ -#define NBRF_DONTPEER (NBRF_WAITING|NBRF_ONEWAY|NBRF_TOOOLD| \ - NBRF_TOOMANYROUTES|NBRF_NOTPRUNING) - -#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */ |