1  | 
     | 
     | 
    /*	$OpenBSD: route6d.c,v 1.92 2017/08/23 11:25:07 jca Exp $	*/  | 
    
    
    2  | 
     | 
     | 
    /*	$KAME: route6d.c,v 1.111 2006/10/25 06:38:13 jinmei Exp $	*/  | 
    
    
    3  | 
     | 
     | 
     | 
    
    
    4  | 
     | 
     | 
    /*  | 
    
    
    5  | 
     | 
     | 
     * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.  | 
    
    
    6  | 
     | 
     | 
     * All rights reserved.  | 
    
    
    7  | 
     | 
     | 
     *  | 
    
    
    8  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    9  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    10  | 
     | 
     | 
     * are met:  | 
    
    
    11  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    12  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    13  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    14  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    15  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    16  | 
     | 
     | 
     * 3. Neither the name of the project nor the names of its contributors  | 
    
    
    17  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    18  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    19  | 
     | 
     | 
     *  | 
    
    
    20  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    21  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    22  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    23  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE  | 
    
    
    24  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    25  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    26  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    27  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    28  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    29  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    30  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    31  | 
     | 
     | 
     */  | 
    
    
    32  | 
     | 
     | 
     | 
    
    
    33  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    34  | 
     | 
     | 
    #include <sys/ioctl.h>  | 
    
    
    35  | 
     | 
     | 
    #include <sys/socket.h>  | 
    
    
    36  | 
     | 
     | 
    #include <sys/sysctl.h>  | 
    
    
    37  | 
     | 
     | 
    #include <sys/uio.h>  | 
    
    
    38  | 
     | 
     | 
     | 
    
    
    39  | 
     | 
     | 
    #include <net/if.h>  | 
    
    
    40  | 
     | 
     | 
    #include <net/route.h>  | 
    
    
    41  | 
     | 
     | 
    #include <netinet/in.h>  | 
    
    
    42  | 
     | 
     | 
    #include <netinet/ip6.h>  | 
    
    
    43  | 
     | 
     | 
    #include <netinet/udp.h>  | 
    
    
    44  | 
     | 
     | 
    #include <netinet6/in6_var.h>  | 
    
    
    45  | 
     | 
     | 
     | 
    
    
    46  | 
     | 
     | 
    #include <arpa/inet.h>  | 
    
    
    47  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    48  | 
     | 
     | 
    #include <ifaddrs.h>  | 
    
    
    49  | 
     | 
     | 
    #include <netdb.h>  | 
    
    
    50  | 
     | 
     | 
    #include <poll.h>  | 
    
    
    51  | 
     | 
     | 
    #include <signal.h>  | 
    
    
    52  | 
     | 
     | 
    #include <stdarg.h>  | 
    
    
    53  | 
     | 
     | 
    #include <stddef.h>  | 
    
    
    54  | 
     | 
     | 
    #include <stdint.h>  | 
    
    
    55  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    56  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    57  | 
     | 
     | 
    #include <string.h>  | 
    
    
    58  | 
     | 
     | 
    #include <time.h>  | 
    
    
    59  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    60  | 
     | 
     | 
     | 
    
    
    61  | 
     | 
     | 
    #include "route6d.h"  | 
    
    
    62  | 
     | 
     | 
    #include "log.h"  | 
    
    
    63  | 
     | 
     | 
     | 
    
    
    64  | 
     | 
     | 
    #define	MAXFILTER	40  | 
    
    
    65  | 
     | 
     | 
     | 
    
    
    66  | 
     | 
     | 
    #ifdef	DEBUG  | 
    
    
    67  | 
     | 
     | 
    #define	INIT_INTERVAL6	6  | 
    
    
    68  | 
     | 
     | 
    #else  | 
    
    
    69  | 
     | 
     | 
    #define	INIT_INTERVAL6	10	/* Wait to submit a initial riprequest */  | 
    
    
    70  | 
     | 
     | 
    #endif  | 
    
    
    71  | 
     | 
     | 
     | 
    
    
    72  | 
     | 
     | 
    /* alignment constraint for routing socket */  | 
    
    
    73  | 
     | 
     | 
    #define ROUNDUP(a) \  | 
    
    
    74  | 
     | 
     | 
    	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))  | 
    
    
    75  | 
     | 
     | 
    #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))  | 
    
    
    76  | 
     | 
     | 
     | 
    
    
    77  | 
     | 
     | 
    /*  | 
    
    
    78  | 
     | 
     | 
     * Following two macros are highly depending on KAME Release  | 
    
    
    79  | 
     | 
     | 
     */  | 
    
    
    80  | 
     | 
     | 
    #define	IN6_LINKLOCAL_IFINDEX(addr) \  | 
    
    
    81  | 
     | 
     | 
    	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])  | 
    
    
    82  | 
     | 
     | 
     | 
    
    
    83  | 
     | 
     | 
    #define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \  | 
    
    
    84  | 
     | 
     | 
    	do { \ | 
    
    
    85  | 
     | 
     | 
    		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \  | 
    
    
    86  | 
     | 
     | 
    		(addr).s6_addr[3] = (index) & 0xff; \  | 
    
    
    87  | 
     | 
     | 
    	} while (0)  | 
    
    
    88  | 
     | 
     | 
     | 
    
    
    89  | 
     | 
     | 
    struct	ifc {			/* Configuration of an interface */ | 
    
    
    90  | 
     | 
     | 
    	char	*ifc_name;			/* if name */  | 
    
    
    91  | 
     | 
     | 
    	struct	ifc *ifc_next;  | 
    
    
    92  | 
     | 
     | 
    	int	ifc_index;			/* if index */  | 
    
    
    93  | 
     | 
     | 
    	int	ifc_mtu;			/* if mtu */  | 
    
    
    94  | 
     | 
     | 
    	int	ifc_metric;			/* if metric */  | 
    
    
    95  | 
     | 
     | 
    	u_int	ifc_flags;			/* flags */  | 
    
    
    96  | 
     | 
     | 
    	short	ifc_cflags;			/* IFC_XXX */  | 
    
    
    97  | 
     | 
     | 
    	struct	in6_addr ifc_mylladdr;		/* my link-local address */  | 
    
    
    98  | 
     | 
     | 
    	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */  | 
    
    
    99  | 
     | 
     | 
    	struct	iff *ifc_filter;		/* filter structure */  | 
    
    
    100  | 
     | 
     | 
    	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */  | 
    
    
    101  | 
     | 
     | 
    	int	ifc_joined;			/* joined to ff02::9 */  | 
    
    
    102  | 
     | 
     | 
    };  | 
    
    
    103  | 
     | 
     | 
     | 
    
    
    104  | 
     | 
     | 
    struct	ifac {			/* Address associated to an interface */ | 
    
    
    105  | 
     | 
     | 
    	struct	ifc *ifa_conf;		/* back pointer */  | 
    
    
    106  | 
     | 
     | 
    	struct	ifac *ifa_next;  | 
    
    
    107  | 
     | 
     | 
    	struct	in6_addr ifa_addr;	/* address */  | 
    
    
    108  | 
     | 
     | 
    	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */  | 
    
    
    109  | 
     | 
     | 
    	int	ifa_plen;		/* prefix length */  | 
    
    
    110  | 
     | 
     | 
    };  | 
    
    
    111  | 
     | 
     | 
     | 
    
    
    112  | 
     | 
     | 
    struct	iff { | 
    
    
    113  | 
     | 
     | 
    	int	iff_type;  | 
    
    
    114  | 
     | 
     | 
    	struct	in6_addr iff_addr;  | 
    
    
    115  | 
     | 
     | 
    	int	iff_plen;  | 
    
    
    116  | 
     | 
     | 
    	struct	iff *iff_next;  | 
    
    
    117  | 
     | 
     | 
    };  | 
    
    
    118  | 
     | 
     | 
     | 
    
    
    119  | 
     | 
     | 
    struct	ifc *ifc;  | 
    
    
    120  | 
     | 
     | 
    int	nifc;		/* number of valid ifc's */  | 
    
    
    121  | 
     | 
     | 
    struct	ifc **index2ifc;  | 
    
    
    122  | 
     | 
     | 
    int	nindex2ifc;  | 
    
    
    123  | 
     | 
     | 
    struct	ifc *loopifcp = NULL;	/* pointing to loopback */  | 
    
    
    124  | 
     | 
     | 
    struct	pollfd pfd[2];  | 
    
    
    125  | 
     | 
     | 
    int	rtsock;		/* the routing socket */  | 
    
    
    126  | 
     | 
     | 
    int	ripsock;	/* socket to send/receive RIP datagram */  | 
    
    
    127  | 
     | 
     | 
     | 
    
    
    128  | 
     | 
     | 
    struct	rip6 *ripbuf;	/* packet buffer for sending */  | 
    
    
    129  | 
     | 
     | 
     | 
    
    
    130  | 
     | 
     | 
    /*  | 
    
    
    131  | 
     | 
     | 
     * Maintain the routes in a linked list.  When the number of the routes  | 
    
    
    132  | 
     | 
     | 
     * grows, somebody would like to introduce a hash based or a radix tree  | 
    
    
    133  | 
     | 
     | 
     * based structure.  I believe the number of routes handled by RIP is  | 
    
    
    134  | 
     | 
     | 
     * limited and I don't have to manage a complex data structure, however.  | 
    
    
    135  | 
     | 
     | 
     *  | 
    
    
    136  | 
     | 
     | 
     * One of the major drawbacks of the linear linked list is the difficulty  | 
    
    
    137  | 
     | 
     | 
     * of representing the relationship between a couple of routes.  This may  | 
    
    
    138  | 
     | 
     | 
     * be a significant problem when we have to support route aggregation with  | 
    
    
    139  | 
     | 
     | 
     * suppressing the specifics covered by the aggregate.  | 
    
    
    140  | 
     | 
     | 
     */  | 
    
    
    141  | 
     | 
     | 
     | 
    
    
    142  | 
     | 
     | 
    struct	riprt { | 
    
    
    143  | 
     | 
     | 
    	struct	riprt *rrt_next;	/* next destination */  | 
    
    
    144  | 
     | 
     | 
    	struct	netinfo6 rrt_info;	/* network info */  | 
    
    
    145  | 
     | 
     | 
    	struct	in6_addr rrt_gw;	/* gateway */  | 
    
    
    146  | 
     | 
     | 
    	u_long	rrt_flags;		/* kernel routing table flags */  | 
    
    
    147  | 
     | 
     | 
    	u_long	rrt_rflags;		/* route6d routing table flags */  | 
    
    
    148  | 
     | 
     | 
    	time_t	rrt_t;			/* when the route validated */  | 
    
    
    149  | 
     | 
     | 
    	int	rrt_index;		/* ifindex from which this route got */  | 
    
    
    150  | 
     | 
     | 
    };  | 
    
    
    151  | 
     | 
     | 
     | 
    
    
    152  | 
     | 
     | 
    struct	riprt *riprt = 0;  | 
    
    
    153  | 
     | 
     | 
     | 
    
    
    154  | 
     | 
     | 
    int	dflag = 0;	/* debug flag */  | 
    
    
    155  | 
     | 
     | 
    int	qflag = 0;	/* quiet flag */  | 
    
    
    156  | 
     | 
     | 
    int	nflag = 0;	/* don't update kernel routing table */  | 
    
    
    157  | 
     | 
     | 
    int	aflag = 0;	/* age out even the statically defined routes */  | 
    
    
    158  | 
     | 
     | 
    int	hflag = 0;	/* don't split horizon */  | 
    
    
    159  | 
     | 
     | 
    int	lflag = 0;	/* exchange site local routes */  | 
    
    
    160  | 
     | 
     | 
    int	sflag = 0;	/* announce static routes w/ split horizon */  | 
    
    
    161  | 
     | 
     | 
    int	Sflag = 0;	/* announce static routes to every interface */  | 
    
    
    162  | 
     | 
     | 
    int	uflag = 0;	/* always log route updates (additions/deletions) */  | 
    
    
    163  | 
     | 
     | 
    unsigned long routetag = 0;	/* route tag attached on originating case */  | 
    
    
    164  | 
     | 
     | 
     | 
    
    
    165  | 
     | 
     | 
    char	*filter[MAXFILTER];  | 
    
    
    166  | 
     | 
     | 
    int	filtertype[MAXFILTER];  | 
    
    
    167  | 
     | 
     | 
    int	nfilter = 0;  | 
    
    
    168  | 
     | 
     | 
     | 
    
    
    169  | 
     | 
     | 
    pid_t	pid;  | 
    
    
    170  | 
     | 
     | 
     | 
    
    
    171  | 
     | 
     | 
    struct	sockaddr_storage ripsin;  | 
    
    
    172  | 
     | 
     | 
     | 
    
    
    173  | 
     | 
     | 
    time_t	nextalarm = 0;  | 
    
    
    174  | 
     | 
     | 
    time_t	sup_trig_update = 0;  | 
    
    
    175  | 
     | 
     | 
     | 
    
    
    176  | 
     | 
     | 
    static	int	seq = 0;  | 
    
    
    177  | 
     | 
     | 
     | 
    
    
    178  | 
     | 
     | 
    volatile sig_atomic_t seenalrm;  | 
    
    
    179  | 
     | 
     | 
    volatile sig_atomic_t seenquit;  | 
    
    
    180  | 
     | 
     | 
    volatile sig_atomic_t seenusr1;  | 
    
    
    181  | 
     | 
     | 
     | 
    
    
    182  | 
     | 
     | 
    #define	RRTF_AGGREGATE		0x08000000  | 
    
    
    183  | 
     | 
     | 
    #define	RRTF_NOADVERTISE	0x10000000  | 
    
    
    184  | 
     | 
     | 
    #define	RRTF_NH_NOT_LLADDR	0x20000000  | 
    
    
    185  | 
     | 
     | 
    #define RRTF_SENDANYWAY		0x40000000  | 
    
    
    186  | 
     | 
     | 
    #define	RRTF_CHANGED		0x80000000  | 
    
    
    187  | 
     | 
     | 
     | 
    
    
    188  | 
     | 
     | 
    void sighandler(int);  | 
    
    
    189  | 
     | 
     | 
    void ripalarm(void);  | 
    
    
    190  | 
     | 
     | 
    void riprecv(void);  | 
    
    
    191  | 
     | 
     | 
    void ripsend(struct ifc *, struct sockaddr_in6 *, int);  | 
    
    
    192  | 
     | 
     | 
    int out_filter(struct riprt *, struct ifc *);  | 
    
    
    193  | 
     | 
     | 
    void init(void);  | 
    
    
    194  | 
     | 
     | 
    void sockopt(struct ifc *);  | 
    
    
    195  | 
     | 
     | 
    void ifconfig(void);  | 
    
    
    196  | 
     | 
     | 
    void ifconfig1(const char *, const struct sockaddr *, struct ifc *, int);  | 
    
    
    197  | 
     | 
     | 
    void rtrecv(void);  | 
    
    
    198  | 
     | 
     | 
    int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *,  | 
    
    
    199  | 
     | 
     | 
        const struct sockaddr_in6 *);  | 
    
    
    200  | 
     | 
     | 
    int rt_deladdr(struct ifc *, const struct sockaddr_in6 *,  | 
    
    
    201  | 
     | 
     | 
        const struct sockaddr_in6 *);  | 
    
    
    202  | 
     | 
     | 
    void filterconfig(void);  | 
    
    
    203  | 
     | 
     | 
    int getifmtu(int);  | 
    
    
    204  | 
     | 
     | 
    const char *rttypes(struct rt_msghdr *);  | 
    
    
    205  | 
     | 
     | 
    const char *rtflags(struct rt_msghdr *);  | 
    
    
    206  | 
     | 
     | 
    const char *ifflags(int);  | 
    
    
    207  | 
     | 
     | 
    int ifrt(struct ifc *, int);  | 
    
    
    208  | 
     | 
     | 
    void ifrt_p2p(struct ifc *, int);  | 
    
    
    209  | 
     | 
     | 
    void applyplen(struct in6_addr *, int);  | 
    
    
    210  | 
     | 
     | 
    void ifrtdump(int);  | 
    
    
    211  | 
     | 
     | 
    void ifdump(int);  | 
    
    
    212  | 
     | 
     | 
    void ifdump0(const struct ifc *);  | 
    
    
    213  | 
     | 
     | 
    void rtdump(int);  | 
    
    
    214  | 
     | 
     | 
    void rt_entry(struct rt_msghdr *, int);  | 
    
    
    215  | 
     | 
     | 
    __dead void rtdexit(void);  | 
    
    
    216  | 
     | 
     | 
    void riprequest(struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *);  | 
    
    
    217  | 
     | 
     | 
    void ripflush(struct ifc *, struct sockaddr_in6 *);  | 
    
    
    218  | 
     | 
     | 
    void sendrequest(struct ifc *);  | 
    
    
    219  | 
     | 
     | 
    int sin6mask2len(const struct sockaddr_in6 *);  | 
    
    
    220  | 
     | 
     | 
    int mask2len(const struct in6_addr *, int);  | 
    
    
    221  | 
     | 
     | 
    int sendpacket(struct sockaddr_in6 *, int);  | 
    
    
    222  | 
     | 
     | 
    int addroute(struct riprt *, const struct in6_addr *, struct ifc *);  | 
    
    
    223  | 
     | 
     | 
    int delroute(struct netinfo6 *, struct in6_addr *);  | 
    
    
    224  | 
     | 
     | 
    struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *);  | 
    
    
    225  | 
     | 
     | 
    void krtread(int);  | 
    
    
    226  | 
     | 
     | 
    int tobeadv(struct riprt *, struct ifc *);  | 
    
    
    227  | 
     | 
     | 
    char *xstrdup(const char *);  | 
    
    
    228  | 
     | 
     | 
    const char *hms(void);  | 
    
    
    229  | 
     | 
     | 
    const char *inet6_n2p(const struct in6_addr *);  | 
    
    
    230  | 
     | 
     | 
    struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int);  | 
    
    
    231  | 
     | 
     | 
    struct in6_addr *plen2mask(int);  | 
    
    
    232  | 
     | 
     | 
    struct riprt *rtsearch(struct netinfo6 *, struct riprt **);  | 
    
    
    233  | 
     | 
     | 
    int ripinterval(int);  | 
    
    
    234  | 
     | 
     | 
    time_t ripsuptrig(void);  | 
    
    
    235  | 
     | 
     | 
    unsigned int if_maxindex(void);  | 
    
    
    236  | 
     | 
     | 
    struct ifc *ifc_find(char *);  | 
    
    
    237  | 
     | 
     | 
    struct iff *iff_find(struct ifc *, int);  | 
    
    
    238  | 
     | 
     | 
    void setindex2ifc(int, struct ifc *);  | 
    
    
    239  | 
     | 
     | 
     | 
    
    
    240  | 
     | 
     | 
    int  | 
    
    
    241  | 
     | 
     | 
    main(int argc, char *argv[])  | 
    
    
    242  | 
     | 
     | 
    { | 
    
    
    243  | 
     | 
     | 
    	int	ch;  | 
    
    
    244  | 
     | 
     | 
    	int	error = 0;  | 
    
    
    245  | 
     | 
     | 
    	struct	ifc *ifcp;  | 
    
    
    246  | 
     | 
     | 
    	sigset_t mask, omask;  | 
    
    
    247  | 
     | 
     | 
    	char *ep;  | 
    
    
    248  | 
     | 
     | 
     | 
    
    
    249  | 
     | 
     | 
    	log_init(1); /* log to stderr until daemonized */  | 
    
    
    250  | 
     | 
     | 
     | 
    
    
    251  | 
     | 
     | 
    	while ((ch = getopt(argc, argv, "A:N:O:T:L:t:adDhlnqsSu")) != -1) { | 
    
    
    252  | 
     | 
     | 
    		switch (ch) { | 
    
    
    253  | 
     | 
     | 
    		case 'A':  | 
    
    
    254  | 
     | 
     | 
    		case 'N':  | 
    
    
    255  | 
     | 
     | 
    		case 'O':  | 
    
    
    256  | 
     | 
     | 
    		case 'T':  | 
    
    
    257  | 
     | 
     | 
    		case 'L':  | 
    
    
    258  | 
     | 
     | 
    			if (nfilter >= MAXFILTER) { | 
    
    
    259  | 
     | 
     | 
    				fatalx("Exceeds MAXFILTER"); | 
    
    
    260  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    261  | 
     | 
     | 
    			}  | 
    
    
    262  | 
     | 
     | 
    			filtertype[nfilter] = ch;  | 
    
    
    263  | 
     | 
     | 
    			filter[nfilter++] = xstrdup(optarg);  | 
    
    
    264  | 
     | 
     | 
    			break;  | 
    
    
    265  | 
     | 
     | 
    		case 't':  | 
    
    
    266  | 
     | 
     | 
    			ep = NULL;  | 
    
    
    267  | 
     | 
     | 
    			routetag = strtoul(optarg, &ep, 0);  | 
    
    
    268  | 
     | 
     | 
    			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { | 
    
    
    269  | 
     | 
     | 
    				fatalx("invalid route tag"); | 
    
    
    270  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    271  | 
     | 
     | 
    			}  | 
    
    
    272  | 
     | 
     | 
    			break;  | 
    
    
    273  | 
     | 
     | 
    #define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0) | 
    
    
    274  | 
     | 
     | 
    		FLAG('a', aflag, 1); break; | 
    
    
    275  | 
     | 
     | 
    		FLAG('d', dflag, 1); break; | 
    
    
    276  | 
     | 
     | 
    		FLAG('D', dflag, 2); break; | 
    
    
    277  | 
     | 
     | 
    		FLAG('h', hflag, 1); break; | 
    
    
    278  | 
     | 
     | 
    		FLAG('l', lflag, 1); break; | 
    
    
    279  | 
     | 
     | 
    		FLAG('n', nflag, 1); break; | 
    
    
    280  | 
     | 
     | 
    		FLAG('q', qflag, 1); break; | 
    
    
    281  | 
     | 
     | 
    		FLAG('s', sflag, 1); break; | 
    
    
    282  | 
     | 
     | 
    		FLAG('S', Sflag, 1); break; | 
    
    
    283  | 
     | 
     | 
    		FLAG('u', uflag, 1); break; | 
    
    
    284  | 
     | 
     | 
    #undef	FLAG  | 
    
    
    285  | 
     | 
     | 
    		default:  | 
    
    
    286  | 
     | 
     | 
    			fatalx("Invalid option specified, terminating"); | 
    
    
    287  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    288  | 
     | 
     | 
    		}  | 
    
    
    289  | 
     | 
     | 
    	}  | 
    
    
    290  | 
     | 
     | 
    	argc -= optind;  | 
    
    
    291  | 
     | 
     | 
    	argv += optind;  | 
    
    
    292  | 
     | 
     | 
    	if (argc > 0) { | 
    
    
    293  | 
     | 
     | 
    		fatalx("bogus extra arguments"); | 
    
    
    294  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    295  | 
     | 
     | 
    	}  | 
    
    
    296  | 
     | 
     | 
     | 
    
    
    297  | 
     | 
     | 
    	if (geteuid()) { | 
    
    
    298  | 
     | 
     | 
    		nflag = 1;  | 
    
    
    299  | 
     | 
     | 
    		log_warn("No kernel update is allowed"); | 
    
    
    300  | 
     | 
     | 
    	}  | 
    
    
    301  | 
     | 
     | 
     | 
    
    
    302  | 
     | 
     | 
    	if (dflag == 0) { | 
    
    
    303  | 
     | 
     | 
    		if (daemon(0, 0) < 0) { | 
    
    
    304  | 
     | 
     | 
    			fatal("daemon"); | 
    
    
    305  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    306  | 
     | 
     | 
    		}  | 
    
    
    307  | 
     | 
     | 
    	}  | 
    
    
    308  | 
     | 
     | 
     | 
    
    
    309  | 
     | 
     | 
    	log_init(dflag);  | 
    
    
    310  | 
     | 
     | 
     | 
    
    
    311  | 
     | 
     | 
    	pid = getpid();  | 
    
    
    312  | 
     | 
     | 
     | 
    
    
    313  | 
     | 
     | 
    	if ((ripbuf = calloc(RIP6_MAXMTU, 1)) == NULL)  | 
    
    
    314  | 
     | 
     | 
    		fatal(NULL);  | 
    
    
    315  | 
     | 
     | 
    	ripbuf->rip6_cmd = RIP6_RESPONSE;  | 
    
    
    316  | 
     | 
     | 
    	ripbuf->rip6_vers = RIP6_VERSION;  | 
    
    
    317  | 
     | 
     | 
    	ripbuf->rip6_res1[0] = 0;  | 
    
    
    318  | 
     | 
     | 
    	ripbuf->rip6_res1[1] = 0;  | 
    
    
    319  | 
     | 
     | 
     | 
    
    
    320  | 
     | 
     | 
    	init();  | 
    
    
    321  | 
     | 
     | 
     | 
    
    
    322  | 
     | 
     | 
    	if (pledge("stdio inet route mcast flock rpath cpath wpath", NULL) == -1) | 
    
    
    323  | 
     | 
     | 
    		fatal("pledge"); | 
    
    
    324  | 
     | 
     | 
     | 
    
    
    325  | 
     | 
     | 
    	ifconfig();  | 
    
    
    326  | 
     | 
     | 
     | 
    
    
    327  | 
     | 
     | 
    	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { | 
    
    
    328  | 
     | 
     | 
    		if (ifcp->ifc_index < 0) { | 
    
    
    329  | 
     | 
     | 
    			log_warn(  | 
    
    
    330  | 
     | 
     | 
    "No ifindex found at %s (no link-local address?)",  | 
    
    
    331  | 
     | 
     | 
    				ifcp->ifc_name);  | 
    
    
    332  | 
     | 
     | 
    			error++;  | 
    
    
    333  | 
     | 
     | 
    		}  | 
    
    
    334  | 
     | 
     | 
    	}  | 
    
    
    335  | 
     | 
     | 
    	if (error)  | 
    
    
    336  | 
     | 
     | 
    		exit(1);  | 
    
    
    337  | 
     | 
     | 
    	if (loopifcp == NULL) { | 
    
    
    338  | 
     | 
     | 
    		fatalx("No loopback found"); | 
    
    
    339  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    340  | 
     | 
     | 
    	}  | 
    
    
    341  | 
     | 
     | 
    	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)  | 
    
    
    342  | 
     | 
     | 
    		ifrt(ifcp, 0);  | 
    
    
    343  | 
     | 
     | 
    	filterconfig();  | 
    
    
    344  | 
     | 
     | 
    	krtread(0);  | 
    
    
    345  | 
     | 
     | 
    	if (dflag)  | 
    
    
    346  | 
     | 
     | 
    		ifrtdump(0);  | 
    
    
    347  | 
     | 
     | 
     | 
    
    
    348  | 
     | 
     | 
    	if (signal(SIGALRM, sighandler) == SIG_ERR ||  | 
    
    
    349  | 
     | 
     | 
    	    signal(SIGQUIT, sighandler) == SIG_ERR ||  | 
    
    
    350  | 
     | 
     | 
    	    signal(SIGTERM, sighandler) == SIG_ERR ||  | 
    
    
    351  | 
     | 
     | 
    	    signal(SIGUSR1, sighandler) == SIG_ERR ||  | 
    
    
    352  | 
     | 
     | 
    	    signal(SIGHUP, sighandler) == SIG_ERR ||  | 
    
    
    353  | 
     | 
     | 
    	    signal(SIGINT, sighandler) == SIG_ERR) { | 
    
    
    354  | 
     | 
     | 
    		fatal("signal"); | 
    
    
    355  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    356  | 
     | 
     | 
    	}  | 
    
    
    357  | 
     | 
     | 
    	/*  | 
    
    
    358  | 
     | 
     | 
    	 * To avoid rip packet congestion (not on a cable but in this  | 
    
    
    359  | 
     | 
     | 
    	 * process), wait for a moment to send the first RIP6_RESPONSE  | 
    
    
    360  | 
     | 
     | 
    	 * packets.  | 
    
    
    361  | 
     | 
     | 
    	 */  | 
    
    
    362  | 
     | 
     | 
    	alarm(ripinterval(INIT_INTERVAL6));  | 
    
    
    363  | 
     | 
     | 
     | 
    
    
    364  | 
     | 
     | 
    	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { | 
    
    
    365  | 
     | 
     | 
    		if (iff_find(ifcp, 'N'))  | 
    
    
    366  | 
     | 
     | 
    			continue;  | 
    
    
    367  | 
     | 
     | 
    		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))  | 
    
    
    368  | 
     | 
     | 
    			sendrequest(ifcp);  | 
    
    
    369  | 
     | 
     | 
    	}  | 
    
    
    370  | 
     | 
     | 
     | 
    
    
    371  | 
     | 
     | 
    	log_info("**** Started ****"); | 
    
    
    372  | 
     | 
     | 
    	sigemptyset(&mask);  | 
    
    
    373  | 
     | 
     | 
    	sigaddset(&mask, SIGALRM);  | 
    
    
    374  | 
     | 
     | 
    	while (1) { | 
    
    
    375  | 
     | 
     | 
    		if (seenalrm) { | 
    
    
    376  | 
     | 
     | 
    			ripalarm();  | 
    
    
    377  | 
     | 
     | 
    			seenalrm = 0;  | 
    
    
    378  | 
     | 
     | 
    			continue;  | 
    
    
    379  | 
     | 
     | 
    		}  | 
    
    
    380  | 
     | 
     | 
    		if (seenquit) { | 
    
    
    381  | 
     | 
     | 
    			rtdexit();  | 
    
    
    382  | 
     | 
     | 
    			seenquit = 0;  | 
    
    
    383  | 
     | 
     | 
    			continue;  | 
    
    
    384  | 
     | 
     | 
    		}  | 
    
    
    385  | 
     | 
     | 
    		if (seenusr1) { | 
    
    
    386  | 
     | 
     | 
    			ifrtdump(SIGUSR1);  | 
    
    
    387  | 
     | 
     | 
    			seenusr1 = 0;  | 
    
    
    388  | 
     | 
     | 
    			continue;  | 
    
    
    389  | 
     | 
     | 
    		}  | 
    
    
    390  | 
     | 
     | 
     | 
    
    
    391  | 
     | 
     | 
    		switch (poll(pfd, 2, INFTIM))  | 
    
    
    392  | 
     | 
     | 
    		{ | 
    
    
    393  | 
     | 
     | 
    		case -1:  | 
    
    
    394  | 
     | 
     | 
    			if (errno != EINTR) { | 
    
    
    395  | 
     | 
     | 
    				fatal("poll"); | 
    
    
    396  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    397  | 
     | 
     | 
    			}  | 
    
    
    398  | 
     | 
     | 
    			continue;  | 
    
    
    399  | 
     | 
     | 
    		case 0:  | 
    
    
    400  | 
     | 
     | 
    			continue;  | 
    
    
    401  | 
     | 
     | 
    		default:  | 
    
    
    402  | 
     | 
     | 
    			if (pfd[0].revents & POLLIN) { | 
    
    
    403  | 
     | 
     | 
    				sigprocmask(SIG_BLOCK, &mask, &omask);  | 
    
    
    404  | 
     | 
     | 
    				riprecv();  | 
    
    
    405  | 
     | 
     | 
    				sigprocmask(SIG_SETMASK, &omask, NULL);  | 
    
    
    406  | 
     | 
     | 
    			}  | 
    
    
    407  | 
     | 
     | 
    			if (pfd[1].revents & POLLIN) { | 
    
    
    408  | 
     | 
     | 
    				sigprocmask(SIG_BLOCK, &mask, &omask);  | 
    
    
    409  | 
     | 
     | 
    				rtrecv();  | 
    
    
    410  | 
     | 
     | 
    				sigprocmask(SIG_SETMASK, &omask, NULL);  | 
    
    
    411  | 
     | 
     | 
    			}  | 
    
    
    412  | 
     | 
     | 
    		}  | 
    
    
    413  | 
     | 
     | 
    	}  | 
    
    
    414  | 
     | 
     | 
    }  | 
    
    
    415  | 
     | 
     | 
     | 
    
    
    416  | 
     | 
     | 
    void  | 
    
    
    417  | 
     | 
     | 
    sighandler(int signo)  | 
    
    
    418  | 
     | 
     | 
    { | 
    
    
    419  | 
     | 
     | 
     | 
    
    
    420  | 
     | 
     | 
    	switch (signo) { | 
    
    
    421  | 
     | 
     | 
    	case SIGALRM:  | 
    
    
    422  | 
     | 
     | 
    		seenalrm++;  | 
    
    
    423  | 
     | 
     | 
    		break;  | 
    
    
    424  | 
     | 
     | 
    	case SIGQUIT:  | 
    
    
    425  | 
     | 
     | 
    	case SIGTERM:  | 
    
    
    426  | 
     | 
     | 
    		seenquit++;  | 
    
    
    427  | 
     | 
     | 
    		break;  | 
    
    
    428  | 
     | 
     | 
    	case SIGUSR1:  | 
    
    
    429  | 
     | 
     | 
    	case SIGHUP:  | 
    
    
    430  | 
     | 
     | 
    	case SIGINT:  | 
    
    
    431  | 
     | 
     | 
    		seenusr1++;  | 
    
    
    432  | 
     | 
     | 
    		break;  | 
    
    
    433  | 
     | 
     | 
    	}  | 
    
    
    434  | 
     | 
     | 
    }  | 
    
    
    435  | 
     | 
     | 
     | 
    
    
    436  | 
     | 
     | 
    /*  | 
    
    
    437  | 
     | 
     | 
     * gracefully exits after resetting sockopts.  | 
    
    
    438  | 
     | 
     | 
     */  | 
    
    
    439  | 
     | 
     | 
    void  | 
    
    
    440  | 
     | 
     | 
    rtdexit(void)  | 
    
    
    441  | 
     | 
     | 
    { | 
    
    
    442  | 
     | 
     | 
    	struct	riprt *rrt;  | 
    
    
    443  | 
     | 
     | 
     | 
    
    
    444  | 
     | 
     | 
    	alarm(0);  | 
    
    
    445  | 
     | 
     | 
    	for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    446  | 
     | 
     | 
    		if (rrt->rrt_rflags & RRTF_AGGREGATE) { | 
    
    
    447  | 
     | 
     | 
    			delroute(&rrt->rrt_info, &rrt->rrt_gw);  | 
    
    
    448  | 
     | 
     | 
    		}  | 
    
    
    449  | 
     | 
     | 
    	}  | 
    
    
    450  | 
     | 
     | 
    	close(ripsock);  | 
    
    
    451  | 
     | 
     | 
    	close(rtsock);  | 
    
    
    452  | 
     | 
     | 
    	log_info("**** Terminated ****"); | 
    
    
    453  | 
     | 
     | 
    	exit(1);  | 
    
    
    454  | 
     | 
     | 
    }  | 
    
    
    455  | 
     | 
     | 
     | 
    
    
    456  | 
     | 
     | 
    /*  | 
    
    
    457  | 
     | 
     | 
     * Called periodically:  | 
    
    
    458  | 
     | 
     | 
     *	1. age out the learned route. remove it if necessary.  | 
    
    
    459  | 
     | 
     | 
     *	2. submit RIP6_RESPONSE packets.  | 
    
    
    460  | 
     | 
     | 
     * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have  | 
    
    
    461  | 
     | 
     | 
     * to invoke this function in every 1 or 5 or 10 seconds only to age the  | 
    
    
    462  | 
     | 
     | 
     * routes more precisely.  | 
    
    
    463  | 
     | 
     | 
     */  | 
    
    
    464  | 
     | 
     | 
    void  | 
    
    
    465  | 
     | 
     | 
    ripalarm(void)  | 
    
    
    466  | 
     | 
     | 
    { | 
    
    
    467  | 
     | 
     | 
    	struct	ifc *ifcp;  | 
    
    
    468  | 
     | 
     | 
    	struct	riprt *rrt, *rrt_prev, *rrt_next;  | 
    
    
    469  | 
     | 
     | 
    	time_t	t_lifetime, t_holddown;  | 
    
    
    470  | 
     | 
     | 
     | 
    
    
    471  | 
     | 
     | 
    	/* age the RIP routes */  | 
    
    
    472  | 
     | 
     | 
    	rrt_prev = 0;  | 
    
    
    473  | 
     | 
     | 
    	t_lifetime = time(NULL) - RIP_LIFETIME;  | 
    
    
    474  | 
     | 
     | 
    	t_holddown = t_lifetime - RIP_HOLDDOWN;  | 
    
    
    475  | 
     | 
     | 
    	for (rrt = riprt; rrt; rrt = rrt_next) { | 
    
    
    476  | 
     | 
     | 
    		rrt_next = rrt->rrt_next;  | 
    
    
    477  | 
     | 
     | 
     | 
    
    
    478  | 
     | 
     | 
    		if (rrt->rrt_t == 0) { | 
    
    
    479  | 
     | 
     | 
    			rrt_prev = rrt;  | 
    
    
    480  | 
     | 
     | 
    			continue;  | 
    
    
    481  | 
     | 
     | 
    		}  | 
    
    
    482  | 
     | 
     | 
    		if (rrt->rrt_t < t_holddown) { | 
    
    
    483  | 
     | 
     | 
    			if (rrt_prev) { | 
    
    
    484  | 
     | 
     | 
    				rrt_prev->rrt_next = rrt->rrt_next;  | 
    
    
    485  | 
     | 
     | 
    			} else { | 
    
    
    486  | 
     | 
     | 
    				riprt = rrt->rrt_next;  | 
    
    
    487  | 
     | 
     | 
    			}  | 
    
    
    488  | 
     | 
     | 
    			delroute(&rrt->rrt_info, &rrt->rrt_gw);  | 
    
    
    489  | 
     | 
     | 
    			free(rrt);  | 
    
    
    490  | 
     | 
     | 
    			continue;  | 
    
    
    491  | 
     | 
     | 
    		}  | 
    
    
    492  | 
     | 
     | 
    		if (rrt->rrt_t < t_lifetime)  | 
    
    
    493  | 
     | 
     | 
    			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    494  | 
     | 
     | 
    		rrt_prev = rrt;  | 
    
    
    495  | 
     | 
     | 
    	}  | 
    
    
    496  | 
     | 
     | 
    	/* Supply updates */  | 
    
    
    497  | 
     | 
     | 
    	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { | 
    
    
    498  | 
     | 
     | 
    		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))  | 
    
    
    499  | 
     | 
     | 
    			ripsend(ifcp, &ifcp->ifc_ripsin, 0);  | 
    
    
    500  | 
     | 
     | 
    	}  | 
    
    
    501  | 
     | 
     | 
    	alarm(ripinterval(SUPPLY_INTERVAL6));  | 
    
    
    502  | 
     | 
     | 
    }  | 
    
    
    503  | 
     | 
     | 
     | 
    
    
    504  | 
     | 
     | 
    void  | 
    
    
    505  | 
     | 
     | 
    init(void)  | 
    
    
    506  | 
     | 
     | 
    { | 
    
    
    507  | 
     | 
     | 
    	int	i, error;  | 
    
    
    508  | 
     | 
     | 
    	const int int0 = 0, int1 = 1, int255 = 255;  | 
    
    
    509  | 
     | 
     | 
    	struct	addrinfo hints, *res;  | 
    
    
    510  | 
     | 
     | 
    	char	port[NI_MAXSERV];  | 
    
    
    511  | 
     | 
     | 
     | 
    
    
    512  | 
     | 
     | 
    	ifc = (struct ifc *)NULL;  | 
    
    
    513  | 
     | 
     | 
    	nifc = 0;  | 
    
    
    514  | 
     | 
     | 
    	nindex2ifc = 0;	/*initial guess*/  | 
    
    
    515  | 
     | 
     | 
    	index2ifc = NULL;  | 
    
    
    516  | 
     | 
     | 
    	snprintf(port, sizeof(port), "%u", RIP6_PORT);  | 
    
    
    517  | 
     | 
     | 
     | 
    
    
    518  | 
     | 
     | 
    	memset(&hints, 0, sizeof(hints));  | 
    
    
    519  | 
     | 
     | 
    	hints.ai_family = PF_INET6;  | 
    
    
    520  | 
     | 
     | 
    	hints.ai_socktype = SOCK_DGRAM;  | 
    
    
    521  | 
     | 
     | 
    	hints.ai_flags = AI_PASSIVE;  | 
    
    
    522  | 
     | 
     | 
    	error = getaddrinfo(NULL, port, &hints, &res);  | 
    
    
    523  | 
     | 
     | 
    	if (error) { | 
    
    
    524  | 
     | 
     | 
    		fatalx(gai_strerror(error));  | 
    
    
    525  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    526  | 
     | 
     | 
    	}  | 
    
    
    527  | 
     | 
     | 
    	if (res->ai_next) { | 
    
    
    528  | 
     | 
     | 
    		fatalx(":: resolved to multiple address"); | 
    
    
    529  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    530  | 
     | 
     | 
    	}  | 
    
    
    531  | 
     | 
     | 
     | 
    
    
    532  | 
     | 
     | 
    	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);  | 
    
    
    533  | 
     | 
     | 
    	if (ripsock < 0) { | 
    
    
    534  | 
     | 
     | 
    		fatal("rip socket"); | 
    
    
    535  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    536  | 
     | 
     | 
    	}  | 
    
    
    537  | 
     | 
     | 
    	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,  | 
    
    
    538  | 
     | 
     | 
    	    &int1, sizeof(int1)) < 0) { | 
    
    
    539  | 
     | 
     | 
    		fatal("rip IPV6_V6ONLY"); | 
    
    
    540  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    541  | 
     | 
     | 
    	}  | 
    
    
    542  | 
     | 
     | 
    	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { | 
    
    
    543  | 
     | 
     | 
    		fatal("rip bind"); | 
    
    
    544  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    545  | 
     | 
     | 
    	}  | 
    
    
    546  | 
     | 
     | 
    	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,  | 
    
    
    547  | 
     | 
     | 
    	    &int255, sizeof(int255)) < 0) { | 
    
    
    548  | 
     | 
     | 
    		fatal("rip IPV6_MULTICAST_HOPS"); | 
    
    
    549  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    550  | 
     | 
     | 
    	}  | 
    
    
    551  | 
     | 
     | 
    	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,  | 
    
    
    552  | 
     | 
     | 
    	    &int0, sizeof(int0)) < 0) { | 
    
    
    553  | 
     | 
     | 
    		fatal("rip IPV6_MULTICAST_LOOP"); | 
    
    
    554  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    555  | 
     | 
     | 
    	}  | 
    
    
    556  | 
     | 
     | 
     | 
    
    
    557  | 
     | 
     | 
    	i = 1;  | 
    
    
    558  | 
     | 
     | 
    	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i,  | 
    
    
    559  | 
     | 
     | 
    	    sizeof(i)) < 0) { | 
    
    
    560  | 
     | 
     | 
    		fatal("rip IPV6_RECVPKTINFO"); | 
    
    
    561  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    562  | 
     | 
     | 
    	}  | 
    
    
    563  | 
     | 
     | 
     | 
    
    
    564  | 
     | 
     | 
    	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,  | 
    
    
    565  | 
     | 
     | 
    	    &int1, sizeof(int1)) < 0) { | 
    
    
    566  | 
     | 
     | 
    		fatal("rip IPV6_RECVHOPLIMIT"); | 
    
    
    567  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    568  | 
     | 
     | 
    	}  | 
    
    
    569  | 
     | 
     | 
     | 
    
    
    570  | 
     | 
     | 
    	memset(&hints, 0, sizeof(hints));  | 
    
    
    571  | 
     | 
     | 
    	hints.ai_family = PF_INET6;  | 
    
    
    572  | 
     | 
     | 
    	hints.ai_socktype = SOCK_DGRAM;  | 
    
    
    573  | 
     | 
     | 
    	error = getaddrinfo(RIP6_DEST, port, &hints, &res);  | 
    
    
    574  | 
     | 
     | 
    	if (error) { | 
    
    
    575  | 
     | 
     | 
    		fatalx(gai_strerror(error));  | 
    
    
    576  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    577  | 
     | 
     | 
    	}  | 
    
    
    578  | 
     | 
     | 
    	if (res->ai_next) { | 
    
    
    579  | 
     | 
     | 
    		fatalx(RIP6_DEST " resolved to multiple address");  | 
    
    
    580  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    581  | 
     | 
     | 
    	}  | 
    
    
    582  | 
     | 
     | 
    	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);  | 
    
    
    583  | 
     | 
     | 
     | 
    
    
    584  | 
     | 
     | 
    	pfd[0].fd = ripsock;  | 
    
    
    585  | 
     | 
     | 
    	pfd[0].events = POLLIN;  | 
    
    
    586  | 
     | 
     | 
     | 
    
    
    587  | 
     | 
     | 
    	if (nflag == 0) { | 
    
    
    588  | 
     | 
     | 
    		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { | 
    
    
    589  | 
     | 
     | 
    			fatal("route socket"); | 
    
    
    590  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    591  | 
     | 
     | 
    		}  | 
    
    
    592  | 
     | 
     | 
    		pfd[1].fd = rtsock;  | 
    
    
    593  | 
     | 
     | 
    		pfd[1].events = POLLIN;  | 
    
    
    594  | 
     | 
     | 
    	} else  | 
    
    
    595  | 
     | 
     | 
    		pfd[1].fd = -1;  | 
    
    
    596  | 
     | 
     | 
     | 
    
    
    597  | 
     | 
     | 
    }  | 
    
    
    598  | 
     | 
     | 
     | 
    
    
    599  | 
     | 
     | 
    #define	RIPSIZE(n) \  | 
    
    
    600  | 
     | 
     | 
    	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))  | 
    
    
    601  | 
     | 
     | 
     | 
    
    
    602  | 
     | 
     | 
    /*  | 
    
    
    603  | 
     | 
     | 
     * ripflush flushes the rip datagram stored in the rip buffer  | 
    
    
    604  | 
     | 
     | 
     */  | 
    
    
    605  | 
     | 
     | 
    static int nrt;  | 
    
    
    606  | 
     | 
     | 
    static struct netinfo6 *np;  | 
    
    
    607  | 
     | 
     | 
     | 
    
    
    608  | 
     | 
     | 
    void  | 
    
    
    609  | 
     | 
     | 
    ripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6)  | 
    
    
    610  | 
     | 
     | 
    { | 
    
    
    611  | 
     | 
     | 
    	int i;  | 
    
    
    612  | 
     | 
     | 
    	int error;  | 
    
    
    613  | 
     | 
     | 
     | 
    
    
    614  | 
     | 
     | 
    	if (ifcp)  | 
    
    
    615  | 
     | 
     | 
    		log_debug("Send(%s): info(%d) to %s.%d", | 
    
    
    616  | 
     | 
     | 
    			ifcp->ifc_name, nrt,  | 
    
    
    617  | 
     | 
     | 
    			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));  | 
    
    
    618  | 
     | 
     | 
    	else  | 
    
    
    619  | 
     | 
     | 
    		log_debug("Send: info(%d) to %s.%d", | 
    
    
    620  | 
     | 
     | 
    			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));  | 
    
    
    621  | 
     | 
     | 
    	if (dflag >= 2) { | 
    
    
    622  | 
     | 
     | 
    		np = ripbuf->rip6_nets;  | 
    
    
    623  | 
     | 
     | 
    		for (i = 0; i < nrt; i++, np++) { | 
    
    
    624  | 
     | 
     | 
    			if (np->rip6_metric == NEXTHOP_METRIC) { | 
    
    
    625  | 
     | 
     | 
    				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))  | 
    
    
    626  | 
     | 
     | 
    					log_enqueue("    NextHop reset"); | 
    
    
    627  | 
     | 
     | 
    				else { | 
    
    
    628  | 
     | 
     | 
    					log_enqueue("    NextHop %s", | 
    
    
    629  | 
     | 
     | 
    						inet6_n2p(&np->rip6_dest));  | 
    
    
    630  | 
     | 
     | 
    				}  | 
    
    
    631  | 
     | 
     | 
    			} else { | 
    
    
    632  | 
     | 
     | 
    				log_enqueue("    %s/%d[%d]", | 
    
    
    633  | 
     | 
     | 
    					inet6_n2p(&np->rip6_dest),  | 
    
    
    634  | 
     | 
     | 
    					np->rip6_plen, np->rip6_metric);  | 
    
    
    635  | 
     | 
     | 
    			}  | 
    
    
    636  | 
     | 
     | 
    			if (np->rip6_tag) { | 
    
    
    637  | 
     | 
     | 
    				log_enqueue("  tag=0x%04x", | 
    
    
    638  | 
     | 
     | 
    					ntohs(np->rip6_tag) & 0xffff);  | 
    
    
    639  | 
     | 
     | 
    			}  | 
    
    
    640  | 
     | 
     | 
    			log_debug(""); | 
    
    
    641  | 
     | 
     | 
    		}  | 
    
    
    642  | 
     | 
     | 
    	}  | 
    
    
    643  | 
     | 
     | 
    	error = sendpacket(sin6, RIPSIZE(nrt));  | 
    
    
    644  | 
     | 
     | 
    	if (error == EAFNOSUPPORT) { | 
    
    
    645  | 
     | 
     | 
    		/* Protocol not supported */  | 
    
    
    646  | 
     | 
     | 
    		log_debug("Could not send info to %s (%s): " | 
    
    
    647  | 
     | 
     | 
    			"set IFF_UP to 0",  | 
    
    
    648  | 
     | 
     | 
    			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));  | 
    
    
    649  | 
     | 
     | 
    		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */  | 
    
    
    650  | 
     | 
     | 
    	}  | 
    
    
    651  | 
     | 
     | 
    	nrt = 0; np = ripbuf->rip6_nets;  | 
    
    
    652  | 
     | 
     | 
    }  | 
    
    
    653  | 
     | 
     | 
     | 
    
    
    654  | 
     | 
     | 
    /*  | 
    
    
    655  | 
     | 
     | 
     * Generate RIP6_RESPONSE packets and send them.  | 
    
    
    656  | 
     | 
     | 
     */  | 
    
    
    657  | 
     | 
     | 
    void  | 
    
    
    658  | 
     | 
     | 
    ripsend(struct ifc *ifcp, struct sockaddr_in6 *sin6, int flag)  | 
    
    
    659  | 
     | 
     | 
    { | 
    
    
    660  | 
     | 
     | 
    	struct	riprt *rrt;  | 
    
    
    661  | 
     | 
     | 
    	struct	in6_addr *nh;	/* next hop */  | 
    
    
    662  | 
     | 
     | 
    	int	maxrte;  | 
    
    
    663  | 
     | 
     | 
     | 
    
    
    664  | 
     | 
     | 
    	if (qflag)  | 
    
    
    665  | 
     | 
     | 
    		return;  | 
    
    
    666  | 
     | 
     | 
     | 
    
    
    667  | 
     | 
     | 
    	if (ifcp == NULL) { | 
    
    
    668  | 
     | 
     | 
    		/*  | 
    
    
    669  | 
     | 
     | 
    		 * Request from non-link local address is not  | 
    
    
    670  | 
     | 
     | 
    		 * a regular route6d update.  | 
    
    
    671  | 
     | 
     | 
    		 */  | 
    
    
    672  | 
     | 
     | 
    		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -  | 
    
    
    673  | 
     | 
     | 
    				sizeof(struct udphdr) -  | 
    
    
    674  | 
     | 
     | 
    				sizeof(struct rip6) + sizeof(struct netinfo6)) /  | 
    
    
    675  | 
     | 
     | 
    				sizeof(struct netinfo6);  | 
    
    
    676  | 
     | 
     | 
    		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;  | 
    
    
    677  | 
     | 
     | 
    		for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    678  | 
     | 
     | 
    			if (rrt->rrt_rflags & RRTF_NOADVERTISE)  | 
    
    
    679  | 
     | 
     | 
    				continue;  | 
    
    
    680  | 
     | 
     | 
    			/* Put the route to the buffer */  | 
    
    
    681  | 
     | 
     | 
    			*np = rrt->rrt_info;  | 
    
    
    682  | 
     | 
     | 
    			np++; nrt++;  | 
    
    
    683  | 
     | 
     | 
    			if (nrt == maxrte) { | 
    
    
    684  | 
     | 
     | 
    				ripflush(NULL, sin6);  | 
    
    
    685  | 
     | 
     | 
    				nh = NULL;  | 
    
    
    686  | 
     | 
     | 
    			}  | 
    
    
    687  | 
     | 
     | 
    		}  | 
    
    
    688  | 
     | 
     | 
    		if (nrt)	/* Send last packet */  | 
    
    
    689  | 
     | 
     | 
    			ripflush(NULL, sin6);  | 
    
    
    690  | 
     | 
     | 
    		return;  | 
    
    
    691  | 
     | 
     | 
    	}  | 
    
    
    692  | 
     | 
     | 
     | 
    
    
    693  | 
     | 
     | 
    	if ((flag & RRTF_SENDANYWAY) == 0 &&  | 
    
    
    694  | 
     | 
     | 
    	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))  | 
    
    
    695  | 
     | 
     | 
    		return;  | 
    
    
    696  | 
     | 
     | 
     | 
    
    
    697  | 
     | 
     | 
    	/* -N: no use */  | 
    
    
    698  | 
     | 
     | 
    	if (iff_find(ifcp, 'N') != NULL)  | 
    
    
    699  | 
     | 
     | 
    		return;  | 
    
    
    700  | 
     | 
     | 
     | 
    
    
    701  | 
     | 
     | 
    	/* -T: generate default route only */  | 
    
    
    702  | 
     | 
     | 
    	if (iff_find(ifcp, 'T') != NULL) { | 
    
    
    703  | 
     | 
     | 
    		struct netinfo6 rrt_info;  | 
    
    
    704  | 
     | 
     | 
    		memset(&rrt_info, 0, sizeof(struct netinfo6));  | 
    
    
    705  | 
     | 
     | 
    		rrt_info.rip6_dest = in6addr_any;  | 
    
    
    706  | 
     | 
     | 
    		rrt_info.rip6_plen = 0;  | 
    
    
    707  | 
     | 
     | 
    		rrt_info.rip6_metric = 1;  | 
    
    
    708  | 
     | 
     | 
    		rrt_info.rip6_metric += ifcp->ifc_metric;  | 
    
    
    709  | 
     | 
     | 
    		rrt_info.rip6_tag = htons(routetag & 0xffff);  | 
    
    
    710  | 
     | 
     | 
    		np = ripbuf->rip6_nets;  | 
    
    
    711  | 
     | 
     | 
    		*np = rrt_info;  | 
    
    
    712  | 
     | 
     | 
    		nrt = 1;  | 
    
    
    713  | 
     | 
     | 
    		ripflush(ifcp, sin6);  | 
    
    
    714  | 
     | 
     | 
    		return;  | 
    
    
    715  | 
     | 
     | 
    	}  | 
    
    
    716  | 
     | 
     | 
     | 
    
    
    717  | 
     | 
     | 
    	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -  | 
    
    
    718  | 
     | 
     | 
    			sizeof(struct udphdr) -  | 
    
    
    719  | 
     | 
     | 
    			sizeof(struct rip6) + sizeof(struct netinfo6)) /  | 
    
    
    720  | 
     | 
     | 
    			sizeof(struct netinfo6);  | 
    
    
    721  | 
     | 
     | 
     | 
    
    
    722  | 
     | 
     | 
    	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;  | 
    
    
    723  | 
     | 
     | 
    	for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    724  | 
     | 
     | 
    		if (rrt->rrt_rflags & RRTF_NOADVERTISE)  | 
    
    
    725  | 
     | 
     | 
    			continue;  | 
    
    
    726  | 
     | 
     | 
     | 
    
    
    727  | 
     | 
     | 
    		/* Need to check filter here */  | 
    
    
    728  | 
     | 
     | 
    		if (out_filter(rrt, ifcp) == 0)  | 
    
    
    729  | 
     | 
     | 
    			continue;  | 
    
    
    730  | 
     | 
     | 
     | 
    
    
    731  | 
     | 
     | 
    		/* Check split horizon and other conditions */  | 
    
    
    732  | 
     | 
     | 
    		if (tobeadv(rrt, ifcp) == 0)  | 
    
    
    733  | 
     | 
     | 
    			continue;  | 
    
    
    734  | 
     | 
     | 
     | 
    
    
    735  | 
     | 
     | 
    		/* Only considers the routes with flag if specified */  | 
    
    
    736  | 
     | 
     | 
    		if ((flag & RRTF_CHANGED) &&  | 
    
    
    737  | 
     | 
     | 
    		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)  | 
    
    
    738  | 
     | 
     | 
    			continue;  | 
    
    
    739  | 
     | 
     | 
     | 
    
    
    740  | 
     | 
     | 
    		/* Check nexthop */  | 
    
    
    741  | 
     | 
     | 
    		if (rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    742  | 
     | 
     | 
    		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&  | 
    
    
    743  | 
     | 
     | 
    		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { | 
    
    
    744  | 
     | 
     | 
    			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { | 
    
    
    745  | 
     | 
     | 
    				if (nrt == maxrte - 2)  | 
    
    
    746  | 
     | 
     | 
    					ripflush(ifcp, sin6);  | 
    
    
    747  | 
     | 
     | 
    				np->rip6_dest = rrt->rrt_gw;  | 
    
    
    748  | 
     | 
     | 
    				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))  | 
    
    
    749  | 
     | 
     | 
    					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);  | 
    
    
    750  | 
     | 
     | 
    				np->rip6_plen = 0;  | 
    
    
    751  | 
     | 
     | 
    				np->rip6_tag = 0;  | 
    
    
    752  | 
     | 
     | 
    				np->rip6_metric = NEXTHOP_METRIC;  | 
    
    
    753  | 
     | 
     | 
    				nh = &rrt->rrt_gw;  | 
    
    
    754  | 
     | 
     | 
    				np++; nrt++;  | 
    
    
    755  | 
     | 
     | 
    			}  | 
    
    
    756  | 
     | 
     | 
    		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||  | 
    
    
    757  | 
     | 
     | 
    			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||  | 
    
    
    758  | 
     | 
     | 
    				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { | 
    
    
    759  | 
     | 
     | 
    			/* Reset nexthop */  | 
    
    
    760  | 
     | 
     | 
    			if (nrt == maxrte - 2)  | 
    
    
    761  | 
     | 
     | 
    				ripflush(ifcp, sin6);  | 
    
    
    762  | 
     | 
     | 
    			memset(np, 0, sizeof(struct netinfo6));  | 
    
    
    763  | 
     | 
     | 
    			np->rip6_metric = NEXTHOP_METRIC;  | 
    
    
    764  | 
     | 
     | 
    			nh = NULL;  | 
    
    
    765  | 
     | 
     | 
    			np++; nrt++;  | 
    
    
    766  | 
     | 
     | 
    		}  | 
    
    
    767  | 
     | 
     | 
     | 
    
    
    768  | 
     | 
     | 
    		/* Put the route to the buffer */  | 
    
    
    769  | 
     | 
     | 
    		*np = rrt->rrt_info;  | 
    
    
    770  | 
     | 
     | 
    		np++; nrt++;  | 
    
    
    771  | 
     | 
     | 
    		if (nrt == maxrte) { | 
    
    
    772  | 
     | 
     | 
    			ripflush(ifcp, sin6);  | 
    
    
    773  | 
     | 
     | 
    			nh = NULL;  | 
    
    
    774  | 
     | 
     | 
    		}  | 
    
    
    775  | 
     | 
     | 
    	}  | 
    
    
    776  | 
     | 
     | 
    	if (nrt)	/* Send last packet */  | 
    
    
    777  | 
     | 
     | 
    		ripflush(ifcp, sin6);  | 
    
    
    778  | 
     | 
     | 
    }  | 
    
    
    779  | 
     | 
     | 
     | 
    
    
    780  | 
     | 
     | 
    /*  | 
    
    
    781  | 
     | 
     | 
     * outbound filter logic, per-route/interface.  | 
    
    
    782  | 
     | 
     | 
     */  | 
    
    
    783  | 
     | 
     | 
    int  | 
    
    
    784  | 
     | 
     | 
    out_filter(struct riprt *rrt, struct ifc *ifcp)  | 
    
    
    785  | 
     | 
     | 
    { | 
    
    
    786  | 
     | 
     | 
    	struct iff *iffp;  | 
    
    
    787  | 
     | 
     | 
    	struct in6_addr ia;  | 
    
    
    788  | 
     | 
     | 
    	int ok;  | 
    
    
    789  | 
     | 
     | 
     | 
    
    
    790  | 
     | 
     | 
    	/*  | 
    
    
    791  | 
     | 
     | 
    	 * -A: filter out less specific routes, if we have aggregated  | 
    
    
    792  | 
     | 
     | 
    	 * route configured.  | 
    
    
    793  | 
     | 
     | 
    	 */  | 
    
    
    794  | 
     | 
     | 
    	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    795  | 
     | 
     | 
    		if (iffp->iff_type != 'A')  | 
    
    
    796  | 
     | 
     | 
    			continue;  | 
    
    
    797  | 
     | 
     | 
    		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)  | 
    
    
    798  | 
     | 
     | 
    			continue;  | 
    
    
    799  | 
     | 
     | 
    		ia = rrt->rrt_info.rip6_dest;  | 
    
    
    800  | 
     | 
     | 
    		applyplen(&ia, iffp->iff_plen);  | 
    
    
    801  | 
     | 
     | 
    		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))  | 
    
    
    802  | 
     | 
     | 
    			return 0;  | 
    
    
    803  | 
     | 
     | 
    	}  | 
    
    
    804  | 
     | 
     | 
     | 
    
    
    805  | 
     | 
     | 
    	/*  | 
    
    
    806  | 
     | 
     | 
    	 * if it is an aggregated route, advertise it only to the  | 
    
    
    807  | 
     | 
     | 
    	 * interfaces specified on -A.  | 
    
    
    808  | 
     | 
     | 
    	 */  | 
    
    
    809  | 
     | 
     | 
    	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { | 
    
    
    810  | 
     | 
     | 
    		ok = 0;  | 
    
    
    811  | 
     | 
     | 
    		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    812  | 
     | 
     | 
    			if (iffp->iff_type != 'A')  | 
    
    
    813  | 
     | 
     | 
    				continue;  | 
    
    
    814  | 
     | 
     | 
    			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&  | 
    
    
    815  | 
     | 
     | 
    			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,  | 
    
    
    816  | 
     | 
     | 
    			    &iffp->iff_addr)) { | 
    
    
    817  | 
     | 
     | 
    				ok = 1;  | 
    
    
    818  | 
     | 
     | 
    				break;  | 
    
    
    819  | 
     | 
     | 
    			}  | 
    
    
    820  | 
     | 
     | 
    		}  | 
    
    
    821  | 
     | 
     | 
    		if (!ok)  | 
    
    
    822  | 
     | 
     | 
    			return 0;  | 
    
    
    823  | 
     | 
     | 
    	}  | 
    
    
    824  | 
     | 
     | 
     | 
    
    
    825  | 
     | 
     | 
    	/*  | 
    
    
    826  | 
     | 
     | 
    	 * -O: advertise only if prefix matches the configured prefix.  | 
    
    
    827  | 
     | 
     | 
    	 */  | 
    
    
    828  | 
     | 
     | 
    	if (iff_find(ifcp, 'O')) { | 
    
    
    829  | 
     | 
     | 
    		ok = 0;  | 
    
    
    830  | 
     | 
     | 
    		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    831  | 
     | 
     | 
    			if (iffp->iff_type != 'O')  | 
    
    
    832  | 
     | 
     | 
    				continue;  | 
    
    
    833  | 
     | 
     | 
    			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)  | 
    
    
    834  | 
     | 
     | 
    				continue;  | 
    
    
    835  | 
     | 
     | 
    			ia = rrt->rrt_info.rip6_dest;  | 
    
    
    836  | 
     | 
     | 
    			applyplen(&ia, iffp->iff_plen);  | 
    
    
    837  | 
     | 
     | 
    			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { | 
    
    
    838  | 
     | 
     | 
    				ok = 1;  | 
    
    
    839  | 
     | 
     | 
    				break;  | 
    
    
    840  | 
     | 
     | 
    			}  | 
    
    
    841  | 
     | 
     | 
    		}  | 
    
    
    842  | 
     | 
     | 
    		if (!ok)  | 
    
    
    843  | 
     | 
     | 
    			return 0;  | 
    
    
    844  | 
     | 
     | 
    	}  | 
    
    
    845  | 
     | 
     | 
     | 
    
    
    846  | 
     | 
     | 
    	/* the prefix should be advertised */  | 
    
    
    847  | 
     | 
     | 
    	return 1;  | 
    
    
    848  | 
     | 
     | 
    }  | 
    
    
    849  | 
     | 
     | 
     | 
    
    
    850  | 
     | 
     | 
    /*  | 
    
    
    851  | 
     | 
     | 
     * Determine if the route is to be advertised on the specified interface.  | 
    
    
    852  | 
     | 
     | 
     * It checks options specified in the arguments and the split horizon rule.  | 
    
    
    853  | 
     | 
     | 
     */  | 
    
    
    854  | 
     | 
     | 
    int  | 
    
    
    855  | 
     | 
     | 
    tobeadv(struct riprt *rrt, struct ifc *ifcp)  | 
    
    
    856  | 
     | 
     | 
    { | 
    
    
    857  | 
     | 
     | 
     | 
    
    
    858  | 
     | 
     | 
    	/* Special care for static routes */  | 
    
    
    859  | 
     | 
     | 
    	if (rrt->rrt_flags & RTF_STATIC) { | 
    
    
    860  | 
     | 
     | 
    		/* XXX don't advertise reject/blackhole routes */  | 
    
    
    861  | 
     | 
     | 
    		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))  | 
    
    
    862  | 
     | 
     | 
    			return 0;  | 
    
    
    863  | 
     | 
     | 
     | 
    
    
    864  | 
     | 
     | 
    		if (Sflag)	/* Yes, advertise it anyway */  | 
    
    
    865  | 
     | 
     | 
    			return 1;  | 
    
    
    866  | 
     | 
     | 
    		if (sflag && rrt->rrt_index != ifcp->ifc_index)  | 
    
    
    867  | 
     | 
     | 
    			return 1;  | 
    
    
    868  | 
     | 
     | 
    		return 0;  | 
    
    
    869  | 
     | 
     | 
    	}  | 
    
    
    870  | 
     | 
     | 
    	/* Regular split horizon */  | 
    
    
    871  | 
     | 
     | 
    	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)  | 
    
    
    872  | 
     | 
     | 
    		return 0;  | 
    
    
    873  | 
     | 
     | 
    	return 1;  | 
    
    
    874  | 
     | 
     | 
    }  | 
    
    
    875  | 
     | 
     | 
     | 
    
    
    876  | 
     | 
     | 
    /*  | 
    
    
    877  | 
     | 
     | 
     * Send a rip packet actually.  | 
    
    
    878  | 
     | 
     | 
     */  | 
    
    
    879  | 
     | 
     | 
    int  | 
    
    
    880  | 
     | 
     | 
    sendpacket(struct sockaddr_in6 *sin6, int len)  | 
    
    
    881  | 
     | 
     | 
    { | 
    
    
    882  | 
     | 
     | 
    	struct msghdr m;  | 
    
    
    883  | 
     | 
     | 
    	struct cmsghdr *cm;  | 
    
    
    884  | 
     | 
     | 
    	struct iovec iov[2];  | 
    
    
    885  | 
     | 
     | 
    	union { | 
    
    
    886  | 
     | 
     | 
    		struct cmsghdr hdr;  | 
    
    
    887  | 
     | 
     | 
    		u_char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];  | 
    
    
    888  | 
     | 
     | 
    	} cmsgbuf;  | 
    
    
    889  | 
     | 
     | 
    	struct in6_pktinfo *pi;  | 
    
    
    890  | 
     | 
     | 
    	int idx;  | 
    
    
    891  | 
     | 
     | 
    	struct sockaddr_in6 sincopy;  | 
    
    
    892  | 
     | 
     | 
     | 
    
    
    893  | 
     | 
     | 
    	/* do not overwrite the given sin */  | 
    
    
    894  | 
     | 
     | 
    	sincopy = *sin6;  | 
    
    
    895  | 
     | 
     | 
    	sin6 = &sincopy;  | 
    
    
    896  | 
     | 
     | 
     | 
    
    
    897  | 
     | 
     | 
    	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||  | 
    
    
    898  | 
     | 
     | 
    	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { | 
    
    
    899  | 
     | 
     | 
    		/* XXX: do not mix the interface index and link index */  | 
    
    
    900  | 
     | 
     | 
    		idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);  | 
    
    
    901  | 
     | 
     | 
    		SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);  | 
    
    
    902  | 
     | 
     | 
    		sin6->sin6_scope_id = idx;  | 
    
    
    903  | 
     | 
     | 
    	} else  | 
    
    
    904  | 
     | 
     | 
    		idx = 0;  | 
    
    
    905  | 
     | 
     | 
     | 
    
    
    906  | 
     | 
     | 
    	m.msg_name = (caddr_t)sin6;  | 
    
    
    907  | 
     | 
     | 
    	m.msg_namelen = sizeof(*sin6);  | 
    
    
    908  | 
     | 
     | 
    	iov[0].iov_base = (caddr_t)ripbuf;  | 
    
    
    909  | 
     | 
     | 
    	iov[0].iov_len = len;  | 
    
    
    910  | 
     | 
     | 
    	m.msg_iov = iov;  | 
    
    
    911  | 
     | 
     | 
    	m.msg_iovlen = 1;  | 
    
    
    912  | 
     | 
     | 
    	if (!idx) { | 
    
    
    913  | 
     | 
     | 
    		m.msg_control = NULL;  | 
    
    
    914  | 
     | 
     | 
    		m.msg_controllen = 0;  | 
    
    
    915  | 
     | 
     | 
    	} else { | 
    
    
    916  | 
     | 
     | 
    		memset(&cmsgbuf, 0, sizeof(cmsgbuf));  | 
    
    
    917  | 
     | 
     | 
    		m.msg_control = (caddr_t)&cmsgbuf.buf;  | 
    
    
    918  | 
     | 
     | 
    		m.msg_controllen = sizeof(cmsgbuf.buf);  | 
    
    
    919  | 
     | 
     | 
    		cm = CMSG_FIRSTHDR(&m);  | 
    
    
    920  | 
     | 
     | 
    		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));  | 
    
    
    921  | 
     | 
     | 
    		cm->cmsg_level = IPPROTO_IPV6;  | 
    
    
    922  | 
     | 
     | 
    		cm->cmsg_type = IPV6_PKTINFO;  | 
    
    
    923  | 
     | 
     | 
    		pi = (struct in6_pktinfo *)CMSG_DATA(cm);  | 
    
    
    924  | 
     | 
     | 
    		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/  | 
    
    
    925  | 
     | 
     | 
    		pi->ipi6_ifindex = idx;  | 
    
    
    926  | 
     | 
     | 
    	}  | 
    
    
    927  | 
     | 
     | 
     | 
    
    
    928  | 
     | 
     | 
    	if (sendmsg(ripsock, &m, 0) < 0) { | 
    
    
    929  | 
     | 
     | 
    		log_debug("sendmsg: %s", strerror(errno)); | 
    
    
    930  | 
     | 
     | 
    		return errno;  | 
    
    
    931  | 
     | 
     | 
    	}  | 
    
    
    932  | 
     | 
     | 
     | 
    
    
    933  | 
     | 
     | 
    	return 0;  | 
    
    
    934  | 
     | 
     | 
    }  | 
    
    
    935  | 
     | 
     | 
     | 
    
    
    936  | 
     | 
     | 
    /*  | 
    
    
    937  | 
     | 
     | 
     * Receive and process RIP packets.  Update the routes/kernel forwarding  | 
    
    
    938  | 
     | 
     | 
     * table if necessary.  | 
    
    
    939  | 
     | 
     | 
     */  | 
    
    
    940  | 
     | 
     | 
    void  | 
    
    
    941  | 
     | 
     | 
    riprecv(void)  | 
    
    
    942  | 
     | 
     | 
    { | 
    
    
    943  | 
     | 
     | 
    	struct	ifc *ifcp, *ic;  | 
    
    
    944  | 
     | 
     | 
    	struct	sockaddr_in6 fsock;  | 
    
    
    945  | 
     | 
     | 
    	struct	in6_addr nh;	/* next hop */  | 
    
    
    946  | 
     | 
     | 
    	struct	rip6 *rp;  | 
    
    
    947  | 
     | 
     | 
    	struct	netinfo6 *np, *nq;  | 
    
    
    948  | 
     | 
     | 
    	struct	riprt *rrt;  | 
    
    
    949  | 
     | 
     | 
    	ssize_t	len, nn;  | 
    
    
    950  | 
     | 
     | 
    	unsigned int need_trigger, idx;  | 
    
    
    951  | 
     | 
     | 
    	char	buf[4 * RIP6_MAXMTU];  | 
    
    
    952  | 
     | 
     | 
    	time_t	t;  | 
    
    
    953  | 
     | 
     | 
    	struct msghdr m;  | 
    
    
    954  | 
     | 
     | 
    	struct cmsghdr *cm;  | 
    
    
    955  | 
     | 
     | 
    	struct iovec iov[2];  | 
    
    
    956  | 
     | 
     | 
    	union { | 
    
    
    957  | 
     | 
     | 
    		struct cmsghdr hdr;  | 
    
    
    958  | 
     | 
     | 
    		u_char buf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +  | 
    
    
    959  | 
     | 
     | 
    		    CMSG_SPACE(sizeof(int))];  | 
    
    
    960  | 
     | 
     | 
    	} cmsgbuf;  | 
    
    
    961  | 
     | 
     | 
    	struct in6_pktinfo *pi = NULL;  | 
    
    
    962  | 
     | 
     | 
    	int *hlimp = NULL;  | 
    
    
    963  | 
     | 
     | 
    	struct iff *iffp;  | 
    
    
    964  | 
     | 
     | 
    	struct in6_addr ia;  | 
    
    
    965  | 
     | 
     | 
    	int ok;  | 
    
    
    966  | 
     | 
     | 
    	time_t t_half_lifetime;  | 
    
    
    967  | 
     | 
     | 
     | 
    
    
    968  | 
     | 
     | 
    	need_trigger = 0;  | 
    
    
    969  | 
     | 
     | 
     | 
    
    
    970  | 
     | 
     | 
    	m.msg_name = (caddr_t)&fsock;  | 
    
    
    971  | 
     | 
     | 
    	m.msg_namelen = sizeof(fsock);  | 
    
    
    972  | 
     | 
     | 
    	iov[0].iov_base = (caddr_t)buf;  | 
    
    
    973  | 
     | 
     | 
    	iov[0].iov_len = sizeof(buf);  | 
    
    
    974  | 
     | 
     | 
    	m.msg_iov = iov;  | 
    
    
    975  | 
     | 
     | 
    	m.msg_iovlen = 1;  | 
    
    
    976  | 
     | 
     | 
    	m.msg_control = (caddr_t)&cmsgbuf.buf;  | 
    
    
    977  | 
     | 
     | 
    	m.msg_controllen = sizeof(cmsgbuf.buf);  | 
    
    
    978  | 
     | 
     | 
    	if ((len = recvmsg(ripsock, &m, 0)) < 0) { | 
    
    
    979  | 
     | 
     | 
    		fatal("recvmsg"); | 
    
    
    980  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    981  | 
     | 
     | 
    	}  | 
    
    
    982  | 
     | 
     | 
    	idx = 0;  | 
    
    
    983  | 
     | 
     | 
    	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);  | 
    
    
    984  | 
     | 
     | 
    	     cm;  | 
    
    
    985  | 
     | 
     | 
    	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { | 
    
    
    986  | 
     | 
     | 
    		if (cm->cmsg_level != IPPROTO_IPV6)  | 
    
    
    987  | 
     | 
     | 
    			continue;  | 
    
    
    988  | 
     | 
     | 
    		switch (cm->cmsg_type) { | 
    
    
    989  | 
     | 
     | 
    		case IPV6_PKTINFO:  | 
    
    
    990  | 
     | 
     | 
    			if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { | 
    
    
    991  | 
     | 
     | 
    				log_debug(  | 
    
    
    992  | 
     | 
     | 
    				    "invalid cmsg length for IPV6_PKTINFO");  | 
    
    
    993  | 
     | 
     | 
    				return;  | 
    
    
    994  | 
     | 
     | 
    			}  | 
    
    
    995  | 
     | 
     | 
    			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));  | 
    
    
    996  | 
     | 
     | 
    			idx = pi->ipi6_ifindex;  | 
    
    
    997  | 
     | 
     | 
    			break;  | 
    
    
    998  | 
     | 
     | 
    		case IPV6_HOPLIMIT:  | 
    
    
    999  | 
     | 
     | 
    			if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { | 
    
    
    1000  | 
     | 
     | 
    				log_debug(  | 
    
    
    1001  | 
     | 
     | 
    				    "invalid cmsg length for IPV6_HOPLIMIT");  | 
    
    
    1002  | 
     | 
     | 
    				return;  | 
    
    
    1003  | 
     | 
     | 
    			}  | 
    
    
    1004  | 
     | 
     | 
    			hlimp = (int *)CMSG_DATA(cm);  | 
    
    
    1005  | 
     | 
     | 
    			break;  | 
    
    
    1006  | 
     | 
     | 
    		}  | 
    
    
    1007  | 
     | 
     | 
    	}  | 
    
    
    1008  | 
     | 
     | 
    	if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))  | 
    
    
    1009  | 
     | 
     | 
    		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);  | 
    
    
    1010  | 
     | 
     | 
     | 
    
    
    1011  | 
     | 
     | 
    	if (len < sizeof(struct rip6)) { | 
    
    
    1012  | 
     | 
     | 
    		log_debug("Packet too short"); | 
    
    
    1013  | 
     | 
     | 
    		return;  | 
    
    
    1014  | 
     | 
     | 
    	}  | 
    
    
    1015  | 
     | 
     | 
     | 
    
    
    1016  | 
     | 
     | 
    	if (pi == NULL || hlimp == NULL) { | 
    
    
    1017  | 
     | 
     | 
    		/*  | 
    
    
    1018  | 
     | 
     | 
    		 * This can happen when the kernel failed to allocate memory  | 
    
    
    1019  | 
     | 
     | 
    		 * for the ancillary data.  Although we might be able to handle  | 
    
    
    1020  | 
     | 
     | 
    		 * some cases without this info, those are minor and not so  | 
    
    
    1021  | 
     | 
     | 
    		 * important, so it's better to discard the packet for safer  | 
    
    
    1022  | 
     | 
     | 
    		 * operation.  | 
    
    
    1023  | 
     | 
     | 
    		 */  | 
    
    
    1024  | 
     | 
     | 
    		log_debug("IPv6 packet information cannot be retrieved"); | 
    
    
    1025  | 
     | 
     | 
    		return;  | 
    
    
    1026  | 
     | 
     | 
    	}  | 
    
    
    1027  | 
     | 
     | 
     | 
    
    
    1028  | 
     | 
     | 
    	nh = fsock.sin6_addr;  | 
    
    
    1029  | 
     | 
     | 
    	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /  | 
    
    
    1030  | 
     | 
     | 
    		sizeof(struct netinfo6);  | 
    
    
    1031  | 
     | 
     | 
    	rp = (struct rip6 *)buf;  | 
    
    
    1032  | 
     | 
     | 
    	np = rp->rip6_nets;  | 
    
    
    1033  | 
     | 
     | 
     | 
    
    
    1034  | 
     | 
     | 
    	if (rp->rip6_vers != RIP6_VERSION) { | 
    
    
    1035  | 
     | 
     | 
    		log_debug("Incorrect RIP version %d", rp->rip6_vers); | 
    
    
    1036  | 
     | 
     | 
    		return;  | 
    
    
    1037  | 
     | 
     | 
    	}  | 
    
    
    1038  | 
     | 
     | 
    	if (rp->rip6_cmd == RIP6_REQUEST) { | 
    
    
    1039  | 
     | 
     | 
    		if (idx && idx < nindex2ifc) { | 
    
    
    1040  | 
     | 
     | 
    			ifcp = index2ifc[idx];  | 
    
    
    1041  | 
     | 
     | 
    			riprequest(ifcp, np, nn, &fsock);  | 
    
    
    1042  | 
     | 
     | 
    		} else { | 
    
    
    1043  | 
     | 
     | 
    			riprequest(NULL, np, nn, &fsock);  | 
    
    
    1044  | 
     | 
     | 
    		}  | 
    
    
    1045  | 
     | 
     | 
    		return;  | 
    
    
    1046  | 
     | 
     | 
    	}  | 
    
    
    1047  | 
     | 
     | 
     | 
    
    
    1048  | 
     | 
     | 
    	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { | 
    
    
    1049  | 
     | 
     | 
    		log_debug("Response from non-ll addr: %s", | 
    
    
    1050  | 
     | 
     | 
    		    inet6_n2p(&fsock.sin6_addr));  | 
    
    
    1051  | 
     | 
     | 
    		return;		/* Ignore packets from non-link-local addr */  | 
    
    
    1052  | 
     | 
     | 
    	}  | 
    
    
    1053  | 
     | 
     | 
    	if (ntohs(fsock.sin6_port) != RIP6_PORT) { | 
    
    
    1054  | 
     | 
     | 
    		log_debug("Response from non-rip port from %s", | 
    
    
    1055  | 
     | 
     | 
    		    inet6_n2p(&fsock.sin6_addr));  | 
    
    
    1056  | 
     | 
     | 
    		return;  | 
    
    
    1057  | 
     | 
     | 
    	}  | 
    
    
    1058  | 
     | 
     | 
    	if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { | 
    
    
    1059  | 
     | 
     | 
    		log_debug(  | 
    
    
    1060  | 
     | 
     | 
    		    "Response packet with a smaller hop limit (%d) from %s",  | 
    
    
    1061  | 
     | 
     | 
    		    *hlimp, inet6_n2p(&fsock.sin6_addr));  | 
    
    
    1062  | 
     | 
     | 
    		return;  | 
    
    
    1063  | 
     | 
     | 
    	}  | 
    
    
    1064  | 
     | 
     | 
    	/*  | 
    
    
    1065  | 
     | 
     | 
    	 * Further validation: since this program does not send off-link  | 
    
    
    1066  | 
     | 
     | 
    	 * requests, an incoming response must always come from an on-link  | 
    
    
    1067  | 
     | 
     | 
    	 * node.  Although this is normally ensured by the source address  | 
    
    
    1068  | 
     | 
     | 
    	 * check above, it may not 100% be safe because there are router  | 
    
    
    1069  | 
     | 
     | 
    	 * implementations that (invalidly) allow a packet with a link-local  | 
    
    
    1070  | 
     | 
     | 
    	 * source address to be forwarded to a different link.  | 
    
    
    1071  | 
     | 
     | 
    	 * So we also check whether the destination address is a link-local  | 
    
    
    1072  | 
     | 
     | 
    	 * address or the hop limit is 255.  Note that RFC2080 does not require  | 
    
    
    1073  | 
     | 
     | 
    	 * the specific hop limit for a unicast response, so we cannot assume  | 
    
    
    1074  | 
     | 
     | 
    	 * the limitation.  | 
    
    
    1075  | 
     | 
     | 
    	 */  | 
    
    
    1076  | 
     | 
     | 
    	if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { | 
    
    
    1077  | 
     | 
     | 
    		log_debug(  | 
    
    
    1078  | 
     | 
     | 
    		    "Response packet possibly from an off-link node: "  | 
    
    
    1079  | 
     | 
     | 
    		    "from %s to %s hlim=%d",  | 
    
    
    1080  | 
     | 
     | 
    		    inet6_n2p(&fsock.sin6_addr), inet6_n2p(&pi->ipi6_addr),  | 
    
    
    1081  | 
     | 
     | 
    		    *hlimp);  | 
    
    
    1082  | 
     | 
     | 
    		return;  | 
    
    
    1083  | 
     | 
     | 
    	}  | 
    
    
    1084  | 
     | 
     | 
     | 
    
    
    1085  | 
     | 
     | 
    	idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);  | 
    
    
    1086  | 
     | 
     | 
    	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;  | 
    
    
    1087  | 
     | 
     | 
    	if (!ifcp) { | 
    
    
    1088  | 
     | 
     | 
    		log_debug("Packets to unknown interface index %d", idx); | 
    
    
    1089  | 
     | 
     | 
    		return;		/* Ignore it */  | 
    
    
    1090  | 
     | 
     | 
    	}  | 
    
    
    1091  | 
     | 
     | 
    	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))  | 
    
    
    1092  | 
     | 
     | 
    		return;		/* The packet is from me; ignore */  | 
    
    
    1093  | 
     | 
     | 
    	if (rp->rip6_cmd != RIP6_RESPONSE) { | 
    
    
    1094  | 
     | 
     | 
    		log_debug("Invalid command %d", rp->rip6_cmd); | 
    
    
    1095  | 
     | 
     | 
    		return;  | 
    
    
    1096  | 
     | 
     | 
    	}  | 
    
    
    1097  | 
     | 
     | 
     | 
    
    
    1098  | 
     | 
     | 
    	/* -N: no use */  | 
    
    
    1099  | 
     | 
     | 
    	if (iff_find(ifcp, 'N') != NULL)  | 
    
    
    1100  | 
     | 
     | 
    		return;  | 
    
    
    1101  | 
     | 
     | 
     | 
    
    
    1102  | 
     | 
     | 
    	log_debug("Recv(%s): from %s.%d info(%zd)", | 
    
    
    1103  | 
     | 
     | 
    	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);  | 
    
    
    1104  | 
     | 
     | 
     | 
    
    
    1105  | 
     | 
     | 
    	t = time(NULL);  | 
    
    
    1106  | 
     | 
     | 
    	t_half_lifetime = t - (RIP_LIFETIME/2);  | 
    
    
    1107  | 
     | 
     | 
    	for (; nn; nn--, np++) { | 
    
    
    1108  | 
     | 
     | 
    		if (np->rip6_metric == NEXTHOP_METRIC) { | 
    
    
    1109  | 
     | 
     | 
    			/* modify neighbor address */  | 
    
    
    1110  | 
     | 
     | 
    			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { | 
    
    
    1111  | 
     | 
     | 
    				nh = np->rip6_dest;  | 
    
    
    1112  | 
     | 
     | 
    				SET_IN6_LINKLOCAL_IFINDEX(nh, idx);  | 
    
    
    1113  | 
     | 
     | 
    				log_debug("\tNexthop: %s", inet6_n2p(&nh)); | 
    
    
    1114  | 
     | 
     | 
    			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { | 
    
    
    1115  | 
     | 
     | 
    				nh = fsock.sin6_addr;  | 
    
    
    1116  | 
     | 
     | 
    				log_debug("\tNexthop: %s", inet6_n2p(&nh)); | 
    
    
    1117  | 
     | 
     | 
    			} else { | 
    
    
    1118  | 
     | 
     | 
    				nh = fsock.sin6_addr;  | 
    
    
    1119  | 
     | 
     | 
    				log_debug("\tInvalid Nexthop: %s", | 
    
    
    1120  | 
     | 
     | 
    				    inet6_n2p(&np->rip6_dest));  | 
    
    
    1121  | 
     | 
     | 
    			}  | 
    
    
    1122  | 
     | 
     | 
    			continue;  | 
    
    
    1123  | 
     | 
     | 
    		}  | 
    
    
    1124  | 
     | 
     | 
    		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { | 
    
    
    1125  | 
     | 
     | 
    			log_debug("\tMulticast netinfo6: %s/%d [%d]", | 
    
    
    1126  | 
     | 
     | 
    				inet6_n2p(&np->rip6_dest),  | 
    
    
    1127  | 
     | 
     | 
    				np->rip6_plen, np->rip6_metric);  | 
    
    
    1128  | 
     | 
     | 
    			continue;  | 
    
    
    1129  | 
     | 
     | 
    		}  | 
    
    
    1130  | 
     | 
     | 
    		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { | 
    
    
    1131  | 
     | 
     | 
    			log_debug("\tLoopback netinfo6: %s/%d [%d]", | 
    
    
    1132  | 
     | 
     | 
    				inet6_n2p(&np->rip6_dest),  | 
    
    
    1133  | 
     | 
     | 
    				np->rip6_plen, np->rip6_metric);  | 
    
    
    1134  | 
     | 
     | 
    			continue;  | 
    
    
    1135  | 
     | 
     | 
    		}  | 
    
    
    1136  | 
     | 
     | 
    		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { | 
    
    
    1137  | 
     | 
     | 
    			log_debug("\tLink Local netinfo6: %s/%d [%d]", | 
    
    
    1138  | 
     | 
     | 
    				inet6_n2p(&np->rip6_dest),  | 
    
    
    1139  | 
     | 
     | 
    				np->rip6_plen, np->rip6_metric);  | 
    
    
    1140  | 
     | 
     | 
    			continue;  | 
    
    
    1141  | 
     | 
     | 
    		}  | 
    
    
    1142  | 
     | 
     | 
    		/* may need to pass sitelocal prefix in some case, however*/  | 
    
    
    1143  | 
     | 
     | 
    		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { | 
    
    
    1144  | 
     | 
     | 
    			log_debug("\tSite Local netinfo6: %s/%d [%d]", | 
    
    
    1145  | 
     | 
     | 
    				inet6_n2p(&np->rip6_dest),  | 
    
    
    1146  | 
     | 
     | 
    				np->rip6_plen, np->rip6_metric);  | 
    
    
    1147  | 
     | 
     | 
    			continue;  | 
    
    
    1148  | 
     | 
     | 
    		}  | 
    
    
    1149  | 
     | 
     | 
    		if (dflag >= 2) { | 
    
    
    1150  | 
     | 
     | 
    			log_enqueue("\tnetinfo6: %s/%d [%d]", | 
    
    
    1151  | 
     | 
     | 
    			    inet6_n2p(&np->rip6_dest),  | 
    
    
    1152  | 
     | 
     | 
    			    np->rip6_plen, np->rip6_metric);  | 
    
    
    1153  | 
     | 
     | 
    			if (np->rip6_tag)  | 
    
    
    1154  | 
     | 
     | 
    				log_enqueue("  tag=0x%04x", | 
    
    
    1155  | 
     | 
     | 
    				    ntohs(np->rip6_tag) & 0xffff);  | 
    
    
    1156  | 
     | 
     | 
    			ia = np->rip6_dest;  | 
    
    
    1157  | 
     | 
     | 
    			applyplen(&ia, np->rip6_plen);  | 
    
    
    1158  | 
     | 
     | 
    			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))  | 
    
    
    1159  | 
     | 
     | 
    				log_enqueue(" [junk outside prefix]"); | 
    
    
    1160  | 
     | 
     | 
    		}  | 
    
    
    1161  | 
     | 
     | 
     | 
    
    
    1162  | 
     | 
     | 
    		/*  | 
    
    
    1163  | 
     | 
     | 
    		 * -L: listen only if the prefix matches the configuration  | 
    
    
    1164  | 
     | 
     | 
    		 */  | 
    
    
    1165  | 
     | 
     | 
    		ok = 1;		/* if there's no L filter, it is ok */  | 
    
    
    1166  | 
     | 
     | 
    		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    1167  | 
     | 
     | 
    			if (iffp->iff_type != 'L')  | 
    
    
    1168  | 
     | 
     | 
    				continue;  | 
    
    
    1169  | 
     | 
     | 
    			ok = 0;  | 
    
    
    1170  | 
     | 
     | 
    			if (np->rip6_plen < iffp->iff_plen)  | 
    
    
    1171  | 
     | 
     | 
    				continue;  | 
    
    
    1172  | 
     | 
     | 
    			/* special rule: ::/0 means default, not "in /0" */  | 
    
    
    1173  | 
     | 
     | 
    			if (iffp->iff_plen == 0 && np->rip6_plen > 0)  | 
    
    
    1174  | 
     | 
     | 
    				continue;  | 
    
    
    1175  | 
     | 
     | 
    			ia = np->rip6_dest;  | 
    
    
    1176  | 
     | 
     | 
    			applyplen(&ia, iffp->iff_plen);  | 
    
    
    1177  | 
     | 
     | 
    			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { | 
    
    
    1178  | 
     | 
     | 
    				ok = 1;  | 
    
    
    1179  | 
     | 
     | 
    				break;  | 
    
    
    1180  | 
     | 
     | 
    			}  | 
    
    
    1181  | 
     | 
     | 
    		}  | 
    
    
    1182  | 
     | 
     | 
     | 
    
    
    1183  | 
     | 
     | 
    		if (!ok) { | 
    
    
    1184  | 
     | 
     | 
    			if (dflag >= 2)  | 
    
    
    1185  | 
     | 
     | 
    				log_debug("  (filtered)"); | 
    
    
    1186  | 
     | 
     | 
    			continue;  | 
    
    
    1187  | 
     | 
     | 
    		}  | 
    
    
    1188  | 
     | 
     | 
     | 
    
    
    1189  | 
     | 
     | 
    		if (dflag >= 2)  | 
    
    
    1190  | 
     | 
     | 
    			log_debug(""); | 
    
    
    1191  | 
     | 
     | 
     | 
    
    
    1192  | 
     | 
     | 
    		np->rip6_metric++;  | 
    
    
    1193  | 
     | 
     | 
    		np->rip6_metric += ifcp->ifc_metric;  | 
    
    
    1194  | 
     | 
     | 
    		if (np->rip6_metric > HOPCNT_INFINITY6)  | 
    
    
    1195  | 
     | 
     | 
    			np->rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    1196  | 
     | 
     | 
     | 
    
    
    1197  | 
     | 
     | 
    		applyplen(&np->rip6_dest, np->rip6_plen);  | 
    
    
    1198  | 
     | 
     | 
    		if ((rrt = rtsearch(np, NULL)) != NULL) { | 
    
    
    1199  | 
     | 
     | 
    			if (rrt->rrt_t == 0)  | 
    
    
    1200  | 
     | 
     | 
    				continue;	/* Intf route has priority */  | 
    
    
    1201  | 
     | 
     | 
    			nq = &rrt->rrt_info;  | 
    
    
    1202  | 
     | 
     | 
    			if (nq->rip6_metric > np->rip6_metric) { | 
    
    
    1203  | 
     | 
     | 
    				if (rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    1204  | 
     | 
     | 
    				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { | 
    
    
    1205  | 
     | 
     | 
    					/* Small metric from the same gateway */  | 
    
    
    1206  | 
     | 
     | 
    					nq->rip6_metric = np->rip6_metric;  | 
    
    
    1207  | 
     | 
     | 
    				} else { | 
    
    
    1208  | 
     | 
     | 
    					/* Better route found */  | 
    
    
    1209  | 
     | 
     | 
    					rrt->rrt_index = ifcp->ifc_index;  | 
    
    
    1210  | 
     | 
     | 
    					/* Update routing table */  | 
    
    
    1211  | 
     | 
     | 
    					delroute(nq, &rrt->rrt_gw);  | 
    
    
    1212  | 
     | 
     | 
    					rrt->rrt_gw = nh;  | 
    
    
    1213  | 
     | 
     | 
    					*nq = *np;  | 
    
    
    1214  | 
     | 
     | 
    					addroute(rrt, &nh, ifcp);  | 
    
    
    1215  | 
     | 
     | 
    				}  | 
    
    
    1216  | 
     | 
     | 
    				rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    1217  | 
     | 
     | 
    				rrt->rrt_t = t;  | 
    
    
    1218  | 
     | 
     | 
    				need_trigger = 1;  | 
    
    
    1219  | 
     | 
     | 
    			} else if (nq->rip6_metric < np->rip6_metric &&  | 
    
    
    1220  | 
     | 
     | 
    				   rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    1221  | 
     | 
     | 
    				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { | 
    
    
    1222  | 
     | 
     | 
    				/* Got worse route from same gw */  | 
    
    
    1223  | 
     | 
     | 
    				nq->rip6_metric = np->rip6_metric;  | 
    
    
    1224  | 
     | 
     | 
    				rrt->rrt_t = t;  | 
    
    
    1225  | 
     | 
     | 
    				rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    1226  | 
     | 
     | 
    				need_trigger = 1;  | 
    
    
    1227  | 
     | 
     | 
    			} else if (nq->rip6_metric == np->rip6_metric &&  | 
    
    
    1228  | 
     | 
     | 
    				   np->rip6_metric < HOPCNT_INFINITY6) { | 
    
    
    1229  | 
     | 
     | 
    				if (rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    1230  | 
     | 
     | 
    				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { | 
    
    
    1231  | 
     | 
     | 
    					/* same metric, same route from same gw */  | 
    
    
    1232  | 
     | 
     | 
    					rrt->rrt_t = t;  | 
    
    
    1233  | 
     | 
     | 
    				} else if (rrt->rrt_t < t_half_lifetime) { | 
    
    
    1234  | 
     | 
     | 
    					/* Better route found */  | 
    
    
    1235  | 
     | 
     | 
    					rrt->rrt_index = ifcp->ifc_index;  | 
    
    
    1236  | 
     | 
     | 
    					/* Update routing table */  | 
    
    
    1237  | 
     | 
     | 
    					delroute(nq, &rrt->rrt_gw);  | 
    
    
    1238  | 
     | 
     | 
    					rrt->rrt_gw = nh;  | 
    
    
    1239  | 
     | 
     | 
    					*nq = *np;  | 
    
    
    1240  | 
     | 
     | 
    					addroute(rrt, &nh, ifcp);  | 
    
    
    1241  | 
     | 
     | 
    					rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    1242  | 
     | 
     | 
    					rrt->rrt_t = t;  | 
    
    
    1243  | 
     | 
     | 
    				}  | 
    
    
    1244  | 
     | 
     | 
    			}  | 
    
    
    1245  | 
     | 
     | 
    			/*  | 
    
    
    1246  | 
     | 
     | 
    			 * if nq->rip6_metric == HOPCNT_INFINITY6 then  | 
    
    
    1247  | 
     | 
     | 
    			 * do not update age value.  Do nothing.  | 
    
    
    1248  | 
     | 
     | 
    			 */  | 
    
    
    1249  | 
     | 
     | 
    		} else if (np->rip6_metric < HOPCNT_INFINITY6) { | 
    
    
    1250  | 
     | 
     | 
    			/* Got a new valid route */  | 
    
    
    1251  | 
     | 
     | 
    			if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { | 
    
    
    1252  | 
     | 
     | 
    				fatal("calloc: struct riprt"); | 
    
    
    1253  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    1254  | 
     | 
     | 
    			}  | 
    
    
    1255  | 
     | 
     | 
    			nq = &rrt->rrt_info;  | 
    
    
    1256  | 
     | 
     | 
     | 
    
    
    1257  | 
     | 
     | 
    			rrt->rrt_index = ifcp->ifc_index;  | 
    
    
    1258  | 
     | 
     | 
    			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;  | 
    
    
    1259  | 
     | 
     | 
    			rrt->rrt_gw = nh;  | 
    
    
    1260  | 
     | 
     | 
    			*nq = *np;  | 
    
    
    1261  | 
     | 
     | 
    			applyplen(&nq->rip6_dest, nq->rip6_plen);  | 
    
    
    1262  | 
     | 
     | 
    			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)  | 
    
    
    1263  | 
     | 
     | 
    				rrt->rrt_flags |= RTF_HOST;  | 
    
    
    1264  | 
     | 
     | 
     | 
    
    
    1265  | 
     | 
     | 
    			/* Put the route to the list */  | 
    
    
    1266  | 
     | 
     | 
    			rrt->rrt_next = riprt;  | 
    
    
    1267  | 
     | 
     | 
    			riprt = rrt;  | 
    
    
    1268  | 
     | 
     | 
    			/* Update routing table */  | 
    
    
    1269  | 
     | 
     | 
    			addroute(rrt, &nh, ifcp);  | 
    
    
    1270  | 
     | 
     | 
    			rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    1271  | 
     | 
     | 
    			need_trigger = 1;  | 
    
    
    1272  | 
     | 
     | 
    			rrt->rrt_t = t;  | 
    
    
    1273  | 
     | 
     | 
    		}  | 
    
    
    1274  | 
     | 
     | 
    	}  | 
    
    
    1275  | 
     | 
     | 
    	/* XXX need to care the interval between triggered updates */  | 
    
    
    1276  | 
     | 
     | 
    	if (need_trigger) { | 
    
    
    1277  | 
     | 
     | 
    		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { | 
    
    
    1278  | 
     | 
     | 
    			for (ic = ifc; ic; ic = ic->ifc_next) { | 
    
    
    1279  | 
     | 
     | 
    				if (ifcp->ifc_index == ic->ifc_index)  | 
    
    
    1280  | 
     | 
     | 
    					continue;  | 
    
    
    1281  | 
     | 
     | 
    				if (ic->ifc_flags & IFF_UP)  | 
    
    
    1282  | 
     | 
     | 
    					ripsend(ic, &ic->ifc_ripsin,  | 
    
    
    1283  | 
     | 
     | 
    						RRTF_CHANGED);  | 
    
    
    1284  | 
     | 
     | 
    			}  | 
    
    
    1285  | 
     | 
     | 
    		}  | 
    
    
    1286  | 
     | 
     | 
    		/* Reset the flag */  | 
    
    
    1287  | 
     | 
     | 
    		for (rrt = riprt; rrt; rrt = rrt->rrt_next)  | 
    
    
    1288  | 
     | 
     | 
    			rrt->rrt_rflags &= ~RRTF_CHANGED;  | 
    
    
    1289  | 
     | 
     | 
    	}  | 
    
    
    1290  | 
     | 
     | 
    }  | 
    
    
    1291  | 
     | 
     | 
     | 
    
    
    1292  | 
     | 
     | 
    /*  | 
    
    
    1293  | 
     | 
     | 
     * Send all routes request packet to the specified interface.  | 
    
    
    1294  | 
     | 
     | 
     */  | 
    
    
    1295  | 
     | 
     | 
    void  | 
    
    
    1296  | 
     | 
     | 
    sendrequest(struct ifc *ifcp)  | 
    
    
    1297  | 
     | 
     | 
    { | 
    
    
    1298  | 
     | 
     | 
    	struct netinfo6 *np;  | 
    
    
    1299  | 
     | 
     | 
    	int error;  | 
    
    
    1300  | 
     | 
     | 
     | 
    
    
    1301  | 
     | 
     | 
    	if (ifcp->ifc_flags & IFF_LOOPBACK)  | 
    
    
    1302  | 
     | 
     | 
    		return;  | 
    
    
    1303  | 
     | 
     | 
    	ripbuf->rip6_cmd = RIP6_REQUEST;  | 
    
    
    1304  | 
     | 
     | 
    	np = ripbuf->rip6_nets;  | 
    
    
    1305  | 
     | 
     | 
    	memset(np, 0, sizeof(struct netinfo6));  | 
    
    
    1306  | 
     | 
     | 
    	np->rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    1307  | 
     | 
     | 
    	log_debug("Send rtdump Request to %s (%s)", | 
    
    
    1308  | 
     | 
     | 
    		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));  | 
    
    
    1309  | 
     | 
     | 
    	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));  | 
    
    
    1310  | 
     | 
     | 
    	if (error == EAFNOSUPPORT) { | 
    
    
    1311  | 
     | 
     | 
    		/* Protocol not supported */  | 
    
    
    1312  | 
     | 
     | 
    		log_debug("Could not send rtdump Request to %s (%s): " | 
    
    
    1313  | 
     | 
     | 
    			"set IFF_UP to 0",  | 
    
    
    1314  | 
     | 
     | 
    			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));  | 
    
    
    1315  | 
     | 
     | 
    		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */  | 
    
    
    1316  | 
     | 
     | 
    	}  | 
    
    
    1317  | 
     | 
     | 
    	ripbuf->rip6_cmd = RIP6_RESPONSE;  | 
    
    
    1318  | 
     | 
     | 
    }  | 
    
    
    1319  | 
     | 
     | 
     | 
    
    
    1320  | 
     | 
     | 
    /*  | 
    
    
    1321  | 
     | 
     | 
     * Process a RIP6_REQUEST packet.  | 
    
    
    1322  | 
     | 
     | 
     */  | 
    
    
    1323  | 
     | 
     | 
    void  | 
    
    
    1324  | 
     | 
     | 
    riprequest(struct ifc *ifcp, struct netinfo6 *np, int nn,  | 
    
    
    1325  | 
     | 
     | 
        struct sockaddr_in6 *sin6)  | 
    
    
    1326  | 
     | 
     | 
    { | 
    
    
    1327  | 
     | 
     | 
    	int i;  | 
    
    
    1328  | 
     | 
     | 
    	struct riprt *rrt;  | 
    
    
    1329  | 
     | 
     | 
     | 
    
    
    1330  | 
     | 
     | 
    	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&  | 
    
    
    1331  | 
     | 
     | 
    	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { | 
    
    
    1332  | 
     | 
     | 
    		/* Specific response, don't split-horizon */  | 
    
    
    1333  | 
     | 
     | 
    		log_debug("\tRIP Request"); | 
    
    
    1334  | 
     | 
     | 
    		for (i = 0; i < nn; i++, np++) { | 
    
    
    1335  | 
     | 
     | 
    			rrt = rtsearch(np, NULL);  | 
    
    
    1336  | 
     | 
     | 
    			if (rrt)  | 
    
    
    1337  | 
     | 
     | 
    				np->rip6_metric = rrt->rrt_info.rip6_metric;  | 
    
    
    1338  | 
     | 
     | 
    			else  | 
    
    
    1339  | 
     | 
     | 
    				np->rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    1340  | 
     | 
     | 
    		}  | 
    
    
    1341  | 
     | 
     | 
    		(void)sendpacket(sin6, RIPSIZE(nn));  | 
    
    
    1342  | 
     | 
     | 
    		return;  | 
    
    
    1343  | 
     | 
     | 
    	}  | 
    
    
    1344  | 
     | 
     | 
    	/* Whole routing table dump */  | 
    
    
    1345  | 
     | 
     | 
    	log_debug("\tRIP Request -- whole routing table"); | 
    
    
    1346  | 
     | 
     | 
    	ripsend(ifcp, sin6, RRTF_SENDANYWAY);  | 
    
    
    1347  | 
     | 
     | 
    }  | 
    
    
    1348  | 
     | 
     | 
     | 
    
    
    1349  | 
     | 
     | 
    /*  | 
    
    
    1350  | 
     | 
     | 
     * Get information of each interface.  | 
    
    
    1351  | 
     | 
     | 
     */  | 
    
    
    1352  | 
     | 
     | 
    void  | 
    
    
    1353  | 
     | 
     | 
    ifconfig(void)  | 
    
    
    1354  | 
     | 
     | 
    { | 
    
    
    1355  | 
     | 
     | 
    	struct ifaddrs *ifap, *ifa;  | 
    
    
    1356  | 
     | 
     | 
    	struct ifc *ifcp;  | 
    
    
    1357  | 
     | 
     | 
    	struct ipv6_mreq mreq;  | 
    
    
    1358  | 
     | 
     | 
    	int s;  | 
    
    
    1359  | 
     | 
     | 
     | 
    
    
    1360  | 
     | 
     | 
    	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { | 
    
    
    1361  | 
     | 
     | 
    		fatal("socket"); | 
    
    
    1362  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    1363  | 
     | 
     | 
    	}  | 
    
    
    1364  | 
     | 
     | 
     | 
    
    
    1365  | 
     | 
     | 
    	if (getifaddrs(&ifap) != 0) { | 
    
    
    1366  | 
     | 
     | 
    		fatal("getifaddrs"); | 
    
    
    1367  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    1368  | 
     | 
     | 
    	}  | 
    
    
    1369  | 
     | 
     | 
     | 
    
    
    1370  | 
     | 
     | 
    	for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | 
    
    
    1371  | 
     | 
     | 
    		if (ifa->ifa_addr->sa_family != AF_INET6)  | 
    
    
    1372  | 
     | 
     | 
    			continue;  | 
    
    
    1373  | 
     | 
     | 
    		ifcp = ifc_find(ifa->ifa_name);  | 
    
    
    1374  | 
     | 
     | 
    		/* we are interested in multicast-capable interfaces */  | 
    
    
    1375  | 
     | 
     | 
    		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)  | 
    
    
    1376  | 
     | 
     | 
    			continue;  | 
    
    
    1377  | 
     | 
     | 
    		if (!ifcp) { | 
    
    
    1378  | 
     | 
     | 
    			/* new interface */  | 
    
    
    1379  | 
     | 
     | 
    			if ((ifcp = calloc(1, sizeof(struct ifc))) == NULL) { | 
    
    
    1380  | 
     | 
     | 
    				fatal("calloc: struct ifc"); | 
    
    
    1381  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    1382  | 
     | 
     | 
    			}  | 
    
    
    1383  | 
     | 
     | 
    			ifcp->ifc_index = -1;  | 
    
    
    1384  | 
     | 
     | 
    			ifcp->ifc_next = ifc;  | 
    
    
    1385  | 
     | 
     | 
    			ifc = ifcp;  | 
    
    
    1386  | 
     | 
     | 
    			nifc++;  | 
    
    
    1387  | 
     | 
     | 
    			ifcp->ifc_name = xstrdup(ifa->ifa_name);  | 
    
    
    1388  | 
     | 
     | 
    			ifcp->ifc_addr = 0;  | 
    
    
    1389  | 
     | 
     | 
    			ifcp->ifc_filter = 0;  | 
    
    
    1390  | 
     | 
     | 
    			ifcp->ifc_flags = ifa->ifa_flags;  | 
    
    
    1391  | 
     | 
     | 
    			log_debug("newif %s <%s>", ifcp->ifc_name, | 
    
    
    1392  | 
     | 
     | 
    				ifflags(ifcp->ifc_flags));  | 
    
    
    1393  | 
     | 
     | 
    			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))  | 
    
    
    1394  | 
     | 
     | 
    				loopifcp = ifcp;  | 
    
    
    1395  | 
     | 
     | 
    		} else { | 
    
    
    1396  | 
     | 
     | 
    			/* update flag, this may be up again */  | 
    
    
    1397  | 
     | 
     | 
    			if (ifcp->ifc_flags != ifa->ifa_flags) { | 
    
    
    1398  | 
     | 
     | 
    				log_enqueue("%s: <%s> -> ", ifcp->ifc_name, | 
    
    
    1399  | 
     | 
     | 
    					ifflags(ifcp->ifc_flags));  | 
    
    
    1400  | 
     | 
     | 
    				log_debug("<%s>", ifflags(ifa->ifa_flags)); | 
    
    
    1401  | 
     | 
     | 
    				ifcp->ifc_cflags |= IFC_CHANGED;  | 
    
    
    1402  | 
     | 
     | 
    			}  | 
    
    
    1403  | 
     | 
     | 
    			ifcp->ifc_flags = ifa->ifa_flags;  | 
    
    
    1404  | 
     | 
     | 
    		}  | 
    
    
    1405  | 
     | 
     | 
    		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);  | 
    
    
    1406  | 
     | 
     | 
    		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP  | 
    
    
    1407  | 
     | 
     | 
    		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { | 
    
    
    1408  | 
     | 
     | 
    			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;  | 
    
    
    1409  | 
     | 
     | 
    			mreq.ipv6mr_interface = ifcp->ifc_index;  | 
    
    
    1410  | 
     | 
     | 
    			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,  | 
    
    
    1411  | 
     | 
     | 
    			    &mreq, sizeof(mreq)) < 0) { | 
    
    
    1412  | 
     | 
     | 
    				fatalx("IPV6_JOIN_GROUP"); | 
    
    
    1413  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    1414  | 
     | 
     | 
    			}  | 
    
    
    1415  | 
     | 
     | 
    			log_debug("join %s %s", ifcp->ifc_name, RIP6_DEST); | 
    
    
    1416  | 
     | 
     | 
    			ifcp->ifc_joined++;  | 
    
    
    1417  | 
     | 
     | 
    		}  | 
    
    
    1418  | 
     | 
     | 
    	}  | 
    
    
    1419  | 
     | 
     | 
    	close(s);  | 
    
    
    1420  | 
     | 
     | 
    	freeifaddrs(ifap);  | 
    
    
    1421  | 
     | 
     | 
    }  | 
    
    
    1422  | 
     | 
     | 
     | 
    
    
    1423  | 
     | 
     | 
    void  | 
    
    
    1424  | 
     | 
     | 
    ifconfig1(const char *name, const struct sockaddr *sa, struct ifc *ifcp, int s)  | 
    
    
    1425  | 
     | 
     | 
    { | 
    
    
    1426  | 
     | 
     | 
    	struct	in6_ifreq ifr;  | 
    
    
    1427  | 
     | 
     | 
    	const struct sockaddr_in6 *sin6;  | 
    
    
    1428  | 
     | 
     | 
    	struct	ifac *ifa;  | 
    
    
    1429  | 
     | 
     | 
    	int	plen;  | 
    
    
    1430  | 
     | 
     | 
    	char	buf[BUFSIZ];  | 
    
    
    1431  | 
     | 
     | 
     | 
    
    
    1432  | 
     | 
     | 
    	sin6 = (const struct sockaddr_in6 *)sa;  | 
    
    
    1433  | 
     | 
     | 
    	if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag)  | 
    
    
    1434  | 
     | 
     | 
    		return;  | 
    
    
    1435  | 
     | 
     | 
    	ifr.ifr_addr = *sin6;  | 
    
    
    1436  | 
     | 
     | 
    	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));  | 
    
    
    1437  | 
     | 
     | 
    	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { | 
    
    
    1438  | 
     | 
     | 
    		fatal("ioctl: SIOCGIFNETMASK_IN6"); | 
    
    
    1439  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    1440  | 
     | 
     | 
    	}  | 
    
    
    1441  | 
     | 
     | 
    	plen = sin6mask2len(&ifr.ifr_addr);  | 
    
    
    1442  | 
     | 
     | 
    	if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { | 
    
    
    1443  | 
     | 
     | 
    		/* same interface found */  | 
    
    
    1444  | 
     | 
     | 
    		/* need check if something changed */  | 
    
    
    1445  | 
     | 
     | 
    		/* XXX not yet implemented */  | 
    
    
    1446  | 
     | 
     | 
    		return;  | 
    
    
    1447  | 
     | 
     | 
    	}  | 
    
    
    1448  | 
     | 
     | 
    	/*  | 
    
    
    1449  | 
     | 
     | 
    	 * New address is found  | 
    
    
    1450  | 
     | 
     | 
    	 */  | 
    
    
    1451  | 
     | 
     | 
    	if ((ifa = calloc(1, sizeof(struct ifac))) == NULL) { | 
    
    
    1452  | 
     | 
     | 
    		fatal("calloc: struct ifac"); | 
    
    
    1453  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    1454  | 
     | 
     | 
    	}  | 
    
    
    1455  | 
     | 
     | 
    	ifa->ifa_conf = ifcp;  | 
    
    
    1456  | 
     | 
     | 
    	ifa->ifa_next = ifcp->ifc_addr;  | 
    
    
    1457  | 
     | 
     | 
    	ifcp->ifc_addr = ifa;  | 
    
    
    1458  | 
     | 
     | 
    	ifa->ifa_addr = sin6->sin6_addr;  | 
    
    
    1459  | 
     | 
     | 
    	ifa->ifa_plen = plen;  | 
    
    
    1460  | 
     | 
     | 
    	if (ifcp->ifc_flags & IFF_POINTOPOINT) { | 
    
    
    1461  | 
     | 
     | 
    		ifr.ifr_addr = *sin6;  | 
    
    
    1462  | 
     | 
     | 
    		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { | 
    
    
    1463  | 
     | 
     | 
    			fatal("ioctl: SIOCGIFDSTADDR_IN6"); | 
    
    
    1464  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    1465  | 
     | 
     | 
    		}  | 
    
    
    1466  | 
     | 
     | 
    		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;  | 
    
    
    1467  | 
     | 
     | 
    		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));  | 
    
    
    1468  | 
     | 
     | 
    		log_debug("found address %s/%d -- %s", | 
    
    
    1469  | 
     | 
     | 
    			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);  | 
    
    
    1470  | 
     | 
     | 
    	} else { | 
    
    
    1471  | 
     | 
     | 
    		log_debug("found address %s/%d", | 
    
    
    1472  | 
     | 
     | 
    			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);  | 
    
    
    1473  | 
     | 
     | 
    	}  | 
    
    
    1474  | 
     | 
     | 
    	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { | 
    
    
    1475  | 
     | 
     | 
    		ifcp->ifc_mylladdr = ifa->ifa_addr;  | 
    
    
    1476  | 
     | 
     | 
    		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);  | 
    
    
    1477  | 
     | 
     | 
    		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);  | 
    
    
    1478  | 
     | 
     | 
    		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,  | 
    
    
    1479  | 
     | 
     | 
    			ifcp->ifc_index);  | 
    
    
    1480  | 
     | 
     | 
    		setindex2ifc(ifcp->ifc_index, ifcp);  | 
    
    
    1481  | 
     | 
     | 
    		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);  | 
    
    
    1482  | 
     | 
     | 
    		if (ifcp->ifc_mtu > RIP6_MAXMTU)  | 
    
    
    1483  | 
     | 
     | 
    			ifcp->ifc_mtu = RIP6_MAXMTU;  | 
    
    
    1484  | 
     | 
     | 
    		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { | 
    
    
    1485  | 
     | 
     | 
    			fatal("ioctl: SIOCGIFMETRIC"); | 
    
    
    1486  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    1487  | 
     | 
     | 
    		}  | 
    
    
    1488  | 
     | 
     | 
    		ifcp->ifc_metric = ifr.ifr_metric;  | 
    
    
    1489  | 
     | 
     | 
    		log_debug("\tindex: %d, mtu: %d, metric: %d", | 
    
    
    1490  | 
     | 
     | 
    			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);  | 
    
    
    1491  | 
     | 
     | 
    	} else  | 
    
    
    1492  | 
     | 
     | 
    		ifcp->ifc_cflags |= IFC_CHANGED;  | 
    
    
    1493  | 
     | 
     | 
    }  | 
    
    
    1494  | 
     | 
     | 
     | 
    
    
    1495  | 
     | 
     | 
    /*  | 
    
    
    1496  | 
     | 
     | 
     * Receive and process routing messages.  | 
    
    
    1497  | 
     | 
     | 
     * Update interface information as necesssary.  | 
    
    
    1498  | 
     | 
     | 
     */  | 
    
    
    1499  | 
     | 
     | 
    void  | 
    
    
    1500  | 
     | 
     | 
    rtrecv(void)  | 
    
    
    1501  | 
     | 
     | 
    { | 
    
    
    1502  | 
     | 
     | 
    	char buf[BUFSIZ];  | 
    
    
    1503  | 
     | 
     | 
    	char *p, *q;  | 
    
    
    1504  | 
     | 
     | 
    	struct rt_msghdr *rtm;  | 
    
    
    1505  | 
     | 
     | 
    	struct ifa_msghdr *ifam;  | 
    
    
    1506  | 
     | 
     | 
    	struct if_msghdr *ifm;  | 
    
    
    1507  | 
     | 
     | 
    	int len;  | 
    
    
    1508  | 
     | 
     | 
    	struct ifc *ifcp, *ic;  | 
    
    
    1509  | 
     | 
     | 
    	int iface = 0, rtable = 0;  | 
    
    
    1510  | 
     | 
     | 
    	struct sockaddr_in6 *rta[RTAX_MAX];  | 
    
    
    1511  | 
     | 
     | 
    	struct sockaddr_in6 mask;  | 
    
    
    1512  | 
     | 
     | 
    	int i, addrs;  | 
    
    
    1513  | 
     | 
     | 
    	struct riprt *rrt;  | 
    
    
    1514  | 
     | 
     | 
     | 
    
    
    1515  | 
     | 
     | 
    	if ((len = read(rtsock, buf, sizeof(buf))) < 0) { | 
    
    
    1516  | 
     | 
     | 
    		perror("read from rtsock"); | 
    
    
    1517  | 
     | 
     | 
    		exit(1);  | 
    
    
    1518  | 
     | 
     | 
    	}  | 
    
    
    1519  | 
     | 
     | 
    	if (len < sizeof(*rtm)) { | 
    
    
    1520  | 
     | 
     | 
    		log_debug("short read from rtsock: %d (should be > %zu)", | 
    
    
    1521  | 
     | 
     | 
    			len, sizeof(*rtm));  | 
    
    
    1522  | 
     | 
     | 
    		return;  | 
    
    
    1523  | 
     | 
     | 
    	}  | 
    
    
    1524  | 
     | 
     | 
    	if (dflag >= 2) { | 
    
    
    1525  | 
     | 
     | 
    		log_debug("rtmsg:"); | 
    
    
    1526  | 
     | 
     | 
    		for (i = 0; i < len; i++) { | 
    
    
    1527  | 
     | 
     | 
    			log_enqueue("%02x ", buf[i] & 0xff); | 
    
    
    1528  | 
     | 
     | 
    			if (i % 16 == 15)  | 
    
    
    1529  | 
     | 
     | 
    				log_debug(""); | 
    
    
    1530  | 
     | 
     | 
    		}  | 
    
    
    1531  | 
     | 
     | 
    		log_debug(""); | 
    
    
    1532  | 
     | 
     | 
    	}  | 
    
    
    1533  | 
     | 
     | 
     | 
    
    
    1534  | 
     | 
     | 
    	p = buf;  | 
    
    
    1535  | 
     | 
     | 
    	/* safety against bogus message */  | 
    
    
    1536  | 
     | 
     | 
    	if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { | 
    
    
    1537  | 
     | 
     | 
    		log_debug("bogus rtmsg: length=%d", | 
    
    
    1538  | 
     | 
     | 
    		    ((struct rt_msghdr *)p)->rtm_msglen);  | 
    
    
    1539  | 
     | 
     | 
    		return;  | 
    
    
    1540  | 
     | 
     | 
    	}  | 
    
    
    1541  | 
     | 
     | 
    	if (((struct rt_msghdr *)p)->rtm_version != RTM_VERSION)  | 
    
    
    1542  | 
     | 
     | 
    		return;  | 
    
    
    1543  | 
     | 
     | 
     | 
    
    
    1544  | 
     | 
     | 
    	rtm = NULL;  | 
    
    
    1545  | 
     | 
     | 
    	ifam = NULL;  | 
    
    
    1546  | 
     | 
     | 
    	ifm = NULL;  | 
    
    
    1547  | 
     | 
     | 
    	switch (((struct rt_msghdr *)p)->rtm_type) { | 
    
    
    1548  | 
     | 
     | 
    	case RTM_NEWADDR:  | 
    
    
    1549  | 
     | 
     | 
    	case RTM_DELADDR:  | 
    
    
    1550  | 
     | 
     | 
    		ifam = (struct ifa_msghdr *)p;  | 
    
    
    1551  | 
     | 
     | 
    		addrs = ifam->ifam_addrs;  | 
    
    
    1552  | 
     | 
     | 
    		q = (char *)(ifam + 1);  | 
    
    
    1553  | 
     | 
     | 
    		break;  | 
    
    
    1554  | 
     | 
     | 
    	case RTM_IFINFO:  | 
    
    
    1555  | 
     | 
     | 
    		ifm = (struct if_msghdr *)p;  | 
    
    
    1556  | 
     | 
     | 
    		addrs = ifm->ifm_addrs;  | 
    
    
    1557  | 
     | 
     | 
    		q = (char *)(ifm + 1);  | 
    
    
    1558  | 
     | 
     | 
    		break;  | 
    
    
    1559  | 
     | 
     | 
    	default:  | 
    
    
    1560  | 
     | 
     | 
    		rtm = (struct rt_msghdr *)p;  | 
    
    
    1561  | 
     | 
     | 
    		addrs = rtm->rtm_addrs;  | 
    
    
    1562  | 
     | 
     | 
    		q = (char *)(p + rtm->rtm_hdrlen);  | 
    
    
    1563  | 
     | 
     | 
    		if (rtm->rtm_pid == pid) { | 
    
    
    1564  | 
     | 
     | 
    #if 0  | 
    
    
    1565  | 
     | 
     | 
    			log_debug("rtmsg looped back to me, ignored"); | 
    
    
    1566  | 
     | 
     | 
    #endif  | 
    
    
    1567  | 
     | 
     | 
    			return;  | 
    
    
    1568  | 
     | 
     | 
    		}  | 
    
    
    1569  | 
     | 
     | 
    		break;  | 
    
    
    1570  | 
     | 
     | 
    	}  | 
    
    
    1571  | 
     | 
     | 
    	memset(&rta, 0, sizeof(rta));  | 
    
    
    1572  | 
     | 
     | 
    	for (i = 0; i < RTAX_MAX; i++) { | 
    
    
    1573  | 
     | 
     | 
    		if (addrs & (1 << i)) { | 
    
    
    1574  | 
     | 
     | 
    			rta[i] = (struct sockaddr_in6 *)q;  | 
    
    
    1575  | 
     | 
     | 
    			q += ROUNDUP(rta[i]->sin6_len);  | 
    
    
    1576  | 
     | 
     | 
    		}  | 
    
    
    1577  | 
     | 
     | 
    	}  | 
    
    
    1578  | 
     | 
     | 
     | 
    
    
    1579  | 
     | 
     | 
    	log_debug("rtsock: %s (addrs=%x)", | 
    
    
    1580  | 
     | 
     | 
    	    rttypes((struct rt_msghdr *)p), addrs);  | 
    
    
    1581  | 
     | 
     | 
    	if (dflag >= 2) { | 
    
    
    1582  | 
     | 
     | 
    		for (i = 0;  | 
    
    
    1583  | 
     | 
     | 
    		     i < ((struct rt_msghdr *)p)->rtm_msglen;  | 
    
    
    1584  | 
     | 
     | 
    		     i++) { | 
    
    
    1585  | 
     | 
     | 
    			log_enqueue("%02x ", p[i] & 0xff); | 
    
    
    1586  | 
     | 
     | 
    			if (i % 16 == 15)  | 
    
    
    1587  | 
     | 
     | 
    				log_debug(""); | 
    
    
    1588  | 
     | 
     | 
    		}  | 
    
    
    1589  | 
     | 
     | 
    		log_debug(""); | 
    
    
    1590  | 
     | 
     | 
    	}  | 
    
    
    1591  | 
     | 
     | 
    	/*  | 
    
    
    1592  | 
     | 
     | 
    	 * Easy ones first.  | 
    
    
    1593  | 
     | 
     | 
    	 *  | 
    
    
    1594  | 
     | 
     | 
    	 * We may be able to optimize by using ifm->ifm_index or  | 
    
    
    1595  | 
     | 
     | 
    	 * ifam->ifam_index.  For simplicity we don't do that here.  | 
    
    
    1596  | 
     | 
     | 
    	 */  | 
    
    
    1597  | 
     | 
     | 
    	switch (((struct rt_msghdr *)p)->rtm_type) { | 
    
    
    1598  | 
     | 
     | 
    	case RTM_NEWADDR:  | 
    
    
    1599  | 
     | 
     | 
    	case RTM_IFINFO:  | 
    
    
    1600  | 
     | 
     | 
    		iface++;  | 
    
    
    1601  | 
     | 
     | 
    		return;  | 
    
    
    1602  | 
     | 
     | 
    	case RTM_ADD:  | 
    
    
    1603  | 
     | 
     | 
    		rtable++;  | 
    
    
    1604  | 
     | 
     | 
    		return;  | 
    
    
    1605  | 
     | 
     | 
    	case RTM_LOSING:  | 
    
    
    1606  | 
     | 
     | 
    	case RTM_MISS:  | 
    
    
    1607  | 
     | 
     | 
    	case RTM_RESOLVE:  | 
    
    
    1608  | 
     | 
     | 
    	case RTM_GET:  | 
    
    
    1609  | 
     | 
     | 
    	case RTM_LOCK:  | 
    
    
    1610  | 
     | 
     | 
    		/* nothing to be done here */  | 
    
    
    1611  | 
     | 
     | 
    		log_debug("\tnothing to be done, ignored"); | 
    
    
    1612  | 
     | 
     | 
    		return;  | 
    
    
    1613  | 
     | 
     | 
    	}  | 
    
    
    1614  | 
     | 
     | 
     | 
    
    
    1615  | 
     | 
     | 
    #if 0  | 
    
    
    1616  | 
     | 
     | 
    	if (rta[RTAX_DST] == NULL) { | 
    
    
    1617  | 
     | 
     | 
    		log_debug("\tno destination, ignored"); | 
    
    
    1618  | 
     | 
     | 
    		return;  | 
    
    
    1619  | 
     | 
     | 
    	}  | 
    
    
    1620  | 
     | 
     | 
    	if (rta[RTAX_DST]->sin6_family != AF_INET6) { | 
    
    
    1621  | 
     | 
     | 
    		log_debug("\taf mismatch, ignored"); | 
    
    
    1622  | 
     | 
     | 
    		return;  | 
    
    
    1623  | 
     | 
     | 
    	}  | 
    
    
    1624  | 
     | 
     | 
    	if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { | 
    
    
    1625  | 
     | 
     | 
    		log_debug("\tlinklocal destination, ignored"); | 
    
    
    1626  | 
     | 
     | 
    		return;  | 
    
    
    1627  | 
     | 
     | 
    	}  | 
    
    
    1628  | 
     | 
     | 
    	if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { | 
    
    
    1629  | 
     | 
     | 
    		log_debug("\tloopback destination, ignored"); | 
    
    
    1630  | 
     | 
     | 
    		return;		/* Loopback */  | 
    
    
    1631  | 
     | 
     | 
    	}  | 
    
    
    1632  | 
     | 
     | 
    	if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { | 
    
    
    1633  | 
     | 
     | 
    		log_debug("\tmulticast destination, ignored"); | 
    
    
    1634  | 
     | 
     | 
    		return;  | 
    
    
    1635  | 
     | 
     | 
    	}  | 
    
    
    1636  | 
     | 
     | 
    #endif  | 
    
    
    1637  | 
     | 
     | 
     | 
    
    
    1638  | 
     | 
     | 
    	/* hard ones */  | 
    
    
    1639  | 
     | 
     | 
    	switch (((struct rt_msghdr *)p)->rtm_type) { | 
    
    
    1640  | 
     | 
     | 
    	case RTM_NEWADDR:  | 
    
    
    1641  | 
     | 
     | 
    	case RTM_IFINFO:  | 
    
    
    1642  | 
     | 
     | 
    	case RTM_ADD:  | 
    
    
    1643  | 
     | 
     | 
    	case RTM_LOSING:  | 
    
    
    1644  | 
     | 
     | 
    	case RTM_MISS:  | 
    
    
    1645  | 
     | 
     | 
    	case RTM_RESOLVE:  | 
    
    
    1646  | 
     | 
     | 
    	case RTM_GET:  | 
    
    
    1647  | 
     | 
     | 
    	case RTM_LOCK:  | 
    
    
    1648  | 
     | 
     | 
    		/* should already be handled */  | 
    
    
    1649  | 
     | 
     | 
    		fatalx("rtrecv: never reach here"); | 
    
    
    1650  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    1651  | 
     | 
     | 
    	case RTM_DELETE:  | 
    
    
    1652  | 
     | 
     | 
    		if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { | 
    
    
    1653  | 
     | 
     | 
    			log_debug("\tsome of dst/gw/netmask are " | 
    
    
    1654  | 
     | 
     | 
    			    "unavailable, ignored");  | 
    
    
    1655  | 
     | 
     | 
    			break;  | 
    
    
    1656  | 
     | 
     | 
    		}  | 
    
    
    1657  | 
     | 
     | 
    		if ((rtm->rtm_flags & RTF_HOST) != 0) { | 
    
    
    1658  | 
     | 
     | 
    			mask.sin6_len = sizeof(mask);  | 
    
    
    1659  | 
     | 
     | 
    			memset(&mask.sin6_addr, 0xff,  | 
    
    
    1660  | 
     | 
     | 
    			    sizeof(mask.sin6_addr));  | 
    
    
    1661  | 
     | 
     | 
    			rta[RTAX_NETMASK] = &mask;  | 
    
    
    1662  | 
     | 
     | 
    		} else if (!rta[RTAX_NETMASK]) { | 
    
    
    1663  | 
     | 
     | 
    			log_debug("\tsome of dst/gw/netmask are " | 
    
    
    1664  | 
     | 
     | 
    			    "unavailable, ignored");  | 
    
    
    1665  | 
     | 
     | 
    			break;  | 
    
    
    1666  | 
     | 
     | 
    		}  | 
    
    
    1667  | 
     | 
     | 
    		if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],  | 
    
    
    1668  | 
     | 
     | 
    			rta[RTAX_NETMASK]) == 0) { | 
    
    
    1669  | 
     | 
     | 
    			rtable++;	/*just to be sure*/  | 
    
    
    1670  | 
     | 
     | 
    		}  | 
    
    
    1671  | 
     | 
     | 
    		break;  | 
    
    
    1672  | 
     | 
     | 
    	case RTM_CHANGE:  | 
    
    
    1673  | 
     | 
     | 
    	case RTM_REDIRECT:  | 
    
    
    1674  | 
     | 
     | 
    		log_debug("\tnot supported yet, ignored"); | 
    
    
    1675  | 
     | 
     | 
    		break;  | 
    
    
    1676  | 
     | 
     | 
    	case RTM_DELADDR:  | 
    
    
    1677  | 
     | 
     | 
    		if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { | 
    
    
    1678  | 
     | 
     | 
    			log_debug("\tno netmask or ifa given, ignored"); | 
    
    
    1679  | 
     | 
     | 
    			break;  | 
    
    
    1680  | 
     | 
     | 
    		}  | 
    
    
    1681  | 
     | 
     | 
    		if (ifam->ifam_index < nindex2ifc)  | 
    
    
    1682  | 
     | 
     | 
    			ifcp = index2ifc[ifam->ifam_index];  | 
    
    
    1683  | 
     | 
     | 
    		else  | 
    
    
    1684  | 
     | 
     | 
    			ifcp = NULL;  | 
    
    
    1685  | 
     | 
     | 
    		if (!ifcp) { | 
    
    
    1686  | 
     | 
     | 
    			log_debug("\tinvalid ifam_index %d, ignored", | 
    
    
    1687  | 
     | 
     | 
    			    ifam->ifam_index);  | 
    
    
    1688  | 
     | 
     | 
    			break;  | 
    
    
    1689  | 
     | 
     | 
    		}  | 
    
    
    1690  | 
     | 
     | 
    		if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))  | 
    
    
    1691  | 
     | 
     | 
    			iface++;  | 
    
    
    1692  | 
     | 
     | 
    		break;  | 
    
    
    1693  | 
     | 
     | 
    	}  | 
    
    
    1694  | 
     | 
     | 
     | 
    
    
    1695  | 
     | 
     | 
    	if (iface) { | 
    
    
    1696  | 
     | 
     | 
    		log_debug("rtsock: reconfigure interfaces, refresh interface routes"); | 
    
    
    1697  | 
     | 
     | 
    		ifconfig();  | 
    
    
    1698  | 
     | 
     | 
    		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)  | 
    
    
    1699  | 
     | 
     | 
    			if (ifcp->ifc_cflags & IFC_CHANGED) { | 
    
    
    1700  | 
     | 
     | 
    				if (ifrt(ifcp, 1)) { | 
    
    
    1701  | 
     | 
     | 
    					for (ic = ifc; ic; ic = ic->ifc_next) { | 
    
    
    1702  | 
     | 
     | 
    						if (ifcp->ifc_index == ic->ifc_index)  | 
    
    
    1703  | 
     | 
     | 
    							continue;  | 
    
    
    1704  | 
     | 
     | 
    						if (ic->ifc_flags & IFF_UP)  | 
    
    
    1705  | 
     | 
     | 
    							ripsend(ic, &ic->ifc_ripsin,  | 
    
    
    1706  | 
     | 
     | 
    							RRTF_CHANGED);  | 
    
    
    1707  | 
     | 
     | 
    					}  | 
    
    
    1708  | 
     | 
     | 
    					/* Reset the flag */  | 
    
    
    1709  | 
     | 
     | 
    					for (rrt = riprt; rrt; rrt = rrt->rrt_next)  | 
    
    
    1710  | 
     | 
     | 
    						rrt->rrt_rflags &= ~RRTF_CHANGED;  | 
    
    
    1711  | 
     | 
     | 
    				}  | 
    
    
    1712  | 
     | 
     | 
    				ifcp->ifc_cflags &= ~IFC_CHANGED;  | 
    
    
    1713  | 
     | 
     | 
    			}  | 
    
    
    1714  | 
     | 
     | 
    	}  | 
    
    
    1715  | 
     | 
     | 
    	if (rtable) { | 
    
    
    1716  | 
     | 
     | 
    		log_debug("rtsock: read routing table again"); | 
    
    
    1717  | 
     | 
     | 
    		krtread(1);  | 
    
    
    1718  | 
     | 
     | 
    	}  | 
    
    
    1719  | 
     | 
     | 
    }  | 
    
    
    1720  | 
     | 
     | 
     | 
    
    
    1721  | 
     | 
     | 
    /*  | 
    
    
    1722  | 
     | 
     | 
     * remove specified route from the internal routing table.  | 
    
    
    1723  | 
     | 
     | 
     */  | 
    
    
    1724  | 
     | 
     | 
    int  | 
    
    
    1725  | 
     | 
     | 
    rt_del(const struct sockaddr_in6 *sdst, const struct sockaddr_in6 *sgw,  | 
    
    
    1726  | 
     | 
     | 
        const struct sockaddr_in6 *smask)  | 
    
    
    1727  | 
     | 
     | 
    { | 
    
    
    1728  | 
     | 
     | 
    	const struct in6_addr *dst = NULL;  | 
    
    
    1729  | 
     | 
     | 
    	const struct in6_addr *gw = NULL;  | 
    
    
    1730  | 
     | 
     | 
    	int prefix;  | 
    
    
    1731  | 
     | 
     | 
    	struct netinfo6 ni6;  | 
    
    
    1732  | 
     | 
     | 
    	struct riprt *rrt = NULL;  | 
    
    
    1733  | 
     | 
     | 
    	time_t t_lifetime;  | 
    
    
    1734  | 
     | 
     | 
     | 
    
    
    1735  | 
     | 
     | 
    	if (sdst->sin6_family != AF_INET6) { | 
    
    
    1736  | 
     | 
     | 
    		log_debug("\tother AF, ignored"); | 
    
    
    1737  | 
     | 
     | 
    		return -1;  | 
    
    
    1738  | 
     | 
     | 
    	}  | 
    
    
    1739  | 
     | 
     | 
    	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)  | 
    
    
    1740  | 
     | 
     | 
    	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)  | 
    
    
    1741  | 
     | 
     | 
    	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { | 
    
    
    1742  | 
     | 
     | 
    		log_debug("\taddress %s not interesting, ignored", | 
    
    
    1743  | 
     | 
     | 
    			inet6_n2p(&sdst->sin6_addr));  | 
    
    
    1744  | 
     | 
     | 
    		return -1;  | 
    
    
    1745  | 
     | 
     | 
    	}  | 
    
    
    1746  | 
     | 
     | 
    	dst = &sdst->sin6_addr;  | 
    
    
    1747  | 
     | 
     | 
    	if (sgw->sin6_family == AF_INET6) { | 
    
    
    1748  | 
     | 
     | 
    		/* easy case */  | 
    
    
    1749  | 
     | 
     | 
    		gw = &sgw->sin6_addr;  | 
    
    
    1750  | 
     | 
     | 
    		prefix = sin6mask2len(smask);  | 
    
    
    1751  | 
     | 
     | 
    	} else if (sgw->sin6_family == AF_LINK) { | 
    
    
    1752  | 
     | 
     | 
    		/*  | 
    
    
    1753  | 
     | 
     | 
    		 * Interface route... a hard case.  We need to get the prefix  | 
    
    
    1754  | 
     | 
     | 
    		 * length from the kernel, but we now are parsing rtmsg.  | 
    
    
    1755  | 
     | 
     | 
    		 * We'll purge matching routes from my list, then get the  | 
    
    
    1756  | 
     | 
     | 
    		 * fresh list.  | 
    
    
    1757  | 
     | 
     | 
    		 */  | 
    
    
    1758  | 
     | 
     | 
    		struct riprt *longest;  | 
    
    
    1759  | 
     | 
     | 
    		log_debug("\t%s is a interface route, guessing prefixlen", | 
    
    
    1760  | 
     | 
     | 
    			inet6_n2p(dst));  | 
    
    
    1761  | 
     | 
     | 
    		longest = NULL;  | 
    
    
    1762  | 
     | 
     | 
    		for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    1763  | 
     | 
     | 
    			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,  | 
    
    
    1764  | 
     | 
     | 
    					&sdst->sin6_addr)  | 
    
    
    1765  | 
     | 
     | 
    			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { | 
    
    
    1766  | 
     | 
     | 
    				if (!longest  | 
    
    
    1767  | 
     | 
     | 
    				 || longest->rrt_info.rip6_plen <  | 
    
    
    1768  | 
     | 
     | 
    						 rrt->rrt_info.rip6_plen) { | 
    
    
    1769  | 
     | 
     | 
    					longest = rrt;  | 
    
    
    1770  | 
     | 
     | 
    				}  | 
    
    
    1771  | 
     | 
     | 
    			}  | 
    
    
    1772  | 
     | 
     | 
    		}  | 
    
    
    1773  | 
     | 
     | 
    		rrt = longest;  | 
    
    
    1774  | 
     | 
     | 
    		if (!rrt) { | 
    
    
    1775  | 
     | 
     | 
    			log_debug("\tno matching interface route found"); | 
    
    
    1776  | 
     | 
     | 
    			return -1;  | 
    
    
    1777  | 
     | 
     | 
    		}  | 
    
    
    1778  | 
     | 
     | 
    		gw = &in6addr_loopback;  | 
    
    
    1779  | 
     | 
     | 
    		prefix = rrt->rrt_info.rip6_plen;  | 
    
    
    1780  | 
     | 
     | 
    	} else { | 
    
    
    1781  | 
     | 
     | 
    		log_debug("\tunsupported af: (gw=%d)", sgw->sin6_family); | 
    
    
    1782  | 
     | 
     | 
    		return -1;  | 
    
    
    1783  | 
     | 
     | 
    	}  | 
    
    
    1784  | 
     | 
     | 
     | 
    
    
    1785  | 
     | 
     | 
    	log_enqueue("\tdeleting %s/%d ", inet6_n2p(dst), prefix); | 
    
    
    1786  | 
     | 
     | 
    	log_debug("gw %s", inet6_n2p(gw)); | 
    
    
    1787  | 
     | 
     | 
    	t_lifetime = time(NULL) - RIP_LIFETIME;  | 
    
    
    1788  | 
     | 
     | 
    	/* age route for interface address */  | 
    
    
    1789  | 
     | 
     | 
    	memset(&ni6, 0, sizeof(ni6));  | 
    
    
    1790  | 
     | 
     | 
    	ni6.rip6_dest = *dst;  | 
    
    
    1791  | 
     | 
     | 
    	ni6.rip6_plen = prefix;  | 
    
    
    1792  | 
     | 
     | 
    	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/  | 
    
    
    1793  | 
     | 
     | 
    	log_debug("\tfind route %s/%d", inet6_n2p(&ni6.rip6_dest), | 
    
    
    1794  | 
     | 
     | 
    		ni6.rip6_plen);  | 
    
    
    1795  | 
     | 
     | 
    	if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { | 
    
    
    1796  | 
     | 
     | 
    		log_debug("\tno route found"); | 
    
    
    1797  | 
     | 
     | 
    		return -1;  | 
    
    
    1798  | 
     | 
     | 
    	}  | 
    
    
    1799  | 
     | 
     | 
    #if 0  | 
    
    
    1800  | 
     | 
     | 
    	if ((rrt->rrt_flags & RTF_STATIC) == 0) { | 
    
    
    1801  | 
     | 
     | 
    		log_debug("\tyou can delete static routes only"); | 
    
    
    1802  | 
     | 
     | 
    	} else  | 
    
    
    1803  | 
     | 
     | 
    #endif  | 
    
    
    1804  | 
     | 
     | 
    	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { | 
    
    
    1805  | 
     | 
     | 
    		log_enqueue("\tgw mismatch: %s <-> ", | 
    
    
    1806  | 
     | 
     | 
    			inet6_n2p(&rrt->rrt_gw));  | 
    
    
    1807  | 
     | 
     | 
    		log_debug("%s", inet6_n2p(gw)); | 
    
    
    1808  | 
     | 
     | 
    	} else { | 
    
    
    1809  | 
     | 
     | 
    		log_debug("\troute found, age it"); | 
    
    
    1810  | 
     | 
     | 
    		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { | 
    
    
    1811  | 
     | 
     | 
    			rrt->rrt_t = t_lifetime;  | 
    
    
    1812  | 
     | 
     | 
    			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    1813  | 
     | 
     | 
    		}  | 
    
    
    1814  | 
     | 
     | 
    	}  | 
    
    
    1815  | 
     | 
     | 
    	return 0;  | 
    
    
    1816  | 
     | 
     | 
    }  | 
    
    
    1817  | 
     | 
     | 
     | 
    
    
    1818  | 
     | 
     | 
    /*  | 
    
    
    1819  | 
     | 
     | 
     * remove specified address from internal interface/routing table.  | 
    
    
    1820  | 
     | 
     | 
     */  | 
    
    
    1821  | 
     | 
     | 
    int  | 
    
    
    1822  | 
     | 
     | 
    rt_deladdr(struct ifc *ifcp, const struct sockaddr_in6 *sifa,  | 
    
    
    1823  | 
     | 
     | 
        const struct sockaddr_in6 *smask)  | 
    
    
    1824  | 
     | 
     | 
    { | 
    
    
    1825  | 
     | 
     | 
    	const struct in6_addr *addr = NULL;  | 
    
    
    1826  | 
     | 
     | 
    	int prefix;  | 
    
    
    1827  | 
     | 
     | 
    	struct ifac *ifa = NULL;  | 
    
    
    1828  | 
     | 
     | 
    	struct netinfo6 ni6;  | 
    
    
    1829  | 
     | 
     | 
    	struct riprt *rrt = NULL;  | 
    
    
    1830  | 
     | 
     | 
    	time_t t_lifetime;  | 
    
    
    1831  | 
     | 
     | 
    	int updated = 0;  | 
    
    
    1832  | 
     | 
     | 
     | 
    
    
    1833  | 
     | 
     | 
    	if (sifa->sin6_family != AF_INET6) { | 
    
    
    1834  | 
     | 
     | 
    		log_debug("\tother AF, ignored"); | 
    
    
    1835  | 
     | 
     | 
    		return -1;  | 
    
    
    1836  | 
     | 
     | 
    	}  | 
    
    
    1837  | 
     | 
     | 
    	addr = &sifa->sin6_addr;  | 
    
    
    1838  | 
     | 
     | 
    	prefix = sin6mask2len(smask);  | 
    
    
    1839  | 
     | 
     | 
     | 
    
    
    1840  | 
     | 
     | 
    	log_debug("\tdeleting %s/%d from %s", | 
    
    
    1841  | 
     | 
     | 
    		inet6_n2p(addr), prefix, ifcp->ifc_name);  | 
    
    
    1842  | 
     | 
     | 
    	ifa = ifa_match(ifcp, addr, prefix);  | 
    
    
    1843  | 
     | 
     | 
    	if (!ifa) { | 
    
    
    1844  | 
     | 
     | 
    		log_debug("\tno matching ifa found for %s/%d on %s", | 
    
    
    1845  | 
     | 
     | 
    			inet6_n2p(addr), prefix, ifcp->ifc_name);  | 
    
    
    1846  | 
     | 
     | 
    		return -1;  | 
    
    
    1847  | 
     | 
     | 
    	}  | 
    
    
    1848  | 
     | 
     | 
    	if (ifa->ifa_conf != ifcp) { | 
    
    
    1849  | 
     | 
     | 
    		log_debug("\taddress table corrupt: back pointer does not match " | 
    
    
    1850  | 
     | 
     | 
    			"(%s != %s)",  | 
    
    
    1851  | 
     | 
     | 
    			ifcp->ifc_name, ifa->ifa_conf->ifc_name);  | 
    
    
    1852  | 
     | 
     | 
    		return -1;  | 
    
    
    1853  | 
     | 
     | 
    	}  | 
    
    
    1854  | 
     | 
     | 
    	/* remove ifa from interface */  | 
    
    
    1855  | 
     | 
     | 
    	if (ifcp->ifc_addr == ifa)  | 
    
    
    1856  | 
     | 
     | 
    		ifcp->ifc_addr = ifa->ifa_next;  | 
    
    
    1857  | 
     | 
     | 
    	else { | 
    
    
    1858  | 
     | 
     | 
    		struct ifac *p;  | 
    
    
    1859  | 
     | 
     | 
    		for (p = ifcp->ifc_addr; p; p = p->ifa_next) { | 
    
    
    1860  | 
     | 
     | 
    			if (p->ifa_next == ifa) { | 
    
    
    1861  | 
     | 
     | 
    				p->ifa_next = ifa->ifa_next;  | 
    
    
    1862  | 
     | 
     | 
    				break;  | 
    
    
    1863  | 
     | 
     | 
    			}  | 
    
    
    1864  | 
     | 
     | 
    		}  | 
    
    
    1865  | 
     | 
     | 
    	}  | 
    
    
    1866  | 
     | 
     | 
    	ifa->ifa_next = NULL;  | 
    
    
    1867  | 
     | 
     | 
    	ifa->ifa_conf = NULL;  | 
    
    
    1868  | 
     | 
     | 
    	t_lifetime = time(NULL) - RIP_LIFETIME;  | 
    
    
    1869  | 
     | 
     | 
    	/* age route for interface address */  | 
    
    
    1870  | 
     | 
     | 
    	memset(&ni6, 0, sizeof(ni6));  | 
    
    
    1871  | 
     | 
     | 
    	ni6.rip6_dest = ifa->ifa_addr;  | 
    
    
    1872  | 
     | 
     | 
    	ni6.rip6_plen = ifa->ifa_plen;  | 
    
    
    1873  | 
     | 
     | 
    	applyplen(&ni6.rip6_dest, ni6.rip6_plen);  | 
    
    
    1874  | 
     | 
     | 
    	log_debug("\tfind interface route %s/%d on %d", | 
    
    
    1875  | 
     | 
     | 
    		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);  | 
    
    
    1876  | 
     | 
     | 
    	if ((rrt = rtsearch(&ni6, NULL)) != NULL) { | 
    
    
    1877  | 
     | 
     | 
    		struct in6_addr none;  | 
    
    
    1878  | 
     | 
     | 
    		memset(&none, 0, sizeof(none));  | 
    
    
    1879  | 
     | 
     | 
    		if (rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    1880  | 
     | 
     | 
    		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||  | 
    
    
    1881  | 
     | 
     | 
    		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { | 
    
    
    1882  | 
     | 
     | 
    			log_debug("\troute found, age it"); | 
    
    
    1883  | 
     | 
     | 
    			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { | 
    
    
    1884  | 
     | 
     | 
    				rrt->rrt_t = t_lifetime;  | 
    
    
    1885  | 
     | 
     | 
    				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    1886  | 
     | 
     | 
    			}  | 
    
    
    1887  | 
     | 
     | 
    			updated++;  | 
    
    
    1888  | 
     | 
     | 
    		} else { | 
    
    
    1889  | 
     | 
     | 
    			log_debug("\tnon-interface route found: %s/%d on %d", | 
    
    
    1890  | 
     | 
     | 
    				inet6_n2p(&rrt->rrt_info.rip6_dest),  | 
    
    
    1891  | 
     | 
     | 
    				rrt->rrt_info.rip6_plen,  | 
    
    
    1892  | 
     | 
     | 
    				rrt->rrt_index);  | 
    
    
    1893  | 
     | 
     | 
    		}  | 
    
    
    1894  | 
     | 
     | 
    	} else  | 
    
    
    1895  | 
     | 
     | 
    		log_debug("\tno interface route found"); | 
    
    
    1896  | 
     | 
     | 
    	/* age route for p2p destination */  | 
    
    
    1897  | 
     | 
     | 
    	if (ifcp->ifc_flags & IFF_POINTOPOINT) { | 
    
    
    1898  | 
     | 
     | 
    		memset(&ni6, 0, sizeof(ni6));  | 
    
    
    1899  | 
     | 
     | 
    		ni6.rip6_dest = ifa->ifa_raddr;  | 
    
    
    1900  | 
     | 
     | 
    		ni6.rip6_plen = 128;  | 
    
    
    1901  | 
     | 
     | 
    		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/  | 
    
    
    1902  | 
     | 
     | 
    		log_debug("\tfind p2p route %s/%d on %d", | 
    
    
    1903  | 
     | 
     | 
    			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,  | 
    
    
    1904  | 
     | 
     | 
    			ifcp->ifc_index);  | 
    
    
    1905  | 
     | 
     | 
    		if ((rrt = rtsearch(&ni6, NULL)) != NULL) { | 
    
    
    1906  | 
     | 
     | 
    			if (rrt->rrt_index == ifcp->ifc_index &&  | 
    
    
    1907  | 
     | 
     | 
    			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { | 
    
    
    1908  | 
     | 
     | 
    				log_debug("\troute found, age it"); | 
    
    
    1909  | 
     | 
     | 
    				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { | 
    
    
    1910  | 
     | 
     | 
    					rrt->rrt_t = t_lifetime;  | 
    
    
    1911  | 
     | 
     | 
    					rrt->rrt_info.rip6_metric =  | 
    
    
    1912  | 
     | 
     | 
    					    HOPCNT_INFINITY6;  | 
    
    
    1913  | 
     | 
     | 
    					updated++;  | 
    
    
    1914  | 
     | 
     | 
    				}  | 
    
    
    1915  | 
     | 
     | 
    			} else { | 
    
    
    1916  | 
     | 
     | 
    				log_debug("\tnon-p2p route found: %s/%d on %d", | 
    
    
    1917  | 
     | 
     | 
    					inet6_n2p(&rrt->rrt_info.rip6_dest),  | 
    
    
    1918  | 
     | 
     | 
    					rrt->rrt_info.rip6_plen,  | 
    
    
    1919  | 
     | 
     | 
    					rrt->rrt_index);  | 
    
    
    1920  | 
     | 
     | 
    			}  | 
    
    
    1921  | 
     | 
     | 
    		} else  | 
    
    
    1922  | 
     | 
     | 
    			log_debug("\tno p2p route found"); | 
    
    
    1923  | 
     | 
     | 
    	}  | 
    
    
    1924  | 
     | 
     | 
    	return updated ? 0 : -1;  | 
    
    
    1925  | 
     | 
     | 
    }  | 
    
    
    1926  | 
     | 
     | 
     | 
    
    
    1927  | 
     | 
     | 
    /*  | 
    
    
    1928  | 
     | 
     | 
     * Get each interface address and put those interface routes to the route  | 
    
    
    1929  | 
     | 
     | 
     * list.  | 
    
    
    1930  | 
     | 
     | 
     */  | 
    
    
    1931  | 
     | 
     | 
    int  | 
    
    
    1932  | 
     | 
     | 
    ifrt(struct ifc *ifcp, int again)  | 
    
    
    1933  | 
     | 
     | 
    { | 
    
    
    1934  | 
     | 
     | 
    	struct ifac *ifa;  | 
    
    
    1935  | 
     | 
     | 
    	struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt;  | 
    
    
    1936  | 
     | 
     | 
    	struct netinfo6 *np;  | 
    
    
    1937  | 
     | 
     | 
    	time_t t_lifetime;  | 
    
    
    1938  | 
     | 
     | 
    	int need_trigger = 0;  | 
    
    
    1939  | 
     | 
     | 
     | 
    
    
    1940  | 
     | 
     | 
    #if 0  | 
    
    
    1941  | 
     | 
     | 
    	if (ifcp->ifc_flags & IFF_LOOPBACK)  | 
    
    
    1942  | 
     | 
     | 
    		return 0;			/* ignore loopback */  | 
    
    
    1943  | 
     | 
     | 
    #endif  | 
    
    
    1944  | 
     | 
     | 
     | 
    
    
    1945  | 
     | 
     | 
    	if (ifcp->ifc_flags & IFF_POINTOPOINT) { | 
    
    
    1946  | 
     | 
     | 
    		ifrt_p2p(ifcp, again);  | 
    
    
    1947  | 
     | 
     | 
    		return 0;  | 
    
    
    1948  | 
     | 
     | 
    	}  | 
    
    
    1949  | 
     | 
     | 
     | 
    
    
    1950  | 
     | 
     | 
    	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { | 
    
    
    1951  | 
     | 
     | 
    		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { | 
    
    
    1952  | 
     | 
     | 
    #if 0  | 
    
    
    1953  | 
     | 
     | 
    			log_debug("route: %s on %s: " | 
    
    
    1954  | 
     | 
     | 
    			    "skip linklocal interface address",  | 
    
    
    1955  | 
     | 
     | 
    			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);  | 
    
    
    1956  | 
     | 
     | 
    #endif  | 
    
    
    1957  | 
     | 
     | 
    			continue;  | 
    
    
    1958  | 
     | 
     | 
    		}  | 
    
    
    1959  | 
     | 
     | 
    		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { | 
    
    
    1960  | 
     | 
     | 
    #if 0  | 
    
    
    1961  | 
     | 
     | 
    			log_debug("route: %s: skip unspec interface address", | 
    
    
    1962  | 
     | 
     | 
    			    ifcp->ifc_name);  | 
    
    
    1963  | 
     | 
     | 
    #endif  | 
    
    
    1964  | 
     | 
     | 
    			continue;  | 
    
    
    1965  | 
     | 
     | 
    		}  | 
    
    
    1966  | 
     | 
     | 
    		if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) { | 
    
    
    1967  | 
     | 
     | 
    #if 0  | 
    
    
    1968  | 
     | 
     | 
    			log_debug("route: %s: skip loopback address", | 
    
    
    1969  | 
     | 
     | 
    			    ifcp->ifc_name);  | 
    
    
    1970  | 
     | 
     | 
    #endif  | 
    
    
    1971  | 
     | 
     | 
    			continue;  | 
    
    
    1972  | 
     | 
     | 
    		}  | 
    
    
    1973  | 
     | 
     | 
    		if (ifcp->ifc_flags & IFF_UP) { | 
    
    
    1974  | 
     | 
     | 
    			if ((rrt = calloc(1, sizeof(struct riprt))) == NULL)  | 
    
    
    1975  | 
     | 
     | 
    				fatal("calloc: struct riprt"); | 
    
    
    1976  | 
     | 
     | 
    			rrt->rrt_index = ifcp->ifc_index;  | 
    
    
    1977  | 
     | 
     | 
    			rrt->rrt_t = 0;	/* don't age */  | 
    
    
    1978  | 
     | 
     | 
    			rrt->rrt_info.rip6_dest = ifa->ifa_addr;  | 
    
    
    1979  | 
     | 
     | 
    			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);  | 
    
    
    1980  | 
     | 
     | 
    			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;  | 
    
    
    1981  | 
     | 
     | 
    			rrt->rrt_info.rip6_plen = ifa->ifa_plen;  | 
    
    
    1982  | 
     | 
     | 
    			if (ifa->ifa_plen == 128)  | 
    
    
    1983  | 
     | 
     | 
    				rrt->rrt_flags = RTF_HOST;  | 
    
    
    1984  | 
     | 
     | 
    			else  | 
    
    
    1985  | 
     | 
     | 
    				rrt->rrt_flags = RTF_CLONING;  | 
    
    
    1986  | 
     | 
     | 
    			rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    1987  | 
     | 
     | 
    			applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);  | 
    
    
    1988  | 
     | 
     | 
    			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));  | 
    
    
    1989  | 
     | 
     | 
    			rrt->rrt_gw = ifa->ifa_addr;  | 
    
    
    1990  | 
     | 
     | 
    			np = &rrt->rrt_info;  | 
    
    
    1991  | 
     | 
     | 
    			search_rrt = rtsearch(np, &prev_rrt);  | 
    
    
    1992  | 
     | 
     | 
    			if (search_rrt != NULL) { | 
    
    
    1993  | 
     | 
     | 
    				if (search_rrt->rrt_info.rip6_metric <=  | 
    
    
    1994  | 
     | 
     | 
    				    rrt->rrt_info.rip6_metric) { | 
    
    
    1995  | 
     | 
     | 
    					/* Already have better route */  | 
    
    
    1996  | 
     | 
     | 
    					if (!again) { | 
    
    
    1997  | 
     | 
     | 
    						log_debug("route: %s/%d: " | 
    
    
    1998  | 
     | 
     | 
    						    "already registered (%s)",  | 
    
    
    1999  | 
     | 
     | 
    						    inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2000  | 
     | 
     | 
    						    ifcp->ifc_name);  | 
    
    
    2001  | 
     | 
     | 
    					}  | 
    
    
    2002  | 
     | 
     | 
    					goto next;  | 
    
    
    2003  | 
     | 
     | 
    				}  | 
    
    
    2004  | 
     | 
     | 
     | 
    
    
    2005  | 
     | 
     | 
    				if (prev_rrt)  | 
    
    
    2006  | 
     | 
     | 
    					prev_rrt->rrt_next = rrt->rrt_next;  | 
    
    
    2007  | 
     | 
     | 
    				else  | 
    
    
    2008  | 
     | 
     | 
    					riprt = rrt->rrt_next;  | 
    
    
    2009  | 
     | 
     | 
    				delroute(&rrt->rrt_info, &rrt->rrt_gw);  | 
    
    
    2010  | 
     | 
     | 
    			}  | 
    
    
    2011  | 
     | 
     | 
    			/* Attach the route to the list */  | 
    
    
    2012  | 
     | 
     | 
    			log_debug("route: %s/%d: register route (%s)", | 
    
    
    2013  | 
     | 
     | 
    			    inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2014  | 
     | 
     | 
    			    ifcp->ifc_name);  | 
    
    
    2015  | 
     | 
     | 
    			rrt->rrt_next = riprt;  | 
    
    
    2016  | 
     | 
     | 
    			riprt = rrt;  | 
    
    
    2017  | 
     | 
     | 
    			addroute(rrt, &rrt->rrt_gw, ifcp);  | 
    
    
    2018  | 
     | 
     | 
    			rrt = NULL;  | 
    
    
    2019  | 
     | 
     | 
    			sendrequest(ifcp);  | 
    
    
    2020  | 
     | 
     | 
    			ripsend(ifcp, &ifcp->ifc_ripsin, 0);  | 
    
    
    2021  | 
     | 
     | 
    			need_trigger = 1;  | 
    
    
    2022  | 
     | 
     | 
    		} else { | 
    
    
    2023  | 
     | 
     | 
    			for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { | 
    
    
    2024  | 
     | 
     | 
    				if (loop_rrt->rrt_index == ifcp->ifc_index) { | 
    
    
    2025  | 
     | 
     | 
    					t_lifetime = time(NULL) - RIP_LIFETIME;  | 
    
    
    2026  | 
     | 
     | 
    					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { | 
    
    
    2027  | 
     | 
     | 
    						loop_rrt->rrt_t = t_lifetime;  | 
    
    
    2028  | 
     | 
     | 
    						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;  | 
    
    
    2029  | 
     | 
     | 
    						loop_rrt->rrt_rflags |= RRTF_CHANGED;  | 
    
    
    2030  | 
     | 
     | 
    						need_trigger = 1;  | 
    
    
    2031  | 
     | 
     | 
    					}  | 
    
    
    2032  | 
     | 
     | 
    				}  | 
    
    
    2033  | 
     | 
     | 
    			}  | 
    
    
    2034  | 
     | 
     | 
                    }  | 
    
    
    2035  | 
     | 
     | 
    	next:  | 
    
    
    2036  | 
     | 
     | 
    		free(rrt);  | 
    
    
    2037  | 
     | 
     | 
    	}  | 
    
    
    2038  | 
     | 
     | 
    	return need_trigger;  | 
    
    
    2039  | 
     | 
     | 
    }  | 
    
    
    2040  | 
     | 
     | 
     | 
    
    
    2041  | 
     | 
     | 
    /*  | 
    
    
    2042  | 
     | 
     | 
     * there are couple of p2p interface routing models.  "behavior" lets  | 
    
    
    2043  | 
     | 
     | 
     * you pick one.  it looks that gated behavior fits best with BSDs,  | 
    
    
    2044  | 
     | 
     | 
     * since BSD kernels do not look at prefix length on p2p interfaces.  | 
    
    
    2045  | 
     | 
     | 
     */  | 
    
    
    2046  | 
     | 
     | 
    void  | 
    
    
    2047  | 
     | 
     | 
    ifrt_p2p(struct ifc *ifcp, int again)  | 
    
    
    2048  | 
     | 
     | 
    { | 
    
    
    2049  | 
     | 
     | 
    	struct ifac *ifa;  | 
    
    
    2050  | 
     | 
     | 
    	struct riprt *rrt, *orrt, *prevrrt;  | 
    
    
    2051  | 
     | 
     | 
    	struct netinfo6 *np;  | 
    
    
    2052  | 
     | 
     | 
    	struct in6_addr addr, dest;  | 
    
    
    2053  | 
     | 
     | 
    	int advert, ignore, i;  | 
    
    
    2054  | 
     | 
     | 
    #define P2PADVERT_NETWORK	1  | 
    
    
    2055  | 
     | 
     | 
    #define P2PADVERT_ADDR		2  | 
    
    
    2056  | 
     | 
     | 
    #define P2PADVERT_DEST		4  | 
    
    
    2057  | 
     | 
     | 
    #define P2PADVERT_MAX		4  | 
    
    
    2058  | 
     | 
     | 
    	const enum { CISCO, GATED, ROUTE6D } behavior = GATED; | 
    
    
    2059  | 
     | 
     | 
    	const char *category = "";  | 
    
    
    2060  | 
     | 
     | 
    	const char *noadv;  | 
    
    
    2061  | 
     | 
     | 
     | 
    
    
    2062  | 
     | 
     | 
    	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { | 
    
    
    2063  | 
     | 
     | 
    		addr = ifa->ifa_addr;  | 
    
    
    2064  | 
     | 
     | 
    		dest = ifa->ifa_raddr;  | 
    
    
    2065  | 
     | 
     | 
    		applyplen(&addr, ifa->ifa_plen);  | 
    
    
    2066  | 
     | 
     | 
    		applyplen(&dest, ifa->ifa_plen);  | 
    
    
    2067  | 
     | 
     | 
    		advert = ignore = 0;  | 
    
    
    2068  | 
     | 
     | 
    		switch (behavior) { | 
    
    
    2069  | 
     | 
     | 
    		case CISCO:  | 
    
    
    2070  | 
     | 
     | 
    			/*  | 
    
    
    2071  | 
     | 
     | 
    			 * honor addr/plen, just like normal shared medium  | 
    
    
    2072  | 
     | 
     | 
    			 * interface.  this may cause trouble if you reuse  | 
    
    
    2073  | 
     | 
     | 
    			 * addr/plen on other interfaces.  | 
    
    
    2074  | 
     | 
     | 
    			 *  | 
    
    
    2075  | 
     | 
     | 
    			 * advertise addr/plen.  | 
    
    
    2076  | 
     | 
     | 
    			 */  | 
    
    
    2077  | 
     | 
     | 
    			advert |= P2PADVERT_NETWORK;  | 
    
    
    2078  | 
     | 
     | 
    			break;  | 
    
    
    2079  | 
     | 
     | 
    		case GATED:  | 
    
    
    2080  | 
     | 
     | 
    			/*  | 
    
    
    2081  | 
     | 
     | 
    			 * prefixlen on p2p interface is meaningless.  | 
    
    
    2082  | 
     | 
     | 
    			 * advertise addr/128 and dest/128.  | 
    
    
    2083  | 
     | 
     | 
    			 *  | 
    
    
    2084  | 
     | 
     | 
    			 * do not install network route to route6d routing  | 
    
    
    2085  | 
     | 
     | 
    			 * table (if we do, it would prevent route installation  | 
    
    
    2086  | 
     | 
     | 
    			 * for other p2p interface that shares addr/plen).  | 
    
    
    2087  | 
     | 
     | 
    			 *  | 
    
    
    2088  | 
     | 
     | 
    			 * XXX what should we do if dest is ::?  it will not  | 
    
    
    2089  | 
     | 
     | 
    			 * get announced anyways (see following filter),  | 
    
    
    2090  | 
     | 
     | 
    			 * but we need to think.  | 
    
    
    2091  | 
     | 
     | 
    			 */  | 
    
    
    2092  | 
     | 
     | 
    			advert |= P2PADVERT_ADDR;  | 
    
    
    2093  | 
     | 
     | 
    			advert |= P2PADVERT_DEST;  | 
    
    
    2094  | 
     | 
     | 
    			ignore |= P2PADVERT_NETWORK;  | 
    
    
    2095  | 
     | 
     | 
    			break;  | 
    
    
    2096  | 
     | 
     | 
    		case ROUTE6D:  | 
    
    
    2097  | 
     | 
     | 
    			/*  | 
    
    
    2098  | 
     | 
     | 
    			 * just for testing.  actually the code is redundant  | 
    
    
    2099  | 
     | 
     | 
    			 * given the current p2p interface address assignment  | 
    
    
    2100  | 
     | 
     | 
    			 * rule for kame kernel.  | 
    
    
    2101  | 
     | 
     | 
    			 *  | 
    
    
    2102  | 
     | 
     | 
    			 * intent:  | 
    
    
    2103  | 
     | 
     | 
    			 *	A/n -> announce A/n  | 
    
    
    2104  | 
     | 
     | 
    			 *	A B/n, A and B share prefix -> A/n (= B/n)  | 
    
    
    2105  | 
     | 
     | 
    			 *	A B/n, do not share prefix -> A/128 and B/128  | 
    
    
    2106  | 
     | 
     | 
    			 * actually, A/64 and A B/128 are the only cases  | 
    
    
    2107  | 
     | 
     | 
    			 * permitted by the kernel:  | 
    
    
    2108  | 
     | 
     | 
    			 *	A/64 -> A/64  | 
    
    
    2109  | 
     | 
     | 
    			 *	A B/128 -> A/128 and B/128  | 
    
    
    2110  | 
     | 
     | 
    			 */  | 
    
    
    2111  | 
     | 
     | 
    			if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { | 
    
    
    2112  | 
     | 
     | 
    				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))  | 
    
    
    2113  | 
     | 
     | 
    					advert |= P2PADVERT_NETWORK;  | 
    
    
    2114  | 
     | 
     | 
    				else { | 
    
    
    2115  | 
     | 
     | 
    					advert |= P2PADVERT_ADDR;  | 
    
    
    2116  | 
     | 
     | 
    					advert |= P2PADVERT_DEST;  | 
    
    
    2117  | 
     | 
     | 
    					ignore |= P2PADVERT_NETWORK;  | 
    
    
    2118  | 
     | 
     | 
    				}  | 
    
    
    2119  | 
     | 
     | 
    			} else  | 
    
    
    2120  | 
     | 
     | 
    				advert |= P2PADVERT_NETWORK;  | 
    
    
    2121  | 
     | 
     | 
    			break;  | 
    
    
    2122  | 
     | 
     | 
    		}  | 
    
    
    2123  | 
     | 
     | 
     | 
    
    
    2124  | 
     | 
     | 
    		for (i = 1; i <= P2PADVERT_MAX; i *= 2) { | 
    
    
    2125  | 
     | 
     | 
    			if ((ignore & i) != 0)  | 
    
    
    2126  | 
     | 
     | 
    				continue;  | 
    
    
    2127  | 
     | 
     | 
    			if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { | 
    
    
    2128  | 
     | 
     | 
    				fatal("calloc: struct riprt"); | 
    
    
    2129  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    2130  | 
     | 
     | 
    			}  | 
    
    
    2131  | 
     | 
     | 
    			rrt->rrt_index = ifcp->ifc_index;  | 
    
    
    2132  | 
     | 
     | 
    			rrt->rrt_t = 0;	/* don't age */  | 
    
    
    2133  | 
     | 
     | 
    			switch (i) { | 
    
    
    2134  | 
     | 
     | 
    			case P2PADVERT_NETWORK:  | 
    
    
    2135  | 
     | 
     | 
    				rrt->rrt_info.rip6_dest = ifa->ifa_addr;  | 
    
    
    2136  | 
     | 
     | 
    				rrt->rrt_info.rip6_plen = ifa->ifa_plen;  | 
    
    
    2137  | 
     | 
     | 
    				applyplen(&rrt->rrt_info.rip6_dest,  | 
    
    
    2138  | 
     | 
     | 
    				    ifa->ifa_plen);  | 
    
    
    2139  | 
     | 
     | 
    				category = "network";  | 
    
    
    2140  | 
     | 
     | 
    				break;  | 
    
    
    2141  | 
     | 
     | 
    			case P2PADVERT_ADDR:  | 
    
    
    2142  | 
     | 
     | 
    				rrt->rrt_info.rip6_dest = ifa->ifa_addr;  | 
    
    
    2143  | 
     | 
     | 
    				rrt->rrt_info.rip6_plen = 128;  | 
    
    
    2144  | 
     | 
     | 
    				rrt->rrt_gw = in6addr_loopback;  | 
    
    
    2145  | 
     | 
     | 
    				category = "addr";  | 
    
    
    2146  | 
     | 
     | 
    				break;  | 
    
    
    2147  | 
     | 
     | 
    			case P2PADVERT_DEST:  | 
    
    
    2148  | 
     | 
     | 
    				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;  | 
    
    
    2149  | 
     | 
     | 
    				rrt->rrt_info.rip6_plen = 128;  | 
    
    
    2150  | 
     | 
     | 
    				rrt->rrt_gw = ifa->ifa_addr;  | 
    
    
    2151  | 
     | 
     | 
    				category = "dest";  | 
    
    
    2152  | 
     | 
     | 
    				break;  | 
    
    
    2153  | 
     | 
     | 
    			}  | 
    
    
    2154  | 
     | 
     | 
    			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||  | 
    
    
    2155  | 
     | 
     | 
    			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { | 
    
    
    2156  | 
     | 
     | 
    #if 0  | 
    
    
    2157  | 
     | 
     | 
    				log_debug("route: %s: skip unspec/linklocal " | 
    
    
    2158  | 
     | 
     | 
    				    "(%s on %s)", category, ifcp->ifc_name);  | 
    
    
    2159  | 
     | 
     | 
    #endif  | 
    
    
    2160  | 
     | 
     | 
    				free(rrt);  | 
    
    
    2161  | 
     | 
     | 
    				continue;  | 
    
    
    2162  | 
     | 
     | 
    			}  | 
    
    
    2163  | 
     | 
     | 
    			if ((advert & i) == 0) { | 
    
    
    2164  | 
     | 
     | 
    				rrt->rrt_rflags |= RRTF_NOADVERTISE;  | 
    
    
    2165  | 
     | 
     | 
    				noadv = ", NO-ADV";  | 
    
    
    2166  | 
     | 
     | 
    			} else  | 
    
    
    2167  | 
     | 
     | 
    				noadv = "";  | 
    
    
    2168  | 
     | 
     | 
    			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);  | 
    
    
    2169  | 
     | 
     | 
    			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;  | 
    
    
    2170  | 
     | 
     | 
    			np = &rrt->rrt_info;  | 
    
    
    2171  | 
     | 
     | 
    			orrt = rtsearch(np, &prevrrt);  | 
    
    
    2172  | 
     | 
     | 
    			if (!orrt) { | 
    
    
    2173  | 
     | 
     | 
    				/* Attach the route to the list */  | 
    
    
    2174  | 
     | 
     | 
    				log_debug("route: %s/%d: register route " | 
    
    
    2175  | 
     | 
     | 
    				    "(%s on %s%s)",  | 
    
    
    2176  | 
     | 
     | 
    				    inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2177  | 
     | 
     | 
    				    category, ifcp->ifc_name, noadv);  | 
    
    
    2178  | 
     | 
     | 
    				rrt->rrt_next = riprt;  | 
    
    
    2179  | 
     | 
     | 
    				riprt = rrt;  | 
    
    
    2180  | 
     | 
     | 
    			} else if (rrt->rrt_index != orrt->rrt_index ||  | 
    
    
    2181  | 
     | 
     | 
    			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { | 
    
    
    2182  | 
     | 
     | 
    				/* swap route */  | 
    
    
    2183  | 
     | 
     | 
    				rrt->rrt_next = orrt->rrt_next;  | 
    
    
    2184  | 
     | 
     | 
    				if (prevrrt)  | 
    
    
    2185  | 
     | 
     | 
    					prevrrt->rrt_next = rrt;  | 
    
    
    2186  | 
     | 
     | 
    				else  | 
    
    
    2187  | 
     | 
     | 
    					riprt = rrt;  | 
    
    
    2188  | 
     | 
     | 
    				free(orrt);  | 
    
    
    2189  | 
     | 
     | 
     | 
    
    
    2190  | 
     | 
     | 
    				log_debug("route: %s/%d: update (%s on %s%s)", | 
    
    
    2191  | 
     | 
     | 
    				    inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2192  | 
     | 
     | 
    				    category, ifcp->ifc_name, noadv);  | 
    
    
    2193  | 
     | 
     | 
    			} else { | 
    
    
    2194  | 
     | 
     | 
    				/* Already found */  | 
    
    
    2195  | 
     | 
     | 
    				if (!again) { | 
    
    
    2196  | 
     | 
     | 
    					log_debug("route: %s/%d: " | 
    
    
    2197  | 
     | 
     | 
    					    "already registered (%s on %s%s)",  | 
    
    
    2198  | 
     | 
     | 
    					    inet6_n2p(&np->rip6_dest),  | 
    
    
    2199  | 
     | 
     | 
    					    np->rip6_plen, category,  | 
    
    
    2200  | 
     | 
     | 
    					    ifcp->ifc_name, noadv);  | 
    
    
    2201  | 
     | 
     | 
    				}  | 
    
    
    2202  | 
     | 
     | 
    				free(rrt);  | 
    
    
    2203  | 
     | 
     | 
    			}  | 
    
    
    2204  | 
     | 
     | 
    		}  | 
    
    
    2205  | 
     | 
     | 
    	}  | 
    
    
    2206  | 
     | 
     | 
    #undef P2PADVERT_NETWORK  | 
    
    
    2207  | 
     | 
     | 
    #undef P2PADVERT_ADDR  | 
    
    
    2208  | 
     | 
     | 
    #undef P2PADVERT_DEST  | 
    
    
    2209  | 
     | 
     | 
    #undef P2PADVERT_MAX  | 
    
    
    2210  | 
     | 
     | 
    }  | 
    
    
    2211  | 
     | 
     | 
     | 
    
    
    2212  | 
     | 
     | 
    int  | 
    
    
    2213  | 
     | 
     | 
    getifmtu(int ifindex)  | 
    
    
    2214  | 
     | 
     | 
    { | 
    
    
    2215  | 
     | 
     | 
    	int	mib[6];  | 
    
    
    2216  | 
     | 
     | 
    	char	*buf = NULL;  | 
    
    
    2217  | 
     | 
     | 
    	size_t	needed;  | 
    
    
    2218  | 
     | 
     | 
    	struct	if_msghdr *ifm;  | 
    
    
    2219  | 
     | 
     | 
    	int	mtu;  | 
    
    
    2220  | 
     | 
     | 
     | 
    
    
    2221  | 
     | 
     | 
    	mib[0] = CTL_NET;  | 
    
    
    2222  | 
     | 
     | 
    	mib[1] = PF_ROUTE;  | 
    
    
    2223  | 
     | 
     | 
    	mib[2] = 0;  | 
    
    
    2224  | 
     | 
     | 
    	mib[3] = AF_INET6;  | 
    
    
    2225  | 
     | 
     | 
    	mib[4] = NET_RT_IFLIST;  | 
    
    
    2226  | 
     | 
     | 
    	mib[5] = ifindex;  | 
    
    
    2227  | 
     | 
     | 
    	while (1) { | 
    
    
    2228  | 
     | 
     | 
    		if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)  | 
    
    
    2229  | 
     | 
     | 
    			fatal("sysctl estimate NET_RT_IFLIST"); | 
    
    
    2230  | 
     | 
     | 
    		if (needed == 0)  | 
    
    
    2231  | 
     | 
     | 
    			break;  | 
    
    
    2232  | 
     | 
     | 
    		if ((buf = realloc(buf, needed)) == NULL)  | 
    
    
    2233  | 
     | 
     | 
    			fatal(NULL);  | 
    
    
    2234  | 
     | 
     | 
    		if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { | 
    
    
    2235  | 
     | 
     | 
    			if (errno == ENOMEM)  | 
    
    
    2236  | 
     | 
     | 
    				continue;  | 
    
    
    2237  | 
     | 
     | 
    			fatal("sysctl NET_RT_IFLIST"); | 
    
    
    2238  | 
     | 
     | 
    		}  | 
    
    
    2239  | 
     | 
     | 
    		break;  | 
    
    
    2240  | 
     | 
     | 
    	}  | 
    
    
    2241  | 
     | 
     | 
    	ifm = (struct if_msghdr *)buf;  | 
    
    
    2242  | 
     | 
     | 
    	mtu = ifm->ifm_data.ifi_mtu;  | 
    
    
    2243  | 
     | 
     | 
    	free(buf);  | 
    
    
    2244  | 
     | 
     | 
    	return mtu;  | 
    
    
    2245  | 
     | 
     | 
    }  | 
    
    
    2246  | 
     | 
     | 
     | 
    
    
    2247  | 
     | 
     | 
    const char *  | 
    
    
    2248  | 
     | 
     | 
    rttypes(struct rt_msghdr *rtm)  | 
    
    
    2249  | 
     | 
     | 
    { | 
    
    
    2250  | 
     | 
     | 
    #define	RTTYPE(s, f) \  | 
    
    
    2251  | 
     | 
     | 
    do { \ | 
    
    
    2252  | 
     | 
     | 
    	if (rtm->rtm_type == (f)) \  | 
    
    
    2253  | 
     | 
     | 
    		return (s); \  | 
    
    
    2254  | 
     | 
     | 
    } while (0)  | 
    
    
    2255  | 
     | 
     | 
    	RTTYPE("ADD", RTM_ADD); | 
    
    
    2256  | 
     | 
     | 
    	RTTYPE("DELETE", RTM_DELETE); | 
    
    
    2257  | 
     | 
     | 
    	RTTYPE("CHANGE", RTM_CHANGE); | 
    
    
    2258  | 
     | 
     | 
    	RTTYPE("GET", RTM_GET); | 
    
    
    2259  | 
     | 
     | 
    	RTTYPE("LOSING", RTM_LOSING); | 
    
    
    2260  | 
     | 
     | 
    	RTTYPE("REDIRECT", RTM_REDIRECT); | 
    
    
    2261  | 
     | 
     | 
    	RTTYPE("MISS", RTM_MISS); | 
    
    
    2262  | 
     | 
     | 
    	RTTYPE("LOCK", RTM_LOCK); | 
    
    
    2263  | 
     | 
     | 
    	RTTYPE("RESOLVE", RTM_RESOLVE); | 
    
    
    2264  | 
     | 
     | 
    	RTTYPE("NEWADDR", RTM_NEWADDR); | 
    
    
    2265  | 
     | 
     | 
    	RTTYPE("DELADDR", RTM_DELADDR); | 
    
    
    2266  | 
     | 
     | 
    	RTTYPE("IFINFO", RTM_IFINFO); | 
    
    
    2267  | 
     | 
     | 
    #ifdef RTM_OIFINFO  | 
    
    
    2268  | 
     | 
     | 
    	RTTYPE("OIFINFO", RTM_OIFINFO); | 
    
    
    2269  | 
     | 
     | 
    #endif  | 
    
    
    2270  | 
     | 
     | 
    #ifdef RTM_IFANNOUNCE  | 
    
    
    2271  | 
     | 
     | 
    	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); | 
    
    
    2272  | 
     | 
     | 
    #endif  | 
    
    
    2273  | 
     | 
     | 
    #ifdef RTM_NEWMADDR  | 
    
    
    2274  | 
     | 
     | 
    	RTTYPE("NEWMADDR", RTM_NEWMADDR); | 
    
    
    2275  | 
     | 
     | 
    #endif  | 
    
    
    2276  | 
     | 
     | 
    #ifdef RTM_DELMADDR  | 
    
    
    2277  | 
     | 
     | 
    	RTTYPE("DELMADDR", RTM_DELMADDR); | 
    
    
    2278  | 
     | 
     | 
    #endif  | 
    
    
    2279  | 
     | 
     | 
    #undef RTTYPE  | 
    
    
    2280  | 
     | 
     | 
    	return NULL;  | 
    
    
    2281  | 
     | 
     | 
    }  | 
    
    
    2282  | 
     | 
     | 
     | 
    
    
    2283  | 
     | 
     | 
    const char *  | 
    
    
    2284  | 
     | 
     | 
    rtflags(struct rt_msghdr *rtm)  | 
    
    
    2285  | 
     | 
     | 
    { | 
    
    
    2286  | 
     | 
     | 
    	static char buf[BUFSIZ];  | 
    
    
    2287  | 
     | 
     | 
     | 
    
    
    2288  | 
     | 
     | 
    	/*  | 
    
    
    2289  | 
     | 
     | 
    	 * letter conflict should be okay.  painful when *BSD diverges...  | 
    
    
    2290  | 
     | 
     | 
    	 */  | 
    
    
    2291  | 
     | 
     | 
    	strlcpy(buf, "", sizeof(buf));  | 
    
    
    2292  | 
     | 
     | 
    #define	RTFLAG(s, f) \  | 
    
    
    2293  | 
     | 
     | 
    do { \ | 
    
    
    2294  | 
     | 
     | 
    	if (rtm->rtm_flags & (f)) \  | 
    
    
    2295  | 
     | 
     | 
    		strlcat(buf, (s), sizeof(buf)); \  | 
    
    
    2296  | 
     | 
     | 
    } while (0)  | 
    
    
    2297  | 
     | 
     | 
    	RTFLAG("U", RTF_UP); | 
    
    
    2298  | 
     | 
     | 
    	RTFLAG("G", RTF_GATEWAY); | 
    
    
    2299  | 
     | 
     | 
    	RTFLAG("H", RTF_HOST); | 
    
    
    2300  | 
     | 
     | 
    	RTFLAG("R", RTF_REJECT); | 
    
    
    2301  | 
     | 
     | 
    	RTFLAG("D", RTF_DYNAMIC); | 
    
    
    2302  | 
     | 
     | 
    	RTFLAG("M", RTF_MODIFIED); | 
    
    
    2303  | 
     | 
     | 
    	RTFLAG("d", RTF_DONE); | 
    
    
    2304  | 
     | 
     | 
    	RTFLAG("m", RTF_MULTICAST); | 
    
    
    2305  | 
     | 
     | 
    	RTFLAG("C", RTF_CLONING); | 
    
    
    2306  | 
     | 
     | 
    	RTFLAG("c", RTF_CLONED); | 
    
    
    2307  | 
     | 
     | 
    	RTFLAG("L", RTF_LLINFO); | 
    
    
    2308  | 
     | 
     | 
    	RTFLAG("S", RTF_STATIC); | 
    
    
    2309  | 
     | 
     | 
    	RTFLAG("B", RTF_BLACKHOLE); | 
    
    
    2310  | 
     | 
     | 
    	RTFLAG("3", RTF_PROTO3); | 
    
    
    2311  | 
     | 
     | 
    	RTFLAG("2", RTF_PROTO2); | 
    
    
    2312  | 
     | 
     | 
    	RTFLAG("1", RTF_PROTO1); | 
    
    
    2313  | 
     | 
     | 
    	RTFLAG("b", RTF_BROADCAST); | 
    
    
    2314  | 
     | 
     | 
    #undef RTFLAG  | 
    
    
    2315  | 
     | 
     | 
    	return buf;  | 
    
    
    2316  | 
     | 
     | 
    }  | 
    
    
    2317  | 
     | 
     | 
     | 
    
    
    2318  | 
     | 
     | 
    const char *  | 
    
    
    2319  | 
     | 
     | 
    ifflags(int flags)  | 
    
    
    2320  | 
     | 
     | 
    { | 
    
    
    2321  | 
     | 
     | 
    	static char buf[BUFSIZ];  | 
    
    
    2322  | 
     | 
     | 
     | 
    
    
    2323  | 
     | 
     | 
    	strlcpy(buf, "", sizeof(buf));  | 
    
    
    2324  | 
     | 
     | 
    #define	IFFLAG(s, f) \  | 
    
    
    2325  | 
     | 
     | 
    do { \ | 
    
    
    2326  | 
     | 
     | 
    	if (flags & (f)) { \ | 
    
    
    2327  | 
     | 
     | 
    		if (buf[0]) \  | 
    
    
    2328  | 
     | 
     | 
    			strlcat(buf, ",", sizeof(buf)); \  | 
    
    
    2329  | 
     | 
     | 
    		strlcat(buf, (s), sizeof(buf)); \  | 
    
    
    2330  | 
     | 
     | 
    	} \  | 
    
    
    2331  | 
     | 
     | 
    } while (0)  | 
    
    
    2332  | 
     | 
     | 
    	IFFLAG("UP", IFF_UP); | 
    
    
    2333  | 
     | 
     | 
    	IFFLAG("BROADCAST", IFF_BROADCAST); | 
    
    
    2334  | 
     | 
     | 
    	IFFLAG("DEBUG", IFF_DEBUG); | 
    
    
    2335  | 
     | 
     | 
    	IFFLAG("LOOPBACK", IFF_LOOPBACK); | 
    
    
    2336  | 
     | 
     | 
    	IFFLAG("POINTOPOINT", IFF_POINTOPOINT); | 
    
    
    2337  | 
     | 
     | 
    #ifdef IFF_NOTRAILERS  | 
    
    
    2338  | 
     | 
     | 
    	IFFLAG("NOTRAILERS", IFF_NOTRAILERS); | 
    
    
    2339  | 
     | 
     | 
    #endif  | 
    
    
    2340  | 
     | 
     | 
    #ifdef IFF_SMART  | 
    
    
    2341  | 
     | 
     | 
    	IFFLAG("SMART", IFF_SMART); | 
    
    
    2342  | 
     | 
     | 
    #endif  | 
    
    
    2343  | 
     | 
     | 
    	IFFLAG("RUNNING", IFF_RUNNING); | 
    
    
    2344  | 
     | 
     | 
    	IFFLAG("NOARP", IFF_NOARP); | 
    
    
    2345  | 
     | 
     | 
    	IFFLAG("PROMISC", IFF_PROMISC); | 
    
    
    2346  | 
     | 
     | 
    	IFFLAG("ALLMULTI", IFF_ALLMULTI); | 
    
    
    2347  | 
     | 
     | 
    	IFFLAG("OACTIVE", IFF_OACTIVE); | 
    
    
    2348  | 
     | 
     | 
    	IFFLAG("SIMPLEX", IFF_SIMPLEX); | 
    
    
    2349  | 
     | 
     | 
    	IFFLAG("LINK0", IFF_LINK0); | 
    
    
    2350  | 
     | 
     | 
    	IFFLAG("LINK1", IFF_LINK1); | 
    
    
    2351  | 
     | 
     | 
    	IFFLAG("LINK2", IFF_LINK2); | 
    
    
    2352  | 
     | 
     | 
    	IFFLAG("MULTICAST", IFF_MULTICAST); | 
    
    
    2353  | 
     | 
     | 
    #undef IFFLAG  | 
    
    
    2354  | 
     | 
     | 
    	return buf;  | 
    
    
    2355  | 
     | 
     | 
    }  | 
    
    
    2356  | 
     | 
     | 
     | 
    
    
    2357  | 
     | 
     | 
    void  | 
    
    
    2358  | 
     | 
     | 
    krtread(int again)  | 
    
    
    2359  | 
     | 
     | 
    { | 
    
    
    2360  | 
     | 
     | 
    	int mib[6];  | 
    
    
    2361  | 
     | 
     | 
    	size_t msize;  | 
    
    
    2362  | 
     | 
     | 
    	char *buf, *p, *lim;  | 
    
    
    2363  | 
     | 
     | 
    	struct rt_msghdr *rtm;  | 
    
    
    2364  | 
     | 
     | 
    	int retry;  | 
    
    
    2365  | 
     | 
     | 
    	const char *errmsg;  | 
    
    
    2366  | 
     | 
     | 
     | 
    
    
    2367  | 
     | 
     | 
    	retry = 0;  | 
    
    
    2368  | 
     | 
     | 
    	buf = NULL;  | 
    
    
    2369  | 
     | 
     | 
    	mib[0] = CTL_NET;  | 
    
    
    2370  | 
     | 
     | 
    	mib[1] = PF_ROUTE;  | 
    
    
    2371  | 
     | 
     | 
    	mib[2] = 0;  | 
    
    
    2372  | 
     | 
     | 
    	mib[3] = AF_INET6;	/* Address family */  | 
    
    
    2373  | 
     | 
     | 
    	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */  | 
    
    
    2374  | 
     | 
     | 
    	mib[5] = 0;		/* No flags */  | 
    
    
    2375  | 
     | 
     | 
    	do { | 
    
    
    2376  | 
     | 
     | 
    		retry++;  | 
    
    
    2377  | 
     | 
     | 
    		free(buf);  | 
    
    
    2378  | 
     | 
     | 
    		buf = NULL;  | 
    
    
    2379  | 
     | 
     | 
    		errmsg = NULL;  | 
    
    
    2380  | 
     | 
     | 
    		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { | 
    
    
    2381  | 
     | 
     | 
    			errmsg = "sysctl estimate";  | 
    
    
    2382  | 
     | 
     | 
    			continue;  | 
    
    
    2383  | 
     | 
     | 
    		}  | 
    
    
    2384  | 
     | 
     | 
    		if ((buf = malloc(msize)) == NULL) { | 
    
    
    2385  | 
     | 
     | 
    			errmsg = "malloc";  | 
    
    
    2386  | 
     | 
     | 
    			continue;  | 
    
    
    2387  | 
     | 
     | 
    		}  | 
    
    
    2388  | 
     | 
     | 
    		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { | 
    
    
    2389  | 
     | 
     | 
    			errmsg = "sysctl NET_RT_DUMP";  | 
    
    
    2390  | 
     | 
     | 
    			continue;  | 
    
    
    2391  | 
     | 
     | 
    		}  | 
    
    
    2392  | 
     | 
     | 
    	} while (retry < 5 && errmsg != NULL);  | 
    
    
    2393  | 
     | 
     | 
    	if (errmsg) { | 
    
    
    2394  | 
     | 
     | 
    		fatal(errmsg);  | 
    
    
    2395  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    2396  | 
     | 
     | 
    	} else if (1 < retry)  | 
    
    
    2397  | 
     | 
     | 
    		log_info("NET_RT_DUMP %d retries", retry); | 
    
    
    2398  | 
     | 
     | 
     | 
    
    
    2399  | 
     | 
     | 
    	lim = buf + msize;  | 
    
    
    2400  | 
     | 
     | 
    	for (p = buf; p < lim; p += rtm->rtm_msglen) { | 
    
    
    2401  | 
     | 
     | 
    		rtm = (struct rt_msghdr *)p;  | 
    
    
    2402  | 
     | 
     | 
    		if (rtm->rtm_version != RTM_VERSION)  | 
    
    
    2403  | 
     | 
     | 
    			continue;  | 
    
    
    2404  | 
     | 
     | 
    		rt_entry(rtm, again);  | 
    
    
    2405  | 
     | 
     | 
    	}  | 
    
    
    2406  | 
     | 
     | 
    	free(buf);  | 
    
    
    2407  | 
     | 
     | 
    }  | 
    
    
    2408  | 
     | 
     | 
     | 
    
    
    2409  | 
     | 
     | 
    void  | 
    
    
    2410  | 
     | 
     | 
    rt_entry(struct rt_msghdr *rtm, int again)  | 
    
    
    2411  | 
     | 
     | 
    { | 
    
    
    2412  | 
     | 
     | 
    	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;  | 
    
    
    2413  | 
     | 
     | 
    	struct	sockaddr_in6 *sin6_ifp;  | 
    
    
    2414  | 
     | 
     | 
    	char	*rtmp, *ifname = NULL;  | 
    
    
    2415  | 
     | 
     | 
    	struct	riprt *rrt, *orrt;  | 
    
    
    2416  | 
     | 
     | 
    	struct	netinfo6 *np;  | 
    
    
    2417  | 
     | 
     | 
    	int	s;  | 
    
    
    2418  | 
     | 
     | 
     | 
    
    
    2419  | 
     | 
     | 
    	sin6_dst = sin6_gw = sin6_mask = sin6_ifp = 0;  | 
    
    
    2420  | 
     | 
     | 
    	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &  | 
    
    
    2421  | 
     | 
     | 
    		(RTF_CLONING|RTF_LLINFO|RTF_BLACKHOLE)) { | 
    
    
    2422  | 
     | 
     | 
    		return;		/* not interested in the link route */  | 
    
    
    2423  | 
     | 
     | 
    	}  | 
    
    
    2424  | 
     | 
     | 
    	/* do not look at cloned routes */  | 
    
    
    2425  | 
     | 
     | 
    #ifdef RTF_WASCLONED  | 
    
    
    2426  | 
     | 
     | 
    	if (rtm->rtm_flags & RTF_WASCLONED)  | 
    
    
    2427  | 
     | 
     | 
    		return;  | 
    
    
    2428  | 
     | 
     | 
    #endif  | 
    
    
    2429  | 
     | 
     | 
    #ifdef RTF_CLONED  | 
    
    
    2430  | 
     | 
     | 
    	if (rtm->rtm_flags & RTF_CLONED)  | 
    
    
    2431  | 
     | 
     | 
    		return;  | 
    
    
    2432  | 
     | 
     | 
    #endif  | 
    
    
    2433  | 
     | 
     | 
    	/*  | 
    
    
    2434  | 
     | 
     | 
    	 * do not look at dynamic routes.  | 
    
    
    2435  | 
     | 
     | 
    	 * netbsd/openbsd cloned routes have UGHD.  | 
    
    
    2436  | 
     | 
     | 
    	 */  | 
    
    
    2437  | 
     | 
     | 
    	if (rtm->rtm_flags & RTF_DYNAMIC)  | 
    
    
    2438  | 
     | 
     | 
    		return;  | 
    
    
    2439  | 
     | 
     | 
    	rtmp = (char *)((char *)rtm + rtm->rtm_hdrlen);  | 
    
    
    2440  | 
     | 
     | 
    	/* Destination */  | 
    
    
    2441  | 
     | 
     | 
    	if ((rtm->rtm_addrs & RTA_DST) == 0)  | 
    
    
    2442  | 
     | 
     | 
    		return;		/* ignore routes without destination address */  | 
    
    
    2443  | 
     | 
     | 
    	sin6_dst = (struct sockaddr_in6 *)rtmp;  | 
    
    
    2444  | 
     | 
     | 
    	rtmp += ROUNDUP(sin6_dst->sin6_len);  | 
    
    
    2445  | 
     | 
     | 
    	if (rtm->rtm_addrs & RTA_GATEWAY) { | 
    
    
    2446  | 
     | 
     | 
    		sin6_gw = (struct sockaddr_in6 *)rtmp;  | 
    
    
    2447  | 
     | 
     | 
    		rtmp += ROUNDUP(sin6_gw->sin6_len);  | 
    
    
    2448  | 
     | 
     | 
    	}  | 
    
    
    2449  | 
     | 
     | 
    	if (rtm->rtm_addrs & RTA_NETMASK) { | 
    
    
    2450  | 
     | 
     | 
    		sin6_mask = (struct sockaddr_in6 *)rtmp;  | 
    
    
    2451  | 
     | 
     | 
    		rtmp += ROUNDUP(sin6_mask->sin6_len);  | 
    
    
    2452  | 
     | 
     | 
    	}  | 
    
    
    2453  | 
     | 
     | 
    	if (rtm->rtm_addrs & RTA_IFP) { | 
    
    
    2454  | 
     | 
     | 
    		sin6_ifp = (struct sockaddr_in6 *)rtmp;  | 
    
    
    2455  | 
     | 
     | 
    		rtmp += ROUNDUP(sin6_ifp->sin6_len);  | 
    
    
    2456  | 
     | 
     | 
    	}  | 
    
    
    2457  | 
     | 
     | 
     | 
    
    
    2458  | 
     | 
     | 
    	/* Destination */  | 
    
    
    2459  | 
     | 
     | 
    	if (sin6_dst->sin6_family != AF_INET6)  | 
    
    
    2460  | 
     | 
     | 
    		return;  | 
    
    
    2461  | 
     | 
     | 
    	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))  | 
    
    
    2462  | 
     | 
     | 
    		return;		/* Link-local */  | 
    
    
    2463  | 
     | 
     | 
    	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))  | 
    
    
    2464  | 
     | 
     | 
    		return;		/* Loopback */  | 
    
    
    2465  | 
     | 
     | 
    	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))  | 
    
    
    2466  | 
     | 
     | 
    		return;  | 
    
    
    2467  | 
     | 
     | 
     | 
    
    
    2468  | 
     | 
     | 
    	if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { | 
    
    
    2469  | 
     | 
     | 
    		fatal("calloc: struct riprt"); | 
    
    
    2470  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    2471  | 
     | 
     | 
    	}  | 
    
    
    2472  | 
     | 
     | 
    	np = &rrt->rrt_info;  | 
    
    
    2473  | 
     | 
     | 
    	rrt->rrt_t = time(NULL);  | 
    
    
    2474  | 
     | 
     | 
    	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))  | 
    
    
    2475  | 
     | 
     | 
    		rrt->rrt_t = 0;	/* Don't age static routes */  | 
    
    
    2476  | 
     | 
     | 
    	if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)  | 
    
    
    2477  | 
     | 
     | 
    		rrt->rrt_t = 0;	/* Don't age non-gateway host routes */  | 
    
    
    2478  | 
     | 
     | 
    	np->rip6_tag = 0;  | 
    
    
    2479  | 
     | 
     | 
    	np->rip6_metric = 1;  | 
    
    
    2480  | 
     | 
     | 
    	rrt->rrt_flags = rtm->rtm_flags;  | 
    
    
    2481  | 
     | 
     | 
    	np->rip6_dest = sin6_dst->sin6_addr;  | 
    
    
    2482  | 
     | 
     | 
     | 
    
    
    2483  | 
     | 
     | 
    	/* Mask or plen */  | 
    
    
    2484  | 
     | 
     | 
    	if (rtm->rtm_flags & RTF_HOST)  | 
    
    
    2485  | 
     | 
     | 
    		np->rip6_plen = 128;	/* Host route */  | 
    
    
    2486  | 
     | 
     | 
    	else if (sin6_mask)  | 
    
    
    2487  | 
     | 
     | 
    		np->rip6_plen = sin6mask2len(sin6_mask);  | 
    
    
    2488  | 
     | 
     | 
    	else  | 
    
    
    2489  | 
     | 
     | 
    		np->rip6_plen = 0;  | 
    
    
    2490  | 
     | 
     | 
     | 
    
    
    2491  | 
     | 
     | 
    	orrt = rtsearch(np, NULL);  | 
    
    
    2492  | 
     | 
     | 
    	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { | 
    
    
    2493  | 
     | 
     | 
    		/* Already found */  | 
    
    
    2494  | 
     | 
     | 
    		if (!again) { | 
    
    
    2495  | 
     | 
     | 
    			log_debug("route: %s/%d flags %s: already registered", | 
    
    
    2496  | 
     | 
     | 
    				inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2497  | 
     | 
     | 
    				rtflags(rtm));  | 
    
    
    2498  | 
     | 
     | 
    		}  | 
    
    
    2499  | 
     | 
     | 
    		free(rrt);  | 
    
    
    2500  | 
     | 
     | 
    		return;  | 
    
    
    2501  | 
     | 
     | 
    	}  | 
    
    
    2502  | 
     | 
     | 
    	/* Gateway */  | 
    
    
    2503  | 
     | 
     | 
    	if (!sin6_gw)  | 
    
    
    2504  | 
     | 
     | 
    		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));  | 
    
    
    2505  | 
     | 
     | 
    	else { | 
    
    
    2506  | 
     | 
     | 
    		if (sin6_gw->sin6_family == AF_INET6)  | 
    
    
    2507  | 
     | 
     | 
    			rrt->rrt_gw = sin6_gw->sin6_addr;  | 
    
    
    2508  | 
     | 
     | 
    		else if (sin6_gw->sin6_family == AF_LINK) { | 
    
    
    2509  | 
     | 
     | 
    			/* XXX in case ppp link? */  | 
    
    
    2510  | 
     | 
     | 
    			rrt->rrt_gw = in6addr_loopback;  | 
    
    
    2511  | 
     | 
     | 
    		} else  | 
    
    
    2512  | 
     | 
     | 
    			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));  | 
    
    
    2513  | 
     | 
     | 
    	}  | 
    
    
    2514  | 
     | 
     | 
    	log_enqueue("route: %s/%d flags %s", | 
    
    
    2515  | 
     | 
     | 
    		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));  | 
    
    
    2516  | 
     | 
     | 
    	log_enqueue(" gw %s", inet6_n2p(&rrt->rrt_gw)); | 
    
    
    2517  | 
     | 
     | 
     | 
    
    
    2518  | 
     | 
     | 
    	/* Interface */  | 
    
    
    2519  | 
     | 
     | 
    	s = rtm->rtm_index;  | 
    
    
    2520  | 
     | 
     | 
    	if (s < nindex2ifc && index2ifc[s])  | 
    
    
    2521  | 
     | 
     | 
    		ifname = index2ifc[s]->ifc_name;  | 
    
    
    2522  | 
     | 
     | 
    	else { | 
    
    
    2523  | 
     | 
     | 
    		log_debug(" not configured"); | 
    
    
    2524  | 
     | 
     | 
    		free(rrt);  | 
    
    
    2525  | 
     | 
     | 
    		return;  | 
    
    
    2526  | 
     | 
     | 
    	}  | 
    
    
    2527  | 
     | 
     | 
    	log_debug(" if %s sock %d", ifname, s); | 
    
    
    2528  | 
     | 
     | 
    	rrt->rrt_index = s;  | 
    
    
    2529  | 
     | 
     | 
     | 
    
    
    2530  | 
     | 
     | 
    	/* Check gateway */  | 
    
    
    2531  | 
     | 
     | 
    	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&  | 
    
    
    2532  | 
     | 
     | 
    	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { | 
    
    
    2533  | 
     | 
     | 
    		log_warnx("***** Gateway %s is not a link-local address.", | 
    
    
    2534  | 
     | 
     | 
    			inet6_n2p(&rrt->rrt_gw));  | 
    
    
    2535  | 
     | 
     | 
    		log_warnx("*****     dest(%s) if(%s) -- Not optimized.", | 
    
    
    2536  | 
     | 
     | 
    			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);  | 
    
    
    2537  | 
     | 
     | 
    		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;  | 
    
    
    2538  | 
     | 
     | 
    	}  | 
    
    
    2539  | 
     | 
     | 
     | 
    
    
    2540  | 
     | 
     | 
    	/* Put it to the route list */  | 
    
    
    2541  | 
     | 
     | 
    	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { | 
    
    
    2542  | 
     | 
     | 
    		/* replace route list */  | 
    
    
    2543  | 
     | 
     | 
    		rrt->rrt_next = orrt->rrt_next;  | 
    
    
    2544  | 
     | 
     | 
    		*orrt = *rrt;  | 
    
    
    2545  | 
     | 
     | 
    		log_debug("route: %s/%d flags %s: replace new route", | 
    
    
    2546  | 
     | 
     | 
    		    inet6_n2p(&np->rip6_dest), np->rip6_plen,  | 
    
    
    2547  | 
     | 
     | 
    		    rtflags(rtm));  | 
    
    
    2548  | 
     | 
     | 
    		free(rrt);  | 
    
    
    2549  | 
     | 
     | 
    	} else { | 
    
    
    2550  | 
     | 
     | 
    		rrt->rrt_next = riprt;  | 
    
    
    2551  | 
     | 
     | 
    		riprt = rrt;  | 
    
    
    2552  | 
     | 
     | 
    	}  | 
    
    
    2553  | 
     | 
     | 
    }  | 
    
    
    2554  | 
     | 
     | 
     | 
    
    
    2555  | 
     | 
     | 
    int  | 
    
    
    2556  | 
     | 
     | 
    addroute(struct riprt *rrt, const struct in6_addr *gw, struct ifc *ifcp)  | 
    
    
    2557  | 
     | 
     | 
    { | 
    
    
    2558  | 
     | 
     | 
    	struct	netinfo6 *np;  | 
    
    
    2559  | 
     | 
     | 
    	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];  | 
    
    
    2560  | 
     | 
     | 
    	struct	rt_msghdr	*rtm;  | 
    
    
    2561  | 
     | 
     | 
    	struct	sockaddr_in6	*sin6;  | 
    
    
    2562  | 
     | 
     | 
    	int	len;  | 
    
    
    2563  | 
     | 
     | 
     | 
    
    
    2564  | 
     | 
     | 
    	np = &rrt->rrt_info;  | 
    
    
    2565  | 
     | 
     | 
    	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));  | 
    
    
    2566  | 
     | 
     | 
    	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));  | 
    
    
    2567  | 
     | 
     | 
    	if (uflag)  | 
    
    
    2568  | 
     | 
     | 
    		log_info("RTADD: %s/%d gw %s [%d] ifa %s", | 
    
    
    2569  | 
     | 
     | 
    		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,  | 
    
    
    2570  | 
     | 
     | 
    		    np->rip6_metric - 1, buf2);  | 
    
    
    2571  | 
     | 
     | 
    	else  | 
    
    
    2572  | 
     | 
     | 
    		log_debug("RTADD: %s/%d gw %s [%d] ifa %s", | 
    
    
    2573  | 
     | 
     | 
    		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,  | 
    
    
    2574  | 
     | 
     | 
    		    np->rip6_metric - 1, buf2);  | 
    
    
    2575  | 
     | 
     | 
     | 
    
    
    2576  | 
     | 
     | 
    	if (nflag)  | 
    
    
    2577  | 
     | 
     | 
    		return 0;  | 
    
    
    2578  | 
     | 
     | 
     | 
    
    
    2579  | 
     | 
     | 
    	memset(buf, 0, sizeof(buf));  | 
    
    
    2580  | 
     | 
     | 
    	rtm = (struct rt_msghdr *)buf;  | 
    
    
    2581  | 
     | 
     | 
    	rtm->rtm_type = RTM_ADD;  | 
    
    
    2582  | 
     | 
     | 
    	rtm->rtm_version = RTM_VERSION;  | 
    
    
    2583  | 
     | 
     | 
    	rtm->rtm_seq = ++seq;  | 
    
    
    2584  | 
     | 
     | 
    	rtm->rtm_flags = rrt->rrt_flags;  | 
    
    
    2585  | 
     | 
     | 
    	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;  | 
    
    
    2586  | 
     | 
     | 
    	rtm->rtm_inits = RTV_HOPCOUNT;  | 
    
    
    2587  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];  | 
    
    
    2588  | 
     | 
     | 
    	/* Destination */  | 
    
    
    2589  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2590  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2591  | 
     | 
     | 
    	sin6->sin6_addr = np->rip6_dest;  | 
    
    
    2592  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2593  | 
     | 
     | 
    	/* Gateway */  | 
    
    
    2594  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2595  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2596  | 
     | 
     | 
    	sin6->sin6_addr = *gw;  | 
    
    
    2597  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2598  | 
     | 
     | 
    	/* Netmask */  | 
    
    
    2599  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2600  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2601  | 
     | 
     | 
    	sin6->sin6_addr = *(plen2mask(np->rip6_plen));  | 
    
    
    2602  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2603  | 
     | 
     | 
     | 
    
    
    2604  | 
     | 
     | 
    	len = (char *)sin6 - (char *)buf;  | 
    
    
    2605  | 
     | 
     | 
    	rtm->rtm_msglen = len;  | 
    
    
    2606  | 
     | 
     | 
    	if (write(rtsock, buf, len) > 0)  | 
    
    
    2607  | 
     | 
     | 
    		return 0;  | 
    
    
    2608  | 
     | 
     | 
     | 
    
    
    2609  | 
     | 
     | 
    	if (errno == EEXIST) { | 
    
    
    2610  | 
     | 
     | 
    		log_warnx("RTADD: Route already exists %s/%d gw %s", | 
    
    
    2611  | 
     | 
     | 
    		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);  | 
    
    
    2612  | 
     | 
     | 
    	} else { | 
    
    
    2613  | 
     | 
     | 
    		log_warnx("RTADD: Can not write to rtsock (addroute): %s", | 
    
    
    2614  | 
     | 
     | 
    		    strerror(errno));  | 
    
    
    2615  | 
     | 
     | 
    	}  | 
    
    
    2616  | 
     | 
     | 
    	return -1;  | 
    
    
    2617  | 
     | 
     | 
    }  | 
    
    
    2618  | 
     | 
     | 
     | 
    
    
    2619  | 
     | 
     | 
    int  | 
    
    
    2620  | 
     | 
     | 
    delroute(struct netinfo6 *np, struct in6_addr *gw)  | 
    
    
    2621  | 
     | 
     | 
    { | 
    
    
    2622  | 
     | 
     | 
    	u_char	buf[BUFSIZ], buf2[BUFSIZ];  | 
    
    
    2623  | 
     | 
     | 
    	struct	rt_msghdr	*rtm;  | 
    
    
    2624  | 
     | 
     | 
    	struct	sockaddr_in6	*sin6;  | 
    
    
    2625  | 
     | 
     | 
    	int	len;  | 
    
    
    2626  | 
     | 
     | 
     | 
    
    
    2627  | 
     | 
     | 
    	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));  | 
    
    
    2628  | 
     | 
     | 
    	if (uflag)  | 
    
    
    2629  | 
     | 
     | 
    		log_info("RTDEL: %s/%d gw %s", inet6_n2p(&np->rip6_dest), | 
    
    
    2630  | 
     | 
     | 
    		    np->rip6_plen, buf2);  | 
    
    
    2631  | 
     | 
     | 
    	else  | 
    
    
    2632  | 
     | 
     | 
    		log_debug("RTDEL: %s/%d gw %s", inet6_n2p(&np->rip6_dest), | 
    
    
    2633  | 
     | 
     | 
    		    np->rip6_plen, buf2);  | 
    
    
    2634  | 
     | 
     | 
     | 
    
    
    2635  | 
     | 
     | 
    	if (nflag)  | 
    
    
    2636  | 
     | 
     | 
    		return 0;  | 
    
    
    2637  | 
     | 
     | 
     | 
    
    
    2638  | 
     | 
     | 
    	memset(buf, 0, sizeof(buf));  | 
    
    
    2639  | 
     | 
     | 
    	rtm = (struct rt_msghdr *)buf;  | 
    
    
    2640  | 
     | 
     | 
    	rtm->rtm_type = RTM_DELETE;  | 
    
    
    2641  | 
     | 
     | 
    	rtm->rtm_version = RTM_VERSION;  | 
    
    
    2642  | 
     | 
     | 
    	rtm->rtm_seq = ++seq;  | 
    
    
    2643  | 
     | 
     | 
    	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;  | 
    
    
    2644  | 
     | 
     | 
    	if (np->rip6_plen == sizeof(struct in6_addr) * 8)  | 
    
    
    2645  | 
     | 
     | 
    		rtm->rtm_flags |= RTF_HOST;  | 
    
    
    2646  | 
     | 
     | 
    	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;  | 
    
    
    2647  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];  | 
    
    
    2648  | 
     | 
     | 
    	/* Destination */  | 
    
    
    2649  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2650  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2651  | 
     | 
     | 
    	sin6->sin6_addr = np->rip6_dest;  | 
    
    
    2652  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2653  | 
     | 
     | 
    	/* Gateway */  | 
    
    
    2654  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2655  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2656  | 
     | 
     | 
    	sin6->sin6_addr = *gw;  | 
    
    
    2657  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2658  | 
     | 
     | 
    	/* Netmask */  | 
    
    
    2659  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2660  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2661  | 
     | 
     | 
    	sin6->sin6_addr = *(plen2mask(np->rip6_plen));  | 
    
    
    2662  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2663  | 
     | 
     | 
     | 
    
    
    2664  | 
     | 
     | 
    	len = (char *)sin6 - (char *)buf;  | 
    
    
    2665  | 
     | 
     | 
    	rtm->rtm_msglen = len;  | 
    
    
    2666  | 
     | 
     | 
    	if (write(rtsock, buf, len) >= 0)  | 
    
    
    2667  | 
     | 
     | 
    		return 0;  | 
    
    
    2668  | 
     | 
     | 
     | 
    
    
    2669  | 
     | 
     | 
    	if (errno == ESRCH) { | 
    
    
    2670  | 
     | 
     | 
    		log_warnx("RTDEL: Route does not exist: %s/%d gw %s", | 
    
    
    2671  | 
     | 
     | 
    		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);  | 
    
    
    2672  | 
     | 
     | 
    	} else { | 
    
    
    2673  | 
     | 
     | 
    		log_warnx("RTDEL: Can not write to rtsock (delroute): %s", | 
    
    
    2674  | 
     | 
     | 
    		    strerror(errno));  | 
    
    
    2675  | 
     | 
     | 
    	}  | 
    
    
    2676  | 
     | 
     | 
    	return -1;  | 
    
    
    2677  | 
     | 
     | 
    }  | 
    
    
    2678  | 
     | 
     | 
     | 
    
    
    2679  | 
     | 
     | 
    struct in6_addr *  | 
    
    
    2680  | 
     | 
     | 
    getroute(struct netinfo6 *np, struct in6_addr *gw)  | 
    
    
    2681  | 
     | 
     | 
    { | 
    
    
    2682  | 
     | 
     | 
    	u_char buf[BUFSIZ];  | 
    
    
    2683  | 
     | 
     | 
    	int len;  | 
    
    
    2684  | 
     | 
     | 
    	struct rt_msghdr *rtm;  | 
    
    
    2685  | 
     | 
     | 
    	struct sockaddr_in6 *sin6;  | 
    
    
    2686  | 
     | 
     | 
     | 
    
    
    2687  | 
     | 
     | 
    	rtm = (struct rt_msghdr *)buf;  | 
    
    
    2688  | 
     | 
     | 
    	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);  | 
    
    
    2689  | 
     | 
     | 
    	memset(rtm, 0, len);  | 
    
    
    2690  | 
     | 
     | 
    	rtm->rtm_type = RTM_GET;  | 
    
    
    2691  | 
     | 
     | 
    	rtm->rtm_version = RTM_VERSION;  | 
    
    
    2692  | 
     | 
     | 
    	rtm->rtm_seq = ++seq;  | 
    
    
    2693  | 
     | 
     | 
    	rtm->rtm_addrs = RTA_DST;  | 
    
    
    2694  | 
     | 
     | 
    	rtm->rtm_msglen = len;  | 
    
    
    2695  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];  | 
    
    
    2696  | 
     | 
     | 
    	sin6->sin6_len = sizeof(struct sockaddr_in6);  | 
    
    
    2697  | 
     | 
     | 
    	sin6->sin6_family = AF_INET6;  | 
    
    
    2698  | 
     | 
     | 
    	sin6->sin6_addr = np->rip6_dest;  | 
    
    
    2699  | 
     | 
     | 
    	if (write(rtsock, buf, len) < 0) { | 
    
    
    2700  | 
     | 
     | 
    		if (errno == ESRCH)	/* No such route found */  | 
    
    
    2701  | 
     | 
     | 
    			return NULL;  | 
    
    
    2702  | 
     | 
     | 
    		perror("write to rtsock"); | 
    
    
    2703  | 
     | 
     | 
    		exit(1);  | 
    
    
    2704  | 
     | 
     | 
    	}  | 
    
    
    2705  | 
     | 
     | 
    	do { | 
    
    
    2706  | 
     | 
     | 
    		if ((len = read(rtsock, buf, sizeof(buf))) < 0) { | 
    
    
    2707  | 
     | 
     | 
    			perror("read from rtsock"); | 
    
    
    2708  | 
     | 
     | 
    			exit(1);  | 
    
    
    2709  | 
     | 
     | 
    		}  | 
    
    
    2710  | 
     | 
     | 
    		rtm = (struct rt_msghdr *)buf;  | 
    
    
    2711  | 
     | 
     | 
    	} while (rtm->rtm_version != RTM_VERSION ||  | 
    
    
    2712  | 
     | 
     | 
    	    rtm->rtm_seq != seq || rtm->rtm_pid != pid);  | 
    
    
    2713  | 
     | 
     | 
    	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];  | 
    
    
    2714  | 
     | 
     | 
    	if (rtm->rtm_addrs & RTA_DST) { | 
    
    
    2715  | 
     | 
     | 
    		sin6 = (struct sockaddr_in6 *)  | 
    
    
    2716  | 
     | 
     | 
    			((char *)sin6 + ROUNDUP(sin6->sin6_len));  | 
    
    
    2717  | 
     | 
     | 
    	}  | 
    
    
    2718  | 
     | 
     | 
    	if (rtm->rtm_addrs & RTA_GATEWAY) { | 
    
    
    2719  | 
     | 
     | 
    		*gw = sin6->sin6_addr;  | 
    
    
    2720  | 
     | 
     | 
    		return gw;  | 
    
    
    2721  | 
     | 
     | 
    	}  | 
    
    
    2722  | 
     | 
     | 
    	return NULL;  | 
    
    
    2723  | 
     | 
     | 
    }  | 
    
    
    2724  | 
     | 
     | 
     | 
    
    
    2725  | 
     | 
     | 
    const char *  | 
    
    
    2726  | 
     | 
     | 
    inet6_n2p(const struct in6_addr *p)  | 
    
    
    2727  | 
     | 
     | 
    { | 
    
    
    2728  | 
     | 
     | 
    	static char buf[BUFSIZ];  | 
    
    
    2729  | 
     | 
     | 
     | 
    
    
    2730  | 
     | 
     | 
    	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));  | 
    
    
    2731  | 
     | 
     | 
    }  | 
    
    
    2732  | 
     | 
     | 
     | 
    
    
    2733  | 
     | 
     | 
    void  | 
    
    
    2734  | 
     | 
     | 
    ifrtdump(int sig)  | 
    
    
    2735  | 
     | 
     | 
    { | 
    
    
    2736  | 
     | 
     | 
     | 
    
    
    2737  | 
     | 
     | 
    	ifdump(sig);  | 
    
    
    2738  | 
     | 
     | 
    	rtdump(sig);  | 
    
    
    2739  | 
     | 
     | 
    }  | 
    
    
    2740  | 
     | 
     | 
     | 
    
    
    2741  | 
     | 
     | 
    void  | 
    
    
    2742  | 
     | 
     | 
    ifdump(int sig)  | 
    
    
    2743  | 
     | 
     | 
    { | 
    
    
    2744  | 
     | 
     | 
    	struct ifc *ifcp;  | 
    
    
    2745  | 
     | 
     | 
    	int i;  | 
    
    
    2746  | 
     | 
     | 
     | 
    
    
    2747  | 
     | 
     | 
    	log_info("%s: Interface Table Dump", hms()); | 
    
    
    2748  | 
     | 
     | 
    	log_info("  Number of interfaces: %d", nifc); | 
    
    
    2749  | 
     | 
     | 
    	for (i = 0; i < 2; i++) { | 
    
    
    2750  | 
     | 
     | 
    		log_info("  %sadvertising interfaces:", i ? "non-" : ""); | 
    
    
    2751  | 
     | 
     | 
    		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { | 
    
    
    2752  | 
     | 
     | 
    			if (i == 0) { | 
    
    
    2753  | 
     | 
     | 
    				if ((ifcp->ifc_flags & IFF_UP) == 0)  | 
    
    
    2754  | 
     | 
     | 
    					continue;  | 
    
    
    2755  | 
     | 
     | 
    				if (iff_find(ifcp, 'N') != NULL)  | 
    
    
    2756  | 
     | 
     | 
    					continue;  | 
    
    
    2757  | 
     | 
     | 
    			} else { | 
    
    
    2758  | 
     | 
     | 
    				if (ifcp->ifc_flags & IFF_UP)  | 
    
    
    2759  | 
     | 
     | 
    					continue;  | 
    
    
    2760  | 
     | 
     | 
    			}  | 
    
    
    2761  | 
     | 
     | 
    			ifdump0(ifcp);  | 
    
    
    2762  | 
     | 
     | 
    		}  | 
    
    
    2763  | 
     | 
     | 
    	}  | 
    
    
    2764  | 
     | 
     | 
    	log_info(""); | 
    
    
    2765  | 
     | 
     | 
    }  | 
    
    
    2766  | 
     | 
     | 
     | 
    
    
    2767  | 
     | 
     | 
    void  | 
    
    
    2768  | 
     | 
     | 
    ifdump0(const struct ifc *ifcp)  | 
    
    
    2769  | 
     | 
     | 
    { | 
    
    
    2770  | 
     | 
     | 
    	struct ifac *ifa;  | 
    
    
    2771  | 
     | 
     | 
    	struct iff *iffp;  | 
    
    
    2772  | 
     | 
     | 
    	char buf[BUFSIZ];  | 
    
    
    2773  | 
     | 
     | 
    	const char *ft;  | 
    
    
    2774  | 
     | 
     | 
    	int addr;  | 
    
    
    2775  | 
     | 
     | 
     | 
    
    
    2776  | 
     | 
     | 
    	log_info("    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)", | 
    
    
    2777  | 
     | 
     | 
    		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),  | 
    
    
    2778  | 
     | 
     | 
    		inet6_n2p(&ifcp->ifc_mylladdr),  | 
    
    
    2779  | 
     | 
     | 
    		ifcp->ifc_mtu, ifcp->ifc_metric);  | 
    
    
    2780  | 
     | 
     | 
    	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { | 
    
    
    2781  | 
     | 
     | 
    		if (ifcp->ifc_flags & IFF_POINTOPOINT) { | 
    
    
    2782  | 
     | 
     | 
    			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,  | 
    
    
    2783  | 
     | 
     | 
    				buf, sizeof(buf));  | 
    
    
    2784  | 
     | 
     | 
    			log_info("\t%s/%d -- %s", | 
    
    
    2785  | 
     | 
     | 
    				inet6_n2p(&ifa->ifa_addr),  | 
    
    
    2786  | 
     | 
     | 
    				ifa->ifa_plen, buf);  | 
    
    
    2787  | 
     | 
     | 
    		} else { | 
    
    
    2788  | 
     | 
     | 
    			log_info("\t%s/%d", | 
    
    
    2789  | 
     | 
     | 
    				inet6_n2p(&ifa->ifa_addr),  | 
    
    
    2790  | 
     | 
     | 
    				ifa->ifa_plen);  | 
    
    
    2791  | 
     | 
     | 
    		}  | 
    
    
    2792  | 
     | 
     | 
    	}  | 
    
    
    2793  | 
     | 
     | 
    	if (ifcp->ifc_filter) { | 
    
    
    2794  | 
     | 
     | 
    		log_enqueue("\tFilter:"); | 
    
    
    2795  | 
     | 
     | 
    		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    2796  | 
     | 
     | 
    			addr = 0;  | 
    
    
    2797  | 
     | 
     | 
    			switch (iffp->iff_type) { | 
    
    
    2798  | 
     | 
     | 
    			case 'A':  | 
    
    
    2799  | 
     | 
     | 
    				ft = "Aggregate"; addr++; break;  | 
    
    
    2800  | 
     | 
     | 
    			case 'N':  | 
    
    
    2801  | 
     | 
     | 
    				ft = "No-use"; break;  | 
    
    
    2802  | 
     | 
     | 
    			case 'O':  | 
    
    
    2803  | 
     | 
     | 
    				ft = "Advertise-only"; addr++; break;  | 
    
    
    2804  | 
     | 
     | 
    			case 'T':  | 
    
    
    2805  | 
     | 
     | 
    				ft = "Default-only"; break;  | 
    
    
    2806  | 
     | 
     | 
    			case 'L':  | 
    
    
    2807  | 
     | 
     | 
    				ft = "Listen-only"; addr++; break;  | 
    
    
    2808  | 
     | 
     | 
    			default:  | 
    
    
    2809  | 
     | 
     | 
    				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);  | 
    
    
    2810  | 
     | 
     | 
    				ft = buf;  | 
    
    
    2811  | 
     | 
     | 
    				addr++;  | 
    
    
    2812  | 
     | 
     | 
    				break;  | 
    
    
    2813  | 
     | 
     | 
    			}  | 
    
    
    2814  | 
     | 
     | 
    			log_enqueue(" %s", ft); | 
    
    
    2815  | 
     | 
     | 
    			if (addr) { | 
    
    
    2816  | 
     | 
     | 
    				log_enqueue("(%s/%d)", | 
    
    
    2817  | 
     | 
     | 
    				    inet6_n2p(&iffp->iff_addr), iffp->iff_plen);  | 
    
    
    2818  | 
     | 
     | 
    			}  | 
    
    
    2819  | 
     | 
     | 
    		}  | 
    
    
    2820  | 
     | 
     | 
    		log_info(""); | 
    
    
    2821  | 
     | 
     | 
    	}  | 
    
    
    2822  | 
     | 
     | 
    }  | 
    
    
    2823  | 
     | 
     | 
     | 
    
    
    2824  | 
     | 
     | 
    void  | 
    
    
    2825  | 
     | 
     | 
    rtdump(int sig)  | 
    
    
    2826  | 
     | 
     | 
    { | 
    
    
    2827  | 
     | 
     | 
    	struct	riprt *rrt;  | 
    
    
    2828  | 
     | 
     | 
    	char	buf[BUFSIZ];  | 
    
    
    2829  | 
     | 
     | 
    	time_t	t, age;  | 
    
    
    2830  | 
     | 
     | 
     | 
    
    
    2831  | 
     | 
     | 
    	t = time(NULL);  | 
    
    
    2832  | 
     | 
     | 
    	log_info("%s: Routing Table Dump", hms()); | 
    
    
    2833  | 
     | 
     | 
    	for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    2834  | 
     | 
     | 
    		if (rrt->rrt_t == 0)  | 
    
    
    2835  | 
     | 
     | 
    			age = 0;  | 
    
    
    2836  | 
     | 
     | 
    		else  | 
    
    
    2837  | 
     | 
     | 
    			age = t - rrt->rrt_t;  | 
    
    
    2838  | 
     | 
     | 
    		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,  | 
    
    
    2839  | 
     | 
     | 
    			buf, sizeof(buf));  | 
    
    
    2840  | 
     | 
     | 
    		log_enqueue("    %s/%d if(%d:%s) gw(%s) [%d] age(%lld)", | 
    
    
    2841  | 
     | 
     | 
    			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,  | 
    
    
    2842  | 
     | 
     | 
    			index2ifc[rrt->rrt_index]->ifc_name,  | 
    
    
    2843  | 
     | 
     | 
    			inet6_n2p(&rrt->rrt_gw),  | 
    
    
    2844  | 
     | 
     | 
    			rrt->rrt_info.rip6_metric, (long long)age);  | 
    
    
    2845  | 
     | 
     | 
    		if (rrt->rrt_info.rip6_tag) { | 
    
    
    2846  | 
     | 
     | 
    			log_enqueue(" tag(0x%04x)", | 
    
    
    2847  | 
     | 
     | 
    				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);  | 
    
    
    2848  | 
     | 
     | 
    		}  | 
    
    
    2849  | 
     | 
     | 
    		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)  | 
    
    
    2850  | 
     | 
     | 
    			log_enqueue(" NOT-LL"); | 
    
    
    2851  | 
     | 
     | 
    		if (rrt->rrt_rflags & RRTF_NOADVERTISE)  | 
    
    
    2852  | 
     | 
     | 
    			log_enqueue(" NO-ADV"); | 
    
    
    2853  | 
     | 
     | 
    		log_info(""); | 
    
    
    2854  | 
     | 
     | 
    	}  | 
    
    
    2855  | 
     | 
     | 
    }  | 
    
    
    2856  | 
     | 
     | 
     | 
    
    
    2857  | 
     | 
     | 
    /*  | 
    
    
    2858  | 
     | 
     | 
     * Parse the -A (and -O) options and put corresponding filter object to the  | 
    
    
    2859  | 
     | 
     | 
     * specified interface structures.  Each of the -A/O option has the following  | 
    
    
    2860  | 
     | 
     | 
     * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)  | 
    
    
    2861  | 
     | 
     | 
     * 		-O 5f09:c400::/32,ef0,ef1  (only when match)  | 
    
    
    2862  | 
     | 
     | 
     */  | 
    
    
    2863  | 
     | 
     | 
    void  | 
    
    
    2864  | 
     | 
     | 
    filterconfig(void)  | 
    
    
    2865  | 
     | 
     | 
    { | 
    
    
    2866  | 
     | 
     | 
    	int i;  | 
    
    
    2867  | 
     | 
     | 
    	char *p, *ap, *iflp, *ifname, *ep;  | 
    
    
    2868  | 
     | 
     | 
    	struct iff ftmp, *iff_obj;  | 
    
    
    2869  | 
     | 
     | 
    	struct ifc *ifcp;  | 
    
    
    2870  | 
     | 
     | 
    	struct riprt *rrt;  | 
    
    
    2871  | 
     | 
     | 
    #if 0  | 
    
    
    2872  | 
     | 
     | 
    	struct in6_addr gw;  | 
    
    
    2873  | 
     | 
     | 
    #endif  | 
    
    
    2874  | 
     | 
     | 
    	u_long plen;  | 
    
    
    2875  | 
     | 
     | 
     | 
    
    
    2876  | 
     | 
     | 
    	for (i = 0; i < nfilter; i++) { | 
    
    
    2877  | 
     | 
     | 
    		ap = filter[i];  | 
    
    
    2878  | 
     | 
     | 
    		iflp = NULL;  | 
    
    
    2879  | 
     | 
     | 
    		ifcp = NULL;  | 
    
    
    2880  | 
     | 
     | 
    		if (filtertype[i] == 'N' || filtertype[i] == 'T') { | 
    
    
    2881  | 
     | 
     | 
    			iflp = ap;  | 
    
    
    2882  | 
     | 
     | 
    			goto ifonly;  | 
    
    
    2883  | 
     | 
     | 
    		}  | 
    
    
    2884  | 
     | 
     | 
    		if ((p = strchr(ap, ',')) != NULL) { | 
    
    
    2885  | 
     | 
     | 
    			*p++ = '\0';  | 
    
    
    2886  | 
     | 
     | 
    			iflp = p;  | 
    
    
    2887  | 
     | 
     | 
    		}  | 
    
    
    2888  | 
     | 
     | 
    		if ((p = strchr(ap, '/')) == NULL) { | 
    
    
    2889  | 
     | 
     | 
    			log_warnx("no prefixlen specified for '%s'", ap); | 
    
    
    2890  | 
     | 
     | 
    			fatalx("exiting"); | 
    
    
    2891  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2892  | 
     | 
     | 
    		}  | 
    
    
    2893  | 
     | 
     | 
    		*p++ = '\0';  | 
    
    
    2894  | 
     | 
     | 
    		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { | 
    
    
    2895  | 
     | 
     | 
    			log_warnx("invalid prefix specified for '%s'", ap); | 
    
    
    2896  | 
     | 
     | 
    			fatalx("exiting"); | 
    
    
    2897  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2898  | 
     | 
     | 
    		}  | 
    
    
    2899  | 
     | 
     | 
    		errno = 0;  | 
    
    
    2900  | 
     | 
     | 
    		ep = NULL;  | 
    
    
    2901  | 
     | 
     | 
    		plen = strtoul(p, &ep, 10);  | 
    
    
    2902  | 
     | 
     | 
    		if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) { | 
    
    
    2903  | 
     | 
     | 
    			log_warnx("invalid prefix length specified for '%s'", ap); | 
    
    
    2904  | 
     | 
     | 
    			fatalx("exiting"); | 
    
    
    2905  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2906  | 
     | 
     | 
    		}  | 
    
    
    2907  | 
     | 
     | 
    		ftmp.iff_plen = plen;  | 
    
    
    2908  | 
     | 
     | 
    		ftmp.iff_next = NULL;  | 
    
    
    2909  | 
     | 
     | 
    		applyplen(&ftmp.iff_addr, ftmp.iff_plen);  | 
    
    
    2910  | 
     | 
     | 
    ifonly:  | 
    
    
    2911  | 
     | 
     | 
    		ftmp.iff_type = filtertype[i];  | 
    
    
    2912  | 
     | 
     | 
    		if (iflp == NULL || *iflp == '\0') { | 
    
    
    2913  | 
     | 
     | 
    			log_warnx("no interface specified for '%s'", ap); | 
    
    
    2914  | 
     | 
     | 
    			fatal("exiting"); | 
    
    
    2915  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2916  | 
     | 
     | 
    		}  | 
    
    
    2917  | 
     | 
     | 
    		/* parse the interface listing portion */  | 
    
    
    2918  | 
     | 
     | 
    		while (iflp) { | 
    
    
    2919  | 
     | 
     | 
    			ifname = iflp;  | 
    
    
    2920  | 
     | 
     | 
    			if ((iflp = strchr(iflp, ',')) != NULL)  | 
    
    
    2921  | 
     | 
     | 
    				*iflp++ = '\0';  | 
    
    
    2922  | 
     | 
     | 
    			ifcp = ifc_find(ifname);  | 
    
    
    2923  | 
     | 
     | 
    			if (ifcp == NULL) { | 
    
    
    2924  | 
     | 
     | 
    				log_warnx("no interface %s exists", ifname); | 
    
    
    2925  | 
     | 
     | 
    				fatalx("exiting"); | 
    
    
    2926  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    2927  | 
     | 
     | 
    			}  | 
    
    
    2928  | 
     | 
     | 
    			iff_obj = malloc(sizeof(struct iff));  | 
    
    
    2929  | 
     | 
     | 
    			if (iff_obj == NULL) { | 
    
    
    2930  | 
     | 
     | 
    				fatal("malloc of iff_obj"); | 
    
    
    2931  | 
     | 
     | 
    				/*NOTREACHED*/  | 
    
    
    2932  | 
     | 
     | 
    			}  | 
    
    
    2933  | 
     | 
     | 
    			memcpy((void *)iff_obj, (void *)&ftmp,  | 
    
    
    2934  | 
     | 
     | 
    			    sizeof(struct iff));  | 
    
    
    2935  | 
     | 
     | 
    			/* link it to the interface filter */  | 
    
    
    2936  | 
     | 
     | 
    			iff_obj->iff_next = ifcp->ifc_filter;  | 
    
    
    2937  | 
     | 
     | 
    			ifcp->ifc_filter = iff_obj;  | 
    
    
    2938  | 
     | 
     | 
    		}  | 
    
    
    2939  | 
     | 
     | 
     | 
    
    
    2940  | 
     | 
     | 
    		/*  | 
    
    
    2941  | 
     | 
     | 
    		 * -A: aggregate configuration.  | 
    
    
    2942  | 
     | 
     | 
    		 */  | 
    
    
    2943  | 
     | 
     | 
    		if (filtertype[i] != 'A')  | 
    
    
    2944  | 
     | 
     | 
    			continue;  | 
    
    
    2945  | 
     | 
     | 
    		/* put the aggregate to the kernel routing table */  | 
    
    
    2946  | 
     | 
     | 
    		rrt = calloc(1, sizeof(struct riprt));  | 
    
    
    2947  | 
     | 
     | 
    		if (rrt == NULL) { | 
    
    
    2948  | 
     | 
     | 
    			fatal("calloc: rrt"); | 
    
    
    2949  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2950  | 
     | 
     | 
    		}  | 
    
    
    2951  | 
     | 
     | 
    		rrt->rrt_info.rip6_dest = ftmp.iff_addr;  | 
    
    
    2952  | 
     | 
     | 
    		rrt->rrt_info.rip6_plen = ftmp.iff_plen;  | 
    
    
    2953  | 
     | 
     | 
    		rrt->rrt_info.rip6_metric = 1;  | 
    
    
    2954  | 
     | 
     | 
    		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);  | 
    
    
    2955  | 
     | 
     | 
    		rrt->rrt_gw = in6addr_loopback;  | 
    
    
    2956  | 
     | 
     | 
    		rrt->rrt_flags = RTF_UP | RTF_REJECT;  | 
    
    
    2957  | 
     | 
     | 
    		rrt->rrt_rflags = RRTF_AGGREGATE;  | 
    
    
    2958  | 
     | 
     | 
    		rrt->rrt_t = 0;  | 
    
    
    2959  | 
     | 
     | 
    		rrt->rrt_index = loopifcp->ifc_index;  | 
    
    
    2960  | 
     | 
     | 
    #if 0  | 
    
    
    2961  | 
     | 
     | 
    		if (getroute(&rrt->rrt_info, &gw)) { | 
    
    
    2962  | 
     | 
     | 
    #if 0  | 
    
    
    2963  | 
     | 
     | 
    			/*  | 
    
    
    2964  | 
     | 
     | 
    			 * When the address has already been registered in the  | 
    
    
    2965  | 
     | 
     | 
    			 * kernel routing table, it should be removed  | 
    
    
    2966  | 
     | 
     | 
    			 */  | 
    
    
    2967  | 
     | 
     | 
    			delroute(&rrt->rrt_info, &gw);  | 
    
    
    2968  | 
     | 
     | 
    #else  | 
    
    
    2969  | 
     | 
     | 
    			/* it is safer behavior */  | 
    
    
    2970  | 
     | 
     | 
    			errno = EINVAL;  | 
    
    
    2971  | 
     | 
     | 
    			fatal("%s/%u already in routing table, " | 
    
    
    2972  | 
     | 
     | 
    			    "cannot aggregate",  | 
    
    
    2973  | 
     | 
     | 
    			    inet6_n2p(&rrt->rrt_info.rip6_dest),  | 
    
    
    2974  | 
     | 
     | 
    			    rrt->rrt_info.rip6_plen);  | 
    
    
    2975  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    2976  | 
     | 
     | 
    #endif  | 
    
    
    2977  | 
     | 
     | 
    		}  | 
    
    
    2978  | 
     | 
     | 
    #endif  | 
    
    
    2979  | 
     | 
     | 
    		/* Put the route to the list */  | 
    
    
    2980  | 
     | 
     | 
    		rrt->rrt_next = riprt;  | 
    
    
    2981  | 
     | 
     | 
    		riprt = rrt;  | 
    
    
    2982  | 
     | 
     | 
    		log_debug("Aggregate: %s/%d for %s", | 
    
    
    2983  | 
     | 
     | 
    			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,  | 
    
    
    2984  | 
     | 
     | 
    			ifcp->ifc_name);  | 
    
    
    2985  | 
     | 
     | 
    		/* Add this route to the kernel */  | 
    
    
    2986  | 
     | 
     | 
    		if (nflag) 	/* do not modify kernel routing table */  | 
    
    
    2987  | 
     | 
     | 
    			continue;  | 
    
    
    2988  | 
     | 
     | 
    		addroute(rrt, &in6addr_loopback, loopifcp);  | 
    
    
    2989  | 
     | 
     | 
    	}  | 
    
    
    2990  | 
     | 
     | 
    }  | 
    
    
    2991  | 
     | 
     | 
     | 
    
    
    2992  | 
     | 
     | 
    /***************** utility functions *****************/  | 
    
    
    2993  | 
     | 
     | 
     | 
    
    
    2994  | 
     | 
     | 
    /*  | 
    
    
    2995  | 
     | 
     | 
     * Returns a pointer to ifac whose address and prefix length matches  | 
    
    
    2996  | 
     | 
     | 
     * with the address and prefix length specified in the arguments.  | 
    
    
    2997  | 
     | 
     | 
     */  | 
    
    
    2998  | 
     | 
     | 
    struct ifac *  | 
    
    
    2999  | 
     | 
     | 
    ifa_match(const struct ifc *ifcp, const struct in6_addr *ia, int plen)  | 
    
    
    3000  | 
     | 
     | 
    { | 
    
    
    3001  | 
     | 
     | 
    	struct ifac *ifa;  | 
    
    
    3002  | 
     | 
     | 
     | 
    
    
    3003  | 
     | 
     | 
    	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { | 
    
    
    3004  | 
     | 
     | 
    		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&  | 
    
    
    3005  | 
     | 
     | 
    		    ifa->ifa_plen == plen)  | 
    
    
    3006  | 
     | 
     | 
    			break;  | 
    
    
    3007  | 
     | 
     | 
    	}  | 
    
    
    3008  | 
     | 
     | 
    	return ifa;  | 
    
    
    3009  | 
     | 
     | 
    }  | 
    
    
    3010  | 
     | 
     | 
     | 
    
    
    3011  | 
     | 
     | 
    /*  | 
    
    
    3012  | 
     | 
     | 
     * Return a pointer to riprt structure whose address and prefix length  | 
    
    
    3013  | 
     | 
     | 
     * matches with the address and prefix length found in the argument.  | 
    
    
    3014  | 
     | 
     | 
     * Note: This is not a rtalloc().  Therefore exact match is necessary.  | 
    
    
    3015  | 
     | 
     | 
     */  | 
    
    
    3016  | 
     | 
     | 
    struct riprt *  | 
    
    
    3017  | 
     | 
     | 
    rtsearch(struct	netinfo6 *np, struct riprt **prev_rrt)  | 
    
    
    3018  | 
     | 
     | 
    { | 
    
    
    3019  | 
     | 
     | 
    	struct	riprt	*rrt;  | 
    
    
    3020  | 
     | 
     | 
     | 
    
    
    3021  | 
     | 
     | 
    	if (prev_rrt)  | 
    
    
    3022  | 
     | 
     | 
    		*prev_rrt = NULL;  | 
    
    
    3023  | 
     | 
     | 
    	for (rrt = riprt; rrt; rrt = rrt->rrt_next) { | 
    
    
    3024  | 
     | 
     | 
    		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&  | 
    
    
    3025  | 
     | 
     | 
    		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,  | 
    
    
    3026  | 
     | 
     | 
    				       &np->rip6_dest))  | 
    
    
    3027  | 
     | 
     | 
    			return rrt;  | 
    
    
    3028  | 
     | 
     | 
    		if (prev_rrt)  | 
    
    
    3029  | 
     | 
     | 
    			*prev_rrt = rrt;  | 
    
    
    3030  | 
     | 
     | 
    	}  | 
    
    
    3031  | 
     | 
     | 
    	if (prev_rrt)  | 
    
    
    3032  | 
     | 
     | 
    		*prev_rrt = NULL;  | 
    
    
    3033  | 
     | 
     | 
    	return 0;  | 
    
    
    3034  | 
     | 
     | 
    }  | 
    
    
    3035  | 
     | 
     | 
     | 
    
    
    3036  | 
     | 
     | 
    int  | 
    
    
    3037  | 
     | 
     | 
    sin6mask2len(const struct sockaddr_in6 *sin6)  | 
    
    
    3038  | 
     | 
     | 
    { | 
    
    
    3039  | 
     | 
     | 
     | 
    
    
    3040  | 
     | 
     | 
    	return mask2len(&sin6->sin6_addr,  | 
    
    
    3041  | 
     | 
     | 
    	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));  | 
    
    
    3042  | 
     | 
     | 
    }  | 
    
    
    3043  | 
     | 
     | 
     | 
    
    
    3044  | 
     | 
     | 
    int  | 
    
    
    3045  | 
     | 
     | 
    mask2len(const struct in6_addr *addr, int lenlim)  | 
    
    
    3046  | 
     | 
     | 
    { | 
    
    
    3047  | 
     | 
     | 
    	int i = 0, j;  | 
    
    
    3048  | 
     | 
     | 
    	const u_char *p = (const u_char *)addr;  | 
    
    
    3049  | 
     | 
     | 
     | 
    
    
    3050  | 
     | 
     | 
    	for (j = 0; j < lenlim; j++, p++) { | 
    
    
    3051  | 
     | 
     | 
    		if (*p != 0xff)  | 
    
    
    3052  | 
     | 
     | 
    			break;  | 
    
    
    3053  | 
     | 
     | 
    		i += 8;  | 
    
    
    3054  | 
     | 
     | 
    	}  | 
    
    
    3055  | 
     | 
     | 
    	if (j < lenlim) { | 
    
    
    3056  | 
     | 
     | 
    		switch (*p) { | 
    
    
    3057  | 
     | 
     | 
    #define	MASKLEN(m, l)	case m: do { i += l; break; } while (0) | 
    
    
    3058  | 
     | 
     | 
    		MASKLEN(0xfe, 7); break;  | 
    
    
    3059  | 
     | 
     | 
    		MASKLEN(0xfc, 6); break;  | 
    
    
    3060  | 
     | 
     | 
    		MASKLEN(0xf8, 5); break;  | 
    
    
    3061  | 
     | 
     | 
    		MASKLEN(0xf0, 4); break;  | 
    
    
    3062  | 
     | 
     | 
    		MASKLEN(0xe0, 3); break;  | 
    
    
    3063  | 
     | 
     | 
    		MASKLEN(0xc0, 2); break;  | 
    
    
    3064  | 
     | 
     | 
    		MASKLEN(0x80, 1); break;  | 
    
    
    3065  | 
     | 
     | 
    #undef	MASKLEN  | 
    
    
    3066  | 
     | 
     | 
    		}  | 
    
    
    3067  | 
     | 
     | 
    	}  | 
    
    
    3068  | 
     | 
     | 
    	return i;  | 
    
    
    3069  | 
     | 
     | 
    }  | 
    
    
    3070  | 
     | 
     | 
     | 
    
    
    3071  | 
     | 
     | 
    void  | 
    
    
    3072  | 
     | 
     | 
    applyplen(struct in6_addr *ia, int plen)  | 
    
    
    3073  | 
     | 
     | 
    { | 
    
    
    3074  | 
     | 
     | 
    	static const u_char plent[8] = { | 
    
    
    3075  | 
     | 
     | 
    		0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe  | 
    
    
    3076  | 
     | 
     | 
    	};  | 
    
    
    3077  | 
     | 
     | 
    	u_char	*p;  | 
    
    
    3078  | 
     | 
     | 
    	int	i;  | 
    
    
    3079  | 
     | 
     | 
     | 
    
    
    3080  | 
     | 
     | 
    	p = ia->s6_addr;  | 
    
    
    3081  | 
     | 
     | 
    	for (i = 0; i < 16; i++) { | 
    
    
    3082  | 
     | 
     | 
    		if (plen <= 0)  | 
    
    
    3083  | 
     | 
     | 
    			*p = 0;  | 
    
    
    3084  | 
     | 
     | 
    		else if (plen < 8)  | 
    
    
    3085  | 
     | 
     | 
    			*p &= plent[plen];  | 
    
    
    3086  | 
     | 
     | 
    		p++, plen -= 8;  | 
    
    
    3087  | 
     | 
     | 
    	}  | 
    
    
    3088  | 
     | 
     | 
    }  | 
    
    
    3089  | 
     | 
     | 
     | 
    
    
    3090  | 
     | 
     | 
    struct in6_addr *  | 
    
    
    3091  | 
     | 
     | 
    plen2mask(int n)  | 
    
    
    3092  | 
     | 
     | 
    { | 
    
    
    3093  | 
     | 
     | 
    	static const int pl2m[9] = { | 
    
    
    3094  | 
     | 
     | 
    		0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff  | 
    
    
    3095  | 
     | 
     | 
    	};  | 
    
    
    3096  | 
     | 
     | 
    	static struct in6_addr ia;  | 
    
    
    3097  | 
     | 
     | 
    	u_char	*p;  | 
    
    
    3098  | 
     | 
     | 
    	int	i;  | 
    
    
    3099  | 
     | 
     | 
     | 
    
    
    3100  | 
     | 
     | 
    	memset(&ia, 0, sizeof(struct in6_addr));  | 
    
    
    3101  | 
     | 
     | 
    	p = (u_char *)&ia;  | 
    
    
    3102  | 
     | 
     | 
    	for (i = 0; i < 16; i++, p++, n -= 8) { | 
    
    
    3103  | 
     | 
     | 
    		if (n >= 8) { | 
    
    
    3104  | 
     | 
     | 
    			*p = 0xff;  | 
    
    
    3105  | 
     | 
     | 
    			continue;  | 
    
    
    3106  | 
     | 
     | 
    		}  | 
    
    
    3107  | 
     | 
     | 
    		*p = pl2m[n];  | 
    
    
    3108  | 
     | 
     | 
    		break;  | 
    
    
    3109  | 
     | 
     | 
    	}  | 
    
    
    3110  | 
     | 
     | 
    	return &ia;  | 
    
    
    3111  | 
     | 
     | 
    }  | 
    
    
    3112  | 
     | 
     | 
     | 
    
    
    3113  | 
     | 
     | 
    char *  | 
    
    
    3114  | 
     | 
     | 
    xstrdup(const char *p)  | 
    
    
    3115  | 
     | 
     | 
    { | 
    
    
    3116  | 
     | 
     | 
    	char *q;  | 
    
    
    3117  | 
     | 
     | 
     | 
    
    
    3118  | 
     | 
     | 
    	q = strdup(p);  | 
    
    
    3119  | 
     | 
     | 
    	if (q == NULL) { | 
    
    
    3120  | 
     | 
     | 
    		fatal("strdup"); | 
    
    
    3121  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    3122  | 
     | 
     | 
    	}  | 
    
    
    3123  | 
     | 
     | 
    	return q;  | 
    
    
    3124  | 
     | 
     | 
    }  | 
    
    
    3125  | 
     | 
     | 
     | 
    
    
    3126  | 
     | 
     | 
    const char *  | 
    
    
    3127  | 
     | 
     | 
    hms(void)  | 
    
    
    3128  | 
     | 
     | 
    { | 
    
    
    3129  | 
     | 
     | 
    	static char buf[BUFSIZ];  | 
    
    
    3130  | 
     | 
     | 
    	time_t t;  | 
    
    
    3131  | 
     | 
     | 
    	struct	tm *tm;  | 
    
    
    3132  | 
     | 
     | 
     | 
    
    
    3133  | 
     | 
     | 
    	t = time(NULL);  | 
    
    
    3134  | 
     | 
     | 
    	if ((tm = localtime(&t)) == 0) { | 
    
    
    3135  | 
     | 
     | 
    		fatal("localtime"); | 
    
    
    3136  | 
     | 
     | 
    		/*NOTREACHED*/  | 
    
    
    3137  | 
     | 
     | 
    	}  | 
    
    
    3138  | 
     | 
     | 
    	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,  | 
    
    
    3139  | 
     | 
     | 
    	    tm->tm_sec);  | 
    
    
    3140  | 
     | 
     | 
    	return buf;  | 
    
    
    3141  | 
     | 
     | 
    }  | 
    
    
    3142  | 
     | 
     | 
     | 
    
    
    3143  | 
     | 
     | 
    #define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */  | 
    
    
    3144  | 
     | 
     | 
     | 
    
    
    3145  | 
     | 
     | 
    int  | 
    
    
    3146  | 
     | 
     | 
    ripinterval(int timer)  | 
    
    
    3147  | 
     | 
     | 
    { | 
    
    
    3148  | 
     | 
     | 
    	double r = arc4random();  | 
    
    
    3149  | 
     | 
     | 
    	int interval;  | 
    
    
    3150  | 
     | 
     | 
     | 
    
    
    3151  | 
     | 
     | 
    	interval = (int)(timer + timer * RIPRANDDEV * (r / UINT32_MAX - 0.5));  | 
    
    
    3152  | 
     | 
     | 
    	nextalarm = time(NULL) + interval;  | 
    
    
    3153  | 
     | 
     | 
    	return interval;  | 
    
    
    3154  | 
     | 
     | 
    }  | 
    
    
    3155  | 
     | 
     | 
     | 
    
    
    3156  | 
     | 
     | 
    time_t  | 
    
    
    3157  | 
     | 
     | 
    ripsuptrig(void)  | 
    
    
    3158  | 
     | 
     | 
    { | 
    
    
    3159  | 
     | 
     | 
    	time_t t;  | 
    
    
    3160  | 
     | 
     | 
     | 
    
    
    3161  | 
     | 
     | 
    	double r = arc4random();  | 
    
    
    3162  | 
     | 
     | 
    	t  = (int)(RIP_TRIG_INT6_MIN +  | 
    
    
    3163  | 
     | 
     | 
    		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / UINT32_MAX));  | 
    
    
    3164  | 
     | 
     | 
    	sup_trig_update = time(NULL) + t;  | 
    
    
    3165  | 
     | 
     | 
    	return t;  | 
    
    
    3166  | 
     | 
     | 
    }  | 
    
    
    3167  | 
     | 
     | 
     | 
    
    
    3168  | 
     | 
     | 
    unsigned int  | 
    
    
    3169  | 
     | 
     | 
    if_maxindex(void)  | 
    
    
    3170  | 
     | 
     | 
    { | 
    
    
    3171  | 
     | 
     | 
    	struct if_nameindex *p, *p0;  | 
    
    
    3172  | 
     | 
     | 
    	unsigned int max = 0;  | 
    
    
    3173  | 
     | 
     | 
     | 
    
    
    3174  | 
     | 
     | 
    	p0 = if_nameindex();  | 
    
    
    3175  | 
     | 
     | 
    	for (p = p0; p && p->if_index && p->if_name; p++) { | 
    
    
    3176  | 
     | 
     | 
    		if (max < p->if_index)  | 
    
    
    3177  | 
     | 
     | 
    			max = p->if_index;  | 
    
    
    3178  | 
     | 
     | 
    	}  | 
    
    
    3179  | 
     | 
     | 
    	if_freenameindex(p0);  | 
    
    
    3180  | 
     | 
     | 
    	return max;  | 
    
    
    3181  | 
     | 
     | 
    }  | 
    
    
    3182  | 
     | 
     | 
     | 
    
    
    3183  | 
     | 
     | 
    struct ifc *  | 
    
    
    3184  | 
     | 
     | 
    ifc_find(char *name)  | 
    
    
    3185  | 
     | 
     | 
    { | 
    
    
    3186  | 
     | 
     | 
    	struct ifc *ifcp;  | 
    
    
    3187  | 
     | 
     | 
     | 
    
    
    3188  | 
     | 
     | 
    	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { | 
    
    
    3189  | 
     | 
     | 
    		if (strcmp(name, ifcp->ifc_name) == 0)  | 
    
    
    3190  | 
     | 
     | 
    			return ifcp;  | 
    
    
    3191  | 
     | 
     | 
    	}  | 
    
    
    3192  | 
     | 
     | 
    	return (struct ifc *)NULL;  | 
    
    
    3193  | 
     | 
     | 
    }  | 
    
    
    3194  | 
     | 
     | 
     | 
    
    
    3195  | 
     | 
     | 
    struct iff *  | 
    
    
    3196  | 
     | 
     | 
    iff_find(struct ifc *ifcp, int type)  | 
    
    
    3197  | 
     | 
     | 
    { | 
    
    
    3198  | 
     | 
     | 
    	struct iff *iffp;  | 
    
    
    3199  | 
     | 
     | 
     | 
    
    
    3200  | 
     | 
     | 
    	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { | 
    
    
    3201  | 
     | 
     | 
    		if (iffp->iff_type == type)  | 
    
    
    3202  | 
     | 
     | 
    			return iffp;  | 
    
    
    3203  | 
     | 
     | 
    	}  | 
    
    
    3204  | 
     | 
     | 
    	return NULL;  | 
    
    
    3205  | 
     | 
     | 
    }  | 
    
    
    3206  | 
     | 
     | 
     | 
    
    
    3207  | 
     | 
     | 
    void  | 
    
    
    3208  | 
     | 
     | 
    setindex2ifc(int idx, struct ifc *ifcp)  | 
    
    
    3209  | 
     | 
     | 
    { | 
    
    
    3210  | 
     | 
     | 
    	int n;  | 
    
    
    3211  | 
     | 
     | 
    	struct ifc **p;  | 
    
    
    3212  | 
     | 
     | 
     | 
    
    
    3213  | 
     | 
     | 
    	if (!index2ifc) { | 
    
    
    3214  | 
     | 
     | 
    		nindex2ifc = 5;	/*initial guess*/  | 
    
    
    3215  | 
     | 
     | 
    		index2ifc = calloc(nindex2ifc, sizeof(*index2ifc));  | 
    
    
    3216  | 
     | 
     | 
    		if (index2ifc == NULL) { | 
    
    
    3217  | 
     | 
     | 
    			fatal("calloc"); | 
    
    
    3218  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    3219  | 
     | 
     | 
    		}  | 
    
    
    3220  | 
     | 
     | 
    	}  | 
    
    
    3221  | 
     | 
     | 
    	n = nindex2ifc;  | 
    
    
    3222  | 
     | 
     | 
    	while (nindex2ifc <= idx)  | 
    
    
    3223  | 
     | 
     | 
    		nindex2ifc *= 2;  | 
    
    
    3224  | 
     | 
     | 
    	if (n != nindex2ifc) { | 
    
    
    3225  | 
     | 
     | 
    		p = reallocarray(index2ifc, nindex2ifc, sizeof(*index2ifc));  | 
    
    
    3226  | 
     | 
     | 
    		if (p == NULL) { | 
    
    
    3227  | 
     | 
     | 
    			fatal("reallocarray"); | 
    
    
    3228  | 
     | 
     | 
    			/*NOTREACHED*/  | 
    
    
    3229  | 
     | 
     | 
    		}  | 
    
    
    3230  | 
     | 
     | 
    		memset(p + n, 0, (nindex2ifc - n) * sizeof(*index2ifc));  | 
    
    
    3231  | 
     | 
     | 
    		index2ifc = p;  | 
    
    
    3232  | 
     | 
     | 
    	}  | 
    
    
    3233  | 
     | 
     | 
    	index2ifc[idx] = ifcp;  | 
    
    
    3234  | 
     | 
     | 
    }  |