aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1999-01-20 07:44:19 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1999-01-20 07:44:19 +0000
commit6a9d269dea5681cbacb1734c8ac8d6e218c52546 (patch)
tree4fa0ff03448b7de1a0ffee28b9da8f124b109c9a
parent1f25327484733d0bec3b33044da7bd5d82ad007f (diff)
This commit was manufactured by cvs2svn to create tagvendor/mrouted/3.9-beta3
'mrouted_3_9_beta3_ios12'.
Notes
Notes: svn path=/cvs2svn/branches/XEROX/; revision=42888 svn path=/cvs2svn/tags/mrouted_3_9_beta3_ios12/; revision=42890; tag=vendor/mrouted/3.9-beta3
-rw-r--r--usr.sbin/mrouted/mtrace.8591
-rw-r--r--usr.sbin/mrouted/mtrace.c3138
-rw-r--r--usr.sbin/mrouted/mtrace.h89
3 files changed, 0 insertions, 3818 deletions
diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8
deleted file mode 100644
index 820fde13ec30..000000000000
--- a/usr.sbin/mrouted/mtrace.8
+++ /dev/null
@@ -1,591 +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.
-.\"
-.\" mtrace.8,v 5.2 1998/12/04 04:48:16 fenner Exp
-.\"
-.TH MTRACE 8 "May 8, 1995"
-.UC 6
-.SH NAME
-mtrace \- print multicast path from a source to a receiver
-.SH SYNOPSIS
-.B mtrace
-[
-.B \-e
-.I extrahops
-] [
-.B \-g
-.I gateway
-] [
-.B \-i
-.I if_addr
-] [
-.B \-l
-] [
-.B \-M
-] [
-.B \-m
-.I max_hops
-] [
-.B \-n
-] [
-.B \-O
-] [
-.B \-p
-] [
-.B \-P
-] [
-.B \-q
-.I nqueries
-] [
-.B \-r
-.I resp_dest
-] [
-.B \-s
-] [
-.B \-S
-.I stat_int
-] [
-.B \-t
-.I ttl
-] [
-.B \-T
-] [
-.B \-U
-] [
-.B \-v
-] [
-.B \-w
-.I waittime
-]
-.I source
-[
-.I receiver
-] [
-.I group
-]
-.SH DESCRIPTION
-Assessing problems in the distribution of IP multicast traffic
-can be difficult.
-.B mtrace
-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
-.I receiver
-to the
-.IR 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
-.I source
-host name or address. The default
-.I receiver
-is the host running mtrace, and the default
-.I 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
-.I receiver
-is a unicast address and the
-.I group
-is a multicast address.
-If the
-.B \-g
-flag is specified, the source address defaults to the host running
-mtrace, and the receiver defaults to the router being addressed with
-the
-.B \-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 -i option must be used to set the local address.
-.SH OPTIONS
-.TP 8 8
-.BI \-e\ extrahops
-Try tracing
-.I extrahops
-hops past a non-responding router.
-.TP 8 8
-.BI \-g\ gwy
-Send the trace query via unicast directly to the multicast router
-.I gwy
-rather than multicasting the query.
-This must be the last-hop router on the path from the intended
-.I source
-to the
-.IR receiver .
-.RS 8
-.TP 12 12
-.I CAUTION!!
-Versions 3.3 and 3.5 of
-.B mrouted
-will crash if a trace query is received via a
-unicast packet and
-.B mrouted
-has no route for the
-.I source
-address. Therefore, do not use the
-.B \-g
-option unless the target
-.B mrouted
-has been verified to be 3.4 or newer than 3.5.
-.RE
-.TP 8 8
-.BI \-i\ addr
-Use
-.I addr
-as the local interface address (on a multi-homed host) for sending the
-trace query and as the default for the
-.I receiver
-and the response destination.
-.TP 8 8
-.B \-l
-Loop indefinitely printing packet rate and loss statistics for the
-multicast path every 10 seconds (see
-.B \-S
-.IR stat_int ).
-.TP 8 8
-.B \-M
-Always request the response using multicast rather than attempting
-unicast for the last half of the tries.
-.TP 8 8
-.BI \-m\ n
-Set to
-.I n
-the maximum number of hops that will be traced from the
-.I receiver
-back toward the
-.IR source .
-The default is 32 hops (infinity for the DVMRP routing protocol).
-.TP 8 8
-.B \-n
-Print hop addresses numerically rather than symbolically and numerically
-(saves a nameserver address-to-name lookup for each router found on the
-path).
-.TP 8 8
-.BI \-q\ n
-Set the maximum number of query attempts for any hop to
-.IR n .
-The default is 3.
-.TP 8 8
-.B \-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
--O flag if the last-hop router is a Cisco.
-.TP 8 8
-.B \-p
-Listen passively for multicast responses from traces initiated by
-others. This works best when run on a multicast router.
-.TP 8 8
-.B \-P
-Loop indefinitely collecting the path every 10 seconds (see
-.B \-S
-.IR stat_int )
-and printing it when it changes. Do not print any statistics.
-.TP 8 8
-.BI \-r\ host
-Send the trace response to
-.I host
-rather than to the host on which
-.B mtrace
-is being run, or to a multicast address other than the one registered
-for this purpose (224.0.1.32).
-.TP 8 8
-.B \-s
-Print a short form output including only the multicast path and not
-the packet rate and loss statistics.
-.TP 8 8
-.BI \-S\ n
-Change the interval between statistics gathering traces to
-.I n
-seconds (default 10 seconds).
-.TP 8 8
-.BI \-t\ ttl
-Set the
-.I 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.
-.TP 8 8
-.B \-T
-"Tunnel statistics" mode; show loss rates for overall traffic.
-These statistics can be extremely misleading.
-.TP 8 8
-.B \-U
-Always request the response using unicast rather than attempting
-multicast first.
-.TP 8 8
-.B \-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.
-.TP 8 8
-.BI \-w\ n
-Set the time to wait for a trace response to
-.I n
-seconds (default 3 seconds).
-.SH USAGE
-.SS How It Works
-The technique used by the
-.B traceroute
-tool 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
-.I receiver
-to the
-.IR source .
-A trace query packet is sent to the last
-hop multicast router (the leaf router for the desired
-.I 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
-.IR 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
-.IR 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
-.I source
-to the
-.IR 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
-.I 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
-.B \-t
-option).
-If the last hop router is known, it may also be addressed directly
-using the
-.B \-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
-.B \-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
-.IR receiver .
-.SS Directing the Response
-By default,
-.B mtrace
-first attempts to trace the full reverse path, unless the number of
-hops to trace is explicitly set with the
-.B \-m
-option. If there is no response within a 3 second timeout interval
-(changed with the
-.B \-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
-.B \-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's 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
-.B mtrace .
-Alternatively, the multicast ttl may be set explicitly with the
-.B \-t
-option, the initial multicast attempts can be forced to use unicast
-instead with the
-.B \-U
-option, the final unicast attempts can be forced to use multicast
-isntead with the
-.B \-M
-option, or if you specify
-.B \-UM
-.B mtrace
-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,
-.B mtrace
-will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2
-request (as used by the
-.B mrinfo
-program) to see what kind of router it is.
-.B mtrace
-will try to query three (changed with the
-.B \-e
-option) hops past a non-responding router, in the hopes that even
-though it isn't capable of sending a response, it might be capable of
-forwarding the request on.
-.SH EXAMPLES
-The output of
-.B mtrace
-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
-.I source
-to the
-.IR 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
-.nf
-.ft C
-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.
-.fi
-.PP
-If a hop reports that it is using the default route to forward packets,
-the word
-.B [default]
-is printed after that hop. If the
-.B \-v
-flag is supplied, the route being used to forward packets is printed
-in the form
-.B [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
-.I source
-to the specified
-.IR group .
-The first group of statistics may be expanded to include loss rates
-using the
-.B \-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
-.B \-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
-.B \-s
-option is set or if no multicast group is specified.
-.ie t \{\
-.ft C
-. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
-(If this example is not properly columned with a fixed-width font, get
-.B groff
-and try again.)
-. \}
-.\}
-.PP
-.ft C
-.nf
-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
-.fi
-.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:
-.LP
-.RS
-.PD 0
-.TP 3
-\(bu
-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.
-.TP 3
-\(bu
-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.
-.PD
-.RE
-.LP
-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
-.B \-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
-.B mrouted
-that did not implement the multicast traceroute function, so
-.B mtrace
-switched to hop-by-hop mode. The \*(lqOutput pruned\*(rq error code
-indicates that traffic for group 224.2.143.24 would not be forwarded.
-.PP
-.nf
-.ft C
-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
-.fi
-.SH AUTHOR
-Implemented by Steve Casner based on an initial prototype written by
-Ajit Thyagarajan. The multicast traceroute mechanism was designed by
-Van Jacobson with help from Steve Casner, Steve Deering, Dino
-Farinacci, and Deb Agrawal; it was implemented in
-.B mrouted
-by Ajit Thyagarajan and Bill Fenner. The option syntax and the output
-format of
-.B mtrace
-are modeled after the unicast
-.B traceroute
-program written by Van Jacobson.
-.SH SEE ALSO
-.BR mrouted (8) ,
-.BR mrinfo (8) ,
-.BR map-mbone (8) ,
-.BR traceroute (8)
-.SH BUGS
-.PP
-Statistics collection in passive mode doesn't 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 4bebbc8fe17b..000000000000
--- a/usr.sbin/mrouted/mtrace.c
+++ /dev/null
@@ -1,3138 +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 char rcsid[] =
- "@(#) mtrace.c,v 5.2 1998/12/04 04:48:19 fenner Exp";
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <memory.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <syslog.h>
-#include <netdb.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 *, ...));
-
-
-/*
- * 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)random() >> 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) {
- 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) perror("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) perror("recvfrom");
- continue;
- }
-
- if (recvlen < sizeof(struct ip)) {
- fprintf(stderr,
- "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) {
- fprintf(stderr,
- "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
- recvlen, iphdrlen, ipdatalen);
- continue;
- }
-
- igmp = (struct igmp *) (recv_buf + iphdrlen);
- igmpdatalen = ipdatalen - IGMP_MINLEN;
- if (igmpdatalen < 0) {
- fprintf(stderr,
- "IP data field too short (%u bytes) for IGMP from %s\n",
- 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) {
- fprintf(stderr,
- "Num hops received (%d) exceeds request (%d)\n",
- 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;
- 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) perror("recvfrom");
- continue;
- }
-
- if (recvlen < sizeof(struct ip)) {
- fprintf(stderr,
- "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) {
- fprintf(stderr,
- "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
- recvlen, iphdrlen, ipdatalen);
- continue;
- }
-
- igmp = (struct igmp *) (recv_buf + iphdrlen);
- igmpdatalen = ipdatalen - IGMP_MINLEN;
- if (igmpdatalen < 0) {
- fprintf(stderr,
- "IP data field too short (%u bytes) for IGMP from %s\n",
- 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;
- }
- }
-
- now = localtime(&tr.tv_sec);
- strftime(timebuf, sizeof(timebuf) - 1, "%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';
- /* Fall through */
-
- 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';
- /* Fall through */
-#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 ", ntohl(s->tr_vifin));
- printf("v_out: %ld ", ntohl(s->tr_vifout));
- printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
- printf("v_out: %ld ", ntohl(r->tr_vifout));
- printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
- printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
- printf("pkts: %ld ", 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 ", ntohl(n->tr_vifin));
- printf("v_out: %ld ", ntohl(n->tr_vifout));
- printf("pkts: %ld\n", ntohl(n->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ", ntohl(b->tr_vifin));
- printf("v_out: %ld ", ntohl(b->tr_vifout));
- printf("pkts: %ld\n", ntohl(b->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
- printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
- printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
- printf("\t\t\t\treset: %x hoptime: %lx\n", *r, 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) {
- fprintf(stderr, "mtrace: must be root\n");
- exit(1);
- }
-
- /*
- * 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) goto 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
- goto 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
- goto 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
- goto 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 */
- {
- char *s = strchr(rcsid, ',');
-
- 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 %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
- goto 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
- goto 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
- goto 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
- goto usage;
- case 'g': /* Last-hop gateway (dest of query) */
- if (arg && (gwy = host_addr(arg))) {
- if (arg == argv[0]) argv++, argc--;
- break;
- } else
- goto 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
- goto 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
- goto usage;
- case 'r': /* Dest for response packet */
- if (arg && (raddr = host_addr(arg))) {
- if (arg == argv[0]) argv++, argc--;
- break;
- } else
- goto usage;
- case 'i': /* Local interface address */
- if (arg && (lcl_addr = host_addr(arg))) {
- if (arg == argv[0]) argv++, argc--;
- break;
- } else
- goto 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
- goto usage;
- default:
- goto 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 {
- goto 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))) goto usage;
- } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) goto usage;
- }
- }
-
- if (passive) {
- passive_mode();
- return(0);
- }
-
- if (argc > 0) {
-usage: printf("\
-Usage: mtrace [-MUOPTWVlnpvs] [-e extra_hops] [-f first_hop] [-i if_addr]\n\
- [-g gateway] [-m max_hops] [-q nqueries] [-r resp_dest]\n\
- [-S statint] [-t ttl] [-w wait] source [receiver] [group]\n");
- exit(1);
- }
-
-#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 */
- fprintf(stderr, "mtrace: WARNING: no multicast group specified, so no statistics printed\n");
- numstats = 0;
- }
- } else {
- if (weak)
- fprintf(stderr, "mtrace: WARNING: group was specified so not performing \"weak\" mtrace\n");
- }
-
- /*
- * 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) {
- perror("Determining local address");
- exit(-1);
- }
-
- /*
- * 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)
- goto 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);
-#else
- srandom(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) {
- fprintf(stderr, "mtrace: weak mtrace requires -g if destination is not local.\n");
- exit(1);
- }
-
- 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);
-}
-
-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) strcat(fmt, "warning - ");
- strncat(fmt, format, 80);
- 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 e67dbd0fa145..000000000000
--- 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