1  | 
     | 
     | 
    /*	$OpenBSD: mtrace.c,v 1.39 2017/08/31 12:03:02 otto Exp $	*/  | 
    
    
    2  | 
     | 
     | 
    /*	$NetBSD: mtrace.c,v 1.5 1995/12/10 10:57:15 mycroft Exp $	*/  | 
    
    
    3  | 
     | 
     | 
     | 
    
    
    4  | 
     | 
     | 
    /*  | 
    
    
    5  | 
     | 
     | 
     * mtrace.c  | 
    
    
    6  | 
     | 
     | 
     *  | 
    
    
    7  | 
     | 
     | 
     * This tool traces the branch of a multicast tree from a source to a  | 
    
    
    8  | 
     | 
     | 
     * receiver for a particular multicast group and gives statistics  | 
    
    
    9  | 
     | 
     | 
     * about packet rate and loss for each hop along the path.  It can  | 
    
    
    10  | 
     | 
     | 
     * usually be invoked just as  | 
    
    
    11  | 
     | 
     | 
     *  | 
    
    
    12  | 
     | 
     | 
     *	mtrace source  | 
    
    
    13  | 
     | 
     | 
     *  | 
    
    
    14  | 
     | 
     | 
     * to trace the route from that source to the local host for a default  | 
    
    
    15  | 
     | 
     | 
     * group when only the route is desired and not group-specific packet  | 
    
    
    16  | 
     | 
     | 
     * counts.  See the usage line for more complex forms.  | 
    
    
    17  | 
     | 
     | 
     *  | 
    
    
    18  | 
     | 
     | 
     *  | 
    
    
    19  | 
     | 
     | 
     * Released 4 Apr 1995.  This program was adapted by Steve Casner  | 
    
    
    20  | 
     | 
     | 
     * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and  | 
    
    
    21  | 
     | 
     | 
     * Xerox PARC).  It attempts to parallel in command syntax and output  | 
    
    
    22  | 
     | 
     | 
     * format the unicast traceroute program written by Van Jacobson (LBL)  | 
    
    
    23  | 
     | 
     | 
     * for the parts where that makes sense.  | 
    
    
    24  | 
     | 
     | 
     *  | 
    
    
    25  | 
     | 
     | 
     * Copyright (c) 1998-2001.  | 
    
    
    26  | 
     | 
     | 
     * The University of Southern California/Information Sciences Institute.  | 
    
    
    27  | 
     | 
     | 
     * All rights reserved.  | 
    
    
    28  | 
     | 
     | 
     *  | 
    
    
    29  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    30  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    31  | 
     | 
     | 
     * are met:  | 
    
    
    32  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    33  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    34  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    35  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    36  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    37  | 
     | 
     | 
     * 3. Neither the name of the project nor the names of its contributors  | 
    
    
    38  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    39  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    40  | 
     | 
     | 
     *  | 
    
    
    41  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    42  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    43  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    44  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE  | 
    
    
    45  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    46  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    47  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    48  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    49  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    50  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    51  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    52  | 
     | 
     | 
     */  | 
    
    
    53  | 
     | 
     | 
     | 
    
    
    54  | 
     | 
     | 
    #include <netdb.h>  | 
    
    
    55  | 
     | 
     | 
    #include <sys/time.h>  | 
    
    
    56  | 
     | 
     | 
    #include <string.h>  | 
    
    
    57  | 
     | 
     | 
    #include <poll.h>  | 
    
    
    58  | 
     | 
     | 
    #include <ctype.h>  | 
    
    
    59  | 
     | 
     | 
    #include <sys/ioctl.h>  | 
    
    
    60  | 
     | 
     | 
    #include "defs.h"  | 
    
    
    61  | 
     | 
     | 
    #include <arpa/inet.h>  | 
    
    
    62  | 
     | 
     | 
    #include <stdarg.h>  | 
    
    
    63  | 
     | 
     | 
    #ifdef SUNOS5  | 
    
    
    64  | 
     | 
     | 
    #include <sys/systeminfo.h>  | 
    
    
    65  | 
     | 
     | 
    #endif  | 
    
    
    66  | 
     | 
     | 
    #include <ifaddrs.h>  | 
    
    
    67  | 
     | 
     | 
    #include <err.h>  | 
    
    
    68  | 
     | 
     | 
     | 
    
    
    69  | 
     | 
     | 
    #define DEFAULT_TIMEOUT	3	/* How long to wait before retrying requests */  | 
    
    
    70  | 
     | 
     | 
    #define DEFAULT_RETRIES 3	/* How many times to try */  | 
    
    
    71  | 
     | 
     | 
    #define MAXHOPS UNREACHABLE	/* Don't need more hops than max metric */  | 
    
    
    72  | 
     | 
     | 
    #define UNICAST_TTL 255		/* TTL for unicast response */  | 
    
    
    73  | 
     | 
     | 
    #define MULTICAST_TTL1 64	/* Default TTL for multicast query/response */  | 
    
    
    74  | 
     | 
     | 
    #define MULTICAST_TTL_INC 32	/* TTL increment for increase after timeout */  | 
    
    
    75  | 
     | 
     | 
    #define MULTICAST_TTL_MAX 192	/* Maximum TTL allowed (protect low-BW links */  | 
    
    
    76  | 
     | 
     | 
     | 
    
    
    77  | 
     | 
     | 
    struct resp_buf { | 
    
    
    78  | 
     | 
     | 
        u_long qtime;		/* Time query was issued */  | 
    
    
    79  | 
     | 
     | 
        u_long rtime;		/* Time response was received */  | 
    
    
    80  | 
     | 
     | 
        int	len;			/* Number of reports or length of data */  | 
    
    
    81  | 
     | 
     | 
        struct igmp igmp;		/* IGMP header */  | 
    
    
    82  | 
     | 
     | 
        union { | 
    
    
    83  | 
     | 
     | 
    	struct { | 
    
    
    84  | 
     | 
     | 
    	    struct tr_query q;		/* Query/response header */  | 
    
    
    85  | 
     | 
     | 
    	    struct tr_resp r[MAXHOPS];	/* Per-hop reports */  | 
    
    
    86  | 
     | 
     | 
    	} t;  | 
    
    
    87  | 
     | 
     | 
    	char d[MAX_DVMRP_DATA_LEN];	/* Neighbor data */  | 
    
    
    88  | 
     | 
     | 
        } u;  | 
    
    
    89  | 
     | 
     | 
    } base, incr[2];  | 
    
    
    90  | 
     | 
     | 
     | 
    
    
    91  | 
     | 
     | 
    #define qhdr u.t.q  | 
    
    
    92  | 
     | 
     | 
    #define resps u.t.r  | 
    
    
    93  | 
     | 
     | 
    #define ndata u.d  | 
    
    
    94  | 
     | 
     | 
     | 
    
    
    95  | 
     | 
     | 
    char names[MAXHOPS][40];  | 
    
    
    96  | 
     | 
     | 
    int reset[MAXHOPS];			/* To get around 3.4 bug, ... */  | 
    
    
    97  | 
     | 
     | 
    int swaps[MAXHOPS];			/* To get around 3.6 bug, ... */  | 
    
    
    98  | 
     | 
     | 
     | 
    
    
    99  | 
     | 
     | 
    int timeout = DEFAULT_TIMEOUT;  | 
    
    
    100  | 
     | 
     | 
    int nqueries = DEFAULT_RETRIES;  | 
    
    
    101  | 
     | 
     | 
    int numeric = FALSE;  | 
    
    
    102  | 
     | 
     | 
    int debug = 0;  | 
    
    
    103  | 
     | 
     | 
    int passive = FALSE;  | 
    
    
    104  | 
     | 
     | 
    int multicast = FALSE;  | 
    
    
    105  | 
     | 
     | 
    int statint = 10;  | 
    
    
    106  | 
     | 
     | 
    int verbose = 0;  | 
    
    
    107  | 
     | 
     | 
     | 
    
    
    108  | 
     | 
     | 
    u_int32_t defgrp;			/* Default group if not specified */  | 
    
    
    109  | 
     | 
     | 
    u_int32_t query_cast;			/* All routers multicast addr */  | 
    
    
    110  | 
     | 
     | 
    u_int32_t resp_cast;			/* Mtrace response multicast addr */  | 
    
    
    111  | 
     | 
     | 
     | 
    
    
    112  | 
     | 
     | 
    u_int32_t lcl_addr = 0;			/* This host address, in NET order */  | 
    
    
    113  | 
     | 
     | 
    u_int32_t dst_netmask;			/* netmask to go with qdst */  | 
    
    
    114  | 
     | 
     | 
     | 
    
    
    115  | 
     | 
     | 
    /*  | 
    
    
    116  | 
     | 
     | 
     * Query/response parameters, all initialized to zero and set later  | 
    
    
    117  | 
     | 
     | 
     * to default values or from options.  | 
    
    
    118  | 
     | 
     | 
     */  | 
    
    
    119  | 
     | 
     | 
    u_int32_t qsrc = 0;		/* Source address in the query */  | 
    
    
    120  | 
     | 
     | 
    u_int32_t qgrp = 0;		/* Group address in the query */  | 
    
    
    121  | 
     | 
     | 
    u_int32_t qdst = 0;		/* Destination (receiver) address in query */  | 
    
    
    122  | 
     | 
     | 
    u_char qno  = 0;		/* Max number of hops to query */  | 
    
    
    123  | 
     | 
     | 
    u_int32_t raddr = 0;		/* Address where response should be sent */  | 
    
    
    124  | 
     | 
     | 
    int    qttl = 0;		/* TTL for the query packet */  | 
    
    
    125  | 
     | 
     | 
    u_char rttl = 0;		/* TTL for the response packet */  | 
    
    
    126  | 
     | 
     | 
    u_int32_t gwy = 0;		/* User-supplied last-hop router address */  | 
    
    
    127  | 
     | 
     | 
    u_int32_t tdst = 0;		/* Address where trace is sent (last-hop) */  | 
    
    
    128  | 
     | 
     | 
     | 
    
    
    129  | 
     | 
     | 
    vifi_t  numvifs;		/* to keep loader happy */  | 
    
    
    130  | 
     | 
     | 
    				/* (see kern.c) */  | 
    
    
    131  | 
     | 
     | 
     | 
    
    
    132  | 
     | 
     | 
    char *			inet_name(u_int32_t addr);  | 
    
    
    133  | 
     | 
     | 
    u_int32_t			host_addr(char *name);  | 
    
    
    134  | 
     | 
     | 
    /* u_int is promoted u_char */  | 
    
    
    135  | 
     | 
     | 
    char *			proto_type(u_int type);  | 
    
    
    136  | 
     | 
     | 
    char *			flag_type(u_int type);  | 
    
    
    137  | 
     | 
     | 
     | 
    
    
    138  | 
     | 
     | 
    u_int32_t			get_netmask(int s, u_int32_t dst);  | 
    
    
    139  | 
     | 
     | 
    int			get_ttl(struct resp_buf *buf);  | 
    
    
    140  | 
     | 
     | 
    int			t_diff(u_long a, u_long b);  | 
    
    
    141  | 
     | 
     | 
    u_long			fixtime(u_long time);  | 
    
    
    142  | 
     | 
     | 
    int			send_recv(u_int32_t dst, int type, int code,  | 
    
    
    143  | 
     | 
     | 
    			    int tries, struct resp_buf *save);  | 
    
    
    144  | 
     | 
     | 
    char *			print_host(u_int32_t addr);  | 
    
    
    145  | 
     | 
     | 
    char *			print_host2(u_int32_t addr1, u_int32_t addr2);  | 
    
    
    146  | 
     | 
     | 
    void			print_trace(int index, struct resp_buf *buf);  | 
    
    
    147  | 
     | 
     | 
    int			what_kind(struct resp_buf *buf, char *why);  | 
    
    
    148  | 
     | 
     | 
    char *			scale(int *hop);  | 
    
    
    149  | 
     | 
     | 
    void			stat_line(struct tr_resp *r, struct tr_resp *s,  | 
    
    
    150  | 
     | 
     | 
    			    int have_next, int *res);  | 
    
    
    151  | 
     | 
     | 
    void			fixup_stats(struct resp_buf *base,  | 
    
    
    152  | 
     | 
     | 
    			    struct resp_buf *prev, struct resp_buf *new);  | 
    
    
    153  | 
     | 
     | 
    int			print_stats(struct resp_buf *base,  | 
    
    
    154  | 
     | 
     | 
    			    struct resp_buf *prev, struct resp_buf *new);  | 
    
    
    155  | 
     | 
     | 
    void			check_vif_state(void);  | 
    
    
    156  | 
     | 
     | 
    u_long			byteswap(u_long v);  | 
    
    
    157  | 
     | 
     | 
     | 
    
    
    158  | 
     | 
     | 
    int			main(int argc, char *argv[]);  | 
    
    
    159  | 
     | 
     | 
     | 
    
    
    160  | 
     | 
     | 
     | 
    
    
    161  | 
     | 
     | 
     | 
    
    
    162  | 
     | 
     | 
    char   *  | 
    
    
    163  | 
     | 
     | 
    inet_name(u_int32_t addr)  | 
    
    
    164  | 
     | 
     | 
    { | 
    
    
    165  | 
     | 
     | 
        struct hostent *e;  | 
    
    
    166  | 
     | 
     | 
     | 
    
    
    167  | 
     | 
     | 
        e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);  | 
    
    
    168  | 
     | 
     | 
     | 
    
    
    169  | 
     | 
     | 
        return e ? e->h_name : "?";  | 
    
    
    170  | 
     | 
     | 
    }  | 
    
    
    171  | 
     | 
     | 
     | 
    
    
    172  | 
     | 
     | 
     | 
    
    
    173  | 
     | 
     | 
    u_int32_t  | 
    
    
    174  | 
     | 
     | 
    host_addr(char *name)  | 
    
    
    175  | 
     | 
     | 
    { | 
    
    
    176  | 
     | 
     | 
        struct hostent *e = NULL;  | 
    
    
    177  | 
     | 
     | 
        u_int32_t  addr;  | 
    
    
    178  | 
     | 
     | 
        int	i, dots = 3;  | 
    
    
    179  | 
     | 
     | 
        char	buf[40];  | 
    
    
    180  | 
     | 
     | 
        char	*ip = name;  | 
    
    
    181  | 
     | 
     | 
        char	*op = buf;  | 
    
    
    182  | 
     | 
     | 
     | 
    
    
    183  | 
     | 
     | 
        /*  | 
    
    
    184  | 
     | 
     | 
         * Undo BSD's favor -- take fewer than 4 octets as net/subnet address  | 
    
    
    185  | 
     | 
     | 
         * if the name is all numeric.  | 
    
    
    186  | 
     | 
     | 
         */  | 
    
    
    187  | 
     | 
     | 
        for (i = sizeof(buf) - 7; i > 0; --i) { | 
    
    
    188  | 
     | 
     | 
    	if (*ip == '.')  | 
    
    
    189  | 
     | 
     | 
    		--dots;  | 
    
    
    190  | 
     | 
     | 
    	else if (*ip == '\0')  | 
    
    
    191  | 
     | 
     | 
    		break;  | 
    
    
    192  | 
     | 
     | 
    	else if (!isdigit((unsigned char)*ip))  | 
    
    
    193  | 
     | 
     | 
    		dots = 0;  /* Not numeric, don't add zeroes */  | 
    
    
    194  | 
     | 
     | 
    	*op++ = *ip++;  | 
    
    
    195  | 
     | 
     | 
        }  | 
    
    
    196  | 
     | 
     | 
        for (i = 0; i < dots; ++i) { | 
    
    
    197  | 
     | 
     | 
    	*op++ = '.';  | 
    
    
    198  | 
     | 
     | 
    	*op++ = '0';  | 
    
    
    199  | 
     | 
     | 
        }  | 
    
    
    200  | 
     | 
     | 
        *op = '\0';  | 
    
    
    201  | 
     | 
     | 
     | 
    
    
    202  | 
     | 
     | 
        if (dots <= 0) e = gethostbyname(name);  | 
    
    
    203  | 
     | 
     | 
        if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);  | 
    
    
    204  | 
     | 
     | 
        else { | 
    
    
    205  | 
     | 
     | 
    	addr = inet_addr(buf);  | 
    
    
    206  | 
     | 
     | 
    	if (addr == -1) { | 
    
    
    207  | 
     | 
     | 
    	    addr = 0;  | 
    
    
    208  | 
     | 
     | 
    	    printf("Could not parse %s as host name or address\n", name); | 
    
    
    209  | 
     | 
     | 
    	}  | 
    
    
    210  | 
     | 
     | 
        }  | 
    
    
    211  | 
     | 
     | 
        return addr;  | 
    
    
    212  | 
     | 
     | 
    }  | 
    
    
    213  | 
     | 
     | 
     | 
    
    
    214  | 
     | 
     | 
     | 
    
    
    215  | 
     | 
     | 
    char *  | 
    
    
    216  | 
     | 
     | 
    proto_type(u_int type)  | 
    
    
    217  | 
     | 
     | 
    { | 
    
    
    218  | 
     | 
     | 
        static char buf[80];  | 
    
    
    219  | 
     | 
     | 
     | 
    
    
    220  | 
     | 
     | 
        switch (type) { | 
    
    
    221  | 
     | 
     | 
          case PROTO_DVMRP:  | 
    
    
    222  | 
     | 
     | 
    	return ("DVMRP"); | 
    
    
    223  | 
     | 
     | 
          case PROTO_MOSPF:  | 
    
    
    224  | 
     | 
     | 
    	return ("MOSPF"); | 
    
    
    225  | 
     | 
     | 
          case PROTO_PIM:  | 
    
    
    226  | 
     | 
     | 
    	return ("PIM"); | 
    
    
    227  | 
     | 
     | 
          case PROTO_CBT:  | 
    
    
    228  | 
     | 
     | 
    	return ("CBT"); | 
    
    
    229  | 
     | 
     | 
          default:  | 
    
    
    230  | 
     | 
     | 
    	(void) snprintf(buf, sizeof buf, "Unknown protocol code %d", type);  | 
    
    
    231  | 
     | 
     | 
    	return (buf);  | 
    
    
    232  | 
     | 
     | 
        }  | 
    
    
    233  | 
     | 
     | 
    }  | 
    
    
    234  | 
     | 
     | 
     | 
    
    
    235  | 
     | 
     | 
     | 
    
    
    236  | 
     | 
     | 
    char *  | 
    
    
    237  | 
     | 
     | 
    flag_type(u_int type)  | 
    
    
    238  | 
     | 
     | 
    { | 
    
    
    239  | 
     | 
     | 
        static char buf[80];  | 
    
    
    240  | 
     | 
     | 
     | 
    
    
    241  | 
     | 
     | 
        switch (type) { | 
    
    
    242  | 
     | 
     | 
          case TR_NO_ERR:  | 
    
    
    243  | 
     | 
     | 
    	return (""); | 
    
    
    244  | 
     | 
     | 
          case TR_WRONG_IF:  | 
    
    
    245  | 
     | 
     | 
    	return ("Wrong interface"); | 
    
    
    246  | 
     | 
     | 
          case TR_PRUNED:  | 
    
    
    247  | 
     | 
     | 
    	return ("Prune sent upstream"); | 
    
    
    248  | 
     | 
     | 
          case TR_OPRUNED:  | 
    
    
    249  | 
     | 
     | 
    	return ("Output pruned"); | 
    
    
    250  | 
     | 
     | 
          case TR_SCOPED:  | 
    
    
    251  | 
     | 
     | 
    	return ("Hit scope boundary"); | 
    
    
    252  | 
     | 
     | 
          case TR_NO_RTE:  | 
    
    
    253  | 
     | 
     | 
    	return ("No route"); | 
    
    
    254  | 
     | 
     | 
          case TR_OLD_ROUTER:  | 
    
    
    255  | 
     | 
     | 
    	return ("Next router no mtrace"); | 
    
    
    256  | 
     | 
     | 
          case TR_NO_FWD:  | 
    
    
    257  | 
     | 
     | 
    	return ("Not forwarding"); | 
    
    
    258  | 
     | 
     | 
          case TR_NO_SPACE:  | 
    
    
    259  | 
     | 
     | 
    	return ("No space in packet"); | 
    
    
    260  | 
     | 
     | 
          default:  | 
    
    
    261  | 
     | 
     | 
    	(void) snprintf(buf, sizeof buf, "Unknown error code %d", type);  | 
    
    
    262  | 
     | 
     | 
    	return (buf);  | 
    
    
    263  | 
     | 
     | 
        }  | 
    
    
    264  | 
     | 
     | 
    }  | 
    
    
    265  | 
     | 
     | 
     | 
    
    
    266  | 
     | 
     | 
    /*  | 
    
    
    267  | 
     | 
     | 
     * If destination is on a local net, get the netmask, else set the  | 
    
    
    268  | 
     | 
     | 
     * netmask to all ones.  There are two side effects: if the local  | 
    
    
    269  | 
     | 
     | 
     * address was not explicitly set, and if the destination is on a  | 
    
    
    270  | 
     | 
     | 
     * local net, use that one; in either case, verify that the local  | 
    
    
    271  | 
     | 
     | 
     * address is valid.  | 
    
    
    272  | 
     | 
     | 
     */  | 
    
    
    273  | 
     | 
     | 
     | 
    
    
    274  | 
     | 
     | 
    u_int32_t  | 
    
    
    275  | 
     | 
     | 
    get_netmask(int s, u_int32_t dst)  | 
    
    
    276  | 
     | 
     | 
    { | 
    
    
    277  | 
     | 
     | 
        u_int32_t if_addr, if_mask;  | 
    
    
    278  | 
     | 
     | 
        u_int32_t retval = 0xFFFFFFFF;  | 
    
    
    279  | 
     | 
     | 
        int found = FALSE;  | 
    
    
    280  | 
     | 
     | 
        struct ifaddrs *ifap, *ifa;  | 
    
    
    281  | 
     | 
     | 
     | 
    
    
    282  | 
     | 
     | 
        if (getifaddrs(&ifap) != 0) { | 
    
    
    283  | 
     | 
     | 
    	perror("getifaddrs"); | 
    
    
    284  | 
     | 
     | 
    	return (retval);  | 
    
    
    285  | 
     | 
     | 
        }  | 
    
    
    286  | 
     | 
     | 
        for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | 
    
    
    287  | 
     | 
     | 
    	if (ifa->ifa_addr->sa_family != AF_INET)  | 
    
    
    288  | 
     | 
     | 
                 continue;  | 
    
    
    289  | 
     | 
     | 
    	if_addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;  | 
    
    
    290  | 
     | 
     | 
    	if_mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;  | 
    
    
    291  | 
     | 
     | 
    	if ((dst & if_mask) == (if_addr & if_mask)) { | 
    
    
    292  | 
     | 
     | 
    	    retval = if_mask;  | 
    
    
    293  | 
     | 
     | 
    	    if (lcl_addr == 0)  | 
    
    
    294  | 
     | 
     | 
    		lcl_addr = if_addr;  | 
    
    
    295  | 
     | 
     | 
    	}  | 
    
    
    296  | 
     | 
     | 
    	if (lcl_addr == if_addr)  | 
    
    
    297  | 
     | 
     | 
    	    found = TRUE;  | 
    
    
    298  | 
     | 
     | 
        }  | 
    
    
    299  | 
     | 
     | 
        if (!found && lcl_addr != 0) { | 
    
    
    300  | 
     | 
     | 
    	printf("Interface address is not valid\n"); | 
    
    
    301  | 
     | 
     | 
    	exit(1);  | 
    
    
    302  | 
     | 
     | 
        }  | 
    
    
    303  | 
     | 
     | 
        freeifaddrs(ifap);  | 
    
    
    304  | 
     | 
     | 
        return (retval);  | 
    
    
    305  | 
     | 
     | 
    }  | 
    
    
    306  | 
     | 
     | 
     | 
    
    
    307  | 
     | 
     | 
     | 
    
    
    308  | 
     | 
     | 
    int  | 
    
    
    309  | 
     | 
     | 
    get_ttl(struct resp_buf *buf)  | 
    
    
    310  | 
     | 
     | 
    { | 
    
    
    311  | 
     | 
     | 
        int rno;  | 
    
    
    312  | 
     | 
     | 
        struct tr_resp *b;  | 
    
    
    313  | 
     | 
     | 
        u_int ttl;  | 
    
    
    314  | 
     | 
     | 
     | 
    
    
    315  | 
     | 
     | 
        if (buf && (rno = buf->len) > 0) { | 
    
    
    316  | 
     | 
     | 
    	b = buf->resps + rno - 1;  | 
    
    
    317  | 
     | 
     | 
    	ttl = b->tr_fttl;  | 
    
    
    318  | 
     | 
     | 
     | 
    
    
    319  | 
     | 
     | 
    	while (--rno > 0) { | 
    
    
    320  | 
     | 
     | 
    	    --b;  | 
    
    
    321  | 
     | 
     | 
    	    if (ttl < b->tr_fttl) ttl = b->tr_fttl;  | 
    
    
    322  | 
     | 
     | 
    	    else ++ttl;  | 
    
    
    323  | 
     | 
     | 
    	}  | 
    
    
    324  | 
     | 
     | 
    	ttl += MULTICAST_TTL_INC;  | 
    
    
    325  | 
     | 
     | 
    	if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;  | 
    
    
    326  | 
     | 
     | 
    	if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;  | 
    
    
    327  | 
     | 
     | 
    	return (ttl);  | 
    
    
    328  | 
     | 
     | 
        } else return(MULTICAST_TTL1);  | 
    
    
    329  | 
     | 
     | 
    }  | 
    
    
    330  | 
     | 
     | 
     | 
    
    
    331  | 
     | 
     | 
    /*  | 
    
    
    332  | 
     | 
     | 
     * Calculate the difference between two 32-bit NTP timestamps and return  | 
    
    
    333  | 
     | 
     | 
     * the result in milliseconds.  | 
    
    
    334  | 
     | 
     | 
     */  | 
    
    
    335  | 
     | 
     | 
    int  | 
    
    
    336  | 
     | 
     | 
    t_diff(u_long a, u_long b)  | 
    
    
    337  | 
     | 
     | 
    { | 
    
    
    338  | 
     | 
     | 
        int d = a - b;  | 
    
    
    339  | 
     | 
     | 
     | 
    
    
    340  | 
     | 
     | 
        return ((d * 125) >> 13);  | 
    
    
    341  | 
     | 
     | 
    }  | 
    
    
    342  | 
     | 
     | 
     | 
    
    
    343  | 
     | 
     | 
    /*  | 
    
    
    344  | 
     | 
     | 
     * Fixup for incorrect time format in 3.3 mrouted.  | 
    
    
    345  | 
     | 
     | 
     * This is possible because (JAN_1970 mod 64K) is quite close to 32K,  | 
    
    
    346  | 
     | 
     | 
     * so correct and incorrect times will be far apart.  | 
    
    
    347  | 
     | 
     | 
     */  | 
    
    
    348  | 
     | 
     | 
    u_long  | 
    
    
    349  | 
     | 
     | 
    fixtime(u_long time)  | 
    
    
    350  | 
     | 
     | 
    { | 
    
    
    351  | 
     | 
     | 
        if (abs((int)(time-base.qtime)) > 0x3FFFFFFF)  | 
    
    
    352  | 
     | 
     | 
            time = ((time & 0xFFFF0000) + (JAN_1970 << 16)) +  | 
    
    
    353  | 
     | 
     | 
    	       ((time & 0xFFFF) << 14) / 15625;  | 
    
    
    354  | 
     | 
     | 
        return (time);  | 
    
    
    355  | 
     | 
     | 
    }  | 
    
    
    356  | 
     | 
     | 
     | 
    
    
    357  | 
     | 
     | 
    /*  | 
    
    
    358  | 
     | 
     | 
     * Swap bytes for poor little-endian machines that don't byte-swap  | 
    
    
    359  | 
     | 
     | 
     */  | 
    
    
    360  | 
     | 
     | 
    u_long  | 
    
    
    361  | 
     | 
     | 
    byteswap(u_long v)  | 
    
    
    362  | 
     | 
     | 
    { | 
    
    
    363  | 
     | 
     | 
        return ((v << 24) | ((v & 0xff00) << 8) |  | 
    
    
    364  | 
     | 
     | 
    	    ((v >> 8) & 0xff00) | (v >> 24));  | 
    
    
    365  | 
     | 
     | 
    }  | 
    
    
    366  | 
     | 
     | 
     | 
    
    
    367  | 
     | 
     | 
    int  | 
    
    
    368  | 
     | 
     | 
    send_recv(u_int32_t dst, int type, int code, int tries, struct resp_buf *save)  | 
    
    
    369  | 
     | 
     | 
    { | 
    
    
    370  | 
     | 
     | 
        struct timeval tq, tr, tv;  | 
    
    
    371  | 
     | 
     | 
        struct ip *ip;  | 
    
    
    372  | 
     | 
     | 
        struct igmp *igmp;  | 
    
    
    373  | 
     | 
     | 
        struct tr_query *query, *rquery;  | 
    
    
    374  | 
     | 
     | 
        int ipdatalen, iphdrlen, igmpdatalen;  | 
    
    
    375  | 
     | 
     | 
        u_int32_t local, group;  | 
    
    
    376  | 
     | 
     | 
        int datalen;  | 
    
    
    377  | 
     | 
     | 
        struct pollfd pfd[1];  | 
    
    
    378  | 
     | 
     | 
        int count, recvlen, dummy = 0;  | 
    
    
    379  | 
     | 
     | 
        int len;  | 
    
    
    380  | 
     | 
     | 
        int i;  | 
    
    
    381  | 
     | 
     | 
     | 
    
    
    382  | 
     | 
     | 
        if (type == IGMP_MTRACE_QUERY) { | 
    
    
    383  | 
     | 
     | 
    	group = qgrp;  | 
    
    
    384  | 
     | 
     | 
    	datalen = sizeof(struct tr_query);  | 
    
    
    385  | 
     | 
     | 
        } else { | 
    
    
    386  | 
     | 
     | 
    	group = htonl(MROUTED_LEVEL);  | 
    
    
    387  | 
     | 
     | 
    	datalen = 0;  | 
    
    
    388  | 
     | 
     | 
        }  | 
    
    
    389  | 
     | 
     | 
        if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;  | 
    
    
    390  | 
     | 
     | 
        else local = INADDR_ANY;  | 
    
    
    391  | 
     | 
     | 
     | 
    
    
    392  | 
     | 
     | 
        /*  | 
    
    
    393  | 
     | 
     | 
         * If the reply address was not explicitly specified, start off  | 
    
    
    394  | 
     | 
     | 
         * with the unicast address of this host.  Then, if there is no  | 
    
    
    395  | 
     | 
     | 
         * response after trying half the tries with unicast, switch to  | 
    
    
    396  | 
     | 
     | 
         * the standard multicast reply address.  If the TTL was also not  | 
    
    
    397  | 
     | 
     | 
         * specified, set a multicast TTL and if needed increase it for the  | 
    
    
    398  | 
     | 
     | 
         * last quarter of the tries.  | 
    
    
    399  | 
     | 
     | 
         */  | 
    
    
    400  | 
     | 
     | 
        query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);  | 
    
    
    401  | 
     | 
     | 
        query->tr_raddr = raddr ? raddr : multicast ? resp_cast : lcl_addr;  | 
    
    
    402  | 
     | 
     | 
        query->tr_rttl  = rttl ? rttl :  | 
    
    
    403  | 
     | 
     | 
          IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL;  | 
    
    
    404  | 
     | 
     | 
        query->tr_src   = qsrc;  | 
    
    
    405  | 
     | 
     | 
        query->tr_dst   = qdst;  | 
    
    
    406  | 
     | 
     | 
     | 
    
    
    407  | 
     | 
     | 
        for (i = tries ; i > 0; --i) { | 
    
    
    408  | 
     | 
     | 
    	if (tries == nqueries && raddr == 0) { | 
    
    
    409  | 
     | 
     | 
    	    if (i == ((nqueries + 1) >> 1)) { | 
    
    
    410  | 
     | 
     | 
    		query->tr_raddr = resp_cast;  | 
    
    
    411  | 
     | 
     | 
    		if (rttl == 0) query->tr_rttl = get_ttl(save);  | 
    
    
    412  | 
     | 
     | 
    	    }  | 
    
    
    413  | 
     | 
     | 
    	    if (i <= ((nqueries + 3) >> 2) && rttl == 0) { | 
    
    
    414  | 
     | 
     | 
    		query->tr_rttl += MULTICAST_TTL_INC;  | 
    
    
    415  | 
     | 
     | 
    		if (query->tr_rttl > MULTICAST_TTL_MAX)  | 
    
    
    416  | 
     | 
     | 
    		  query->tr_rttl = MULTICAST_TTL_MAX;  | 
    
    
    417  | 
     | 
     | 
    	    }  | 
    
    
    418  | 
     | 
     | 
    	}  | 
    
    
    419  | 
     | 
     | 
     | 
    
    
    420  | 
     | 
     | 
    	/*  | 
    
    
    421  | 
     | 
     | 
    	 * Change the qid for each request sent to avoid being confused  | 
    
    
    422  | 
     | 
     | 
    	 * by duplicate responses  | 
    
    
    423  | 
     | 
     | 
    	 */  | 
    
    
    424  | 
     | 
     | 
    	query->tr_qid  = arc4random();  | 
    
    
    425  | 
     | 
     | 
     | 
    
    
    426  | 
     | 
     | 
    	/*  | 
    
    
    427  | 
     | 
     | 
    	 * Set timer to calculate delays, then send query  | 
    
    
    428  | 
     | 
     | 
    	 */  | 
    
    
    429  | 
     | 
     | 
    	gettimeofday(&tq, 0);  | 
    
    
    430  | 
     | 
     | 
    	send_igmp(local, dst, type, code, group, datalen);  | 
    
    
    431  | 
     | 
     | 
     | 
    
    
    432  | 
     | 
     | 
    	/*  | 
    
    
    433  | 
     | 
     | 
    	 * Wait for response, discarding false alarms  | 
    
    
    434  | 
     | 
     | 
    	 */  | 
    
    
    435  | 
     | 
     | 
    	pfd[0].fd = igmp_socket;  | 
    
    
    436  | 
     | 
     | 
    	pfd[0].events = POLLIN;  | 
    
    
    437  | 
     | 
     | 
    	while (TRUE) { | 
    
    
    438  | 
     | 
     | 
    	    gettimeofday(&tv, 0);  | 
    
    
    439  | 
     | 
     | 
    	    tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;  | 
    
    
    440  | 
     | 
     | 
    	    tv.tv_usec = tq.tv_usec - tv.tv_usec;  | 
    
    
    441  | 
     | 
     | 
    	    if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;  | 
    
    
    442  | 
     | 
     | 
    	    if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;  | 
    
    
    443  | 
     | 
     | 
     | 
    
    
    444  | 
     | 
     | 
    	    count = poll(pfd, 1, tv.tv_sec * 1000);  | 
    
    
    445  | 
     | 
     | 
     | 
    
    
    446  | 
     | 
     | 
    	    if (count < 0) { | 
    
    
    447  | 
     | 
     | 
    		if (errno != EINTR) perror("poll"); | 
    
    
    448  | 
     | 
     | 
    		continue;  | 
    
    
    449  | 
     | 
     | 
    	    } else if (count == 0) { | 
    
    
    450  | 
     | 
     | 
    		printf("* "); | 
    
    
    451  | 
     | 
     | 
    		fflush(stdout);  | 
    
    
    452  | 
     | 
     | 
    		break;  | 
    
    
    453  | 
     | 
     | 
    	    }  | 
    
    
    454  | 
     | 
     | 
     | 
    
    
    455  | 
     | 
     | 
    	    gettimeofday(&tr, 0);  | 
    
    
    456  | 
     | 
     | 
    	    recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,  | 
    
    
    457  | 
     | 
     | 
    			       0, NULL, &dummy);  | 
    
    
    458  | 
     | 
     | 
     | 
    
    
    459  | 
     | 
     | 
    	    if (recvlen <= 0) { | 
    
    
    460  | 
     | 
     | 
    		if (recvlen && errno != EINTR) perror("recvfrom"); | 
    
    
    461  | 
     | 
     | 
    		continue;  | 
    
    
    462  | 
     | 
     | 
    	    }  | 
    
    
    463  | 
     | 
     | 
     | 
    
    
    464  | 
     | 
     | 
    	    if (recvlen < sizeof(struct ip)) { | 
    
    
    465  | 
     | 
     | 
    		fprintf(stderr,  | 
    
    
    466  | 
     | 
     | 
    			"packet too short (%u bytes) for IP header", recvlen);  | 
    
    
    467  | 
     | 
     | 
    		continue;  | 
    
    
    468  | 
     | 
     | 
    	    }  | 
    
    
    469  | 
     | 
     | 
    	    ip = (struct ip *) recv_buf;  | 
    
    
    470  | 
     | 
     | 
    	    if (ip->ip_p == 0)	/* ignore cache creation requests */  | 
    
    
    471  | 
     | 
     | 
    		continue;  | 
    
    
    472  | 
     | 
     | 
     | 
    
    
    473  | 
     | 
     | 
    	    iphdrlen = ip->ip_hl << 2;  | 
    
    
    474  | 
     | 
     | 
    	    ipdatalen = ntohs(ip->ip_len) - iphdrlen;  | 
    
    
    475  | 
     | 
     | 
    	    if (iphdrlen + ipdatalen != recvlen) { | 
    
    
    476  | 
     | 
     | 
    		fprintf(stderr,  | 
    
    
    477  | 
     | 
     | 
    			"packet shorter (%u bytes) than hdr+data len (%u+%u)\n",  | 
    
    
    478  | 
     | 
     | 
    			recvlen, iphdrlen, ipdatalen);  | 
    
    
    479  | 
     | 
     | 
    		continue;  | 
    
    
    480  | 
     | 
     | 
    	    }  | 
    
    
    481  | 
     | 
     | 
     | 
    
    
    482  | 
     | 
     | 
    	    igmp = (struct igmp *) (recv_buf + iphdrlen);  | 
    
    
    483  | 
     | 
     | 
    	    igmpdatalen = ipdatalen - IGMP_MINLEN;  | 
    
    
    484  | 
     | 
     | 
    	    if (igmpdatalen < 0) { | 
    
    
    485  | 
     | 
     | 
    		fprintf(stderr,  | 
    
    
    486  | 
     | 
     | 
    			"IP data field too short (%u bytes) for IGMP from %s\n",  | 
    
    
    487  | 
     | 
     | 
    			ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));  | 
    
    
    488  | 
     | 
     | 
    		continue;  | 
    
    
    489  | 
     | 
     | 
    	    }  | 
    
    
    490  | 
     | 
     | 
     | 
    
    
    491  | 
     | 
     | 
    	    switch (igmp->igmp_type) { | 
    
    
    492  | 
     | 
     | 
     | 
    
    
    493  | 
     | 
     | 
    	      case IGMP_DVMRP:  | 
    
    
    494  | 
     | 
     | 
    		if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;  | 
    
    
    495  | 
     | 
     | 
    		len = igmpdatalen;  | 
    
    
    496  | 
     | 
     | 
    		/*  | 
    
    
    497  | 
     | 
     | 
    		 * Accept DVMRP_NEIGHBORS2 response if it comes from the  | 
    
    
    498  | 
     | 
     | 
    		 * address queried or if that address is one of the local  | 
    
    
    499  | 
     | 
     | 
    		 * addresses in the response.  | 
    
    
    500  | 
     | 
     | 
    		 */  | 
    
    
    501  | 
     | 
     | 
    		if (ip->ip_src.s_addr != dst) { | 
    
    
    502  | 
     | 
     | 
    		    u_int32_t *p = (u_int32_t *)(igmp + 1);  | 
    
    
    503  | 
     | 
     | 
    		    u_int32_t *ep = p + (len >> 2);  | 
    
    
    504  | 
     | 
     | 
    		    while (p < ep) { | 
    
    
    505  | 
     | 
     | 
    			u_int32_t laddr = *p++;  | 
    
    
    506  | 
     | 
     | 
    			int n = ntohl(*p++) & 0xFF;  | 
    
    
    507  | 
     | 
     | 
    			if (laddr == dst) { | 
    
    
    508  | 
     | 
     | 
    			    ep = p + 1;		/* ensure p < ep after loop */  | 
    
    
    509  | 
     | 
     | 
    			    break;  | 
    
    
    510  | 
     | 
     | 
    			}  | 
    
    
    511  | 
     | 
     | 
    			p += n;  | 
    
    
    512  | 
     | 
     | 
    		    }  | 
    
    
    513  | 
     | 
     | 
    		    if (p >= ep) continue;  | 
    
    
    514  | 
     | 
     | 
    		}  | 
    
    
    515  | 
     | 
     | 
    		break;  | 
    
    
    516  | 
     | 
     | 
     | 
    
    
    517  | 
     | 
     | 
    	      case IGMP_MTRACE_QUERY:	    /* For backward compatibility with 3.3 */  | 
    
    
    518  | 
     | 
     | 
    	      case IGMP_MTRACE_REPLY:  | 
    
    
    519  | 
     | 
     | 
    		if (igmpdatalen <= QLEN) continue;  | 
    
    
    520  | 
     | 
     | 
    		if ((igmpdatalen - QLEN)%RLEN) { | 
    
    
    521  | 
     | 
     | 
    		    printf("packet with incorrect datalen\n"); | 
    
    
    522  | 
     | 
     | 
    		    continue;  | 
    
    
    523  | 
     | 
     | 
    		}  | 
    
    
    524  | 
     | 
     | 
     | 
    
    
    525  | 
     | 
     | 
    		/*  | 
    
    
    526  | 
     | 
     | 
    		 * Ignore responses that don't match query.  | 
    
    
    527  | 
     | 
     | 
    		 */  | 
    
    
    528  | 
     | 
     | 
    		rquery = (struct tr_query *)(igmp + 1);  | 
    
    
    529  | 
     | 
     | 
    		if (rquery->tr_qid != query->tr_qid) continue;  | 
    
    
    530  | 
     | 
     | 
    		if (rquery->tr_src != qsrc) continue;  | 
    
    
    531  | 
     | 
     | 
    		if (rquery->tr_dst != qdst) continue;  | 
    
    
    532  | 
     | 
     | 
    		len = (igmpdatalen - QLEN)/RLEN;  | 
    
    
    533  | 
     | 
     | 
     | 
    
    
    534  | 
     | 
     | 
    		/*  | 
    
    
    535  | 
     | 
     | 
    		 * Ignore trace queries passing through this node when  | 
    
    
    536  | 
     | 
     | 
    		 * mtrace is run on an mrouter that is in the path  | 
    
    
    537  | 
     | 
     | 
    		 * (needed only because IGMP_MTRACE_QUERY is accepted above  | 
    
    
    538  | 
     | 
     | 
    		 * for backward compatibility with multicast release 3.3).  | 
    
    
    539  | 
     | 
     | 
    		 */  | 
    
    
    540  | 
     | 
     | 
    		if (igmp->igmp_type == IGMP_MTRACE_QUERY) { | 
    
    
    541  | 
     | 
     | 
    		    struct tr_resp *r = (struct tr_resp *)(rquery+1) + len - 1;  | 
    
    
    542  | 
     | 
     | 
    		    u_int32_t smask;  | 
    
    
    543  | 
     | 
     | 
     | 
    
    
    544  | 
     | 
     | 
    		    VAL_TO_MASK(smask, r->tr_smask);  | 
    
    
    545  | 
     | 
     | 
    		    if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)  | 
    
    
    546  | 
     | 
     | 
    			&& r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))  | 
    
    
    547  | 
     | 
     | 
    		      continue;  | 
    
    
    548  | 
     | 
     | 
    		}  | 
    
    
    549  | 
     | 
     | 
     | 
    
    
    550  | 
     | 
     | 
    		/*  | 
    
    
    551  | 
     | 
     | 
    		 * A match, we'll keep this one.  | 
    
    
    552  | 
     | 
     | 
    		 */  | 
    
    
    553  | 
     | 
     | 
    		if (len > code) { | 
    
    
    554  | 
     | 
     | 
    		    fprintf(stderr,  | 
    
    
    555  | 
     | 
     | 
    			    "Num hops received (%d) exceeds request (%d)\n",  | 
    
    
    556  | 
     | 
     | 
    			    len, code);  | 
    
    
    557  | 
     | 
     | 
    		}  | 
    
    
    558  | 
     | 
     | 
    		rquery->tr_raddr = query->tr_raddr;	/* Insure these are */  | 
    
    
    559  | 
     | 
     | 
    		rquery->tr_rttl = query->tr_rttl;	/* as we sent them */  | 
    
    
    560  | 
     | 
     | 
    		break;  | 
    
    
    561  | 
     | 
     | 
     | 
    
    
    562  | 
     | 
     | 
    	      default:  | 
    
    
    563  | 
     | 
     | 
    		continue;  | 
    
    
    564  | 
     | 
     | 
    	    }  | 
    
    
    565  | 
     | 
     | 
     | 
    
    
    566  | 
     | 
     | 
    	    /*  | 
    
    
    567  | 
     | 
     | 
    	     * Most of the sanity checking done at this point.  | 
    
    
    568  | 
     | 
     | 
    	     * Return this packet we have been waiting for.  | 
    
    
    569  | 
     | 
     | 
    	     */  | 
    
    
    570  | 
     | 
     | 
    	    if (save) { | 
    
    
    571  | 
     | 
     | 
    		save->qtime = ((tq.tv_sec + JAN_1970) << 16) +  | 
    
    
    572  | 
     | 
     | 
    			      (tq.tv_usec << 10) / 15625;  | 
    
    
    573  | 
     | 
     | 
    		save->rtime = ((tr.tv_sec + JAN_1970) << 16) +  | 
    
    
    574  | 
     | 
     | 
    			      (tr.tv_usec << 10) / 15625;  | 
    
    
    575  | 
     | 
     | 
    		save->len = len;  | 
    
    
    576  | 
     | 
     | 
    		bcopy((char *)igmp, (char *)&save->igmp, ipdatalen);  | 
    
    
    577  | 
     | 
     | 
    	    }  | 
    
    
    578  | 
     | 
     | 
    	    return (recvlen);  | 
    
    
    579  | 
     | 
     | 
    	}  | 
    
    
    580  | 
     | 
     | 
        }  | 
    
    
    581  | 
     | 
     | 
        return (0);  | 
    
    
    582  | 
     | 
     | 
    }  | 
    
    
    583  | 
     | 
     | 
     | 
    
    
    584  | 
     | 
     | 
    /*  | 
    
    
    585  | 
     | 
     | 
     * Most of this code is duplicated elsewhere.  I'm not sure if  | 
    
    
    586  | 
     | 
     | 
     * the duplication is absolutely required or not.  | 
    
    
    587  | 
     | 
     | 
     *  | 
    
    
    588  | 
     | 
     | 
     * Ideally, this would keep track of ongoing statistics  | 
    
    
    589  | 
     | 
     | 
     * collection and print out statistics.  (& keep track  | 
    
    
    590  | 
     | 
     | 
     * of h-b-h traces and only print the longest)  For now,  | 
    
    
    591  | 
     | 
     | 
     * it just snoops on what traces it can.  | 
    
    
    592  | 
     | 
     | 
     */  | 
    
    
    593  | 
     | 
     | 
    void  | 
    
    
    594  | 
     | 
     | 
    passive_mode(void)  | 
    
    
    595  | 
     | 
     | 
    { | 
    
    
    596  | 
     | 
     | 
        struct timeval tr;  | 
    
    
    597  | 
     | 
     | 
        struct ip *ip;  | 
    
    
    598  | 
     | 
     | 
        struct igmp *igmp;  | 
    
    
    599  | 
     | 
     | 
        struct tr_resp *r;  | 
    
    
    600  | 
     | 
     | 
        int ipdatalen, iphdrlen, igmpdatalen;  | 
    
    
    601  | 
     | 
     | 
        int len, recvlen, dummy = 0;  | 
    
    
    602  | 
     | 
     | 
        u_int32_t smask;  | 
    
    
    603  | 
     | 
     | 
     | 
    
    
    604  | 
     | 
     | 
        if (raddr) { | 
    
    
    605  | 
     | 
     | 
    	if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);  | 
    
    
    606  | 
     | 
     | 
        } else k_join(htonl(0xE0000120), INADDR_ANY);  | 
    
    
    607  | 
     | 
     | 
     | 
    
    
    608  | 
     | 
     | 
        while (1) { | 
    
    
    609  | 
     | 
     | 
    	recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,  | 
    
    
    610  | 
     | 
     | 
    			   0, NULL, &dummy);  | 
    
    
    611  | 
     | 
     | 
    	gettimeofday(&tr,0);  | 
    
    
    612  | 
     | 
     | 
     | 
    
    
    613  | 
     | 
     | 
    	if (recvlen <= 0) { | 
    
    
    614  | 
     | 
     | 
    	    if (recvlen && errno != EINTR) perror("recvfrom"); | 
    
    
    615  | 
     | 
     | 
    	    continue;  | 
    
    
    616  | 
     | 
     | 
    	}  | 
    
    
    617  | 
     | 
     | 
     | 
    
    
    618  | 
     | 
     | 
    	if (recvlen < sizeof(struct ip)) { | 
    
    
    619  | 
     | 
     | 
    	    fprintf(stderr,  | 
    
    
    620  | 
     | 
     | 
    		    "packet too short (%u bytes) for IP header", recvlen);  | 
    
    
    621  | 
     | 
     | 
    	    continue;  | 
    
    
    622  | 
     | 
     | 
    	}  | 
    
    
    623  | 
     | 
     | 
    	ip = (struct ip *) recv_buf;  | 
    
    
    624  | 
     | 
     | 
    	if (ip->ip_p == 0)	/* ignore cache creation requests */  | 
    
    
    625  | 
     | 
     | 
    	    continue;  | 
    
    
    626  | 
     | 
     | 
     | 
    
    
    627  | 
     | 
     | 
    	iphdrlen = ip->ip_hl << 2;  | 
    
    
    628  | 
     | 
     | 
    	ipdatalen = ntohs(ip->ip_len) - iphdrlen;  | 
    
    
    629  | 
     | 
     | 
    	if (iphdrlen + ipdatalen != recvlen) { | 
    
    
    630  | 
     | 
     | 
    	    fprintf(stderr,  | 
    
    
    631  | 
     | 
     | 
    		    "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",  | 
    
    
    632  | 
     | 
     | 
    		    recvlen, iphdrlen, ipdatalen);  | 
    
    
    633  | 
     | 
     | 
    	    continue;  | 
    
    
    634  | 
     | 
     | 
    	}  | 
    
    
    635  | 
     | 
     | 
     | 
    
    
    636  | 
     | 
     | 
    	igmp = (struct igmp *) (recv_buf + iphdrlen);  | 
    
    
    637  | 
     | 
     | 
    	igmpdatalen = ipdatalen - IGMP_MINLEN;  | 
    
    
    638  | 
     | 
     | 
    	if (igmpdatalen < 0) { | 
    
    
    639  | 
     | 
     | 
    	    fprintf(stderr,  | 
    
    
    640  | 
     | 
     | 
    		    "IP data field too short (%u bytes) for IGMP from %s\n",  | 
    
    
    641  | 
     | 
     | 
    		    ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));  | 
    
    
    642  | 
     | 
     | 
    	    continue;  | 
    
    
    643  | 
     | 
     | 
    	}  | 
    
    
    644  | 
     | 
     | 
     | 
    
    
    645  | 
     | 
     | 
    	switch (igmp->igmp_type) { | 
    
    
    646  | 
     | 
     | 
     | 
    
    
    647  | 
     | 
     | 
    	  case IGMP_MTRACE_QUERY:	    /* For backward compatibility with 3.3 */  | 
    
    
    648  | 
     | 
     | 
    	  case IGMP_MTRACE_REPLY:  | 
    
    
    649  | 
     | 
     | 
    	    if (igmpdatalen < QLEN) continue;  | 
    
    
    650  | 
     | 
     | 
    	    if ((igmpdatalen - QLEN)%RLEN) { | 
    
    
    651  | 
     | 
     | 
    		printf("packet with incorrect datalen\n"); | 
    
    
    652  | 
     | 
     | 
    		continue;  | 
    
    
    653  | 
     | 
     | 
    	    }  | 
    
    
    654  | 
     | 
     | 
     | 
    
    
    655  | 
     | 
     | 
    	    len = (igmpdatalen - QLEN)/RLEN;  | 
    
    
    656  | 
     | 
     | 
     | 
    
    
    657  | 
     | 
     | 
    	    break;  | 
    
    
    658  | 
     | 
     | 
     | 
    
    
    659  | 
     | 
     | 
    	  default:  | 
    
    
    660  | 
     | 
     | 
    	    continue;  | 
    
    
    661  | 
     | 
     | 
    	}  | 
    
    
    662  | 
     | 
     | 
     | 
    
    
    663  | 
     | 
     | 
    	base.qtime = ((tr.tv_sec + JAN_1970) << 16) +  | 
    
    
    664  | 
     | 
     | 
    		      (tr.tv_usec << 10) / 15625;  | 
    
    
    665  | 
     | 
     | 
    	base.rtime = ((tr.tv_sec + JAN_1970) << 16) +  | 
    
    
    666  | 
     | 
     | 
    		      (tr.tv_usec << 10) / 15625;  | 
    
    
    667  | 
     | 
     | 
    	base.len = len;  | 
    
    
    668  | 
     | 
     | 
    	bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);  | 
    
    
    669  | 
     | 
     | 
    	/*  | 
    
    
    670  | 
     | 
     | 
    	 * If the user specified which traces to monitor,  | 
    
    
    671  | 
     | 
     | 
    	 * only accept traces that correspond to the  | 
    
    
    672  | 
     | 
     | 
    	 * request  | 
    
    
    673  | 
     | 
     | 
    	 */  | 
    
    
    674  | 
     | 
     | 
    	if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||  | 
    
    
    675  | 
     | 
     | 
    	    (qdst != 0 && qdst != base.qhdr.tr_dst) ||  | 
    
    
    676  | 
     | 
     | 
    	    (qgrp != 0 && qgrp != igmp->igmp_group.s_addr))  | 
    
    
    677  | 
     | 
     | 
    	    continue;  | 
    
    
    678  | 
     | 
     | 
     | 
    
    
    679  | 
     | 
     | 
    	printf("Mtrace from %s to %s via group %s (mxhop=%d)\n", | 
    
    
    680  | 
     | 
     | 
    		inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),  | 
    
    
    681  | 
     | 
     | 
    		inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);  | 
    
    
    682  | 
     | 
     | 
    	if (len == 0)  | 
    
    
    683  | 
     | 
     | 
    	    continue;  | 
    
    
    684  | 
     | 
     | 
    	printf("  0  "); | 
    
    
    685  | 
     | 
     | 
    	print_host(base.qhdr.tr_dst);  | 
    
    
    686  | 
     | 
     | 
    	printf("\n"); | 
    
    
    687  | 
     | 
     | 
    	print_trace(1, &base);  | 
    
    
    688  | 
     | 
     | 
    	r = base.resps + base.len - 1;  | 
    
    
    689  | 
     | 
     | 
    	VAL_TO_MASK(smask, r->tr_smask);  | 
    
    
    690  | 
     | 
     | 
    	if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) { | 
    
    
    691  | 
     | 
     | 
    	    printf("%3d  ", -(base.len+1)); | 
    
    
    692  | 
     | 
     | 
    	    print_host(base.qhdr.tr_src);  | 
    
    
    693  | 
     | 
     | 
    	    printf("\n"); | 
    
    
    694  | 
     | 
     | 
    	} else if (r->tr_rmtaddr != 0) { | 
    
    
    695  | 
     | 
     | 
    	    printf("%3d  ", -(base.len+1)); | 
    
    
    696  | 
     | 
     | 
    	    what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?  | 
    
    
    697  | 
     | 
     | 
    				   "doesn't support mtrace"  | 
    
    
    698  | 
     | 
     | 
    				 : "is the next hop");  | 
    
    
    699  | 
     | 
     | 
    	}  | 
    
    
    700  | 
     | 
     | 
    	printf("\n"); | 
    
    
    701  | 
     | 
     | 
        }  | 
    
    
    702  | 
     | 
     | 
    }  | 
    
    
    703  | 
     | 
     | 
     | 
    
    
    704  | 
     | 
     | 
    char *  | 
    
    
    705  | 
     | 
     | 
    print_host(u_int32_t addr)  | 
    
    
    706  | 
     | 
     | 
    { | 
    
    
    707  | 
     | 
     | 
        return print_host2(addr, 0);  | 
    
    
    708  | 
     | 
     | 
    }  | 
    
    
    709  | 
     | 
     | 
     | 
    
    
    710  | 
     | 
     | 
    /*  | 
    
    
    711  | 
     | 
     | 
     * On some routers, one interface has a name and the other doesn't.  | 
    
    
    712  | 
     | 
     | 
     * We always print the address of the outgoing interface, but can  | 
    
    
    713  | 
     | 
     | 
     * sometimes get the name from the incoming interface.  This might be  | 
    
    
    714  | 
     | 
     | 
     * confusing but should be slightly more helpful than just a "?".  | 
    
    
    715  | 
     | 
     | 
     */  | 
    
    
    716  | 
     | 
     | 
    char *  | 
    
    
    717  | 
     | 
     | 
    print_host2(u_int32_t addr1, u_int32_t addr2)  | 
    
    
    718  | 
     | 
     | 
    { | 
    
    
    719  | 
     | 
     | 
        char *name;  | 
    
    
    720  | 
     | 
     | 
     | 
    
    
    721  | 
     | 
     | 
        if (numeric) { | 
    
    
    722  | 
     | 
     | 
    	printf("%s", inet_fmt(addr1, s1)); | 
    
    
    723  | 
     | 
     | 
    	return (""); | 
    
    
    724  | 
     | 
     | 
        }  | 
    
    
    725  | 
     | 
     | 
        name = inet_name(addr1);  | 
    
    
    726  | 
     | 
     | 
        if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)  | 
    
    
    727  | 
     | 
     | 
    	name = inet_name(addr2);  | 
    
    
    728  | 
     | 
     | 
        printf("%s (%s)", name, inet_fmt(addr1, s1)); | 
    
    
    729  | 
     | 
     | 
        return (name);  | 
    
    
    730  | 
     | 
     | 
    }  | 
    
    
    731  | 
     | 
     | 
     | 
    
    
    732  | 
     | 
     | 
    /*  | 
    
    
    733  | 
     | 
     | 
     * Print responses as received (reverse path from dst to src)  | 
    
    
    734  | 
     | 
     | 
     */  | 
    
    
    735  | 
     | 
     | 
    void  | 
    
    
    736  | 
     | 
     | 
    print_trace(int index, struct resp_buf *buf)  | 
    
    
    737  | 
     | 
     | 
    { | 
    
    
    738  | 
     | 
     | 
        struct tr_resp *r;  | 
    
    
    739  | 
     | 
     | 
        char *name;  | 
    
    
    740  | 
     | 
     | 
        int i;  | 
    
    
    741  | 
     | 
     | 
        int hop;  | 
    
    
    742  | 
     | 
     | 
        char *ms;  | 
    
    
    743  | 
     | 
     | 
     | 
    
    
    744  | 
     | 
     | 
        i = abs(index);  | 
    
    
    745  | 
     | 
     | 
        r = buf->resps + i - 1;  | 
    
    
    746  | 
     | 
     | 
     | 
    
    
    747  | 
     | 
     | 
        for (; i <= buf->len; ++i, ++r) { | 
    
    
    748  | 
     | 
     | 
    	if (index > 0) printf("%3d  ", -i); | 
    
    
    749  | 
     | 
     | 
    	name = print_host2(r->tr_outaddr, r->tr_inaddr);  | 
    
    
    750  | 
     | 
     | 
    	printf("  %s  thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl); | 
    
    
    751  | 
     | 
     | 
    	if (verbose) { | 
    
    
    752  | 
     | 
     | 
    	    hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);  | 
    
    
    753  | 
     | 
     | 
    	    ms = scale(&hop);  | 
    
    
    754  | 
     | 
     | 
    	    printf("  %d%s", hop, ms); | 
    
    
    755  | 
     | 
     | 
    	}  | 
    
    
    756  | 
     | 
     | 
    	printf("  %s\n", flag_type(r->tr_rflags)); | 
    
    
    757  | 
     | 
     | 
    	memcpy(names[i-1], name, sizeof(names[0]) - 1);  | 
    
    
    758  | 
     | 
     | 
    	names[i-1][sizeof(names[0])-1] = '\0';  | 
    
    
    759  | 
     | 
     | 
        }  | 
    
    
    760  | 
     | 
     | 
    }  | 
    
    
    761  | 
     | 
     | 
     | 
    
    
    762  | 
     | 
     | 
    /*  | 
    
    
    763  | 
     | 
     | 
     * See what kind of router is the next hop  | 
    
    
    764  | 
     | 
     | 
     */  | 
    
    
    765  | 
     | 
     | 
    int  | 
    
    
    766  | 
     | 
     | 
    what_kind(struct resp_buf *buf, char *why)  | 
    
    
    767  | 
     | 
     | 
    { | 
    
    
    768  | 
     | 
     | 
        u_int32_t smask;  | 
    
    
    769  | 
     | 
     | 
        int retval;  | 
    
    
    770  | 
     | 
     | 
        int hops = buf->len;  | 
    
    
    771  | 
     | 
     | 
        struct tr_resp *r = buf->resps + hops - 1;  | 
    
    
    772  | 
     | 
     | 
        u_int32_t next = r->tr_rmtaddr;  | 
    
    
    773  | 
     | 
     | 
     | 
    
    
    774  | 
     | 
     | 
        retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);  | 
    
    
    775  | 
     | 
     | 
        print_host(next);  | 
    
    
    776  | 
     | 
     | 
        if (retval) { | 
    
    
    777  | 
     | 
     | 
    	u_int32_t version = ntohl(incr[0].igmp.igmp_group.s_addr);  | 
    
    
    778  | 
     | 
     | 
    	u_int32_t *p = (u_int32_t *)incr[0].ndata;  | 
    
    
    779  | 
     | 
     | 
    	u_int32_t *ep = p + (incr[0].len >> 2);  | 
    
    
    780  | 
     | 
     | 
    	char *type = "";  | 
    
    
    781  | 
     | 
     | 
    	retval = 0;  | 
    
    
    782  | 
     | 
     | 
    	switch (version & 0xFF) { | 
    
    
    783  | 
     | 
     | 
    	  case 1:  | 
    
    
    784  | 
     | 
     | 
    	    type = "proteon/mrouted ";  | 
    
    
    785  | 
     | 
     | 
    	    retval = 1;  | 
    
    
    786  | 
     | 
     | 
    	    break;  | 
    
    
    787  | 
     | 
     | 
     | 
    
    
    788  | 
     | 
     | 
    	  case 2:  | 
    
    
    789  | 
     | 
     | 
    	  case 3:  | 
    
    
    790  | 
     | 
     | 
    	    if (((version >> 8) & 0xFF) < 3) retval = 1;  | 
    
    
    791  | 
     | 
     | 
    				/* Fall through */  | 
    
    
    792  | 
     | 
     | 
    	  case 4:  | 
    
    
    793  | 
     | 
     | 
    	    type = "mrouted ";  | 
    
    
    794  | 
     | 
     | 
    	    break;  | 
    
    
    795  | 
     | 
     | 
     | 
    
    
    796  | 
     | 
     | 
    	  case 10:  | 
    
    
    797  | 
     | 
     | 
    	    type = "cisco ";  | 
    
    
    798  | 
     | 
     | 
    	}  | 
    
    
    799  | 
     | 
     | 
    	printf(" [%s%d.%d] %s\n", | 
    
    
    800  | 
     | 
     | 
    	       type, version & 0xFF, (version >> 8) & 0xFF,  | 
    
    
    801  | 
     | 
     | 
    	       why);  | 
    
    
    802  | 
     | 
     | 
    	VAL_TO_MASK(smask, r->tr_smask);  | 
    
    
    803  | 
     | 
     | 
    	while (p < ep) { | 
    
    
    804  | 
     | 
     | 
    	    u_int32_t laddr = *p++;  | 
    
    
    805  | 
     | 
     | 
    	    int flags = (ntohl(*p) & 0xFF00) >> 8;  | 
    
    
    806  | 
     | 
     | 
    	    int n = ntohl(*p++) & 0xFF;  | 
    
    
    807  | 
     | 
     | 
    	    if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&  | 
    
    
    808  | 
     | 
     | 
    		 (laddr & smask) == (qsrc & smask)) { | 
    
    
    809  | 
     | 
     | 
    		printf("%3d  ", -(hops+2)); | 
    
    
    810  | 
     | 
     | 
    		print_host(qsrc);  | 
    
    
    811  | 
     | 
     | 
    		printf("\n"); | 
    
    
    812  | 
     | 
     | 
    		return 1;  | 
    
    
    813  | 
     | 
     | 
    	    }  | 
    
    
    814  | 
     | 
     | 
    	    p += n;  | 
    
    
    815  | 
     | 
     | 
    	}  | 
    
    
    816  | 
     | 
     | 
    	return retval;  | 
    
    
    817  | 
     | 
     | 
        }  | 
    
    
    818  | 
     | 
     | 
        printf(" %s\n", why); | 
    
    
    819  | 
     | 
     | 
        return 0;  | 
    
    
    820  | 
     | 
     | 
    }  | 
    
    
    821  | 
     | 
     | 
     | 
    
    
    822  | 
     | 
     | 
     | 
    
    
    823  | 
     | 
     | 
    char *  | 
    
    
    824  | 
     | 
     | 
    scale(int *hop)  | 
    
    
    825  | 
     | 
     | 
    { | 
    
    
    826  | 
     | 
     | 
        if (*hop > -1000 && *hop < 10000) return (" ms"); | 
    
    
    827  | 
     | 
     | 
        *hop /= 1000;  | 
    
    
    828  | 
     | 
     | 
        if (*hop > -1000 && *hop < 10000) return (" s "); | 
    
    
    829  | 
     | 
     | 
        return ("s "); | 
    
    
    830  | 
     | 
     | 
    }  | 
    
    
    831  | 
     | 
     | 
     | 
    
    
    832  | 
     | 
     | 
    /*  | 
    
    
    833  | 
     | 
     | 
     * Calculate and print one line of packet loss and packet rate statistics.  | 
    
    
    834  | 
     | 
     | 
     * Checks for count of all ones from mrouted 2.3 that doesn't have counters.  | 
    
    
    835  | 
     | 
     | 
     */  | 
    
    
    836  | 
     | 
     | 
    #define NEITHER 0  | 
    
    
    837  | 
     | 
     | 
    #define INS     1  | 
    
    
    838  | 
     | 
     | 
    #define OUTS    2  | 
    
    
    839  | 
     | 
     | 
    #define BOTH    3  | 
    
    
    840  | 
     | 
     | 
    void  | 
    
    
    841  | 
     | 
     | 
    stat_line(struct tr_resp *r, struct tr_resp *s, int have_next, int *rst)  | 
    
    
    842  | 
     | 
     | 
    { | 
    
    
    843  | 
     | 
     | 
        int timediff = (fixtime(ntohl(s->tr_qarr)) -  | 
    
    
    844  | 
     | 
     | 
    			 fixtime(ntohl(r->tr_qarr))) >> 16;  | 
    
    
    845  | 
     | 
     | 
        int v_lost, v_pct;  | 
    
    
    846  | 
     | 
     | 
        int g_lost, g_pct;  | 
    
    
    847  | 
     | 
     | 
        int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);  | 
    
    
    848  | 
     | 
     | 
        int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);  | 
    
    
    849  | 
     | 
     | 
        int v_pps, g_pps;  | 
    
    
    850  | 
     | 
     | 
        char v_str[8], g_str[8];  | 
    
    
    851  | 
     | 
     | 
        int have = NEITHER;  | 
    
    
    852  | 
     | 
     | 
        int res = *rst;  | 
    
    
    853  | 
     | 
     | 
     | 
    
    
    854  | 
     | 
     | 
        if (timediff == 0) timediff = 1;  | 
    
    
    855  | 
     | 
     | 
        v_pps = v_out / timediff;  | 
    
    
    856  | 
     | 
     | 
        g_pps = g_out / timediff;  | 
    
    
    857  | 
     | 
     | 
     | 
    
    
    858  | 
     | 
     | 
        if ((v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0)) ||  | 
    
    
    859  | 
     | 
     | 
    		 (r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))  | 
    
    
    860  | 
     | 
     | 
    	    have |= OUTS;  | 
    
    
    861  | 
     | 
     | 
     | 
    
    
    862  | 
     | 
     | 
        if (have_next) { | 
    
    
    863  | 
     | 
     | 
    	--r,  --s,  --rst;  | 
    
    
    864  | 
     | 
     | 
    	if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||  | 
    
    
    865  | 
     | 
     | 
    	    (r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))  | 
    
    
    866  | 
     | 
     | 
    	  have |= INS;  | 
    
    
    867  | 
     | 
     | 
    	if (*rst)  | 
    
    
    868  | 
     | 
     | 
    	  res = 1;  | 
    
    
    869  | 
     | 
     | 
        }  | 
    
    
    870  | 
     | 
     | 
     | 
    
    
    871  | 
     | 
     | 
        switch (have) { | 
    
    
    872  | 
     | 
     | 
          case BOTH:  | 
    
    
    873  | 
     | 
     | 
    	v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));  | 
    
    
    874  | 
     | 
     | 
    	if (v_out) v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;  | 
    
    
    875  | 
     | 
     | 
    	else v_pct = 0;  | 
    
    
    876  | 
     | 
     | 
    	if (-100 < v_pct && v_pct < 101 && v_out > 10)  | 
    
    
    877  | 
     | 
     | 
    	  snprintf(v_str, sizeof v_str, "%3d", v_pct);  | 
    
    
    878  | 
     | 
     | 
    	else memcpy(v_str, " --", 4);  | 
    
    
    879  | 
     | 
     | 
     | 
    
    
    880  | 
     | 
     | 
    	g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));  | 
    
    
    881  | 
     | 
     | 
    	if (g_out) g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;  | 
    
    
    882  | 
     | 
     | 
    	else g_pct = 0;  | 
    
    
    883  | 
     | 
     | 
    	if (-100 < g_pct && g_pct < 101 && g_out > 10)  | 
    
    
    884  | 
     | 
     | 
    	  snprintf(g_str, sizeof g_str, "%3d", g_pct);  | 
    
    
    885  | 
     | 
     | 
    	else memcpy(g_str, " --", 4);  | 
    
    
    886  | 
     | 
     | 
     | 
    
    
    887  | 
     | 
     | 
    	printf("%6d/%-5d=%s%%%4d pps", | 
    
    
    888  | 
     | 
     | 
    	       v_lost, v_out, v_str, v_pps);  | 
    
    
    889  | 
     | 
     | 
    	if (res)  | 
    
    
    890  | 
     | 
     | 
    	    printf("\n"); | 
    
    
    891  | 
     | 
     | 
    	else  | 
    
    
    892  | 
     | 
     | 
    	    printf("%6d/%-5d=%s%%%4d pps\n", | 
    
    
    893  | 
     | 
     | 
    		   g_lost, g_out, g_str, g_pps);  | 
    
    
    894  | 
     | 
     | 
    	break;  | 
    
    
    895  | 
     | 
     | 
     | 
    
    
    896  | 
     | 
     | 
          case INS:  | 
    
    
    897  | 
     | 
     | 
    	v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);  | 
    
    
    898  | 
     | 
     | 
    	v_pps = v_out / timediff;  | 
    
    
    899  | 
     | 
     | 
    	/* Fall through */  | 
    
    
    900  | 
     | 
     | 
     | 
    
    
    901  | 
     | 
     | 
          case OUTS:  | 
    
    
    902  | 
     | 
     | 
    	printf("       %-5d     %4d pps", | 
    
    
    903  | 
     | 
     | 
    	       v_out, v_pps);  | 
    
    
    904  | 
     | 
     | 
    	if (res)  | 
    
    
    905  | 
     | 
     | 
    	    printf("\n"); | 
    
    
    906  | 
     | 
     | 
    	else  | 
    
    
    907  | 
     | 
     | 
    	    printf("       %-5d     %4d pps\n", | 
    
    
    908  | 
     | 
     | 
    		   g_out, g_pps);  | 
    
    
    909  | 
     | 
     | 
    	break;  | 
    
    
    910  | 
     | 
     | 
     | 
    
    
    911  | 
     | 
     | 
          case NEITHER:  | 
    
    
    912  | 
     | 
     | 
    	printf("\n"); | 
    
    
    913  | 
     | 
     | 
    	break;  | 
    
    
    914  | 
     | 
     | 
        }  | 
    
    
    915  | 
     | 
     | 
     | 
    
    
    916  | 
     | 
     | 
        if (debug > 2) { | 
    
    
    917  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(s->tr_vifin)); | 
    
    
    918  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(s->tr_vifout)); | 
    
    
    919  | 
     | 
     | 
    	printf("pkts: %u\n", ntohl(s->tr_pktcnt)); | 
    
    
    920  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(r->tr_vifin)); | 
    
    
    921  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(r->tr_vifout)); | 
    
    
    922  | 
     | 
     | 
    	printf("pkts: %u\n", ntohl(r->tr_pktcnt)); | 
    
    
    923  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(s->tr_vifin)-ntohl(r->tr_vifin)); | 
    
    
    924  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout)); | 
    
    
    925  | 
     | 
     | 
    	printf("pkts: %u ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt)); | 
    
    
    926  | 
     | 
     | 
    	printf("time: %d\n", timediff); | 
    
    
    927  | 
     | 
     | 
    	printf("\t\t\t\tres: %d\n", res); | 
    
    
    928  | 
     | 
     | 
        }  | 
    
    
    929  | 
     | 
     | 
    }  | 
    
    
    930  | 
     | 
     | 
     | 
    
    
    931  | 
     | 
     | 
    /*  | 
    
    
    932  | 
     | 
     | 
     * A fixup to check if any pktcnt has been reset, and to fix the  | 
    
    
    933  | 
     | 
     | 
     * byteorder bugs in mrouted 3.6 on little-endian machines.  | 
    
    
    934  | 
     | 
     | 
     */  | 
    
    
    935  | 
     | 
     | 
    void  | 
    
    
    936  | 
     | 
     | 
    fixup_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new)  | 
    
    
    937  | 
     | 
     | 
    { | 
    
    
    938  | 
     | 
     | 
        int rno = base->len;  | 
    
    
    939  | 
     | 
     | 
        struct tr_resp *b = base->resps + rno;  | 
    
    
    940  | 
     | 
     | 
        struct tr_resp *p = prev->resps + rno;  | 
    
    
    941  | 
     | 
     | 
        struct tr_resp *n = new->resps + rno;  | 
    
    
    942  | 
     | 
     | 
        int *r = reset + rno;  | 
    
    
    943  | 
     | 
     | 
        int *s = swaps + rno;  | 
    
    
    944  | 
     | 
     | 
        int res;  | 
    
    
    945  | 
     | 
     | 
     | 
    
    
    946  | 
     | 
     | 
        /* Check for byte-swappers */  | 
    
    
    947  | 
     | 
     | 
        while (--rno >= 0) { | 
    
    
    948  | 
     | 
     | 
    	--n; --p; --b; --s;  | 
    
    
    949  | 
     | 
     | 
    	if (*s || ntohl(n->tr_vifout) - ntohl(p->tr_vifout) > 100000) { | 
    
    
    950  | 
     | 
     | 
    	    /* This host sends byteswapped reports; swap 'em */  | 
    
    
    951  | 
     | 
     | 
    	    if (!*s) { | 
    
    
    952  | 
     | 
     | 
    		*s = 1;  | 
    
    
    953  | 
     | 
     | 
    		b->tr_qarr = byteswap(b->tr_qarr);  | 
    
    
    954  | 
     | 
     | 
    		b->tr_vifin = byteswap(b->tr_vifin);  | 
    
    
    955  | 
     | 
     | 
    		b->tr_vifout = byteswap(b->tr_vifout);  | 
    
    
    956  | 
     | 
     | 
    		b->tr_pktcnt = byteswap(b->tr_pktcnt);  | 
    
    
    957  | 
     | 
     | 
    	    }  | 
    
    
    958  | 
     | 
     | 
     | 
    
    
    959  | 
     | 
     | 
    	    n->tr_qarr = byteswap(n->tr_qarr);  | 
    
    
    960  | 
     | 
     | 
    	    n->tr_vifin = byteswap(n->tr_vifin);  | 
    
    
    961  | 
     | 
     | 
    	    n->tr_vifout = byteswap(n->tr_vifout);  | 
    
    
    962  | 
     | 
     | 
    	    n->tr_pktcnt = byteswap(n->tr_pktcnt);  | 
    
    
    963  | 
     | 
     | 
    	}  | 
    
    
    964  | 
     | 
     | 
        }  | 
    
    
    965  | 
     | 
     | 
     | 
    
    
    966  | 
     | 
     | 
        rno = base->len;  | 
    
    
    967  | 
     | 
     | 
        b = base->resps + rno;  | 
    
    
    968  | 
     | 
     | 
        p = prev->resps + rno;  | 
    
    
    969  | 
     | 
     | 
        n = new->resps + rno;  | 
    
    
    970  | 
     | 
     | 
     | 
    
    
    971  | 
     | 
     | 
        while (--rno >= 0) { | 
    
    
    972  | 
     | 
     | 
    	--n; --p; --b; --r;  | 
    
    
    973  | 
     | 
     | 
    	res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||  | 
    
    
    974  | 
     | 
     | 
    	       (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));  | 
    
    
    975  | 
     | 
     | 
    	if (debug > 2)  | 
    
    
    976  | 
     | 
     | 
    	    printf("\t\tr=%d, res=%d\n", *r, res); | 
    
    
    977  | 
     | 
     | 
    	if (*r) { | 
    
    
    978  | 
     | 
     | 
    	    if (res || *r > 1) { | 
    
    
    979  | 
     | 
     | 
    		/*  | 
    
    
    980  | 
     | 
     | 
    		 * This router appears to be a 3.4 with that nasty ol'  | 
    
    
    981  | 
     | 
     | 
    		 * neighbor version bug, which causes it to constantly  | 
    
    
    982  | 
     | 
     | 
    		 * reset.  Just nuke the statistics for this node, and  | 
    
    
    983  | 
     | 
     | 
    		 * don't even bother giving it the benefit of the  | 
    
    
    984  | 
     | 
     | 
    		 * doubt from now on.  | 
    
    
    985  | 
     | 
     | 
    		 */  | 
    
    
    986  | 
     | 
     | 
    		p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;  | 
    
    
    987  | 
     | 
     | 
    		r++;  | 
    
    
    988  | 
     | 
     | 
    	    } else { | 
    
    
    989  | 
     | 
     | 
    		/*  | 
    
    
    990  | 
     | 
     | 
    		 * This is simply the situation that the original  | 
    
    
    991  | 
     | 
     | 
    		 * fixup_stats was meant to deal with -- that a  | 
    
    
    992  | 
     | 
     | 
    		 * 3.3 or 3.4 router deleted a cache entry while  | 
    
    
    993  | 
     | 
     | 
    		 * traffic was still active.  | 
    
    
    994  | 
     | 
     | 
    		 */  | 
    
    
    995  | 
     | 
     | 
    		*r = 0;  | 
    
    
    996  | 
     | 
     | 
    		break;  | 
    
    
    997  | 
     | 
     | 
    	    }  | 
    
    
    998  | 
     | 
     | 
    	} else  | 
    
    
    999  | 
     | 
     | 
    	    *r = res;  | 
    
    
    1000  | 
     | 
     | 
        }  | 
    
    
    1001  | 
     | 
     | 
     | 
    
    
    1002  | 
     | 
     | 
        if (rno < 0) return;  | 
    
    
    1003  | 
     | 
     | 
     | 
    
    
    1004  | 
     | 
     | 
        rno = base->len;  | 
    
    
    1005  | 
     | 
     | 
        b = base->resps + rno;  | 
    
    
    1006  | 
     | 
     | 
        p = prev->resps + rno;  | 
    
    
    1007  | 
     | 
     | 
     | 
    
    
    1008  | 
     | 
     | 
        while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;  | 
    
    
    1009  | 
     | 
     | 
    }  | 
    
    
    1010  | 
     | 
     | 
     | 
    
    
    1011  | 
     | 
     | 
    /*  | 
    
    
    1012  | 
     | 
     | 
     * Print responses with statistics for forward path (from src to dst)  | 
    
    
    1013  | 
     | 
     | 
     */  | 
    
    
    1014  | 
     | 
     | 
    int  | 
    
    
    1015  | 
     | 
     | 
    print_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new)  | 
    
    
    1016  | 
     | 
     | 
    { | 
    
    
    1017  | 
     | 
     | 
        int rtt, hop;  | 
    
    
    1018  | 
     | 
     | 
        char *ms;  | 
    
    
    1019  | 
     | 
     | 
        u_int32_t smask;  | 
    
    
    1020  | 
     | 
     | 
        int rno = base->len - 1;  | 
    
    
    1021  | 
     | 
     | 
        struct tr_resp *b = base->resps + rno;  | 
    
    
    1022  | 
     | 
     | 
        struct tr_resp *p = prev->resps + rno;  | 
    
    
    1023  | 
     | 
     | 
        struct tr_resp *n = new->resps + rno;  | 
    
    
    1024  | 
     | 
     | 
        int *r = reset + rno;  | 
    
    
    1025  | 
     | 
     | 
        u_long resptime = new->rtime;  | 
    
    
    1026  | 
     | 
     | 
        u_long qarrtime = fixtime(ntohl(n->tr_qarr));  | 
    
    
    1027  | 
     | 
     | 
        u_int ttl = n->tr_fttl;  | 
    
    
    1028  | 
     | 
     | 
        int first = (base == prev);  | 
    
    
    1029  | 
     | 
     | 
     | 
    
    
    1030  | 
     | 
     | 
        VAL_TO_MASK(smask, b->tr_smask);  | 
    
    
    1031  | 
     | 
     | 
        printf("  Source        Response Dest"); | 
    
    
    1032  | 
     | 
     | 
        printf("    Packet Statistics For     Only For Traffic\n"); | 
    
    
    1033  | 
     | 
     | 
        printf("%-15s %-15s  All Multicast Traffic     From %s\n", | 
    
    
    1034  | 
     | 
     | 
    	   ((b->tr_inaddr & smask) == (qsrc & smask)) ? s1 : "   * * *       ",  | 
    
    
    1035  | 
     | 
     | 
    	   inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));  | 
    
    
    1036  | 
     | 
     | 
        rtt = t_diff(resptime, new->qtime);  | 
    
    
    1037  | 
     | 
     | 
        ms = scale(&rtt);  | 
    
    
    1038  | 
     | 
     | 
        printf("     %c       __/  rtt%5d%s    Lost/Sent = Pct  Rate       To %s\n", | 
    
    
    1039  | 
     | 
     | 
    	   first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));  | 
    
    
    1040  | 
     | 
     | 
        if (!first) { | 
    
    
    1041  | 
     | 
     | 
    	hop = t_diff(resptime, qarrtime);  | 
    
    
    1042  | 
     | 
     | 
    	ms = scale(&hop);  | 
    
    
    1043  | 
     | 
     | 
    	printf("     v      /     hop%5d%s", hop, ms); | 
    
    
    1044  | 
     | 
     | 
    	printf("    ---------------------     --------------------\n"); | 
    
    
    1045  | 
     | 
     | 
        }  | 
    
    
    1046  | 
     | 
     | 
        if (debug > 2) { | 
    
    
    1047  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(n->tr_vifin)); | 
    
    
    1048  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(n->tr_vifout)); | 
    
    
    1049  | 
     | 
     | 
    	printf("pkts: %u\n", ntohl(n->tr_pktcnt)); | 
    
    
    1050  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(b->tr_vifin)); | 
    
    
    1051  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(b->tr_vifout)); | 
    
    
    1052  | 
     | 
     | 
    	printf("pkts: %u\n", ntohl(b->tr_pktcnt)); | 
    
    
    1053  | 
     | 
     | 
    	printf("\t\t\t\tv_in: %u ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin)); | 
    
    
    1054  | 
     | 
     | 
    	printf("v_out: %u ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout)); | 
    
    
    1055  | 
     | 
     | 
    	printf("pkts: %u\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt)); | 
    
    
    1056  | 
     | 
     | 
    	printf("\t\t\t\treset: %d\n", *r); | 
    
    
    1057  | 
     | 
     | 
        }  | 
    
    
    1058  | 
     | 
     | 
     | 
    
    
    1059  | 
     | 
     | 
        while (TRUE) { | 
    
    
    1060  | 
     | 
     | 
    	if ((n->tr_inaddr != b->tr_inaddr) || (p->tr_inaddr != b->tr_inaddr))  | 
    
    
    1061  | 
     | 
     | 
    	  return 1;		/* Route changed */  | 
    
    
    1062  | 
     | 
     | 
     | 
    
    
    1063  | 
     | 
     | 
    	if ((n->tr_inaddr != n->tr_outaddr))  | 
    
    
    1064  | 
     | 
     | 
    	  printf("%-15s\n", inet_fmt(n->tr_inaddr, s1)); | 
    
    
    1065  | 
     | 
     | 
    	printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1), names[rno], | 
    
    
    1066  | 
     | 
     | 
    		 flag_type(n->tr_rflags));  | 
    
    
    1067  | 
     | 
     | 
     | 
    
    
    1068  | 
     | 
     | 
    	if (rno-- < 1) break;  | 
    
    
    1069  | 
     | 
     | 
     | 
    
    
    1070  | 
     | 
     | 
    	printf("     %c     ^      ttl%5d   ", first ? 'v' : '|', ttl); | 
    
    
    1071  | 
     | 
     | 
    	stat_line(p, n, TRUE, r);  | 
    
    
    1072  | 
     | 
     | 
    	if (!first) { | 
    
    
    1073  | 
     | 
     | 
    	    resptime = qarrtime;  | 
    
    
    1074  | 
     | 
     | 
    	    qarrtime = fixtime(ntohl((n-1)->tr_qarr));  | 
    
    
    1075  | 
     | 
     | 
    	    hop = t_diff(resptime, qarrtime);  | 
    
    
    1076  | 
     | 
     | 
    	    ms = scale(&hop);  | 
    
    
    1077  | 
     | 
     | 
    	    printf("     v     |      hop%5d%s", hop, ms); | 
    
    
    1078  | 
     | 
     | 
    	    stat_line(b, n, TRUE, r);  | 
    
    
    1079  | 
     | 
     | 
    	}  | 
    
    
    1080  | 
     | 
     | 
     | 
    
    
    1081  | 
     | 
     | 
    	--b, --p, --n, --r;  | 
    
    
    1082  | 
     | 
     | 
    	if (ttl < n->tr_fttl) ttl = n->tr_fttl;  | 
    
    
    1083  | 
     | 
     | 
    	else ++ttl;  | 
    
    
    1084  | 
     | 
     | 
        }  | 
    
    
    1085  | 
     | 
     | 
     | 
    
    
    1086  | 
     | 
     | 
        printf("     %c      \\__   ttl%5d   ", first ? 'v' : '|', ttl); | 
    
    
    1087  | 
     | 
     | 
        stat_line(p, n, FALSE, r);  | 
    
    
    1088  | 
     | 
     | 
        if (!first) { | 
    
    
    1089  | 
     | 
     | 
    	hop = t_diff(qarrtime, new->qtime);  | 
    
    
    1090  | 
     | 
     | 
    	ms = scale(&hop);  | 
    
    
    1091  | 
     | 
     | 
    	printf("     v         \\  hop%5d%s", hop, ms); | 
    
    
    1092  | 
     | 
     | 
    	stat_line(b, n, FALSE, r);  | 
    
    
    1093  | 
     | 
     | 
        }  | 
    
    
    1094  | 
     | 
     | 
        printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2)); | 
    
    
    1095  | 
     | 
     | 
        printf("  Receiver      Query Source\n\n"); | 
    
    
    1096  | 
     | 
     | 
        return 0;  | 
    
    
    1097  | 
     | 
     | 
    }  | 
    
    
    1098  | 
     | 
     | 
     | 
    
    
    1099  | 
     | 
     | 
     | 
    
    
    1100  | 
     | 
     | 
    /***************************************************************************  | 
    
    
    1101  | 
     | 
     | 
     *	main  | 
    
    
    1102  | 
     | 
     | 
     ***************************************************************************/  | 
    
    
    1103  | 
     | 
     | 
     | 
    
    
    1104  | 
     | 
     | 
    int  | 
    
    
    1105  | 
     | 
     | 
    main(int argc, char *argv[])  | 
    
    
    1106  | 
     | 
     | 
    { | 
    
    
    1107  | 
     | 
     | 
        int udp;  | 
    
    
    1108  | 
     | 
     | 
        struct sockaddr_in addr;  | 
    
    
    1109  | 
     | 
     | 
        int addrlen = sizeof(addr);  | 
    
    
    1110  | 
     | 
     | 
        int recvlen;  | 
    
    
    1111  | 
     | 
     | 
        struct timeval tv;  | 
    
    
    1112  | 
     | 
     | 
        struct resp_buf *prev, *new;  | 
    
    
    1113  | 
     | 
     | 
        struct tr_resp *r;  | 
    
    
    1114  | 
     | 
     | 
        u_int32_t smask;  | 
    
    
    1115  | 
     | 
     | 
        int rno;  | 
    
    
    1116  | 
     | 
     | 
        int hops, nexthop, tries;  | 
    
    
    1117  | 
     | 
     | 
        u_int32_t lastout = 0;  | 
    
    
    1118  | 
     | 
     | 
        int numstats = 1;  | 
    
    
    1119  | 
     | 
     | 
        int waittime;  | 
    
    
    1120  | 
     | 
     | 
        uid_t uid;  | 
    
    
    1121  | 
     | 
     | 
     | 
    
    
    1122  | 
     | 
     | 
        init_igmp();  | 
    
    
    1123  | 
     | 
     | 
     | 
    
    
    1124  | 
     | 
     | 
        uid = getuid();  | 
    
    
    1125  | 
     | 
     | 
        if (setresuid(uid, uid, uid) == -1)  | 
    
    
    1126  | 
     | 
     | 
    	err(1, "setresuid");  | 
    
    
    1127  | 
     | 
     | 
     | 
    
    
    1128  | 
     | 
     | 
        argv++, argc--;  | 
    
    
    1129  | 
     | 
     | 
        if (argc == 0) goto usage;  | 
    
    
    1130  | 
     | 
     | 
     | 
    
    
    1131  | 
     | 
     | 
        while (argc > 0 && *argv[0] == '-') { | 
    
    
    1132  | 
     | 
     | 
    	char *p = *argv++;  argc--;  | 
    
    
    1133  | 
     | 
     | 
    	p++;  | 
    
    
    1134  | 
     | 
     | 
    	do { | 
    
    
    1135  | 
     | 
     | 
    	    char c = *p++;  | 
    
    
    1136  | 
     | 
     | 
    	    char *arg = NULL;  | 
    
    
    1137  | 
     | 
     | 
    	    if (isdigit((unsigned char)*p)) { | 
    
    
    1138  | 
     | 
     | 
    		arg = p;  | 
    
    
    1139  | 
     | 
     | 
    		p = "";  | 
    
    
    1140  | 
     | 
     | 
    	    } else if (argc > 0) arg = argv[0];  | 
    
    
    1141  | 
     | 
     | 
    	    switch (c) { | 
    
    
    1142  | 
     | 
     | 
    	      case 'd':			/* Unlisted debug print option */  | 
    
    
    1143  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1144  | 
     | 
     | 
    		    debug = atoi(arg);  | 
    
    
    1145  | 
     | 
     | 
    		    if (debug < 0) debug = 0;  | 
    
    
    1146  | 
     | 
     | 
    		    if (debug > 3) debug = 3;  | 
    
    
    1147  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1148  | 
     | 
     | 
    		    break;  | 
    
    
    1149  | 
     | 
     | 
    		} else  | 
    
    
    1150  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1151  | 
     | 
     | 
    	      case 'M':			/* Use multicast for response */  | 
    
    
    1152  | 
     | 
     | 
    		multicast = TRUE;  | 
    
    
    1153  | 
     | 
     | 
    		break;  | 
    
    
    1154  | 
     | 
     | 
    	      case 'l':			/* Loop updating stats indefinitely */  | 
    
    
    1155  | 
     | 
     | 
    		numstats = 3153600;  | 
    
    
    1156  | 
     | 
     | 
    		break;  | 
    
    
    1157  | 
     | 
     | 
    	      case 'n':			/* Don't reverse map host addresses */  | 
    
    
    1158  | 
     | 
     | 
    		numeric = TRUE;  | 
    
    
    1159  | 
     | 
     | 
    		break;  | 
    
    
    1160  | 
     | 
     | 
    	      case 'p':			/* Passive listen for traces */  | 
    
    
    1161  | 
     | 
     | 
    		passive = TRUE;  | 
    
    
    1162  | 
     | 
     | 
    		break;  | 
    
    
    1163  | 
     | 
     | 
    	      case 'v':			/* Verbosity */  | 
    
    
    1164  | 
     | 
     | 
    		verbose = TRUE;  | 
    
    
    1165  | 
     | 
     | 
    		break;  | 
    
    
    1166  | 
     | 
     | 
    	      case 's':			/* Short form, don't wait for stats */  | 
    
    
    1167  | 
     | 
     | 
    		numstats = 0;  | 
    
    
    1168  | 
     | 
     | 
    		break;  | 
    
    
    1169  | 
     | 
     | 
    	      case 'w':			/* Time to wait for packet arrival */  | 
    
    
    1170  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1171  | 
     | 
     | 
    		    timeout = atoi(arg);  | 
    
    
    1172  | 
     | 
     | 
    		    if (timeout < 1) timeout = 1;  | 
    
    
    1173  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1174  | 
     | 
     | 
    		    break;  | 
    
    
    1175  | 
     | 
     | 
    		} else  | 
    
    
    1176  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1177  | 
     | 
     | 
    	      case 'm':			/* Max number of hops to trace */  | 
    
    
    1178  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1179  | 
     | 
     | 
    		    qno = atoi(arg);  | 
    
    
    1180  | 
     | 
     | 
    		    if (qno > MAXHOPS) qno = MAXHOPS;  | 
    
    
    1181  | 
     | 
     | 
    		    else if (qno < 1) qno = 0;  | 
    
    
    1182  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1183  | 
     | 
     | 
    		    break;  | 
    
    
    1184  | 
     | 
     | 
    		} else  | 
    
    
    1185  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1186  | 
     | 
     | 
    	      case 'q':			/* Number of query retries */  | 
    
    
    1187  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1188  | 
     | 
     | 
    		    nqueries = atoi(arg);  | 
    
    
    1189  | 
     | 
     | 
    		    if (nqueries < 1) nqueries = 1;  | 
    
    
    1190  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1191  | 
     | 
     | 
    		    break;  | 
    
    
    1192  | 
     | 
     | 
    		} else  | 
    
    
    1193  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1194  | 
     | 
     | 
    	      case 'g':			/* Last-hop gateway (dest of query) */  | 
    
    
    1195  | 
     | 
     | 
    		if (arg && (gwy = host_addr(arg))) { | 
    
    
    1196  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1197  | 
     | 
     | 
    		    break;  | 
    
    
    1198  | 
     | 
     | 
    		} else  | 
    
    
    1199  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1200  | 
     | 
     | 
    	      case 't':			/* TTL for query packet */  | 
    
    
    1201  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1202  | 
     | 
     | 
    		    qttl = atoi(arg);  | 
    
    
    1203  | 
     | 
     | 
    		    if (qttl < 1) qttl = 1;  | 
    
    
    1204  | 
     | 
     | 
    		    rttl = qttl;  | 
    
    
    1205  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1206  | 
     | 
     | 
    		    break;  | 
    
    
    1207  | 
     | 
     | 
    		} else  | 
    
    
    1208  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1209  | 
     | 
     | 
    	      case 'r':			/* Dest for response packet */  | 
    
    
    1210  | 
     | 
     | 
    		if (arg && (raddr = host_addr(arg))) { | 
    
    
    1211  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1212  | 
     | 
     | 
    		    break;  | 
    
    
    1213  | 
     | 
     | 
    		} else  | 
    
    
    1214  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1215  | 
     | 
     | 
    	      case 'i':			/* Local interface address */  | 
    
    
    1216  | 
     | 
     | 
    		if (arg && (lcl_addr = host_addr(arg))) { | 
    
    
    1217  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1218  | 
     | 
     | 
    		    break;  | 
    
    
    1219  | 
     | 
     | 
    		} else  | 
    
    
    1220  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1221  | 
     | 
     | 
    	      case 'S':			/* Stat accumulation interval */  | 
    
    
    1222  | 
     | 
     | 
    		if (arg && isdigit((unsigned char)*arg)) { | 
    
    
    1223  | 
     | 
     | 
    		    statint = atoi(arg);  | 
    
    
    1224  | 
     | 
     | 
    		    if (statint < 1) statint = 1;  | 
    
    
    1225  | 
     | 
     | 
    		    if (arg == argv[0]) argv++, argc--;  | 
    
    
    1226  | 
     | 
     | 
    		    break;  | 
    
    
    1227  | 
     | 
     | 
    		} else  | 
    
    
    1228  | 
     | 
     | 
    		    goto usage;  | 
    
    
    1229  | 
     | 
     | 
    	      default:  | 
    
    
    1230  | 
     | 
     | 
    		goto usage;  | 
    
    
    1231  | 
     | 
     | 
    	    }  | 
    
    
    1232  | 
     | 
     | 
    	} while (*p);  | 
    
    
    1233  | 
     | 
     | 
        }  | 
    
    
    1234  | 
     | 
     | 
     | 
    
    
    1235  | 
     | 
     | 
        if (argc > 0 && (qsrc = host_addr(argv[0]))) {          /* Source of path */ | 
    
    
    1236  | 
     | 
     | 
    	if (IN_MULTICAST(ntohl(qsrc))) goto usage;  | 
    
    
    1237  | 
     | 
     | 
    	argv++, argc--;  | 
    
    
    1238  | 
     | 
     | 
    	if (argc > 0 && (qdst = host_addr(argv[0]))) {      /* Dest of path */ | 
    
    
    1239  | 
     | 
     | 
    	    argv++, argc--;  | 
    
    
    1240  | 
     | 
     | 
    	    if (argc > 0 && (qgrp = host_addr(argv[0]))) {  /* Path via group */ | 
    
    
    1241  | 
     | 
     | 
    		argv++, argc--;  | 
    
    
    1242  | 
     | 
     | 
    	    }  | 
    
    
    1243  | 
     | 
     | 
    	    if (IN_MULTICAST(ntohl(qdst))) { | 
    
    
    1244  | 
     | 
     | 
    		u_int32_t temp = qdst;  | 
    
    
    1245  | 
     | 
     | 
    		qdst = qgrp;  | 
    
    
    1246  | 
     | 
     | 
    		qgrp = temp;  | 
    
    
    1247  | 
     | 
     | 
    		if (IN_MULTICAST(ntohl(qdst))) goto usage;  | 
    
    
    1248  | 
     | 
     | 
    	    } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) goto usage;  | 
    
    
    1249  | 
     | 
     | 
    	}  | 
    
    
    1250  | 
     | 
     | 
        }  | 
    
    
    1251  | 
     | 
     | 
     | 
    
    
    1252  | 
     | 
     | 
        if (passive) { | 
    
    
    1253  | 
     | 
     | 
    	passive_mode();  | 
    
    
    1254  | 
     | 
     | 
    	return(0);  | 
    
    
    1255  | 
     | 
     | 
        }  | 
    
    
    1256  | 
     | 
     | 
     | 
    
    
    1257  | 
     | 
     | 
        if (argc > 0 || qsrc == 0) { | 
    
    
    1258  | 
     | 
     | 
    usage:	printf("\ | 
    
    
    1259  | 
     | 
     | 
    usage: mtrace [-lMnpsv] [-g gateway] [-i if_addr] [-m max_hops] [-q nqueries]\n\  | 
    
    
    1260  | 
     | 
     | 
                  [-r host] [-S stat_int] [-t ttl] [-w waittime] source [receiver]\n\  | 
    
    
    1261  | 
     | 
     | 
    	      [group]\n");  | 
    
    
    1262  | 
     | 
     | 
    	exit(1);  | 
    
    
    1263  | 
     | 
     | 
        }  | 
    
    
    1264  | 
     | 
     | 
     | 
    
    
    1265  | 
     | 
     | 
        /*  | 
    
    
    1266  | 
     | 
     | 
         * Set useful defaults for as many parameters as possible.  | 
    
    
    1267  | 
     | 
     | 
         */  | 
    
    
    1268  | 
     | 
     | 
     | 
    
    
    1269  | 
     | 
     | 
        defgrp = htonl(0xE0020001);		/* MBone Audio (224.2.0.1) */  | 
    
    
    1270  | 
     | 
     | 
        query_cast = htonl(0xE0000002);	/* All routers multicast addr */  | 
    
    
    1271  | 
     | 
     | 
        resp_cast = htonl(0xE0000120);	/* Mtrace response multicast addr */  | 
    
    
    1272  | 
     | 
     | 
        if (qgrp == 0) qgrp = defgrp;  | 
    
    
    1273  | 
     | 
     | 
     | 
    
    
    1274  | 
     | 
     | 
        /*  | 
    
    
    1275  | 
     | 
     | 
         * Get default local address for multicasts to use in setting defaults.  | 
    
    
    1276  | 
     | 
     | 
         */  | 
    
    
    1277  | 
     | 
     | 
        memset(&addr, 0, sizeof addr);  | 
    
    
    1278  | 
     | 
     | 
        addr.sin_family = AF_INET;  | 
    
    
    1279  | 
     | 
     | 
        addr.sin_len = sizeof(addr);  | 
    
    
    1280  | 
     | 
     | 
        addr.sin_addr.s_addr = qgrp;  | 
    
    
    1281  | 
     | 
     | 
        addr.sin_port = htons(2000);	/* Any port above 1024 will do */  | 
    
    
    1282  | 
     | 
     | 
     | 
    
    
    1283  | 
     | 
     | 
        if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||  | 
    
    
    1284  | 
     | 
     | 
    	(connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||  | 
    
    
    1285  | 
     | 
     | 
    	getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { | 
    
    
    1286  | 
     | 
     | 
    	perror("Determining local address"); | 
    
    
    1287  | 
     | 
     | 
    	exit(1);  | 
    
    
    1288  | 
     | 
     | 
        }  | 
    
    
    1289  | 
     | 
     | 
     | 
    
    
    1290  | 
     | 
     | 
    #ifdef SUNOS5  | 
    
    
    1291  | 
     | 
     | 
       /*  | 
    
    
    1292  | 
     | 
     | 
         * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.  | 
    
    
    1293  | 
     | 
     | 
         * This call to sysinfo will return the hostname.  | 
    
    
    1294  | 
     | 
     | 
         * If the default multicast interface (set with the route  | 
    
    
    1295  | 
     | 
     | 
         * for 224.0.0.0) is not the same as the hostname,  | 
    
    
    1296  | 
     | 
     | 
         * mtrace -i [if_addr] will have to be used.  | 
    
    
    1297  | 
     | 
     | 
         */  | 
    
    
    1298  | 
     | 
     | 
        if (addr.sin_addr.s_addr == 0) { | 
    
    
    1299  | 
     | 
     | 
    	char myhostname[HOST_NAME_MAX+1];  | 
    
    
    1300  | 
     | 
     | 
    	struct hostent *hp;  | 
    
    
    1301  | 
     | 
     | 
    	int error;  | 
    
    
    1302  | 
     | 
     | 
     | 
    
    
    1303  | 
     | 
     | 
    	error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));  | 
    
    
    1304  | 
     | 
     | 
    	if (error == -1) { | 
    
    
    1305  | 
     | 
     | 
    	    perror("Getting my hostname"); | 
    
    
    1306  | 
     | 
     | 
    	    exit(1);  | 
    
    
    1307  | 
     | 
     | 
    	}  | 
    
    
    1308  | 
     | 
     | 
     | 
    
    
    1309  | 
     | 
     | 
    	hp = gethostbyname(myhostname);  | 
    
    
    1310  | 
     | 
     | 
    	if (hp == NULL || hp->h_addrtype != AF_INET ||  | 
    
    
    1311  | 
     | 
     | 
    	    hp->h_length != sizeof(addr.sin_addr)) { | 
    
    
    1312  | 
     | 
     | 
    	    perror("Finding IP address for my hostname"); | 
    
    
    1313  | 
     | 
     | 
    	    exit(1);  | 
    
    
    1314  | 
     | 
     | 
    	}  | 
    
    
    1315  | 
     | 
     | 
     | 
    
    
    1316  | 
     | 
     | 
    	memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);  | 
    
    
    1317  | 
     | 
     | 
        }  | 
    
    
    1318  | 
     | 
     | 
    #endif  | 
    
    
    1319  | 
     | 
     | 
     | 
    
    
    1320  | 
     | 
     | 
        /*  | 
    
    
    1321  | 
     | 
     | 
         * Default destination for path to be queried is the local host.  | 
    
    
    1322  | 
     | 
     | 
         */  | 
    
    
    1323  | 
     | 
     | 
        if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;  | 
    
    
    1324  | 
     | 
     | 
        dst_netmask = get_netmask(udp, qdst);  | 
    
    
    1325  | 
     | 
     | 
        close(udp);  | 
    
    
    1326  | 
     | 
     | 
        if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;  | 
    
    
    1327  | 
     | 
     | 
     | 
    
    
    1328  | 
     | 
     | 
        /*  | 
    
    
    1329  | 
     | 
     | 
         * Protect against unicast queries to mrouted versions that might crash.  | 
    
    
    1330  | 
     | 
     | 
         */  | 
    
    
    1331  | 
     | 
     | 
        if (gwy && !IN_MULTICAST(ntohl(gwy)))  | 
    
    
    1332  | 
     | 
     | 
          if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0])) { | 
    
    
    1333  | 
     | 
     | 
    	  int version = ntohl(incr[0].igmp.igmp_group.s_addr) & 0xFFFF;  | 
    
    
    1334  | 
     | 
     | 
    	  if (version == 0x0303 || version == 0x0503) { | 
    
    
    1335  | 
     | 
     | 
    	    printf("Don't use -g to address an mrouted 3.%d, it might crash\n", | 
    
    
    1336  | 
     | 
     | 
    		   (version >> 8) & 0xFF);  | 
    
    
    1337  | 
     | 
     | 
    	    exit(0);  | 
    
    
    1338  | 
     | 
     | 
    	}  | 
    
    
    1339  | 
     | 
     | 
          }  | 
    
    
    1340  | 
     | 
     | 
     | 
    
    
    1341  | 
     | 
     | 
        printf("Mtrace from %s to %s via group %s\n", | 
    
    
    1342  | 
     | 
     | 
    	   inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));  | 
    
    
    1343  | 
     | 
     | 
     | 
    
    
    1344  | 
     | 
     | 
        if ((qdst & dst_netmask) == (qsrc & dst_netmask)) { | 
    
    
    1345  | 
     | 
     | 
    	printf("Source & receiver are directly connected, no path to trace\n"); | 
    
    
    1346  | 
     | 
     | 
    	exit(0);  | 
    
    
    1347  | 
     | 
     | 
        }  | 
    
    
    1348  | 
     | 
     | 
     | 
    
    
    1349  | 
     | 
     | 
        /*  | 
    
    
    1350  | 
     | 
     | 
         * If the response is to be a multicast address, make sure we  | 
    
    
    1351  | 
     | 
     | 
         * are listening on that multicast address.  | 
    
    
    1352  | 
     | 
     | 
         */  | 
    
    
    1353  | 
     | 
     | 
        if (raddr) { | 
    
    
    1354  | 
     | 
     | 
    	if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);  | 
    
    
    1355  | 
     | 
     | 
        } else k_join(resp_cast, lcl_addr);  | 
    
    
    1356  | 
     | 
     | 
     | 
    
    
    1357  | 
     | 
     | 
        /*  | 
    
    
    1358  | 
     | 
     | 
         * If the destination is on the local net, the last-hop router can  | 
    
    
    1359  | 
     | 
     | 
         * be found by multicast to the all-routers multicast group.  | 
    
    
    1360  | 
     | 
     | 
         * Otherwise, use the group address that is the subject of the  | 
    
    
    1361  | 
     | 
     | 
         * query since by definition the last-hop router will be a member.  | 
    
    
    1362  | 
     | 
     | 
         * Set default TTLs for local remote multicasts.  | 
    
    
    1363  | 
     | 
     | 
         */  | 
    
    
    1364  | 
     | 
     | 
        restart:  | 
    
    
    1365  | 
     | 
     | 
     | 
    
    
    1366  | 
     | 
     | 
        if (gwy == 0)  | 
    
    
    1367  | 
     | 
     | 
          if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast;  | 
    
    
    1368  | 
     | 
     | 
          else tdst = qgrp;  | 
    
    
    1369  | 
     | 
     | 
        else tdst = gwy;  | 
    
    
    1370  | 
     | 
     | 
     | 
    
    
    1371  | 
     | 
     | 
        if (IN_MULTICAST(ntohl(tdst))) { | 
    
    
    1372  | 
     | 
     | 
          k_set_loop(1);	/* If I am running on a router, I need to hear this */  | 
    
    
    1373  | 
     | 
     | 
          if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1);  | 
    
    
    1374  | 
     | 
     | 
          else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);  | 
    
    
    1375  | 
     | 
     | 
        }  | 
    
    
    1376  | 
     | 
     | 
     | 
    
    
    1377  | 
     | 
     | 
        /*  | 
    
    
    1378  | 
     | 
     | 
         * Try a query at the requested number of hops or MAXHOPS if unspecified.  | 
    
    
    1379  | 
     | 
     | 
         */  | 
    
    
    1380  | 
     | 
     | 
        if (qno == 0) { | 
    
    
    1381  | 
     | 
     | 
    	hops = MAXHOPS;  | 
    
    
    1382  | 
     | 
     | 
    	tries = 1;  | 
    
    
    1383  | 
     | 
     | 
    	printf("Querying full reverse path... "); | 
    
    
    1384  | 
     | 
     | 
    	fflush(stdout);  | 
    
    
    1385  | 
     | 
     | 
        } else { | 
    
    
    1386  | 
     | 
     | 
    	hops = qno;  | 
    
    
    1387  | 
     | 
     | 
    	tries = nqueries;  | 
    
    
    1388  | 
     | 
     | 
    	printf("Querying reverse path, maximum %d hops... ", qno); | 
    
    
    1389  | 
     | 
     | 
    	fflush(stdout);  | 
    
    
    1390  | 
     | 
     | 
        }  | 
    
    
    1391  | 
     | 
     | 
        base.rtime = 0;  | 
    
    
    1392  | 
     | 
     | 
        base.len = 0;  | 
    
    
    1393  | 
     | 
     | 
     | 
    
    
    1394  | 
     | 
     | 
        recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, hops, tries, &base);  | 
    
    
    1395  | 
     | 
     | 
     | 
    
    
    1396  | 
     | 
     | 
        /*  | 
    
    
    1397  | 
     | 
     | 
         * If the initial query was successful, print it.  Otherwise, if  | 
    
    
    1398  | 
     | 
     | 
         * the query max hop count is the default of zero, loop starting  | 
    
    
    1399  | 
     | 
     | 
         * from one until there is no response for four hops.  The extra  | 
    
    
    1400  | 
     | 
     | 
         * hops allow getting past an mtrace-capable mrouter that can't  | 
    
    
    1401  | 
     | 
     | 
         * send multicast packets because all phyints are disabled.  | 
    
    
    1402  | 
     | 
     | 
         */  | 
    
    
    1403  | 
     | 
     | 
        if (recvlen) { | 
    
    
    1404  | 
     | 
     | 
    	printf("\n  0  "); | 
    
    
    1405  | 
     | 
     | 
    	print_host(qdst);  | 
    
    
    1406  | 
     | 
     | 
    	printf("\n"); | 
    
    
    1407  | 
     | 
     | 
    	print_trace(1, &base);  | 
    
    
    1408  | 
     | 
     | 
    	r = base.resps + base.len - 1;  | 
    
    
    1409  | 
     | 
     | 
    	if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||  | 
    
    
    1410  | 
     | 
     | 
    		qno != 0) { | 
    
    
    1411  | 
     | 
     | 
    	    printf("%3d  ", -(base.len+1)); | 
    
    
    1412  | 
     | 
     | 
    	    what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?  | 
    
    
    1413  | 
     | 
     | 
    				   "doesn't support mtrace"  | 
    
    
    1414  | 
     | 
     | 
    				 : "is the next hop");  | 
    
    
    1415  | 
     | 
     | 
    	} else { | 
    
    
    1416  | 
     | 
     | 
    	    VAL_TO_MASK(smask, r->tr_smask);  | 
    
    
    1417  | 
     | 
     | 
    	    if ((r->tr_inaddr & smask) == (qsrc & smask)) { | 
    
    
    1418  | 
     | 
     | 
    		printf("%3d  ", -(base.len+1)); | 
    
    
    1419  | 
     | 
     | 
    		print_host(qsrc);  | 
    
    
    1420  | 
     | 
     | 
    		printf("\n"); | 
    
    
    1421  | 
     | 
     | 
    	    }  | 
    
    
    1422  | 
     | 
     | 
    	}  | 
    
    
    1423  | 
     | 
     | 
        } else if (qno == 0) { | 
    
    
    1424  | 
     | 
     | 
    	printf("switching to hop-by-hop:\n  0  "); | 
    
    
    1425  | 
     | 
     | 
    	print_host(qdst);  | 
    
    
    1426  | 
     | 
     | 
    	printf("\n"); | 
    
    
    1427  | 
     | 
     | 
     | 
    
    
    1428  | 
     | 
     | 
    	for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) { | 
    
    
    1429  | 
     | 
     | 
    	    printf("%3d  ", -hops); | 
    
    
    1430  | 
     | 
     | 
    	    fflush(stdout);  | 
    
    
    1431  | 
     | 
     | 
     | 
    
    
    1432  | 
     | 
     | 
    	    /*  | 
    
    
    1433  | 
     | 
     | 
    	     * After a successful first hop, try switching to the unicast  | 
    
    
    1434  | 
     | 
     | 
    	     * address of the last-hop router instead of multicasting the  | 
    
    
    1435  | 
     | 
     | 
    	     * trace query.  This should be safe for mrouted versions 3.3  | 
    
    
    1436  | 
     | 
     | 
    	     * and 3.5 because there is a long route timeout with metric  | 
    
    
    1437  | 
     | 
     | 
    	     * infinity before a route disappears.  Switching to unicast  | 
    
    
    1438  | 
     | 
     | 
    	     * reduces the amount of multicast traffic and avoids a bug  | 
    
    
    1439  | 
     | 
     | 
    	     * with duplicate suppression in mrouted 3.5.  | 
    
    
    1440  | 
     | 
     | 
    	     */  | 
    
    
    1441  | 
     | 
     | 
    	    if (hops == 2 && gwy == 0 &&  | 
    
    
    1442  | 
     | 
     | 
    		(recvlen = send_recv(lastout, IGMP_MTRACE_QUERY, hops, 1, &base)))  | 
    
    
    1443  | 
     | 
     | 
    	      tdst = lastout;  | 
    
    
    1444  | 
     | 
     | 
    	    else recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, hops, nqueries, &base);  | 
    
    
    1445  | 
     | 
     | 
     | 
    
    
    1446  | 
     | 
     | 
    	    if (recvlen == 0) { | 
    
    
    1447  | 
     | 
     | 
    		if (hops == 1) break;  | 
    
    
    1448  | 
     | 
     | 
    		if (hops == nexthop) { | 
    
    
    1449  | 
     | 
     | 
    		    if (what_kind(&base, "didn't respond")) { | 
    
    
    1450  | 
     | 
     | 
    			/* the ask_neighbors determined that the  | 
    
    
    1451  | 
     | 
     | 
    			 * not-responding router is the first-hop. */  | 
    
    
    1452  | 
     | 
     | 
    			break;  | 
    
    
    1453  | 
     | 
     | 
    		    }  | 
    
    
    1454  | 
     | 
     | 
    		} else if (hops < nexthop + 3) { | 
    
    
    1455  | 
     | 
     | 
    		    printf("\n"); | 
    
    
    1456  | 
     | 
     | 
    		} else { | 
    
    
    1457  | 
     | 
     | 
    		    printf("...giving up\n"); | 
    
    
    1458  | 
     | 
     | 
    		    break;  | 
    
    
    1459  | 
     | 
     | 
    		}  | 
    
    
    1460  | 
     | 
     | 
    		continue;  | 
    
    
    1461  | 
     | 
     | 
    	    }  | 
    
    
    1462  | 
     | 
     | 
    	    r = base.resps + base.len - 1;  | 
    
    
    1463  | 
     | 
     | 
    	    if (base.len == hops &&  | 
    
    
    1464  | 
     | 
     | 
    		(hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) { | 
    
    
    1465  | 
     | 
     | 
    		if (hops == nexthop) { | 
    
    
    1466  | 
     | 
     | 
    		    print_trace(-hops, &base);  | 
    
    
    1467  | 
     | 
     | 
    		} else { | 
    
    
    1468  | 
     | 
     | 
    		    printf("\nResuming...\n"); | 
    
    
    1469  | 
     | 
     | 
    		    print_trace(nexthop, &base);  | 
    
    
    1470  | 
     | 
     | 
    		}  | 
    
    
    1471  | 
     | 
     | 
    	    } else { | 
    
    
    1472  | 
     | 
     | 
    		if (base.len < hops) { | 
    
    
    1473  | 
     | 
     | 
    		    /*  | 
    
    
    1474  | 
     | 
     | 
    		     * A shorter trace than requested means a fatal error  | 
    
    
    1475  | 
     | 
     | 
    		     * occurred along the path, or that the route changed  | 
    
    
    1476  | 
     | 
     | 
    		     * to a shorter one.  | 
    
    
    1477  | 
     | 
     | 
    		     *  | 
    
    
    1478  | 
     | 
     | 
    		     * If the trace is longer than the last one we received,  | 
    
    
    1479  | 
     | 
     | 
    		     * then we are resuming from a skipped router (but there  | 
    
    
    1480  | 
     | 
     | 
    		     * is still probably a problem).  | 
    
    
    1481  | 
     | 
     | 
    		     *  | 
    
    
    1482  | 
     | 
     | 
    		     * If the trace is shorter than the last one we  | 
    
    
    1483  | 
     | 
     | 
    		     * received, then the route must have changed (and  | 
    
    
    1484  | 
     | 
     | 
    		     * there is still probably a problem).  | 
    
    
    1485  | 
     | 
     | 
    		     */  | 
    
    
    1486  | 
     | 
     | 
    		    if (nexthop <= base.len) { | 
    
    
    1487  | 
     | 
     | 
    			printf("\nResuming...\n"); | 
    
    
    1488  | 
     | 
     | 
    			print_trace(nexthop, &base);  | 
    
    
    1489  | 
     | 
     | 
    		    } else if (nexthop > base.len + 1) { | 
    
    
    1490  | 
     | 
     | 
    			hops = base.len;  | 
    
    
    1491  | 
     | 
     | 
    			printf("\nRoute must have changed...\n"); | 
    
    
    1492  | 
     | 
     | 
    			print_trace(1, &base);  | 
    
    
    1493  | 
     | 
     | 
    		    }  | 
    
    
    1494  | 
     | 
     | 
    		} else { | 
    
    
    1495  | 
     | 
     | 
    		    /*  | 
    
    
    1496  | 
     | 
     | 
    		     * The last hop address is not the same as it was;  | 
    
    
    1497  | 
     | 
     | 
    		     * the route probably changed underneath us.  | 
    
    
    1498  | 
     | 
     | 
    		     */  | 
    
    
    1499  | 
     | 
     | 
    		    hops = base.len;  | 
    
    
    1500  | 
     | 
     | 
    		    printf("\nRoute must have changed...\n"); | 
    
    
    1501  | 
     | 
     | 
    		    print_trace(1, &base);  | 
    
    
    1502  | 
     | 
     | 
    		}  | 
    
    
    1503  | 
     | 
     | 
    	    }  | 
    
    
    1504  | 
     | 
     | 
    	    lastout = r->tr_outaddr;  | 
    
    
    1505  | 
     | 
     | 
     | 
    
    
    1506  | 
     | 
     | 
    	    if (base.len < hops ||  | 
    
    
    1507  | 
     | 
     | 
    		r->tr_rmtaddr == 0 ||  | 
    
    
    1508  | 
     | 
     | 
    		(r->tr_rflags & 0x80)) { | 
    
    
    1509  | 
     | 
     | 
    		VAL_TO_MASK(smask, r->tr_smask);  | 
    
    
    1510  | 
     | 
     | 
    		if (r->tr_rmtaddr) { | 
    
    
    1511  | 
     | 
     | 
    		    if (hops != nexthop) { | 
    
    
    1512  | 
     | 
     | 
    			printf("\n%3d  ", -(base.len+1)); | 
    
    
    1513  | 
     | 
     | 
    		    }  | 
    
    
    1514  | 
     | 
     | 
    		    what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?  | 
    
    
    1515  | 
     | 
     | 
    				"doesn't support mtrace" :  | 
    
    
    1516  | 
     | 
     | 
    				"would be the next hop");  | 
    
    
    1517  | 
     | 
     | 
    		    /* XXX could do segmented trace if TR_NO_SPACE */  | 
    
    
    1518  | 
     | 
     | 
    		} else if (r->tr_rflags == TR_NO_ERR &&  | 
    
    
    1519  | 
     | 
     | 
    			   (r->tr_inaddr & smask) == (qsrc & smask)) { | 
    
    
    1520  | 
     | 
     | 
    		    printf("%3d  ", -(hops + 1)); | 
    
    
    1521  | 
     | 
     | 
    		    print_host(qsrc);  | 
    
    
    1522  | 
     | 
     | 
    		    printf("\n"); | 
    
    
    1523  | 
     | 
     | 
    		}  | 
    
    
    1524  | 
     | 
     | 
    		break;  | 
    
    
    1525  | 
     | 
     | 
    	    }  | 
    
    
    1526  | 
     | 
     | 
     | 
    
    
    1527  | 
     | 
     | 
    	    nexthop = hops + 1;  | 
    
    
    1528  | 
     | 
     | 
    	}  | 
    
    
    1529  | 
     | 
     | 
        }  | 
    
    
    1530  | 
     | 
     | 
     | 
    
    
    1531  | 
     | 
     | 
        if (base.rtime == 0) { | 
    
    
    1532  | 
     | 
     | 
    	printf("Timed out receiving responses\n"); | 
    
    
    1533  | 
     | 
     | 
    	if (IN_MULTICAST(ntohl(tdst))) { | 
    
    
    1534  | 
     | 
     | 
    	  if (tdst == query_cast)  | 
    
    
    1535  | 
     | 
     | 
    	    printf("Perhaps no local router has a route for source %s\n", | 
    
    
    1536  | 
     | 
     | 
    		   inet_fmt(qsrc, s1));  | 
    
    
    1537  | 
     | 
     | 
    	  else  | 
    
    
    1538  | 
     | 
     | 
    	    printf("Perhaps receiver %s is not a member of group %s,\n\ | 
    
    
    1539  | 
     | 
     | 
    or no router local to it has a route for source %s,\n\  | 
    
    
    1540  | 
     | 
     | 
    or multicast at ttl %d doesn't reach its last-hop router for that source\n",  | 
    
    
    1541  | 
     | 
     | 
    		   inet_fmt(qdst, s2), inet_fmt(qgrp, s3), inet_fmt(qsrc, s1),  | 
    
    
    1542  | 
     | 
     | 
    		   qttl ? qttl : MULTICAST_TTL1);  | 
    
    
    1543  | 
     | 
     | 
    	}  | 
    
    
    1544  | 
     | 
     | 
    	exit(1);  | 
    
    
    1545  | 
     | 
     | 
        }  | 
    
    
    1546  | 
     | 
     | 
     | 
    
    
    1547  | 
     | 
     | 
        printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime)); | 
    
    
    1548  | 
     | 
     | 
     | 
    
    
    1549  | 
     | 
     | 
        /*  | 
    
    
    1550  | 
     | 
     | 
         * Use the saved response which was the longest one received,  | 
    
    
    1551  | 
     | 
     | 
         * and make additional probes after delay to measure loss.  | 
    
    
    1552  | 
     | 
     | 
         */  | 
    
    
    1553  | 
     | 
     | 
        raddr = base.qhdr.tr_raddr;  | 
    
    
    1554  | 
     | 
     | 
        rttl = base.qhdr.tr_rttl;  | 
    
    
    1555  | 
     | 
     | 
        gettimeofday(&tv, 0);  | 
    
    
    1556  | 
     | 
     | 
        waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));  | 
    
    
    1557  | 
     | 
     | 
        prev = &base;  | 
    
    
    1558  | 
     | 
     | 
        new = &incr[numstats&1];  | 
    
    
    1559  | 
     | 
     | 
     | 
    
    
    1560  | 
     | 
     | 
        while (numstats--) { | 
    
    
    1561  | 
     | 
     | 
    	if (waittime < 1)  | 
    
    
    1562  | 
     | 
     | 
    		printf("\n"); | 
    
    
    1563  | 
     | 
     | 
    	else { | 
    
    
    1564  | 
     | 
     | 
    		printf("Waiting to accumulate statistics... "); | 
    
    
    1565  | 
     | 
     | 
    		fflush(stdout);  | 
    
    
    1566  | 
     | 
     | 
    		sleep((unsigned int)waittime);  | 
    
    
    1567  | 
     | 
     | 
    	}  | 
    
    
    1568  | 
     | 
     | 
    	rno = base.len;  | 
    
    
    1569  | 
     | 
     | 
    	recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, rno, nqueries, new);  | 
    
    
    1570  | 
     | 
     | 
     | 
    
    
    1571  | 
     | 
     | 
    	if (recvlen == 0) { | 
    
    
    1572  | 
     | 
     | 
    	    printf("Timed out.\n"); | 
    
    
    1573  | 
     | 
     | 
    	    exit(1);  | 
    
    
    1574  | 
     | 
     | 
    	}  | 
    
    
    1575  | 
     | 
     | 
     | 
    
    
    1576  | 
     | 
     | 
    	if (rno != new->len) { | 
    
    
    1577  | 
     | 
     | 
    	    printf("Trace length doesn't match:\n"); | 
    
    
    1578  | 
     | 
     | 
    	    /*  | 
    
    
    1579  | 
     | 
     | 
    	     * XXX Should this trace result be printed, or is that  | 
    
    
    1580  | 
     | 
     | 
    	     * too verbose?  Perhaps it should just say restarting.  | 
    
    
    1581  | 
     | 
     | 
    	     * But if the path is changing quickly, this may be the  | 
    
    
    1582  | 
     | 
     | 
    	     * only snapshot of the current path.  But, if the path  | 
    
    
    1583  | 
     | 
     | 
    	     * is changing that quickly, does the current path really  | 
    
    
    1584  | 
     | 
     | 
    	     * matter?  | 
    
    
    1585  | 
     | 
     | 
    	     */  | 
    
    
    1586  | 
     | 
     | 
    	    print_trace(1, new);  | 
    
    
    1587  | 
     | 
     | 
    	    printf("Restarting.\n\n"); | 
    
    
    1588  | 
     | 
     | 
    	    numstats++;  | 
    
    
    1589  | 
     | 
     | 
    	    goto restart;  | 
    
    
    1590  | 
     | 
     | 
    	}  | 
    
    
    1591  | 
     | 
     | 
     | 
    
    
    1592  | 
     | 
     | 
    	printf("Results after %d seconds:\n\n", | 
    
    
    1593  | 
     | 
     | 
    	       (int)((new->qtime - base.qtime) >> 16));  | 
    
    
    1594  | 
     | 
     | 
    	fixup_stats(&base, prev, new);  | 
    
    
    1595  | 
     | 
     | 
    	if (print_stats(&base, prev, new)) { | 
    
    
    1596  | 
     | 
     | 
    	    printf("Route changed:\n"); | 
    
    
    1597  | 
     | 
     | 
    	    print_trace(1, new);  | 
    
    
    1598  | 
     | 
     | 
    	    printf("Restarting.\n\n"); | 
    
    
    1599  | 
     | 
     | 
    	    goto restart;  | 
    
    
    1600  | 
     | 
     | 
    	}  | 
    
    
    1601  | 
     | 
     | 
    	prev = new;  | 
    
    
    1602  | 
     | 
     | 
    	new = &incr[numstats&1];  | 
    
    
    1603  | 
     | 
     | 
    	waittime = statint;  | 
    
    
    1604  | 
     | 
     | 
        }  | 
    
    
    1605  | 
     | 
     | 
     | 
    
    
    1606  | 
     | 
     | 
        /*  | 
    
    
    1607  | 
     | 
     | 
         * If the response was multicast back, leave the group  | 
    
    
    1608  | 
     | 
     | 
         */  | 
    
    
    1609  | 
     | 
     | 
        if (raddr) { | 
    
    
    1610  | 
     | 
     | 
    	if (IN_MULTICAST(ntohl(raddr)))	k_leave(raddr, lcl_addr);  | 
    
    
    1611  | 
     | 
     | 
        } else k_leave(resp_cast, lcl_addr);  | 
    
    
    1612  | 
     | 
     | 
     | 
    
    
    1613  | 
     | 
     | 
        return (0);  | 
    
    
    1614  | 
     | 
     | 
    }  | 
    
    
    1615  | 
     | 
     | 
     | 
    
    
    1616  | 
     | 
     | 
    void  | 
    
    
    1617  | 
     | 
     | 
    check_vif_state(void)  | 
    
    
    1618  | 
     | 
     | 
    { | 
    
    
    1619  | 
     | 
     | 
        logit(LOG_WARNING, errno, "sendto");  | 
    
    
    1620  | 
     | 
     | 
    }  | 
    
    
    1621  | 
     | 
     | 
     | 
    
    
    1622  | 
     | 
     | 
    /*  | 
    
    
    1623  | 
     | 
     | 
     * Log errors and other messages to stderr, according to the severity  | 
    
    
    1624  | 
     | 
     | 
     * of the message and the current debug level.  For errors of severity  | 
    
    
    1625  | 
     | 
     | 
     * LOG_ERR or worse, terminate the program.  | 
    
    
    1626  | 
     | 
     | 
     */  | 
    
    
    1627  | 
     | 
     | 
    void  | 
    
    
    1628  | 
     | 
     | 
    logit(int severity, int syserr, char *format, ...)  | 
    
    
    1629  | 
     | 
     | 
    { | 
    
    
    1630  | 
     | 
     | 
        va_list ap;  | 
    
    
    1631  | 
     | 
     | 
     | 
    
    
    1632  | 
     | 
     | 
        switch (debug) { | 
    
    
    1633  | 
     | 
     | 
    	case 0: if (severity > LOG_WARNING) return;  | 
    
    
    1634  | 
     | 
     | 
    	case 1: if (severity > LOG_NOTICE) return;  | 
    
    
    1635  | 
     | 
     | 
    	case 2: if (severity > LOG_INFO  ) return;  | 
    
    
    1636  | 
     | 
     | 
    	default:  | 
    
    
    1637  | 
     | 
     | 
    	    if (severity == LOG_WARNING)  | 
    
    
    1638  | 
     | 
     | 
    		fprintf(stderr, "warning - ");  | 
    
    
    1639  | 
     | 
     | 
    	    va_start(ap, format);  | 
    
    
    1640  | 
     | 
     | 
    	    vfprintf(stderr, format, ap);  | 
    
    
    1641  | 
     | 
     | 
    	    va_end(ap);  | 
    
    
    1642  | 
     | 
     | 
    	    if (syserr == 0)  | 
    
    
    1643  | 
     | 
     | 
    		fprintf(stderr, "\n");  | 
    
    
    1644  | 
     | 
     | 
    	    else if(syserr < sys_nerr)  | 
    
    
    1645  | 
     | 
     | 
    		fprintf(stderr, ": %s\n", sys_errlist[syserr]);  | 
    
    
    1646  | 
     | 
     | 
    	    else  | 
    
    
    1647  | 
     | 
     | 
    		fprintf(stderr, ": errno %d\n", syserr);  | 
    
    
    1648  | 
     | 
     | 
        }  | 
    
    
    1649  | 
     | 
     | 
        if (severity <= LOG_ERR) exit(1);  | 
    
    
    1650  | 
     | 
     | 
    }  | 
    
    
    1651  | 
     | 
     | 
     | 
    
    
    1652  | 
     | 
     | 
    /* dummies */  | 
    
    
    1653  | 
     | 
     | 
    void accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen,  | 
    
    
    1654  | 
     | 
     | 
        u_int32_t level)  | 
    
    
    1655  | 
     | 
     | 
    { | 
    
    
    1656  | 
     | 
     | 
    }  | 
    
    
    1657  | 
     | 
     | 
     | 
    
    
    1658  | 
     | 
     | 
    void accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group,  | 
    
    
    1659  | 
     | 
     | 
        int r_type)  | 
    
    
    1660  | 
     | 
     | 
    { | 
    
    
    1661  | 
     | 
     | 
    }  | 
    
    
    1662  | 
     | 
     | 
     | 
    
    
    1663  | 
     | 
     | 
    void accept_neighbor_request2(u_int32_t src, u_int32_t dst)  | 
    
    
    1664  | 
     | 
     | 
    { | 
    
    
    1665  | 
     | 
     | 
    }  | 
    
    
    1666  | 
     | 
     | 
     | 
    
    
    1667  | 
     | 
     | 
    void accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen,  | 
    
    
    1668  | 
     | 
     | 
        u_int32_t level)  | 
    
    
    1669  | 
     | 
     | 
    { | 
    
    
    1670  | 
     | 
     | 
    }  | 
    
    
    1671  | 
     | 
     | 
     | 
    
    
    1672  | 
     | 
     | 
    void accept_neighbor_request(u_int32_t src, u_int32_t dst)  | 
    
    
    1673  | 
     | 
     | 
    { | 
    
    
    1674  | 
     | 
     | 
    }  | 
    
    
    1675  | 
     | 
     | 
     | 
    
    
    1676  | 
     | 
     | 
    void accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen)  | 
    
    
    1677  | 
     | 
     | 
    { | 
    
    
    1678  | 
     | 
     | 
    }  | 
    
    
    1679  | 
     | 
     | 
     | 
    
    
    1680  | 
     | 
     | 
    void accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen)  | 
    
    
    1681  | 
     | 
     | 
    { | 
    
    
    1682  | 
     | 
     | 
    }  | 
    
    
    1683  | 
     | 
     | 
     | 
    
    
    1684  | 
     | 
     | 
    void accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen)  | 
    
    
    1685  | 
     | 
     | 
    { | 
    
    
    1686  | 
     | 
     | 
    }  | 
    
    
    1687  | 
     | 
     | 
     | 
    
    
    1688  | 
     | 
     | 
    void add_table_entry(u_int32_t origin, u_int32_t mcastgrp)  | 
    
    
    1689  | 
     | 
     | 
    { | 
    
    
    1690  | 
     | 
     | 
    }  | 
    
    
    1691  | 
     | 
     | 
     | 
    
    
    1692  | 
     | 
     | 
    void accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group)  | 
    
    
    1693  | 
     | 
     | 
    { | 
    
    
    1694  | 
     | 
     | 
    }  | 
    
    
    1695  | 
     | 
     | 
     | 
    
    
    1696  | 
     | 
     | 
    void accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group, char *data,  | 
    
    
    1697  | 
     | 
     | 
        u_int no, int datalen)  | 
    
    
    1698  | 
     | 
     | 
    { | 
    
    
    1699  | 
     | 
     | 
    }  | 
    
    
    1700  | 
     | 
     | 
     | 
    
    
    1701  | 
     | 
     | 
    void accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group,  | 
    
    
    1702  | 
     | 
     | 
        int tmo)  | 
    
    
    1703  | 
     | 
     | 
    { | 
    
    
    1704  | 
     | 
     | 
    }  | 
    
    
    1705  | 
     | 
     | 
     | 
    
    
    1706  | 
     | 
     | 
    void accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen,  | 
    
    
    1707  | 
     | 
     | 
        u_int32_t level)  | 
    
    
    1708  | 
     | 
     | 
    { | 
    
    
    1709  | 
     | 
     | 
    }  | 
    
    
    1710  | 
     | 
     | 
     | 
    
    
    1711  | 
     | 
     | 
    void accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen,  | 
    
    
    1712  | 
     | 
     | 
        u_int32_t level)  | 
    
    
    1713  | 
     | 
     | 
    { | 
    
    
    1714  | 
     | 
     | 
    }  | 
    
    
    1715  | 
     | 
     | 
     | 
    
    
    1716  | 
     | 
     | 
    void accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen)  | 
    
    
    1717  | 
     | 
     | 
    { | 
    
    
    1718  | 
     | 
     | 
    }  | 
    
    
    1719  | 
     | 
     | 
     | 
    
    
    1720  | 
     | 
     | 
    void accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen)  | 
    
    
    1721  | 
     | 
     | 
    { | 
    
    
    1722  | 
     | 
     | 
    }  |