1 /* $NetBSD: route6d.c,v 1.61 2008/01/21 20:46:58 dyoung Exp $ */
2 /* $KAME: route6d.c,v 1.94 2002/10/26 20:08:55 itojun Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: route6d.c,v 1.61 2008/01/21 20:46:58 dyoung Exp $");
54 #include <sys/types.h>
55 #include <sys/param.h>
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <sys/sysctl.h>
62 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
63 #include <net/if_var.h>
64 #endif /* __FreeBSD__ >= 3 */
67 #include <net/route.h>
70 #include <netinet/in.h>
71 #include <netinet/in_var.h>
72 #include <netinet/ip6.h>
73 #include <netinet/udp.h>
77 #include <arpa/inet.h>
84 #define INIT_INTERVAL6 6
86 #define INIT_INTERVAL6 10 /* Wait to submit a initial riprequest */
89 /* alignment constraint for routing socket */
91 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
92 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
95 * Following two macros are highly depending on KAME Release
97 #define IN6_LINKLOCAL_IFINDEX(addr) \
98 ((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
100 #define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
102 (addr).s6_addr[2] = ((index) >> 8) & 0xff; \
103 (addr).s6_addr[3] = (index) & 0xff; \
106 struct ifc
{ /* Configuration of an interface */
107 char *ifc_name
; /* if name */
108 struct ifc
*ifc_next
;
109 int ifc_index
; /* if index */
110 int ifc_mtu
; /* if mtu */
111 int ifc_metric
; /* if metric */
112 u_int ifc_flags
; /* flags */
113 short ifc_cflags
; /* IFC_XXX */
114 struct in6_addr ifc_mylladdr
; /* my link-local address */
115 struct sockaddr_in6 ifc_ripsin
; /* rip multicast address */
116 struct iff
*ifc_filter
; /* filter structure */
117 struct ifac
*ifc_addr
; /* list of AF_INET6 addresses */
118 int ifc_joined
; /* joined to ff02::9 */
121 struct ifac
{ /* Address associated to an interface */
122 struct ifc
*ifa_conf
; /* back pointer */
123 struct ifac
*ifa_next
;
124 struct in6_addr ifa_addr
; /* address */
125 struct in6_addr ifa_raddr
; /* remote address, valid in p2p */
126 int ifa_plen
; /* prefix length */
131 struct in6_addr iff_addr
;
133 struct iff
*iff_next
;
137 int nifc
; /* number of valid ifc's */
138 struct ifc
**index2ifc
;
140 struct ifc
*loopifcp
= NULL
; /* pointing to loopback */
141 struct pollfd set
[2];
142 int rtsock
; /* the routing socket */
143 int ripsock
; /* socket to send/receive RIP datagram */
145 struct rip6
*ripbuf
; /* packet buffer for sending */
148 * Maintain the routes in a linked list. When the number of the routes
149 * grows, somebody would like to introduce a hash based or a radix tree
150 * based structure. I believe the number of routes handled by RIP is
151 * limited and I don't have to manage a complex data structure, however.
153 * One of the major drawbacks of the linear linked list is the difficulty
154 * of representing the relationship between a couple of routes. This may
155 * be a significant problem when we have to support route aggregation with
156 * supressing the specifices covered by the aggregate.
160 struct riprt
*rrt_next
; /* next destination */
161 struct riprt
*rrt_same
; /* same destination - future use */
162 struct netinfo6 rrt_info
; /* network info */
163 struct in6_addr rrt_gw
; /* gateway */
164 u_long rrt_flags
; /* kernel routing table flags */
165 u_long rrt_rflags
; /* route6d routing table flags */
166 time_t rrt_t
; /* when the route validated */
167 int rrt_index
; /* ifindex from which this route got */
170 struct riprt
*riprt
= 0;
172 int dflag
= 0; /* debug flag */
173 int qflag
= 0; /* quiet flag */
174 int nflag
= 0; /* don't update kernel routing table */
175 int aflag
= 0; /* age out even the statically defined routes */
176 int hflag
= 0; /* don't split horizon */
177 int lflag
= 0; /* exchange site local routes */
178 int sflag
= 0; /* announce static routes w/ split horizon */
179 int Sflag
= 0; /* announce static routes to every interface */
180 unsigned long routetag
= 0; /* route tag attached on originating case */
182 char *filter
[MAXFILTER
];
183 int filtertype
[MAXFILTER
];
188 struct sockaddr_storage ripsin
;
190 struct rtentry rtentry
;
193 time_t nextalarm
= 0;
194 time_t sup_trig_update
= 0;
202 volatile sig_atomic_t seenalrm
;
203 volatile sig_atomic_t seenquit
;
204 volatile sig_atomic_t seenusr1
;
206 #define RRTF_AGGREGATE 0x08000000
207 #define RRTF_NOADVERTISE 0x10000000
208 #define RRTF_NH_NOT_LLADDR 0x20000000
209 #define RRTF_SENDANYWAY 0x40000000
210 #define RRTF_CHANGED 0x80000000
212 int main(int, char **);
213 void sighandler(int);
216 void ripsend(struct ifc
*, struct sockaddr_in6
*, int);
217 int out_filter(struct riprt
*, struct ifc
*);
219 void sockopt(struct ifc
*);
221 void ifconfig1(const char *, const struct sockaddr
*, struct ifc
*, int);
223 int rt_del(const struct sockaddr_in6
*, const struct sockaddr_in6
*,
224 const struct sockaddr_in6
*);
225 int rt_deladdr(struct ifc
*, const struct sockaddr_in6
*,
226 const struct sockaddr_in6
*);
227 void filterconfig(void);
230 rttypes(struct rt_msghdr
*);
232 rtflags(struct rt_msghdr
*);
235 int ifrt(struct ifc
*, int);
236 void ifrt_p2p(struct ifc
*, int);
237 void applymask(struct in6_addr
*, struct in6_addr
*);
238 void applyplen(struct in6_addr
*, int);
241 void ifdump0(FILE *, const struct ifc
*);
243 void rt_entry(struct rt_msghdr
*, int);
245 void riprequest(struct ifc
*, struct netinfo6
*, int,
246 struct sockaddr_in6
*);
247 void ripflush(struct ifc
*, struct sockaddr_in6
*);
248 void sendrequest(struct ifc
*);
249 int sin6mask2len(const struct sockaddr_in6
*);
250 int mask2len(const struct in6_addr
*, int);
251 int sendpacket(struct sockaddr_in6
*, int);
252 int addroute(struct riprt
*, const struct in6_addr
*, struct ifc
*);
253 int delroute(struct netinfo6
*, struct in6_addr
*);
255 getroute(struct netinfo6
*, struct in6_addr
*);
257 int tobeadv(struct riprt
*, struct ifc
*);
258 char * allocopy(char *);
261 inet6_n2p(const struct in6_addr
*);
263 ifa_match(const struct ifc
*, const struct in6_addr
*, int);
267 rtsearch(struct netinfo6
*, struct riprt
**);
268 int ripinterval(int);
269 time_t ripsuptrig(void);
270 void fatal(const char *, ...)
271 __attribute__((__format__(__printf__
, 1, 2)));
272 void trace(int, const char *, ...)
273 __attribute__((__format__(__printf__
, 2, 3)));
274 void tracet(int, const char *, ...)
275 __attribute__((__format__(__printf__
, 2, 3)));
281 iff_find(struct ifc
*, int);
282 void setindex2ifc(int, struct ifc
*);
284 #define MALLOC(type) ((type *)malloc(sizeof(type)))
287 main(int argc
, char **argv
)
292 sigset_t mask
, omask
;
296 progname
= strrchr(*argv
, '/');
303 while ((ch
= getopt(argc
, argv
, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
310 if (nfilter
>= MAXFILTER
) {
311 fatal("Exceeds MAXFILTER");
314 filtertype
[nfilter
] = ch
;
315 filter
[nfilter
++] = allocopy(optarg
);
319 routetag
= strtoul(optarg
, &ep
, 0);
320 if (!ep
|| *ep
!= '\0' || (routetag
& ~0xffff) != 0) {
321 fatal("invalid route tag");
326 if ((rtlog
= fopen(optarg
, "w")) == NULL
) {
327 fatal("Can not write to routelog");
331 #define FLAG(c, flag, n) case c: do { flag = n; break; } while(0)
332 FLAG('a', aflag
, 1); break;
333 FLAG('d', dflag
, 1); break;
334 FLAG('D', dflag
, 2); break;
335 FLAG('h', hflag
, 1); break;
336 FLAG('l', lflag
, 1); break;
337 FLAG('n', nflag
, 1); break;
338 FLAG('q', qflag
, 1); break;
339 FLAG('s', sflag
, 1); break;
340 FLAG('S', Sflag
, 1); break;
343 fatal("Invalid option specified, terminating");
350 fatal("bogus extra arguments");
356 fprintf(stderr
, "No kernel update is allowed\n");
360 if (daemon(0, 0) < 0) {
366 openlog(progname
, LOG_NDELAY
|LOG_PID
, LOG_DAEMON
);
369 if ((ripbuf
= (struct rip6
*)malloc(RIP6_MAXMTU
)) == NULL
)
371 memset(ripbuf
, 0, RIP6_MAXMTU
);
372 ripbuf
->rip6_cmd
= RIP6_RESPONSE
;
373 ripbuf
->rip6_vers
= RIP6_VERSION
;
374 ripbuf
->rip6_res1
[0] = 0;
375 ripbuf
->rip6_res1
[1] = 0;
379 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
) {
380 if (ifcp
->ifc_index
< 0) {
382 "No ifindex found at %s (no link-local address?)\n",
389 if (loopifcp
== NULL
) {
390 fatal("No loopback found");
393 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
)
402 if ((ripbuf
= (struct rip6
*)malloc(RIP6_MAXMTU
)) == NULL
) {
406 memset(ripbuf
, 0, RIP6_MAXMTU
);
407 ripbuf
->rip6_cmd
= RIP6_RESPONSE
;
408 ripbuf
->rip6_vers
= RIP6_VERSION
;
409 ripbuf
->rip6_res1
[0] = 0;
410 ripbuf
->rip6_res1
[1] = 0;
412 if (signal(SIGALRM
, sighandler
) == SIG_ERR
||
413 signal(SIGQUIT
, sighandler
) == SIG_ERR
||
414 signal(SIGTERM
, sighandler
) == SIG_ERR
||
415 signal(SIGUSR1
, sighandler
) == SIG_ERR
||
416 signal(SIGHUP
, sighandler
) == SIG_ERR
||
417 signal(SIGINT
, sighandler
) == SIG_ERR
) {
422 * To avoid rip packet congestion (not on a cable but in this
423 * process), wait for a moment to send the first RIP6_RESPONSE
426 alarm(ripinterval(INIT_INTERVAL6
));
428 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
) {
429 if (iff_find(ifcp
, 'N'))
431 if (ifcp
->ifc_index
> 0 && (ifcp
->ifc_flags
& IFF_UP
))
435 syslog(LOG_INFO
, "**** Started ****");
437 sigaddset(&mask
, SIGALRM
);
455 switch (poll(set
, 2, INFTIM
))
458 if (errno
!= EINTR
) {
466 if (set
[0].revents
& POLLIN
)
468 sigprocmask(SIG_BLOCK
, &mask
, &omask
);
470 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
472 if (set
[1].revents
& POLLIN
)
474 sigprocmask(SIG_BLOCK
, &mask
, &omask
);
476 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
483 sighandler(int signo
)
503 * gracefully exits after resetting sockopts.
512 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
513 if (rrt
->rrt_rflags
& RRTF_AGGREGATE
) {
514 delroute(&rrt
->rrt_info
, &rrt
->rrt_gw
);
519 syslog(LOG_INFO
, "**** Terminated ****");
525 * Called periodically:
526 * 1. age out the learned route. remove it if necessary.
527 * 2. submit RIP6_RESPONSE packets.
528 * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have
529 * to invoke this function in every 1 or 5 or 10 seconds only to age the
530 * routes more precisely.
537 struct riprt
*rrt
, *rrt_prev
, *rrt_next
;
538 time_t t_lifetime
, t_holddown
;
540 /* age the RIP routes */
542 t_lifetime
= time(NULL
) - RIP_LIFETIME
;
543 t_holddown
= t_lifetime
- RIP_HOLDDOWN
;
544 for (rrt
= riprt
; rrt
; rrt
= rrt_next
) {
545 rrt_next
= rrt
->rrt_next
;
547 if (rrt
->rrt_t
== 0) {
551 if (rrt
->rrt_t
< t_holddown
) {
553 rrt_prev
->rrt_next
= rrt
->rrt_next
;
555 riprt
= rrt
->rrt_next
;
557 delroute(&rrt
->rrt_info
, &rrt
->rrt_gw
);
561 if (rrt
->rrt_t
< t_lifetime
)
562 rrt
->rrt_info
.rip6_metric
= HOPCNT_INFINITY6
;
566 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
) {
567 if (ifcp
->ifc_index
> 0 && (ifcp
->ifc_flags
& IFF_UP
))
568 ripsend(ifcp
, &ifcp
->ifc_ripsin
, 0);
570 alarm(ripinterval(SUPPLY_INTERVAL6
));
577 const int int0
= 0, int1
= 1, int255
= 255;
578 struct addrinfo hints
, *res
;
579 char port
[NI_MAXSERV
];
581 ifc
= (struct ifc
*)NULL
;
583 nindex2ifc
= 0; /*initial guess*/
585 snprintf(port
, sizeof(port
), "%u", RIP6_PORT
);
587 memset(&hints
, 0, sizeof(hints
));
588 hints
.ai_family
= PF_INET6
;
589 hints
.ai_socktype
= SOCK_DGRAM
;
590 hints
.ai_flags
= AI_PASSIVE
;
591 error
= getaddrinfo(NULL
, port
, &hints
, &res
);
593 fatal("%s", gai_strerror(error
));
597 fatal(":: resolved to multiple address");
601 ripsock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
606 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
607 &int1
, sizeof(int1
)) < 0) {
608 fatal("rip IPV6_V6ONLY");
611 if (bind(ripsock
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
615 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
616 &int255
, sizeof(int255
)) < 0) {
617 fatal("rip IPV6_MULTICAST_HOPS");
620 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
621 &int0
, sizeof(int0
)) < 0) {
622 fatal("rip IPV6_MULTICAST_LOOP");
627 #ifdef IPV6_RECVPKTINFO
628 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &i
,
630 fatal("rip IPV6_RECVPKTINFO");
633 #else /* old adv. API */
634 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_PKTINFO
, &i
,
636 fatal("rip IPV6_PKTINFO");
641 memset(&hints
, 0, sizeof(hints
));
642 hints
.ai_family
= PF_INET6
;
643 hints
.ai_socktype
= SOCK_DGRAM
;
644 error
= getaddrinfo(RIP6_DEST
, port
, &hints
, &res
);
646 fatal("%s", gai_strerror(error
));
650 fatal("%s resolved to multiple address", RIP6_DEST
);
653 memcpy(&ripsin
, res
->ai_addr
, res
->ai_addrlen
);
656 set
[0].events
= POLLIN
;
659 if ((rtsock
= socket(PF_ROUTE
, SOCK_RAW
, 0)) < 0) {
660 fatal("route socket");
664 set
[1].events
= POLLIN
;
671 (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
674 * ripflush flushes the rip datagram stored in the rip buffer
677 static struct netinfo6
*nip
;
680 ripflush(struct ifc
*ifcp
, struct sockaddr_in6
*sin6
)
686 tracet(1, "Send(%s): info(%d) to %s.%d\n",
688 inet6_n2p(&sin6
->sin6_addr
), ntohs(sin6
->sin6_port
));
690 tracet(1, "Send: info(%d) to %s.%d\n",
691 nrt
, inet6_n2p(&sin6
->sin6_addr
), ntohs(sin6
->sin6_port
));
693 nip
= ripbuf
->rip6_nets
;
694 for (i
= 0; i
< nrt
; i
++, nip
++) {
695 if (nip
->rip6_metric
== NEXTHOP_METRIC
) {
696 if (IN6_IS_ADDR_UNSPECIFIED(&nip
->rip6_dest
))
697 trace(2, " NextHop reset");
699 trace(2, " NextHop %s",
700 inet6_n2p(&nip
->rip6_dest
));
703 trace(2, " %s/%d[%d]",
704 inet6_n2p(&nip
->rip6_dest
),
705 nip
->rip6_plen
, nip
->rip6_metric
);
708 trace(2, " tag=0x%04x",
709 ntohs(nip
->rip6_tag
) & 0xffff);
714 error
= sendpacket(sin6
, RIPSIZE(nrt
));
715 if (error
== EAFNOSUPPORT
&& ifcp
) {
716 /* Protocol not supported */
717 tracet(1, "Could not send info to %s (%s): "
719 ifcp
->ifc_name
, inet6_n2p(&ifcp
->ifc_ripsin
.sin6_addr
));
720 ifcp
->ifc_flags
&= ~IFF_UP
; /* As if down for AF_INET6 */
722 nrt
= 0; nip
= ripbuf
->rip6_nets
;
726 * Generate RIP6_RESPONSE packets and send them.
729 ripsend(struct ifc
*ifcp
, struct sockaddr_in6
*sin6
, int flag
)
732 struct in6_addr
*nh
; /* next hop */
740 * Request from non-link local address is not
741 * a regular route6d update.
743 maxrte
= (IFMINMTU
- sizeof(struct ip6_hdr
) -
744 sizeof(struct udphdr
) -
745 sizeof(struct rip6
) + sizeof(struct netinfo6
)) /
746 sizeof(struct netinfo6
);
747 nrt
= 0; nip
= ripbuf
->rip6_nets
; nh
= NULL
;
748 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
749 if (rrt
->rrt_rflags
& RRTF_NOADVERTISE
)
751 /* Put the route to the buffer */
752 *nip
= rrt
->rrt_info
;
755 ripflush(NULL
, sin6
);
759 if (nrt
) /* Send last packet */
760 ripflush(NULL
, sin6
);
764 if ((flag
& RRTF_SENDANYWAY
) == 0 &&
765 (qflag
|| (ifcp
->ifc_flags
& IFF_LOOPBACK
)))
769 if (iff_find(ifcp
, 'N') != NULL
)
772 /* -T: generate default route only */
773 if (iff_find(ifcp
, 'T') != NULL
) {
774 struct netinfo6 rrt_info
;
775 memset(&rrt_info
, 0, sizeof(struct netinfo6
));
776 rrt_info
.rip6_dest
= in6addr_any
;
777 rrt_info
.rip6_plen
= 0;
778 rrt_info
.rip6_metric
= 1;
779 rrt_info
.rip6_metric
+= ifcp
->ifc_metric
;
780 rrt_info
.rip6_tag
= htons(routetag
& 0xffff);
781 nip
= ripbuf
->rip6_nets
;
784 ripflush(ifcp
, sin6
);
788 maxrte
= (ifcp
->ifc_mtu
- sizeof(struct ip6_hdr
) -
789 sizeof(struct udphdr
) -
790 sizeof(struct rip6
) + sizeof(struct netinfo6
)) /
791 sizeof(struct netinfo6
);
793 nrt
= 0; nip
= ripbuf
->rip6_nets
; nh
= NULL
;
794 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
795 if (rrt
->rrt_rflags
& RRTF_NOADVERTISE
)
798 /* Need to check filter here */
799 if (out_filter(rrt
, ifcp
) == 0)
802 /* Check split horizon and other conditions */
803 if (tobeadv(rrt
, ifcp
) == 0)
806 /* Only considers the routes with flag if specified */
807 if ((flag
& RRTF_CHANGED
) &&
808 (rrt
->rrt_rflags
& RRTF_CHANGED
) == 0)
812 if (rrt
->rrt_index
== ifcp
->ifc_index
&&
813 !IN6_IS_ADDR_UNSPECIFIED(&rrt
->rrt_gw
) &&
814 (rrt
->rrt_rflags
& RRTF_NH_NOT_LLADDR
) == 0) {
815 if (nh
== NULL
|| !IN6_ARE_ADDR_EQUAL(nh
, &rrt
->rrt_gw
)) {
816 if (nrt
== maxrte
- 2)
817 ripflush(ifcp
, sin6
);
818 nip
->rip6_dest
= rrt
->rrt_gw
;
819 if (IN6_IS_ADDR_LINKLOCAL(&nip
->rip6_dest
))
820 SET_IN6_LINKLOCAL_IFINDEX(nip
->rip6_dest
, 0);
823 nip
->rip6_metric
= NEXTHOP_METRIC
;
827 } else if (nh
&& (rrt
->rrt_index
!= ifcp
->ifc_index
||
828 !IN6_ARE_ADDR_EQUAL(nh
, &rrt
->rrt_gw
) ||
829 rrt
->rrt_rflags
& RRTF_NH_NOT_LLADDR
)) {
831 if (nrt
== maxrte
- 2)
832 ripflush(ifcp
, sin6
);
833 memset(nip
, 0, sizeof(struct netinfo6
));
834 nip
->rip6_metric
= NEXTHOP_METRIC
;
839 /* Put the route to the buffer */
840 *nip
= rrt
->rrt_info
;
843 ripflush(ifcp
, sin6
);
847 if (nrt
) /* Send last packet */
848 ripflush(ifcp
, sin6
);
852 * outbound filter logic, per-route/interface.
855 out_filter(struct riprt
*rrt
, struct ifc
*ifcp
)
862 * -A: filter out less specific routes, if we have aggregated
865 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
866 if (iffp
->iff_type
!= 'A')
868 if (rrt
->rrt_info
.rip6_plen
<= iffp
->iff_plen
)
870 ia
= rrt
->rrt_info
.rip6_dest
;
871 applyplen(&ia
, iffp
->iff_plen
);
872 if (IN6_ARE_ADDR_EQUAL(&ia
, &iffp
->iff_addr
))
877 * if it is an aggregated route, advertise it only to the
878 * interfaces specified on -A.
880 if ((rrt
->rrt_rflags
& RRTF_AGGREGATE
) != 0) {
882 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
883 if (iffp
->iff_type
!= 'A')
885 if (rrt
->rrt_info
.rip6_plen
== iffp
->iff_plen
&&
886 IN6_ARE_ADDR_EQUAL(&rrt
->rrt_info
.rip6_dest
,
897 * -O: advertise only if prefix matches the configured prefix.
899 if (iff_find(ifcp
, 'O')) {
901 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
902 if (iffp
->iff_type
!= 'O')
904 if (rrt
->rrt_info
.rip6_plen
< iffp
->iff_plen
)
906 ia
= rrt
->rrt_info
.rip6_dest
;
907 applyplen(&ia
, iffp
->iff_plen
);
908 if (IN6_ARE_ADDR_EQUAL(&ia
, &iffp
->iff_addr
)) {
917 /* the prefix should be advertised */
922 * Determine if the route is to be advertised on the specified interface.
923 * It checks options specified in the arguments and the split horizon rule.
926 tobeadv(struct riprt
*rrt
, struct ifc
*ifcp
)
929 /* Special care for static routes */
930 if (rrt
->rrt_flags
& RTF_STATIC
) {
931 /* XXX don't advertise reject/blackhole routes */
932 if (rrt
->rrt_flags
& (RTF_REJECT
| RTF_BLACKHOLE
))
935 if (Sflag
) /* Yes, advertise it anyway */
937 if (sflag
&& rrt
->rrt_index
!= ifcp
->ifc_index
)
941 /* Regular split horizon */
942 if (hflag
== 0 && rrt
->rrt_index
== ifcp
->ifc_index
)
948 * Send a rip packet actually.
951 sendpacket(struct sockaddr_in6
*sin6
, int len
)
957 struct in6_pktinfo
*pi
;
959 struct sockaddr_in6 sincopy
;
961 /* do not overwrite the given sin */
965 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) ||
966 IN6_IS_ADDR_MULTICAST(&sin6
->sin6_addr
)) {
967 /* XXX: do not mix the interface index and link index */
968 idx
= IN6_LINKLOCAL_IFINDEX(sin6
->sin6_addr
);
969 SET_IN6_LINKLOCAL_IFINDEX(sin6
->sin6_addr
, 0);
970 sin6
->sin6_scope_id
= idx
;
974 m
.msg_name
= (caddr_t
)sin6
;
975 m
.msg_namelen
= sizeof(*sin6
);
976 iov
[0].iov_base
= (caddr_t
)ripbuf
;
977 iov
[0].iov_len
= len
;
981 m
.msg_control
= NULL
;
982 m
.msg_controllen
= 0;
984 memset(cmsgbuf
, 0, sizeof(cmsgbuf
));
985 cm
= (struct cmsghdr
*)cmsgbuf
;
986 m
.msg_control
= (caddr_t
)cm
;
987 m
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
989 cm
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
990 cm
->cmsg_level
= IPPROTO_IPV6
;
991 cm
->cmsg_type
= IPV6_PKTINFO
;
992 pi
= (struct in6_pktinfo
*)CMSG_DATA(cm
);
993 memset(&pi
->ipi6_addr
, 0, sizeof(pi
->ipi6_addr
)); /*::*/
994 pi
->ipi6_ifindex
= idx
;
997 if (sendmsg(ripsock
, &m
, 0 /*MSG_DONTROUTE*/) < 0) {
998 trace(1, "sendmsg: %s\n", strerror(errno
));
1006 * Receive and process RIP packets. Update the routes/kernel forwarding
1007 * table if necessary.
1012 struct ifc
*ifcp
, *ic
;
1013 struct sockaddr_in6 fsock
;
1014 struct in6_addr nh
; /* next hop */
1016 struct netinfo6
*np
, *nq
;
1019 unsigned int need_trigger
, idx
;
1020 char buf
[4 * RIP6_MAXMTU
];
1024 struct iovec iov
[2];
1025 u_char cmsgbuf
[256];
1026 struct in6_pktinfo
*pi
;
1030 time_t t_half_lifetime
;
1034 m
.msg_name
= (caddr_t
)&fsock
;
1035 m
.msg_namelen
= sizeof(fsock
);
1036 iov
[0].iov_base
= (caddr_t
)buf
;
1037 iov
[0].iov_len
= sizeof(buf
);
1040 cm
= (struct cmsghdr
*)cmsgbuf
;
1041 m
.msg_control
= (caddr_t
)cm
;
1042 m
.msg_controllen
= sizeof(cmsgbuf
);
1043 if ((len
= recvmsg(ripsock
, &m
, 0)) < 0) {
1048 for (cm
= (struct cmsghdr
*)CMSG_FIRSTHDR(&m
);
1050 cm
= (struct cmsghdr
*)CMSG_NXTHDR(&m
, cm
)) {
1051 if (cm
->cmsg_level
== IPPROTO_IPV6
&&
1052 cm
->cmsg_type
== IPV6_PKTINFO
) {
1053 pi
= (struct in6_pktinfo
*)(CMSG_DATA(cm
));
1054 idx
= pi
->ipi6_ifindex
;
1058 if (idx
&& IN6_IS_ADDR_LINKLOCAL(&fsock
.sin6_addr
))
1059 SET_IN6_LINKLOCAL_IFINDEX(fsock
.sin6_addr
, idx
);
1061 if (len
< (int)sizeof(struct rip6
)) {
1062 trace(1, "Packet too short\n");
1066 nh
= fsock
.sin6_addr
;
1067 nn
= (len
- sizeof(struct rip6
) + sizeof(struct netinfo6
)) /
1068 sizeof(struct netinfo6
);
1069 rp
= (struct rip6
*)buf
;
1072 if (rp
->rip6_vers
!= RIP6_VERSION
) {
1073 trace(1, "Incorrect RIP version %d\n", rp
->rip6_vers
);
1076 if (rp
->rip6_cmd
== RIP6_REQUEST
) {
1077 if (idx
&& idx
< (unsigned)nindex2ifc
) {
1078 ifcp
= index2ifc
[idx
];
1079 riprequest(ifcp
, np
, nn
, &fsock
);
1081 riprequest(NULL
, np
, nn
, &fsock
);
1086 if (!IN6_IS_ADDR_LINKLOCAL(&fsock
.sin6_addr
)) {
1087 trace(1, "Packets from non-ll addr: %s\n",
1088 inet6_n2p(&fsock
.sin6_addr
));
1089 return; /* Ignore packets from non-link-local addr */
1091 idx
= IN6_LINKLOCAL_IFINDEX(fsock
.sin6_addr
);
1092 ifcp
= (idx
< (unsigned)nindex2ifc
) ? index2ifc
[idx
] : NULL
;
1094 trace(1, "Packets to unknown interface index %d\n", idx
);
1095 return; /* Ignore it */
1097 if (IN6_ARE_ADDR_EQUAL(&ifcp
->ifc_mylladdr
, &fsock
.sin6_addr
))
1098 return; /* The packet is from me; ignore */
1099 if (rp
->rip6_cmd
!= RIP6_RESPONSE
) {
1100 trace(1, "Invalid command %d\n", rp
->rip6_cmd
);
1105 if (iff_find(ifcp
, 'N') != NULL
)
1108 tracet(1, "Recv(%s): from %s.%d info(%d)\n",
1109 ifcp
->ifc_name
, inet6_n2p(&nh
), ntohs(fsock
.sin6_port
), (int)nn
);
1112 t_half_lifetime
= t
- (RIP_LIFETIME
/2);
1113 for (; nn
; nn
--, np
++) {
1114 if (np
->rip6_metric
== NEXTHOP_METRIC
) {
1115 /* modify neighbor address */
1116 if (IN6_IS_ADDR_LINKLOCAL(&np
->rip6_dest
)) {
1118 SET_IN6_LINKLOCAL_IFINDEX(nh
, idx
);
1119 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh
));
1120 } else if (IN6_IS_ADDR_UNSPECIFIED(&np
->rip6_dest
)) {
1121 nh
= fsock
.sin6_addr
;
1122 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh
));
1124 nh
= fsock
.sin6_addr
;
1125 trace(1, "\tInvalid Nexthop: %s\n",
1126 inet6_n2p(&np
->rip6_dest
));
1130 if (IN6_IS_ADDR_MULTICAST(&np
->rip6_dest
)) {
1131 trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
1132 inet6_n2p(&np
->rip6_dest
),
1133 np
->rip6_plen
, np
->rip6_metric
);
1136 if (IN6_IS_ADDR_LOOPBACK(&np
->rip6_dest
)) {
1137 trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
1138 inet6_n2p(&np
->rip6_dest
),
1139 np
->rip6_plen
, np
->rip6_metric
);
1142 if (IN6_IS_ADDR_LINKLOCAL(&np
->rip6_dest
)) {
1143 trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
1144 inet6_n2p(&np
->rip6_dest
),
1145 np
->rip6_plen
, np
->rip6_metric
);
1148 /* may need to pass sitelocal prefix in some case, however*/
1149 if (IN6_IS_ADDR_SITELOCAL(&np
->rip6_dest
) && !lflag
) {
1150 trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
1151 inet6_n2p(&np
->rip6_dest
),
1152 np
->rip6_plen
, np
->rip6_metric
);
1155 trace(2, "\tnetinfo6: %s/%d [%d]",
1156 inet6_n2p(&np
->rip6_dest
),
1157 np
->rip6_plen
, np
->rip6_metric
);
1159 trace(2, " tag=0x%04x", ntohs(np
->rip6_tag
) & 0xffff);
1162 applyplen(&ia
, np
->rip6_plen
);
1163 if (!IN6_ARE_ADDR_EQUAL(&ia
, &np
->rip6_dest
))
1164 trace(2, " [junk outside prefix]");
1168 * -L: listen only if the prefix matches the configuration
1170 ok
= 1; /* if there's no L filter, it is ok */
1171 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
1172 if (iffp
->iff_type
!= 'L')
1175 if (np
->rip6_plen
< iffp
->iff_plen
)
1177 /* special rule: ::/0 means default, not "in /0" */
1178 if (iffp
->iff_plen
== 0 && np
->rip6_plen
> 0)
1181 applyplen(&ia
, iffp
->iff_plen
);
1182 if (IN6_ARE_ADDR_EQUAL(&ia
, &iffp
->iff_addr
)) {
1188 trace(2, " (filtered)\n");
1194 np
->rip6_metric
+= ifcp
->ifc_metric
;
1195 if (np
->rip6_metric
> HOPCNT_INFINITY6
)
1196 np
->rip6_metric
= HOPCNT_INFINITY6
;
1198 applyplen(&np
->rip6_dest
, np
->rip6_plen
);
1199 if ((rrt
= rtsearch(np
, NULL
)) != NULL
) {
1200 if (rrt
->rrt_t
== 0)
1201 continue; /* Intf route has priority */
1202 nq
= &rrt
->rrt_info
;
1203 if (nq
->rip6_metric
> np
->rip6_metric
) {
1204 if (rrt
->rrt_index
== ifcp
->ifc_index
&&
1205 IN6_ARE_ADDR_EQUAL(&nh
, &rrt
->rrt_gw
)) {
1206 /* Small metric from the same gateway */
1207 nq
->rip6_metric
= np
->rip6_metric
;
1209 /* Better route found */
1210 rrt
->rrt_index
= ifcp
->ifc_index
;
1211 /* Update routing table */
1212 delroute(nq
, &rrt
->rrt_gw
);
1215 addroute(rrt
, &nh
, ifcp
);
1217 rrt
->rrt_rflags
|= RRTF_CHANGED
;
1220 } else if (nq
->rip6_metric
< np
->rip6_metric
&&
1221 rrt
->rrt_index
== ifcp
->ifc_index
&&
1222 IN6_ARE_ADDR_EQUAL(&nh
, &rrt
->rrt_gw
)) {
1223 /* Got worse route from same gw */
1224 nq
->rip6_metric
= np
->rip6_metric
;
1226 rrt
->rrt_rflags
|= RRTF_CHANGED
;
1228 } else if (nq
->rip6_metric
== np
->rip6_metric
&&
1229 np
->rip6_metric
< HOPCNT_INFINITY6
) {
1230 if (rrt
->rrt_index
== ifcp
->ifc_index
&&
1231 IN6_ARE_ADDR_EQUAL(&nh
, &rrt
->rrt_gw
)) {
1232 /* same metric, same route from same gw */
1234 } else if (rrt
->rrt_t
< t_half_lifetime
) {
1235 /* Better route found */
1236 rrt
->rrt_index
= ifcp
->ifc_index
;
1237 /* Update routing table */
1238 delroute(nq
, &rrt
->rrt_gw
);
1241 addroute(rrt
, &nh
, ifcp
);
1242 rrt
->rrt_rflags
|= RRTF_CHANGED
;
1247 * if nq->rip6_metric == HOPCNT_INFINITY6 then
1248 * do not update age value. Do nothing.
1250 } else if (np
->rip6_metric
< HOPCNT_INFINITY6
) {
1251 /* Got a new valid route */
1252 if ((rrt
= MALLOC(struct riprt
)) == NULL
) {
1253 fatal("malloc: struct riprt");
1256 memset(rrt
, 0, sizeof(*rrt
));
1257 nq
= &rrt
->rrt_info
;
1259 rrt
->rrt_same
= NULL
;
1260 rrt
->rrt_index
= ifcp
->ifc_index
;
1261 rrt
->rrt_flags
= RTF_UP
|RTF_GATEWAY
;
1264 applyplen(&nq
->rip6_dest
, nq
->rip6_plen
);
1265 if (nq
->rip6_plen
== sizeof(struct in6_addr
) * 8)
1266 rrt
->rrt_flags
|= RTF_HOST
;
1268 /* Put the route to the list */
1269 rrt
->rrt_next
= riprt
;
1271 /* Update routing table */
1272 addroute(rrt
, &nh
, ifcp
);
1273 rrt
->rrt_rflags
|= RRTF_CHANGED
;
1278 /* XXX need to care the interval between triggered updates */
1280 if (nextalarm
> time(NULL
) + RIP_TRIG_INT6_MAX
) {
1281 for (ic
= ifc
; ic
; ic
= ic
->ifc_next
) {
1282 if (ifcp
->ifc_index
== ic
->ifc_index
)
1284 if (ic
->ifc_flags
& IFF_UP
)
1285 ripsend(ic
, &ic
->ifc_ripsin
,
1289 /* Reset the flag */
1290 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
)
1291 rrt
->rrt_rflags
&= ~RRTF_CHANGED
;
1296 * Send all routes request packet to the specified interface.
1299 sendrequest(struct ifc
*ifcp
)
1301 struct netinfo6
*np
;
1304 if (ifcp
->ifc_flags
& IFF_LOOPBACK
)
1306 ripbuf
->rip6_cmd
= RIP6_REQUEST
;
1307 np
= ripbuf
->rip6_nets
;
1308 memset(np
, 0, sizeof(struct netinfo6
));
1309 np
->rip6_metric
= HOPCNT_INFINITY6
;
1310 tracet(1, "Send rtdump Request to %s (%s)\n",
1311 ifcp
->ifc_name
, inet6_n2p(&ifcp
->ifc_ripsin
.sin6_addr
));
1312 error
= sendpacket(&ifcp
->ifc_ripsin
, RIPSIZE(1));
1313 if (error
== EAFNOSUPPORT
) {
1314 /* Protocol not supported */
1315 tracet(1, "Could not send rtdump Request to %s (%s): "
1316 "set IFF_UP to 0\n",
1317 ifcp
->ifc_name
, inet6_n2p(&ifcp
->ifc_ripsin
.sin6_addr
));
1318 ifcp
->ifc_flags
&= ~IFF_UP
; /* As if down for AF_INET6 */
1320 ripbuf
->rip6_cmd
= RIP6_RESPONSE
;
1324 * Process a RIP6_REQUEST packet.
1327 riprequest(struct ifc
*ifcp
, struct netinfo6
*np
, int nn
,
1328 struct sockaddr_in6
*sin6
)
1333 if (!(nn
== 1 && IN6_IS_ADDR_UNSPECIFIED(&np
->rip6_dest
) &&
1334 np
->rip6_plen
== 0 && np
->rip6_metric
== HOPCNT_INFINITY6
)) {
1335 /* Specific response, don't split-horizon */
1336 trace(1, "\tRIP Request\n");
1337 for (i
= 0; i
< nn
; i
++, np
++) {
1338 rrt
= rtsearch(np
, NULL
);
1340 np
->rip6_metric
= rrt
->rrt_info
.rip6_metric
;
1342 np
->rip6_metric
= HOPCNT_INFINITY6
;
1344 (void)sendpacket(sin6
, RIPSIZE(nn
));
1347 /* Whole routing table dump */
1348 trace(1, "\tRIP Request -- whole routing table\n");
1349 ripsend(ifcp
, sin6
, RRTF_SENDANYWAY
);
1353 * Get information of each interface.
1358 struct ifaddrs
*ifap
, *ifa
;
1360 struct ipv6_mreq mreq
;
1363 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1368 if (getifaddrs(&ifap
) != 0) {
1369 fatal("getifaddrs");
1373 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
1374 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1376 ifcp
= ifc_find(ifa
->ifa_name
);
1377 /* we are interested in multicast-capable interfaces */
1378 if ((ifa
->ifa_flags
& IFF_MULTICAST
) == 0)
1382 if ((ifcp
= MALLOC(struct ifc
)) == NULL
) {
1383 fatal("malloc: struct ifc");
1386 memset(ifcp
, 0, sizeof(*ifcp
));
1387 ifcp
->ifc_index
= -1;
1388 ifcp
->ifc_next
= ifc
;
1391 ifcp
->ifc_name
= allocopy(ifa
->ifa_name
);
1393 ifcp
->ifc_filter
= 0;
1394 ifcp
->ifc_flags
= ifa
->ifa_flags
;
1395 trace(1, "newif %s <%s>\n", ifcp
->ifc_name
,
1396 ifflags(ifcp
->ifc_flags
));
1397 if (!strcmp(ifcp
->ifc_name
, LOOPBACK_IF
))
1400 /* update flag, this may be up again */
1401 if (ifcp
->ifc_flags
!= ifa
->ifa_flags
) {
1402 trace(1, "%s: <%s> -> ", ifcp
->ifc_name
,
1403 ifflags(ifcp
->ifc_flags
));
1404 trace(1, "<%s>\n", ifflags(ifa
->ifa_flags
));
1405 ifcp
->ifc_cflags
|= IFC_CHANGED
;
1407 ifcp
->ifc_flags
= ifa
->ifa_flags
;
1409 ifconfig1(ifa
->ifa_name
, ifa
->ifa_addr
, ifcp
, s
);
1410 if ((ifcp
->ifc_flags
& (IFF_LOOPBACK
| IFF_UP
)) == IFF_UP
1411 && 0 < ifcp
->ifc_index
&& !ifcp
->ifc_joined
) {
1412 mreq
.ipv6mr_multiaddr
= ifcp
->ifc_ripsin
.sin6_addr
;
1413 mreq
.ipv6mr_interface
= ifcp
->ifc_index
;
1414 if (setsockopt(ripsock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
1415 &mreq
, sizeof(mreq
)) < 0) {
1416 fatal("IPV6_JOIN_GROUP");
1419 trace(1, "join %s %s\n", ifcp
->ifc_name
, RIP6_DEST
);
1428 ifconfig1(const char *name
, const struct sockaddr
*sa
, struct ifc
*ifcp
, int s
)
1430 struct in6_ifreq ifr
;
1431 const struct sockaddr_in6
*sin6
;
1436 sin6
= (const struct sockaddr_in6
*)sa
;
1437 if (IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
) && !lflag
)
1439 ifr
.ifr_addr
= *sin6
;
1440 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
1441 if (ioctl(s
, SIOCGIFNETMASK_IN6
, (char *)&ifr
) < 0) {
1442 fatal("ioctl: SIOCGIFNETMASK_IN6");
1445 plen
= sin6mask2len(&ifr
.ifr_addr
);
1446 if ((ifa
= ifa_match(ifcp
, &sin6
->sin6_addr
, plen
)) != NULL
) {
1447 /* same interface found */
1448 /* need check if something changed */
1449 /* XXX not yet implemented */
1453 * New address is found
1455 if ((ifa
= MALLOC(struct ifac
)) == NULL
) {
1456 fatal("malloc: struct ifac");
1459 memset(ifa
, 0, sizeof(*ifa
));
1460 ifa
->ifa_conf
= ifcp
;
1461 ifa
->ifa_next
= ifcp
->ifc_addr
;
1462 ifcp
->ifc_addr
= ifa
;
1463 ifa
->ifa_addr
= sin6
->sin6_addr
;
1464 ifa
->ifa_plen
= plen
;
1465 if (ifcp
->ifc_flags
& IFF_POINTOPOINT
) {
1466 ifr
.ifr_addr
= *sin6
;
1467 if (ioctl(s
, SIOCGIFDSTADDR_IN6
, (char *)&ifr
) < 0) {
1468 fatal("ioctl: SIOCGIFDSTADDR_IN6");
1471 ifa
->ifa_raddr
= ifr
.ifr_dstaddr
.sin6_addr
;
1472 inet_ntop(AF_INET6
, (void *)&ifa
->ifa_raddr
, buf
, sizeof(buf
));
1473 trace(1, "found address %s/%d -- %s\n",
1474 inet6_n2p(&ifa
->ifa_addr
), ifa
->ifa_plen
, buf
);
1476 trace(1, "found address %s/%d\n",
1477 inet6_n2p(&ifa
->ifa_addr
), ifa
->ifa_plen
);
1479 if (ifcp
->ifc_index
< 0 && IN6_IS_ADDR_LINKLOCAL(&ifa
->ifa_addr
)) {
1480 ifcp
->ifc_mylladdr
= ifa
->ifa_addr
;
1481 ifcp
->ifc_index
= IN6_LINKLOCAL_IFINDEX(ifa
->ifa_addr
);
1482 memcpy(&ifcp
->ifc_ripsin
, &ripsin
, ripsin
.ss_len
);
1483 SET_IN6_LINKLOCAL_IFINDEX(ifcp
->ifc_ripsin
.sin6_addr
,
1485 setindex2ifc(ifcp
->ifc_index
, ifcp
);
1486 ifcp
->ifc_mtu
= getifmtu(ifcp
->ifc_index
);
1487 if (ifcp
->ifc_mtu
> RIP6_MAXMTU
)
1488 ifcp
->ifc_mtu
= RIP6_MAXMTU
;
1489 if (ioctl(s
, SIOCGIFMETRIC
, (char *)&ifr
) < 0) {
1490 fatal("ioctl: SIOCGIFMETRIC");
1493 ifcp
->ifc_metric
= ifr
.ifr_metric
;
1494 trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
1495 ifcp
->ifc_index
, ifcp
->ifc_mtu
, ifcp
->ifc_metric
);
1497 ifcp
->ifc_cflags
|= IFC_CHANGED
;
1501 * Receive and process routing messages.
1502 * Update interface information as necessary.
1509 struct rt_msghdr
*rtm
;
1510 struct ifa_msghdr
*ifam
;
1511 struct if_msghdr
*ifm
;
1513 struct ifc
*ifcp
, *ic
;
1514 int iface
= 0, rtable
= 0;
1515 struct sockaddr_in6
*rta
[RTAX_MAX
];
1516 struct sockaddr_in6 mask
;
1520 if ((len
= read(rtsock
, buf
, sizeof(buf
))) < 0) {
1521 perror("read from rtsock");
1524 if (len
< (int)sizeof(*rtm
)) {
1525 trace(1, "short read from rtsock: %d (should be > %lu)\n",
1526 len
, (u_long
)sizeof(*rtm
));
1530 fprintf(stderr
, "rtmsg:\n");
1531 for (i
= 0; i
< len
; i
++) {
1532 fprintf(stderr
, "%02x ", buf
[i
] & 0xff);
1533 if (i
% 16 == 15) fprintf(stderr
, "\n");
1535 fprintf(stderr
, "\n");
1538 for (p
= buf
; p
- buf
< len
; p
+= ((struct rt_msghdr
*)p
)->rtm_msglen
) {
1539 /* safety against bogus message */
1540 if (((struct rt_msghdr
*)p
)->rtm_msglen
<= 0) {
1541 trace(1, "bogus rtmsg: length=%d\n",
1542 ((struct rt_msghdr
*)p
)->rtm_msglen
);
1548 switch (((struct rt_msghdr
*)p
)->rtm_type
) {
1551 ifam
= (struct ifa_msghdr
*)p
;
1552 addrs
= ifam
->ifam_addrs
;
1553 q
= (char *)(ifam
+ 1);
1556 ifm
= (struct if_msghdr
*)p
;
1557 addrs
= ifm
->ifm_addrs
;
1558 q
= (char *)(ifm
+ 1);
1561 rtm
= (struct rt_msghdr
*)p
;
1562 addrs
= rtm
->rtm_addrs
;
1563 q
= (char *)(rtm
+ 1);
1564 if (rtm
->rtm_version
!= RTM_VERSION
) {
1565 trace(1, "unexpected rtmsg version %d "
1567 rtm
->rtm_version
, RTM_VERSION
);
1570 if (rtm
->rtm_pid
== pid
) {
1572 trace(1, "rtmsg looped back to me, ignored\n");
1578 memset(&rta
, 0, sizeof(rta
));
1579 for (i
= 0; i
< RTAX_MAX
; i
++) {
1580 if (addrs
& (1 << i
)) {
1581 rta
[i
] = (struct sockaddr_in6
*)q
;
1582 q
+= ROUNDUP(rta
[i
]->sin6_len
);
1586 trace(1, "rtsock: %s (addrs=%x)\n",
1587 rttypes((struct rt_msghdr
*)p
), addrs
);
1590 i
< ((struct rt_msghdr
*)p
)->rtm_msglen
;
1592 fprintf(stderr
, "%02x ", p
[i
] & 0xff);
1593 if (i
% 16 == 15) fprintf(stderr
, "\n");
1595 fprintf(stderr
, "\n");
1601 * We may be able to optimize by using ifm->ifm_index or
1602 * ifam->ifam_index. For simplicity we don't do that here.
1604 switch (((struct rt_msghdr
*)p
)->rtm_type
) {
1617 /* nothing to be done here */
1618 trace(1, "\tnothing to be done, ignored\n");
1623 if (rta
[RTAX_DST
] == NULL
) {
1624 trace(1, "\tno destination, ignored\n");
1627 if (rta
[RTAX_DST
]->sin6_family
!= AF_INET6
) {
1628 trace(1, "\taf mismatch, ignored\n");
1631 if (IN6_IS_ADDR_LINKLOCAL(&rta
[RTAX_DST
]->sin6_addr
)) {
1632 trace(1, "\tlinklocal destination, ignored\n");
1635 if (IN6_ARE_ADDR_EQUAL(&rta
[RTAX_DST
]->sin6_addr
, &in6addr_loopback
)) {
1636 trace(1, "\tloopback destination, ignored\n");
1637 continue; /* Loopback */
1639 if (IN6_IS_ADDR_MULTICAST(&rta
[RTAX_DST
]->sin6_addr
)) {
1640 trace(1, "\tmulticast destination, ignored\n");
1646 switch (((struct rt_msghdr
*)p
)->rtm_type
) {
1655 /* should already be handled */
1656 fatal("rtrecv: never reach here");
1659 if (!rta
[RTAX_DST
] || !rta
[RTAX_GATEWAY
]) {
1660 trace(1, "\tsome of dst/gw/netamsk are "
1661 "unavailable, ignored\n");
1664 if ((rtm
->rtm_flags
& RTF_HOST
) != 0) {
1665 mask
.sin6_len
= sizeof(mask
);
1666 memset(&mask
.sin6_addr
, 0xff,
1667 sizeof(mask
.sin6_addr
));
1668 rta
[RTAX_NETMASK
] = &mask
;
1669 } else if (!rta
[RTAX_NETMASK
]) {
1670 trace(1, "\tsome of dst/gw/netamsk are "
1671 "unavailable, ignored\n");
1674 if (rt_del(rta
[RTAX_DST
], rta
[RTAX_GATEWAY
],
1675 rta
[RTAX_NETMASK
]) == 0) {
1676 rtable
++; /*just to be sure*/
1681 trace(1, "\tnot supported yet, ignored\n");
1684 if (!rta
[RTAX_NETMASK
] || !rta
[RTAX_IFA
]) {
1685 trace(1, "\tno netmask or ifa given, ignored\n");
1688 if (ifam
->ifam_index
< nindex2ifc
)
1689 ifcp
= index2ifc
[ifam
->ifam_index
];
1693 trace(1, "\tinvalid ifam_index %d, ignored\n",
1697 if (!rt_deladdr(ifcp
, rta
[RTAX_IFA
], rta
[RTAX_NETMASK
]))
1702 trace(1, "\tnot supported yet, ignored\n");
1709 trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
1711 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
)
1712 if (ifcp
->ifc_cflags
& IFC_CHANGED
) {
1713 if (ifrt(ifcp
, 1)) {
1714 for (ic
= ifc
; ic
; ic
= ic
->ifc_next
) {
1715 if (ifcp
->ifc_index
== ic
->ifc_index
)
1717 if (ic
->ifc_flags
& IFF_UP
)
1718 ripsend(ic
, &ic
->ifc_ripsin
,
1721 /* Reset the flag */
1722 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
)
1723 rrt
->rrt_rflags
&= ~RRTF_CHANGED
;
1725 ifcp
->ifc_cflags
&= ~IFC_CHANGED
;
1729 trace(1, "rtsock: read routing table again\n");
1735 * remove specified route from the internal routing table.
1738 rt_del(const struct sockaddr_in6
*sdst
, const struct sockaddr_in6
*sgw
,
1739 const struct sockaddr_in6
*smask
)
1741 const struct in6_addr
*dst
= NULL
;
1742 const struct in6_addr
*gw
= NULL
;
1744 struct netinfo6 ni6
;
1745 struct riprt
*rrt
= NULL
;
1748 if (sdst
->sin6_family
!= AF_INET6
) {
1749 trace(1, "\tother AF, ignored\n");
1752 if (IN6_IS_ADDR_LINKLOCAL(&sdst
->sin6_addr
)
1753 || IN6_ARE_ADDR_EQUAL(&sdst
->sin6_addr
, &in6addr_loopback
)
1754 || IN6_IS_ADDR_MULTICAST(&sdst
->sin6_addr
)) {
1755 trace(1, "\taddress %s not interesting, ignored\n",
1756 inet6_n2p(&sdst
->sin6_addr
));
1759 dst
= &sdst
->sin6_addr
;
1760 if (sgw
->sin6_family
== AF_INET6
) {
1762 gw
= &sgw
->sin6_addr
;
1763 prefix
= sin6mask2len(smask
);
1764 } else if (sgw
->sin6_family
== AF_LINK
) {
1766 * Interface route... a hard case. We need to get the prefix
1767 * length from the kernel, but we now are parsing rtmsg.
1768 * We'll purge matching routes from my list, then get the
1771 struct riprt
*longest
;
1772 trace(1, "\t%s is an interface route, guessing prefixlen\n",
1775 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
1776 if (IN6_ARE_ADDR_EQUAL(&rrt
->rrt_info
.rip6_dest
,
1778 && IN6_IS_ADDR_LOOPBACK(&rrt
->rrt_gw
)) {
1780 || longest
->rrt_info
.rip6_plen
<
1781 rrt
->rrt_info
.rip6_plen
) {
1788 trace(1, "\tno matching interface route found\n");
1791 gw
= &in6addr_loopback
;
1792 prefix
= rrt
->rrt_info
.rip6_plen
;
1794 trace(1, "\tunsupported af: (gw=%d)\n", sgw
->sin6_family
);
1798 trace(1, "\tdeleting %s/%d ", inet6_n2p(dst
), prefix
);
1799 trace(1, "gw %s\n", inet6_n2p(gw
));
1800 t_lifetime
= time(NULL
) - RIP_LIFETIME
;
1801 /* age route for interface address */
1802 memset(&ni6
, 0, sizeof(ni6
));
1803 ni6
.rip6_dest
= *dst
;
1804 ni6
.rip6_plen
= prefix
;
1805 applyplen(&ni6
.rip6_dest
, ni6
.rip6_plen
); /*to be sure*/
1806 trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6
.rip6_dest
),
1808 if (!rrt
&& (rrt
= rtsearch(&ni6
, NULL
)) == NULL
) {
1809 trace(1, "\tno route found\n");
1813 if ((rrt
->rrt_flags
& RTF_STATIC
) == 0) {
1814 trace(1, "\tyou can delete static routes only\n");
1817 if (!IN6_ARE_ADDR_EQUAL(&rrt
->rrt_gw
, gw
)) {
1818 trace(1, "\tgw mismatch: %s <-> ",
1819 inet6_n2p(&rrt
->rrt_gw
));
1820 trace(1, "%s\n", inet6_n2p(gw
));
1822 trace(1, "\troute found, age it\n");
1823 if (rrt
->rrt_t
== 0 || rrt
->rrt_t
> t_lifetime
) {
1824 rrt
->rrt_t
= t_lifetime
;
1825 rrt
->rrt_info
.rip6_metric
= HOPCNT_INFINITY6
;
1832 * remove specified address from internal interface/routing table.
1835 rt_deladdr(struct ifc
*ifcp
, const struct sockaddr_in6
*sifa
,
1836 const struct sockaddr_in6
*smask
)
1838 const struct in6_addr
*addr
= NULL
;
1840 struct ifac
*ifa
= NULL
;
1841 struct netinfo6 ni6
;
1842 struct riprt
*rrt
= NULL
;
1846 if (sifa
->sin6_family
!= AF_INET6
) {
1847 trace(1, "\tother AF, ignored\n");
1850 addr
= &sifa
->sin6_addr
;
1851 prefix
= sin6mask2len(smask
);
1853 trace(1, "\tdeleting %s/%d from %s\n",
1854 inet6_n2p(addr
), prefix
, ifcp
->ifc_name
);
1855 ifa
= ifa_match(ifcp
, addr
, prefix
);
1857 trace(1, "\tno matching ifa found for %s/%d on %s\n",
1858 inet6_n2p(addr
), prefix
, ifcp
->ifc_name
);
1861 if (ifa
->ifa_conf
!= ifcp
) {
1862 trace(1, "\taddress table corrupt: back pointer does not match "
1864 ifcp
->ifc_name
, ifa
->ifa_conf
->ifc_name
);
1867 /* remove ifa from interface */
1868 if (ifcp
->ifc_addr
== ifa
)
1869 ifcp
->ifc_addr
= ifa
->ifa_next
;
1872 for (p
= ifcp
->ifc_addr
; p
; p
= p
->ifa_next
) {
1873 if (p
->ifa_next
== ifa
) {
1874 p
->ifa_next
= ifa
->ifa_next
;
1879 ifa
->ifa_next
= NULL
;
1880 ifa
->ifa_conf
= NULL
;
1881 t_lifetime
= time(NULL
) - RIP_LIFETIME
;
1882 /* age route for interface address */
1883 memset(&ni6
, 0, sizeof(ni6
));
1884 ni6
.rip6_dest
= ifa
->ifa_addr
;
1885 ni6
.rip6_plen
= ifa
->ifa_plen
;
1886 applyplen(&ni6
.rip6_dest
, ni6
.rip6_plen
);
1887 trace(1, "\tfind interface route %s/%d on %d\n",
1888 inet6_n2p(&ni6
.rip6_dest
), ni6
.rip6_plen
, ifcp
->ifc_index
);
1889 if ((rrt
= rtsearch(&ni6
, NULL
)) != NULL
) {
1890 struct in6_addr none
;
1891 memset(&none
, 0, sizeof(none
));
1892 if (rrt
->rrt_index
== ifcp
->ifc_index
&&
1893 (IN6_ARE_ADDR_EQUAL(&rrt
->rrt_gw
, &none
) ||
1894 IN6_IS_ADDR_LOOPBACK(&rrt
->rrt_gw
))) {
1895 trace(1, "\troute found, age it\n");
1896 if (rrt
->rrt_t
== 0 || rrt
->rrt_t
> t_lifetime
) {
1897 rrt
->rrt_t
= t_lifetime
;
1898 rrt
->rrt_info
.rip6_metric
= HOPCNT_INFINITY6
;
1902 trace(1, "\tnon-interface route found: %s/%d on %d\n",
1903 inet6_n2p(&rrt
->rrt_info
.rip6_dest
),
1904 rrt
->rrt_info
.rip6_plen
,
1908 trace(1, "\tno interface route found\n");
1909 /* age route for p2p destination */
1910 if (ifcp
->ifc_flags
& IFF_POINTOPOINT
) {
1911 memset(&ni6
, 0, sizeof(ni6
));
1912 ni6
.rip6_dest
= ifa
->ifa_raddr
;
1913 ni6
.rip6_plen
= 128;
1914 applyplen(&ni6
.rip6_dest
, ni6
.rip6_plen
); /*to be sure*/
1915 trace(1, "\tfind p2p route %s/%d on %d\n",
1916 inet6_n2p(&ni6
.rip6_dest
), ni6
.rip6_plen
,
1918 if ((rrt
= rtsearch(&ni6
, NULL
)) != NULL
) {
1919 if (rrt
->rrt_index
== ifcp
->ifc_index
&&
1920 IN6_ARE_ADDR_EQUAL(&rrt
->rrt_gw
, &ifa
->ifa_addr
)) {
1921 trace(1, "\troute found, age it\n");
1922 if (rrt
->rrt_t
== 0 || rrt
->rrt_t
> t_lifetime
) {
1923 rrt
->rrt_t
= t_lifetime
;
1924 rrt
->rrt_info
.rip6_metric
=
1929 trace(1, "\tnon-p2p route found: %s/%d on %d\n",
1930 inet6_n2p(&rrt
->rrt_info
.rip6_dest
),
1931 rrt
->rrt_info
.rip6_plen
,
1935 trace(1, "\tno p2p route found\n");
1937 return updated
? 0 : -1;
1941 * Get each interface address and put those interface routes to the route
1945 ifrt(struct ifc
*ifcp
, int again
)
1948 struct riprt
*rrt
= NULL
, *search_rrt
, *prev_rrt
, *loop_rrt
;
1949 struct netinfo6
*np
;
1951 int need_trigger
= 0;
1954 if (ifcp
->ifc_flags
& IFF_LOOPBACK
)
1955 return 0; /* ignore loopback */
1958 if (ifcp
->ifc_flags
& IFF_POINTOPOINT
) {
1959 ifrt_p2p(ifcp
, again
);
1963 for (ifa
= ifcp
->ifc_addr
; ifa
; ifa
= ifa
->ifa_next
) {
1964 if (IN6_IS_ADDR_LINKLOCAL(&ifa
->ifa_addr
)) {
1966 trace(1, "route: %s on %s: "
1967 "skip linklocal interface address\n",
1968 inet6_n2p(&ifa
->ifa_addr
), ifcp
->ifc_name
);
1972 if (IN6_IS_ADDR_UNSPECIFIED(&ifa
->ifa_addr
)) {
1974 trace(1, "route: %s: skip unspec interface address\n",
1979 if (IN6_IS_ADDR_LOOPBACK(&ifa
->ifa_addr
)) {
1981 trace(1, "route: %s: skip loopback address\n",
1986 if (ifcp
->ifc_flags
& IFF_UP
) {
1987 if ((rrt
= MALLOC(struct riprt
)) == NULL
)
1988 fatal("malloc: struct riprt");
1989 memset(rrt
, 0, sizeof(*rrt
));
1990 rrt
->rrt_same
= NULL
;
1991 rrt
->rrt_index
= ifcp
->ifc_index
;
1992 rrt
->rrt_t
= 0; /* don't age */
1993 rrt
->rrt_info
.rip6_dest
= ifa
->ifa_addr
;
1994 rrt
->rrt_info
.rip6_tag
= htons(routetag
& 0xffff);
1995 rrt
->rrt_info
.rip6_metric
= 1 + ifcp
->ifc_metric
;
1996 rrt
->rrt_info
.rip6_plen
= ifa
->ifa_plen
;
1997 if (ifa
->ifa_plen
== 128)
1998 rrt
->rrt_flags
= RTF_HOST
;
2000 rrt
->rrt_flags
= RTF_CLONING
;
2001 rrt
->rrt_rflags
|= RRTF_CHANGED
;
2002 applyplen(&rrt
->rrt_info
.rip6_dest
, ifa
->ifa_plen
);
2003 memset(&rrt
->rrt_gw
, 0, sizeof(struct in6_addr
));
2004 rrt
->rrt_gw
= ifa
->ifa_addr
;
2005 np
= &rrt
->rrt_info
;
2006 search_rrt
= rtsearch(np
, &prev_rrt
);
2007 if (search_rrt
!= NULL
) {
2008 if (search_rrt
->rrt_info
.rip6_metric
<=
2009 rrt
->rrt_info
.rip6_metric
) {
2010 /* Already have better route */
2012 trace(1, "route: %s/%d: "
2013 "already registered (%s)\n",
2014 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2021 prev_rrt
->rrt_next
= rrt
->rrt_next
;
2023 riprt
= rrt
->rrt_next
;
2024 delroute(&rrt
->rrt_info
, &rrt
->rrt_gw
);
2026 /* Attach the route to the list */
2027 trace(1, "route: %s/%d: register route (%s)\n",
2028 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2030 rrt
->rrt_next
= riprt
;
2032 addroute(rrt
, &rrt
->rrt_gw
, ifcp
);
2035 ripsend(ifcp
, &ifcp
->ifc_ripsin
, 0);
2038 for (loop_rrt
= riprt
; loop_rrt
; loop_rrt
= loop_rrt
->rrt_next
) {
2039 if (loop_rrt
->rrt_index
== ifcp
->ifc_index
) {
2040 t_lifetime
= time(NULL
) - RIP_LIFETIME
;
2041 if (loop_rrt
->rrt_t
== 0 || loop_rrt
->rrt_t
> t_lifetime
) {
2042 loop_rrt
->rrt_t
= t_lifetime
;
2043 loop_rrt
->rrt_info
.rip6_metric
= HOPCNT_INFINITY6
;
2044 loop_rrt
->rrt_rflags
|= RRTF_CHANGED
;
2054 return need_trigger
;
2058 * there are couple of p2p interface routing models. "behavior" lets
2059 * you pick one. it looks that gated behavior fits best with BSDs,
2060 * since BSD kernels do not look at prefix length on p2p interfaces.
2063 ifrt_p2p(struct ifc
*ifcp
, int again
)
2066 struct riprt
*rrt
, *orrt
, *prevrrt
;
2067 struct netinfo6
*np
;
2068 struct in6_addr addr
, dest
;
2069 int advert
, ignore
, i
;
2070 #define P2PADVERT_NETWORK 1
2071 #define P2PADVERT_ADDR 2
2072 #define P2PADVERT_DEST 4
2073 #define P2PADVERT_MAX 4
2077 #define BEHAVIOR GATED
2078 const char *category
= "";
2081 for (ifa
= ifcp
->ifc_addr
; ifa
; ifa
= ifa
->ifa_next
) {
2082 addr
= ifa
->ifa_addr
;
2083 dest
= ifa
->ifa_raddr
;
2084 applyplen(&addr
, ifa
->ifa_plen
);
2085 applyplen(&dest
, ifa
->ifa_plen
);
2086 advert
= ignore
= 0;
2087 #if BEHAVIOR == CISCO
2089 * honor addr/plen, just like normal shared medium
2090 * interface. this may cause trouble if you reuse
2091 * addr/plen on other interfaces.
2093 * advertise addr/plen.
2095 advert
|= P2PADVERT_NETWORK
;
2097 #if BEHAVIOR == GATED
2099 * prefixlen on p2p interface is meaningless.
2100 * advertise addr/128 and dest/128.
2102 * do not install network route to route6d routing
2103 * table (if we do, it would prevent route installation
2104 * for other p2p interface that shares addr/plen).
2106 * XXX what should we do if dest is ::? it will not
2107 * get announced anyways (see following filter),
2108 * but we need to think.
2110 advert
|= P2PADVERT_ADDR
;
2111 advert
|= P2PADVERT_DEST
;
2112 ignore
|= P2PADVERT_NETWORK
;
2114 #if BEHAVIOR == ROUTE6D
2116 * just for testing. actually the code is redundant
2117 * given the current p2p interface address assignment
2118 * rule for kame kernel.
2121 * A/n -> announce A/n
2122 * A B/n, A and B share prefix -> A/n (= B/n)
2123 * A B/n, do not share prefix -> A/128 and B/128
2124 * actually, A/64 and A B/128 are the only cases
2125 * permitted by the kernel:
2127 * A B/128 -> A/128 and B/128
2129 if (!IN6_IS_ADDR_UNSPECIFIED(&ifa
->ifa_raddr
)) {
2130 if (IN6_ARE_ADDR_EQUAL(&addr
, &dest
))
2131 advert
|= P2PADVERT_NETWORK
;
2133 advert
|= P2PADVERT_ADDR
;
2134 advert
|= P2PADVERT_DEST
;
2135 ignore
|= P2PADVERT_NETWORK
;
2138 advert
|= P2PADVERT_NETWORK
;
2141 for (i
= 1; i
<= P2PADVERT_MAX
; i
*= 2) {
2142 if ((ignore
& i
) != 0)
2144 if ((rrt
= MALLOC(struct riprt
)) == NULL
) {
2145 fatal("malloc: struct riprt");
2148 memset(rrt
, 0, sizeof(*rrt
));
2149 rrt
->rrt_same
= NULL
;
2150 rrt
->rrt_index
= ifcp
->ifc_index
;
2151 rrt
->rrt_t
= 0; /* don't age */
2153 case P2PADVERT_NETWORK
:
2154 rrt
->rrt_info
.rip6_dest
= ifa
->ifa_addr
;
2155 rrt
->rrt_info
.rip6_plen
= ifa
->ifa_plen
;
2156 applyplen(&rrt
->rrt_info
.rip6_dest
,
2158 category
= "network";
2160 case P2PADVERT_ADDR
:
2161 rrt
->rrt_info
.rip6_dest
= ifa
->ifa_addr
;
2162 rrt
->rrt_info
.rip6_plen
= 128;
2163 rrt
->rrt_gw
= in6addr_loopback
;
2166 case P2PADVERT_DEST
:
2167 rrt
->rrt_info
.rip6_dest
= ifa
->ifa_raddr
;
2168 rrt
->rrt_info
.rip6_plen
= 128;
2169 rrt
->rrt_gw
= ifa
->ifa_addr
;
2173 if (IN6_IS_ADDR_UNSPECIFIED(&rrt
->rrt_info
.rip6_dest
) ||
2174 IN6_IS_ADDR_LINKLOCAL(&rrt
->rrt_info
.rip6_dest
)) {
2176 trace(1, "route: %s: skip unspec/linklocal "
2177 "(%s on %s)\n", category
, ifcp
->ifc_name
);
2182 if ((advert
& i
) == 0) {
2183 rrt
->rrt_rflags
|= RRTF_NOADVERTISE
;
2187 rrt
->rrt_info
.rip6_tag
= htons(routetag
& 0xffff);
2188 rrt
->rrt_info
.rip6_metric
= 1 + ifcp
->ifc_metric
;
2189 np
= &rrt
->rrt_info
;
2190 orrt
= rtsearch(np
, &prevrrt
);
2192 /* Attach the route to the list */
2193 trace(1, "route: %s/%d: register route "
2195 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2196 category
, ifcp
->ifc_name
, noadv
);
2197 rrt
->rrt_next
= riprt
;
2199 } else if (rrt
->rrt_index
!= orrt
->rrt_index
||
2200 rrt
->rrt_info
.rip6_metric
!= orrt
->rrt_info
.rip6_metric
) {
2202 rrt
->rrt_next
= orrt
->rrt_next
;
2204 prevrrt
->rrt_next
= rrt
;
2209 trace(1, "route: %s/%d: update (%s on %s%s)\n",
2210 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2211 category
, ifcp
->ifc_name
, noadv
);
2215 trace(1, "route: %s/%d: "
2216 "already registered (%s on %s%s)\n",
2217 inet6_n2p(&np
->rip6_dest
),
2218 np
->rip6_plen
, category
,
2219 ifcp
->ifc_name
, noadv
);
2225 #undef P2PADVERT_NETWORK
2226 #undef P2PADVERT_ADDR
2227 #undef P2PADVERT_DEST
2228 #undef P2PADVERT_MAX
2232 getifmtu(int ifindex
)
2237 struct if_msghdr
*ifm
;
2244 mib
[4] = NET_RT_IFLIST
;
2246 if (sysctl(mib
, 6, NULL
, &msize
, NULL
, 0) < 0) {
2247 fatal("sysctl estimate NET_RT_IFLIST");
2250 if ((buf
= malloc(msize
)) == NULL
) {
2254 if (sysctl(mib
, 6, buf
, &msize
, NULL
, 0) < 0) {
2255 fatal("sysctl NET_RT_IFLIST");
2258 ifm
= (struct if_msghdr
*)buf
;
2259 mtu
= ifm
->ifm_data
.ifi_mtu
;
2261 if (ifindex
!= ifm
->ifm_index
) {
2262 fatal("ifindex does not match with ifm_index");
2271 rttypes(struct rt_msghdr
*rtm
)
2273 #define RTTYPE(s, f) \
2275 if (rtm->rtm_type == (f)) \
2278 RTTYPE("ADD", RTM_ADD
);
2279 RTTYPE("DELETE", RTM_DELETE
);
2280 RTTYPE("CHANGE", RTM_CHANGE
);
2281 RTTYPE("GET", RTM_GET
);
2282 RTTYPE("LOSING", RTM_LOSING
);
2283 RTTYPE("REDIRECT", RTM_REDIRECT
);
2284 RTTYPE("MISS", RTM_MISS
);
2285 RTTYPE("LOCK", RTM_LOCK
);
2286 RTTYPE("OLDADD", RTM_OLDADD
);
2287 RTTYPE("OLDDEL", RTM_OLDDEL
);
2288 RTTYPE("RESOLVE", RTM_RESOLVE
);
2289 RTTYPE("NEWADDR", RTM_NEWADDR
);
2290 RTTYPE("DELADDR", RTM_DELADDR
);
2291 RTTYPE("IFINFO", RTM_IFINFO
);
2293 RTTYPE("OLDADD", RTM_OLDADD
);
2296 RTTYPE("OLDDEL", RTM_OLDDEL
);
2299 RTTYPE("OIFINFO", RTM_OIFINFO
);
2301 #ifdef RTM_IFANNOUNCE
2302 RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE
);
2305 RTTYPE("NEWMADDR", RTM_NEWMADDR
);
2308 RTTYPE("DELMADDR", RTM_DELMADDR
);
2315 rtflags(struct rt_msghdr
*rtm
)
2317 static char buf
[BUFSIZ
];
2320 * letter conflict should be okay. painful when *BSD diverges...
2322 strlcpy(buf
, "", sizeof(buf
));
2323 #define RTFLAG(s, f) \
2325 if (rtm->rtm_flags & (f)) \
2326 strlcat(buf, (s), sizeof(buf)); \
2328 RTFLAG("U", RTF_UP
);
2329 RTFLAG("G", RTF_GATEWAY
);
2330 RTFLAG("H", RTF_HOST
);
2331 RTFLAG("R", RTF_REJECT
);
2332 RTFLAG("D", RTF_DYNAMIC
);
2333 RTFLAG("M", RTF_MODIFIED
);
2334 RTFLAG("d", RTF_DONE
);
2336 RTFLAG("m", RTF_MASK
);
2338 RTFLAG("C", RTF_CLONING
);
2340 RTFLAG("c", RTF_CLONED
);
2342 #ifdef RTF_PRCLONING
2343 RTFLAG("c", RTF_PRCLONING
);
2345 #ifdef RTF_WASCLONED
2346 RTFLAG("W", RTF_WASCLONED
);
2348 RTFLAG("X", RTF_XRESOLVE
);
2349 RTFLAG("L", RTF_LLINFO
);
2350 RTFLAG("S", RTF_STATIC
);
2351 RTFLAG("B", RTF_BLACKHOLE
);
2353 RTFLAG("3", RTF_PROTO3
);
2355 RTFLAG("2", RTF_PROTO2
);
2356 RTFLAG("1", RTF_PROTO1
);
2357 #ifdef RTF_BROADCAST
2358 RTFLAG("b", RTF_BROADCAST
);
2361 RTFLAG("d", RTF_DEFAULT
);
2363 #ifdef RTF_ISAROUTER
2364 RTFLAG("r", RTF_ISAROUTER
);
2367 RTFLAG("T", RTF_TUNNEL
);
2370 RTFLAG("A", RTF_AUTH
);
2373 RTFLAG("E", RTF_CRYPT
);
2382 static char buf
[BUFSIZ
];
2384 strlcpy(buf
, "", sizeof(buf
));
2385 #define IFFLAG(s, f) \
2387 if (flags & (f)) { \
2389 strlcat(buf, ",", sizeof(buf)); \
2390 strlcat(buf, (s), sizeof(buf)); \
2393 IFFLAG("UP", IFF_UP
);
2394 IFFLAG("BROADCAST", IFF_BROADCAST
);
2395 IFFLAG("DEBUG", IFF_DEBUG
);
2396 IFFLAG("LOOPBACK", IFF_LOOPBACK
);
2397 IFFLAG("POINTOPOINT", IFF_POINTOPOINT
);
2398 #ifdef IFF_NOTRAILERS
2399 IFFLAG("NOTRAILERS", IFF_NOTRAILERS
);
2402 IFFLAG("SMART", IFF_SMART
);
2404 IFFLAG("RUNNING", IFF_RUNNING
);
2405 IFFLAG("NOARP", IFF_NOARP
);
2406 IFFLAG("PROMISC", IFF_PROMISC
);
2407 IFFLAG("ALLMULTI", IFF_ALLMULTI
);
2408 IFFLAG("OACTIVE", IFF_OACTIVE
);
2409 IFFLAG("SIMPLEX", IFF_SIMPLEX
);
2410 IFFLAG("LINK0", IFF_LINK0
);
2411 IFFLAG("LINK1", IFF_LINK1
);
2412 IFFLAG("LINK2", IFF_LINK2
);
2413 IFFLAG("MULTICAST", IFF_MULTICAST
);
2423 char *buf
= NULL
, *p
, *lim
;
2424 struct rt_msghdr
*rtm
;
2433 mib
[3] = AF_INET6
; /* Address family */
2434 mib
[4] = NET_RT_DUMP
; /* Dump the kernel routing table */
2435 mib
[5] = 0; /* No flags */
2443 if (sysctl(mib
, 6, NULL
, &msize
, NULL
, 0) < 0) {
2444 errmsg
= "sysctl estimate";
2447 if ((buf
= malloc(msize
)) == NULL
) {
2451 if (sysctl(mib
, 6, buf
, &msize
, NULL
, 0) < 0) {
2452 errmsg
= "sysctl NET_RT_DUMP";
2455 } while (retry
< 5 && errmsg
!= NULL
);
2457 fatal("%s (with %d retries, msize=%lu)", errmsg
, retry
,
2460 } else if (1 < retry
)
2461 syslog(LOG_INFO
, "NET_RT_DUMP %d retries", retry
);
2464 for (p
= buf
; p
< lim
; p
+= rtm
->rtm_msglen
) {
2465 rtm
= (struct rt_msghdr
*)p
;
2466 rt_entry(rtm
, again
);
2472 rt_entry(struct rt_msghdr
*rtm
, int again
)
2474 struct sockaddr_in6
*sin6_dst
, *sin6_gw
, *sin6_mask
;
2475 struct sockaddr_in6
*sin6_genmask
, *sin6_ifp
;
2476 char *rtmp
, *ifname
= NULL
;
2477 struct riprt
*rrt
, *orrt
;
2478 struct netinfo6
*np
;
2481 sin6_dst
= sin6_gw
= sin6_mask
= sin6_genmask
= sin6_ifp
= 0;
2482 if ((rtm
->rtm_flags
& RTF_UP
) == 0 || rtm
->rtm_flags
&
2483 (RTF_CLONING
|RTF_XRESOLVE
|RTF_LLINFO
|RTF_BLACKHOLE
)) {
2484 return; /* not interested in the link route */
2486 /* do not look at cloned routes */
2487 #ifdef RTF_WASCLONED
2488 if (rtm
->rtm_flags
& RTF_WASCLONED
)
2492 if (rtm
->rtm_flags
& RTF_CLONED
)
2496 * do not look at dynamic routes.
2497 * netbsd/openbsd cloned routes have UGHD.
2499 if (rtm
->rtm_flags
& RTF_DYNAMIC
)
2501 rtmp
= (char *)(rtm
+ 1);
2503 if ((rtm
->rtm_addrs
& RTA_DST
) == 0)
2504 return; /* ignore routes without destination address */
2505 sin6_dst
= (struct sockaddr_in6
*)rtmp
;
2506 rtmp
+= ROUNDUP(sin6_dst
->sin6_len
);
2507 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
2508 sin6_gw
= (struct sockaddr_in6
*)rtmp
;
2509 rtmp
+= ROUNDUP(sin6_gw
->sin6_len
);
2511 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
2512 sin6_mask
= (struct sockaddr_in6
*)rtmp
;
2513 rtmp
+= ROUNDUP(sin6_mask
->sin6_len
);
2515 if (rtm
->rtm_addrs
& RTA_GENMASK
) {
2516 sin6_genmask
= (struct sockaddr_in6
*)rtmp
;
2517 rtmp
+= ROUNDUP(sin6_genmask
->sin6_len
);
2519 if (rtm
->rtm_addrs
& RTA_IFP
) {
2520 sin6_ifp
= (struct sockaddr_in6
*)rtmp
;
2521 rtmp
+= ROUNDUP(sin6_ifp
->sin6_len
);
2525 if (sin6_dst
->sin6_family
!= AF_INET6
)
2527 if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst
->sin6_addr
))
2528 return; /* Link-local */
2529 if (IN6_ARE_ADDR_EQUAL(&sin6_dst
->sin6_addr
, &in6addr_loopback
))
2530 return; /* Loopback */
2531 if (IN6_IS_ADDR_MULTICAST(&sin6_dst
->sin6_addr
))
2534 if ((rrt
= MALLOC(struct riprt
)) == NULL
) {
2535 fatal("malloc: struct riprt");
2538 memset(rrt
, 0, sizeof(*rrt
));
2539 np
= &rrt
->rrt_info
;
2540 rrt
->rrt_same
= NULL
;
2541 rrt
->rrt_t
= time(NULL
);
2542 if (aflag
== 0 && (rtm
->rtm_flags
& RTF_STATIC
))
2543 rrt
->rrt_t
= 0; /* Don't age static routes */
2544 if ((rtm
->rtm_flags
& (RTF_HOST
|RTF_GATEWAY
)) == RTF_HOST
)
2545 rrt
->rrt_t
= 0; /* Don't age non-gateway host routes */
2547 np
->rip6_metric
= rtm
->rtm_rmx
.rmx_hopcount
;
2548 if (np
->rip6_metric
< 1)
2549 np
->rip6_metric
= 1;
2550 rrt
->rrt_flags
= rtm
->rtm_flags
;
2551 np
->rip6_dest
= sin6_dst
->sin6_addr
;
2554 if (rtm
->rtm_flags
& RTF_HOST
)
2555 np
->rip6_plen
= 128; /* Host route */
2557 np
->rip6_plen
= sin6mask2len(sin6_mask
);
2561 orrt
= rtsearch(np
, NULL
);
2562 if (orrt
&& orrt
->rrt_info
.rip6_metric
!= HOPCNT_INFINITY6
) {
2565 trace(1, "route: %s/%d flags %s: already registered\n",
2566 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2574 memset(&rrt
->rrt_gw
, 0, sizeof(struct in6_addr
));
2576 if (sin6_gw
->sin6_family
== AF_INET6
)
2577 rrt
->rrt_gw
= sin6_gw
->sin6_addr
;
2578 else if (sin6_gw
->sin6_family
== AF_LINK
) {
2579 /* XXX in case ppp link? */
2580 rrt
->rrt_gw
= in6addr_loopback
;
2582 memset(&rrt
->rrt_gw
, 0, sizeof(struct in6_addr
));
2584 trace(1, "route: %s/%d flags %s",
2585 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, rtflags(rtm
));
2586 trace(1, " gw %s", inet6_n2p(&rrt
->rrt_gw
));
2590 if (s
< nindex2ifc
&& index2ifc
[s
])
2591 ifname
= index2ifc
[s
]->ifc_name
;
2593 trace(1, " not configured\n");
2597 trace(1, " if %s sock %d", ifname
, s
);
2603 if (!IN6_IS_ADDR_LINKLOCAL(&rrt
->rrt_gw
) &&
2604 !IN6_IS_ADDR_LOOPBACK(&rrt
->rrt_gw
)
2606 && (rrt
->rrt_flags
& RTF_LOCAL
) == 0
2609 trace(0, "***** Gateway %s is not a link-local address.\n",
2610 inet6_n2p(&rrt
->rrt_gw
));
2611 trace(0, "***** dest(%s) if(%s) -- Not optimized.\n",
2612 inet6_n2p(&rrt
->rrt_info
.rip6_dest
), ifname
);
2613 rrt
->rrt_rflags
|= RRTF_NH_NOT_LLADDR
;
2616 /* Put it to the route list */
2617 if (orrt
&& orrt
->rrt_info
.rip6_metric
== HOPCNT_INFINITY6
) {
2618 /* replace route list */
2619 rrt
->rrt_next
= orrt
->rrt_next
;
2621 trace(1, "route: %s/%d flags %s: replace new route\n",
2622 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
,
2626 rrt
->rrt_next
= riprt
;
2632 addroute(struct riprt
*rrt
, const struct in6_addr
*gw
, struct ifc
*ifcp
)
2634 struct netinfo6
*np
;
2635 u_char buf
[BUFSIZ
], buf1
[BUFSIZ
], buf2
[BUFSIZ
];
2636 struct rt_msghdr
*rtm
;
2637 struct sockaddr_in6
*sin6
;
2640 np
= &rrt
->rrt_info
;
2641 inet_ntop(AF_INET6
, (const void *)gw
, (char *)buf1
, sizeof(buf1
));
2642 inet_ntop(AF_INET6
, (void *)&ifcp
->ifc_mylladdr
, (char *)buf2
, sizeof(buf2
));
2643 tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
2644 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf1
,
2645 np
->rip6_metric
- 1, buf2
);
2647 fprintf(rtlog
, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
2648 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf1
,
2649 np
->rip6_metric
- 1, buf2
);
2653 memset(buf
, 0, sizeof(buf
));
2654 rtm
= (struct rt_msghdr
*)buf
;
2655 rtm
->rtm_type
= RTM_ADD
;
2656 rtm
->rtm_version
= RTM_VERSION
;
2657 rtm
->rtm_seq
= ++seq
;
2659 rtm
->rtm_flags
= rrt
->rrt_flags
;
2660 rtm
->rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
2661 rtm
->rtm_rmx
.rmx_hopcount
= np
->rip6_metric
- 1;
2662 rtm
->rtm_inits
= RTV_HOPCOUNT
;
2663 sin6
= (struct sockaddr_in6
*)&buf
[sizeof(struct rt_msghdr
)];
2665 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2666 sin6
->sin6_family
= AF_INET6
;
2667 sin6
->sin6_addr
= np
->rip6_dest
;
2668 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2670 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2671 sin6
->sin6_family
= AF_INET6
;
2672 sin6
->sin6_addr
= *gw
;
2673 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2675 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2676 sin6
->sin6_family
= AF_INET6
;
2677 sin6
->sin6_addr
= *(plen2mask(np
->rip6_plen
));
2678 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2680 len
= (char *)sin6
- (char *)buf
;
2681 rtm
->rtm_msglen
= len
;
2682 if (write(rtsock
, buf
, len
) > 0)
2685 if (errno
== EEXIST
) {
2686 trace(0, "ADD: Route already exists %s/%d gw %s\n",
2687 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf1
);
2689 fprintf(rtlog
, "ADD: Route already exists %s/%d gw %s\n",
2690 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf1
);
2692 trace(0, "Can not write to rtsock (addroute): %s\n",
2695 fprintf(rtlog
, "\tCan not write to rtsock: %s\n",
2702 delroute(struct netinfo6
*np
, struct in6_addr
*gw
)
2704 u_char buf
[BUFSIZ
], buf2
[BUFSIZ
];
2705 struct rt_msghdr
*rtm
;
2706 struct sockaddr_in6
*sin6
;
2709 inet_ntop(AF_INET6
, (void *)gw
, (char *)buf2
, sizeof(buf2
));
2710 tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np
->rip6_dest
),
2711 np
->rip6_plen
, buf2
);
2713 fprintf(rtlog
, "%s: DEL: %s/%d gw %s\n",
2714 hms(), inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf2
);
2718 memset(buf
, 0, sizeof(buf
));
2719 rtm
= (struct rt_msghdr
*)buf
;
2720 rtm
->rtm_type
= RTM_DELETE
;
2721 rtm
->rtm_version
= RTM_VERSION
;
2722 rtm
->rtm_seq
= ++seq
;
2724 rtm
->rtm_flags
= RTF_UP
| RTF_GATEWAY
;
2725 if (np
->rip6_plen
== sizeof(struct in6_addr
) * 8)
2726 rtm
->rtm_flags
|= RTF_HOST
;
2727 rtm
->rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
2728 sin6
= (struct sockaddr_in6
*)&buf
[sizeof(struct rt_msghdr
)];
2730 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2731 sin6
->sin6_family
= AF_INET6
;
2732 sin6
->sin6_addr
= np
->rip6_dest
;
2733 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2735 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2736 sin6
->sin6_family
= AF_INET6
;
2737 sin6
->sin6_addr
= *gw
;
2738 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2740 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2741 sin6
->sin6_family
= AF_INET6
;
2742 sin6
->sin6_addr
= *(plen2mask(np
->rip6_plen
));
2743 sin6
= (struct sockaddr_in6
*)((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2745 len
= (char *)sin6
- (char *)buf
;
2746 rtm
->rtm_msglen
= len
;
2747 if (write(rtsock
, buf
, len
) >= 0)
2750 if (errno
== ESRCH
) {
2751 trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2752 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf2
);
2754 fprintf(rtlog
, "RTDEL: Route does not exist: %s/%d gw %s\n",
2755 inet6_n2p(&np
->rip6_dest
), np
->rip6_plen
, buf2
);
2757 trace(0, "Can not write to rtsock (delroute): %s\n",
2760 fprintf(rtlog
, "\tCan not write to rtsock: %s\n",
2767 getroute(struct netinfo6
*np
, struct in6_addr
*gw
)
2772 struct rt_msghdr
*rtm
;
2773 struct sockaddr_in6
*sin6
;
2775 rtm
= (struct rt_msghdr
*)buf
;
2776 len
= sizeof(struct rt_msghdr
) + sizeof(struct sockaddr_in6
);
2777 memset(rtm
, 0, len
);
2778 rtm
->rtm_type
= RTM_GET
;
2779 rtm
->rtm_version
= RTM_VERSION
;
2781 rtm
->rtm_seq
= myseq
;
2782 rtm
->rtm_addrs
= RTA_DST
;
2783 rtm
->rtm_msglen
= len
;
2784 sin6
= (struct sockaddr_in6
*)&buf
[sizeof(struct rt_msghdr
)];
2785 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2786 sin6
->sin6_family
= AF_INET6
;
2787 sin6
->sin6_addr
= np
->rip6_dest
;
2788 if (write(rtsock
, buf
, len
) < 0) {
2789 if (errno
== ESRCH
) /* No such route found */
2791 perror("write to rtsock");
2795 if ((len
= read(rtsock
, buf
, sizeof(buf
))) < 0) {
2796 perror("read from rtsock");
2799 rtm
= (struct rt_msghdr
*)buf
;
2800 } while (rtm
->rtm_seq
!= myseq
|| rtm
->rtm_pid
!= pid
);
2801 sin6
= (struct sockaddr_in6
*)&buf
[sizeof(struct rt_msghdr
)];
2802 if (rtm
->rtm_addrs
& RTA_DST
) {
2803 sin6
= (struct sockaddr_in6
*)
2804 ((char *)sin6
+ ROUNDUP(sin6
->sin6_len
));
2806 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
2807 *gw
= sin6
->sin6_addr
;
2814 inet6_n2p(const struct in6_addr
*p
)
2816 static char buf
[BUFSIZ
];
2818 return inet_ntop(AF_INET6
, (const void *)p
, buf
, sizeof(buf
));
2839 if ((dump
= fopen(ROUTE6D_DUMP
, "a")) == NULL
)
2842 fprintf(dump
, "%s: Interface Table Dump\n", hms());
2843 fprintf(dump
, " Number of interfaces: %d\n", nifc
);
2844 for (i
= 0; i
< 2; i
++) {
2845 fprintf(dump
, " %sadvertising interfaces:\n", i
? "non-" : "");
2846 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
) {
2848 if ((ifcp
->ifc_flags
& IFF_UP
) == 0)
2850 if (iff_find(ifcp
, 'N') != NULL
)
2853 if (ifcp
->ifc_flags
& IFF_UP
)
2856 ifdump0(dump
, ifcp
);
2859 fprintf(dump
, "\n");
2865 ifdump0(FILE *dump
, const struct ifc
*ifcp
)
2873 fprintf(dump
, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
2874 ifcp
->ifc_name
, ifcp
->ifc_index
, ifflags(ifcp
->ifc_flags
),
2875 inet6_n2p(&ifcp
->ifc_mylladdr
),
2876 ifcp
->ifc_mtu
, ifcp
->ifc_metric
);
2877 for (ifa
= ifcp
->ifc_addr
; ifa
; ifa
= ifa
->ifa_next
) {
2878 if (ifcp
->ifc_flags
& IFF_POINTOPOINT
) {
2879 inet_ntop(AF_INET6
, (void *)&ifa
->ifa_raddr
,
2881 fprintf(dump
, "\t%s/%d -- %s\n",
2882 inet6_n2p(&ifa
->ifa_addr
),
2883 ifa
->ifa_plen
, buf
);
2885 fprintf(dump
, "\t%s/%d\n",
2886 inet6_n2p(&ifa
->ifa_addr
),
2890 if (ifcp
->ifc_filter
) {
2891 fprintf(dump
, "\tFilter:");
2892 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
2894 switch (iffp
->iff_type
) {
2896 ft
= "Aggregate"; addr
++; break;
2898 ft
= "No-use"; break;
2900 ft
= "Advertise-only"; addr
++; break;
2902 ft
= "Default-only"; break;
2904 ft
= "Listen-only"; addr
++; break;
2906 snprintf(buf
, sizeof(buf
), "Unknown-%c", iffp
->iff_type
);
2911 fprintf(dump
, " %s", ft
);
2913 fprintf(dump
, "(%s/%d)", inet6_n2p(&iffp
->iff_addr
),
2917 fprintf(dump
, "\n");
2932 if ((dump
= fopen(ROUTE6D_DUMP
, "a")) == NULL
)
2936 fprintf(dump
, "\n%s: Routing Table Dump\n", hms());
2937 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
2938 if (rrt
->rrt_t
== 0)
2941 age
= t
- rrt
->rrt_t
;
2942 inet_ntop(AF_INET6
, (void *)&rrt
->rrt_info
.rip6_dest
,
2944 fprintf(dump
, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
2945 buf
, rrt
->rrt_info
.rip6_plen
, rrt
->rrt_index
,
2946 index2ifc
[rrt
->rrt_index
]->ifc_name
,
2947 inet6_n2p(&rrt
->rrt_gw
),
2948 rrt
->rrt_info
.rip6_metric
, (long)age
);
2949 if (rrt
->rrt_info
.rip6_tag
) {
2950 fprintf(dump
, " tag(0x%04x)",
2951 ntohs(rrt
->rrt_info
.rip6_tag
) & 0xffff);
2953 if (rrt
->rrt_rflags
& RRTF_NH_NOT_LLADDR
)
2954 fprintf(dump
, " NOT-LL");
2955 if (rrt
->rrt_rflags
& RRTF_NOADVERTISE
)
2956 fprintf(dump
, " NO-ADV");
2957 fprintf(dump
, "\n");
2959 fprintf(dump
, "\n");
2965 * Parse the -A (and -O) options and put corresponding filter object to the
2966 * specified interface structures. Each of the -A/O option has the following
2967 * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate)
2968 * -O 5f09:c400::/32,ef0,ef1 (only when match)
2974 char *p
, *ap
, *iflp
, *ifname
, *ep
;
2975 struct iff ftmp
, *iff_obj
;
2983 for (i
= 0; i
< nfilter
; i
++) {
2987 if (filtertype
[i
] == 'N' || filtertype
[i
] == 'T') {
2991 if ((p
= strchr(ap
, ',')) != NULL
) {
2995 if ((p
= strchr(ap
, '/')) == NULL
) {
2996 fatal("no prefixlen specified for '%s'", ap
);
3000 if (inet_pton(AF_INET6
, ap
, &ftmp
.iff_addr
) != 1) {
3001 fatal("invalid prefix specified for '%s'", ap
);
3006 plen
= strtoul(p
, &ep
, 10);
3007 if (errno
|| !*p
|| *ep
|| plen
> sizeof(ftmp
.iff_addr
) * 8) {
3008 fatal("invalid prefix length specified for '%s'", ap
);
3011 ftmp
.iff_plen
= plen
;
3012 ftmp
.iff_next
= NULL
;
3013 applyplen(&ftmp
.iff_addr
, ftmp
.iff_plen
);
3015 ftmp
.iff_type
= filtertype
[i
];
3016 if (iflp
== NULL
|| *iflp
== '\0') {
3017 fatal("no interface specified for '%s'", ap
);
3020 /* parse the interface listing portion */
3023 if ((iflp
= strchr(iflp
, ',')) != NULL
)
3025 ifcp
= ifc_find(ifname
);
3027 fatal("no interface %s exists", ifname
);
3030 iff_obj
= (struct iff
*)malloc(sizeof(struct iff
));
3031 if (iff_obj
== NULL
) {
3032 fatal("malloc of iff_obj");
3035 memcpy((void *)iff_obj
, (void *)&ftmp
,
3036 sizeof(struct iff
));
3037 /* link it to the interface filter */
3038 iff_obj
->iff_next
= ifcp
->ifc_filter
;
3039 ifcp
->ifc_filter
= iff_obj
;
3043 * -A: aggregate configuration.
3045 if (filtertype
[i
] != 'A')
3047 /* put the aggregate to the kernel routing table */
3048 rrt
= (struct riprt
*)malloc(sizeof(struct riprt
));
3050 fatal("malloc: rrt");
3053 memset(rrt
, 0, sizeof(struct riprt
));
3054 rrt
->rrt_info
.rip6_dest
= ftmp
.iff_addr
;
3055 rrt
->rrt_info
.rip6_plen
= ftmp
.iff_plen
;
3056 rrt
->rrt_info
.rip6_metric
= 1;
3057 rrt
->rrt_info
.rip6_tag
= htons(routetag
& 0xffff);
3058 rrt
->rrt_gw
= in6addr_loopback
;
3059 rrt
->rrt_flags
= RTF_UP
| RTF_REJECT
;
3060 rrt
->rrt_rflags
= RRTF_AGGREGATE
;
3062 rrt
->rrt_index
= loopifcp
->ifc_index
;
3064 if (getroute(&rrt
->rrt_info
, &gw
)) {
3067 * When the address has already been registered in the
3068 * kernel routing table, it should be removed
3070 delroute(&rrt
->rrt_info
, &gw
);
3072 /* it is safer behavior */
3074 fatal("%s/%u already in routing table, "
3076 inet6_n2p(&rrt
->rrt_info
.rip6_dest
),
3077 rrt
->rrt_info
.rip6_plen
);
3082 /* Put the route to the list */
3083 rrt
->rrt_next
= riprt
;
3085 trace(1, "Aggregate: %s/%d for %s\n",
3086 inet6_n2p(&ftmp
.iff_addr
), ftmp
.iff_plen
,
3088 /* Add this route to the kernel */
3089 if (nflag
) /* do not modify kernel routing table */
3091 addroute(rrt
, &in6addr_loopback
, loopifcp
);
3095 /***************** utility functions *****************/
3098 * Returns a pointer to ifac whose address and prefix length matches
3099 * with the address and prefix length specified in the arguments.
3102 ifa_match(const struct ifc
*ifcp
, const struct in6_addr
*ia
, int plen
)
3106 for (ifa
= ifcp
->ifc_addr
; ifa
; ifa
= ifa
->ifa_next
) {
3107 if (IN6_ARE_ADDR_EQUAL(&ifa
->ifa_addr
, ia
) &&
3108 ifa
->ifa_plen
== plen
)
3115 * Return a pointer to riprt structure whose address and prefix length
3116 * matches with the address and prefix length found in the argument.
3117 * Note: This is not a rtalloc(). Therefore exact match is necessary.
3120 rtsearch(struct netinfo6
*np
, struct riprt
**prev_rrt
)
3126 for (rrt
= riprt
; rrt
; rrt
= rrt
->rrt_next
) {
3127 if (rrt
->rrt_info
.rip6_plen
== np
->rip6_plen
&&
3128 IN6_ARE_ADDR_EQUAL(&rrt
->rrt_info
.rip6_dest
,
3140 sin6mask2len(const struct sockaddr_in6
*sin6
)
3143 return mask2len(&sin6
->sin6_addr
,
3144 sin6
->sin6_len
- offsetof(struct sockaddr_in6
, sin6_addr
));
3148 mask2len(const struct in6_addr
*addr
, int lenlim
)
3151 const u_char
*p
= (const u_char
*)addr
;
3153 for (j
= 0; j
< lenlim
; j
++, p
++) {
3160 #define MASKLEN(m, l) case m: do { i += l; break; } while (0)
3161 MASKLEN(0xfe, 7); break;
3162 MASKLEN(0xfc, 6); break;
3163 MASKLEN(0xf8, 5); break;
3164 MASKLEN(0xf0, 4); break;
3165 MASKLEN(0xe0, 3); break;
3166 MASKLEN(0xc0, 2); break;
3167 MASKLEN(0x80, 1); break;
3175 applymask(struct in6_addr
*addr
, struct in6_addr
*mask
)
3180 p
= (u_long
*)addr
; q
= (u_long
*)mask
;
3181 for (i
= 0; i
< 4; i
++)
3185 static const u_char plent
[8] = {
3186 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
3190 applyplen(struct in6_addr
*ia
, int plen
)
3196 for (i
= 0; i
< 16; i
++) {
3205 static const int pl2m
[9] = {
3206 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
3212 static struct in6_addr ia
;
3216 memset(&ia
, 0, sizeof(struct in6_addr
));
3218 for (i
= 0; i
< 16; i
++, p
++, n
-= 8) {
3232 int len
= strlen(p
) + 1;
3233 char *q
= (char *)malloc(len
);
3247 static char buf
[BUFSIZ
];
3252 if ((tm
= localtime(&t
)) == 0) {
3256 snprintf(buf
, sizeof(buf
), "%02d:%02d:%02d", tm
->tm_hour
, tm
->tm_min
,
3261 #define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */
3264 ripinterval(int timer
)
3268 interval
= (int)(timer
+ timer
* RIPRANDDEV
* (r
/ RAND_MAX
- 0.5));
3269 nextalarm
= time(NULL
) + interval
;
3279 t
= (int)(RIP_TRIG_INT6_MIN
+
3280 (RIP_TRIG_INT6_MAX
- RIP_TRIG_INT6_MIN
) * (r
/ RAND_MAX
));
3281 sup_trig_update
= time(NULL
) + t
;
3286 fatal(const char *fmt
, ...)
3292 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
3296 syslog(LOG_ERR
, "%s: %s", buf
, strerror(errno
));
3298 syslog(LOG_ERR
, "%s", buf
);
3303 tracet(int level
, const char *fmt
, ...)
3307 if (level
<= dflag
) {
3309 fprintf(stderr
, "%s: ", hms());
3310 vfprintf(stderr
, fmt
, ap
);
3316 vsyslog(LOG_DEBUG
, fmt
, ap
);
3318 vsyslog(LOG_WARNING
, fmt
, ap
);
3324 trace(int level
, const char *fmt
, ...)
3328 if (level
<= dflag
) {
3330 vfprintf(stderr
, fmt
, ap
);
3336 vsyslog(LOG_DEBUG
, fmt
, ap
);
3338 vsyslog(LOG_WARNING
, fmt
, ap
);
3346 struct if_nameindex
*p
, *p0
;
3347 unsigned int max
= 0;
3349 p0
= if_nameindex();
3350 for (p
= p0
; p
&& p
->if_index
&& p
->if_name
; p
++) {
3351 if (max
< p
->if_index
)
3354 if_freenameindex(p0
);
3359 ifc_find(char *name
)
3363 for (ifcp
= ifc
; ifcp
; ifcp
= ifcp
->ifc_next
) {
3364 if (strcmp(name
, ifcp
->ifc_name
) == 0)
3367 return (struct ifc
*)NULL
;
3371 iff_find(struct ifc
*ifcp
, int type
)
3375 for (iffp
= ifcp
->ifc_filter
; iffp
; iffp
= iffp
->iff_next
) {
3376 if (iffp
->iff_type
== type
)
3383 setindex2ifc(int idx
, struct ifc
*ifcp
)
3389 nindex2ifc
= 5; /*initial guess*/
3390 index2ifc
= (struct ifc
**)
3391 malloc(sizeof(*index2ifc
) * nindex2ifc
);
3392 if (index2ifc
== NULL
) {
3396 memset(index2ifc
, 0, sizeof(*index2ifc
) * nindex2ifc
);
3399 for (nsize
= nindex2ifc
; nsize
<= idx
; nsize
*= 2)
3402 p
= (struct ifc
**)realloc(index2ifc
,
3403 sizeof(*index2ifc
) * nsize
);
3408 memset(p
+ n
, 0, sizeof(*index2ifc
) * (nindex2ifc
- n
));
3412 index2ifc
[idx
] = ifcp
;