2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <net/if_types.h>
34 #include <net/route.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <net/if_dl.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/ip.h>
48 #include <sys/sysctl.h>
59 #include "throughput.h"
66 #include "slcompress.h"
70 #include "descriptor.h"
85 p_sockaddr(struct prompt
*prompt
, struct sockaddr
*phost
,
86 struct sockaddr
*pmask
, int width
)
88 struct ncprange range
;
90 struct sockaddr_dl
*dl
= (struct sockaddr_dl
*)phost
;
92 if (log_IsKept(LogDEBUG
)) {
95 log_Printf(LogDEBUG
, "Found the following sockaddr:\n");
96 log_Printf(LogDEBUG
, " Family %d, len %d\n",
97 (int)phost
->sa_family
, (int)phost
->sa_len
);
98 inet_ntop(phost
->sa_family
, phost
->sa_data
, tmp
, sizeof tmp
);
99 log_Printf(LogDEBUG
, " Addr %s\n", tmp
);
101 inet_ntop(pmask
->sa_family
, pmask
->sa_data
, tmp
, sizeof tmp
);
102 log_Printf(LogDEBUG
, " Mask %s\n", tmp
);
106 switch (phost
->sa_family
) {
111 ncprange_setsa(&range
, phost
, pmask
);
112 if (ncprange_isdefault(&range
))
113 prompt_Printf(prompt
, "%-*s ", width
- 1, "default");
115 prompt_Printf(prompt
, "%-*s ", width
- 1, ncprange_ntoa(&range
));
120 snprintf(buf
, sizeof buf
, "%.*s", dl
->sdl_nlen
, dl
->sdl_data
);
121 else if (dl
->sdl_alen
) {
122 if (dl
->sdl_type
== IFT_ETHER
) {
123 if (dl
->sdl_alen
< sizeof buf
/ 3) {
127 MAC
= (u_char
*)dl
->sdl_data
+ dl
->sdl_nlen
;
128 for (f
= 0; f
< dl
->sdl_alen
; f
++)
129 sprintf(buf
+f
*3, "%02x:", MAC
[f
]);
132 strcpy(buf
, "??:??:??:??:??:??");
134 sprintf(buf
, "<IFT type %d>", dl
->sdl_type
);
135 } else if (dl
->sdl_slen
)
136 sprintf(buf
, "<slen %d?>", dl
->sdl_slen
);
138 sprintf(buf
, "link#%d", dl
->sdl_index
);
142 sprintf(buf
, "<AF type %d>", phost
->sa_family
);
146 prompt_Printf(prompt
, "%-*s ", width
-1, buf
);
154 { RTF_GATEWAY
, 'G' },
157 { RTF_DYNAMIC
, 'D' },
158 { RTF_MODIFIED
, 'M' },
160 { RTF_CLONING
, 'C' },
161 { RTF_XRESOLVE
, 'X' },
166 { RTF_BLACKHOLE
, 'B' },
168 { RTF_WASCLONED
, 'W' },
171 { RTF_PRCLONING
, 'c' },
177 { RTF_BROADCAST
, 'b' },
182 #ifndef RTF_WASCLONED
183 #define RTF_WASCLONED (0)
187 p_flags(struct prompt
*prompt
, u_int32_t f
, unsigned max
)
189 char name
[33], *flags
;
190 register struct bits
*p
= bits
;
192 if (max
> sizeof name
- 1)
193 max
= sizeof name
- 1;
195 for (flags
= name
; p
->b_mask
&& flags
- name
< (int)max
; p
++)
199 prompt_Printf(prompt
, "%-*.*s", (int)max
, (int)max
, name
);
202 static int route_nifs
= -1;
208 * XXX: Maybe we should select() on the routing socket so that we can
209 * notice interfaces that come & go (PCCARD support).
210 * Or we could even support a signal that resets these so that
211 * the PCCARD insert/remove events can signal ppp.
213 static char **ifs
; /* Figure these out once */
214 static int debug_done
; /* Debug once */
216 if (idx
> route_nifs
|| (idx
> 0 && ifs
[idx
-1] == NULL
)) {
217 int mib
[6], have
, had
;
219 char *buf
, *ptr
, *end
;
220 struct sockaddr_dl
*dl
;
221 struct if_msghdr
*ifm
;
234 mib
[4] = NET_RT_IFLIST
;
237 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
238 log_Printf(LogERROR
, "Index2Nam: sysctl: estimate: %s\n",
240 return NumStr(idx
, NULL
, 0);
242 if ((buf
= malloc(needed
)) == NULL
)
243 return NumStr(idx
, NULL
, 0);
244 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
246 return NumStr(idx
, NULL
, 0);
251 for (ptr
= buf
; ptr
< end
; ptr
+= ifm
->ifm_msglen
) {
252 ifm
= (struct if_msghdr
*)ptr
;
253 if (ifm
->ifm_type
!= RTM_IFINFO
)
255 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
256 if (ifm
->ifm_index
> 0) {
257 if (ifm
->ifm_index
> have
) {
261 have
= ifm
->ifm_index
+ 5;
263 newifs
= (char **)realloc(ifs
, sizeof(char *) * have
);
265 newifs
= (char **)malloc(sizeof(char *) * have
);
267 log_Printf(LogDEBUG
, "Index2Nam: %s\n", strerror(errno
));
274 return NumStr(idx
, NULL
, 0);
277 memset(ifs
+ had
, '\0', sizeof(char *) * (have
- had
));
279 if (ifs
[ifm
->ifm_index
-1] == NULL
) {
280 ifs
[ifm
->ifm_index
-1] = (char *)malloc(dl
->sdl_nlen
+1);
281 if (ifs
[ifm
->ifm_index
-1] == NULL
)
282 log_Printf(LogDEBUG
, "Skipping interface %d: Out of memory\n",
285 memcpy(ifs
[ifm
->ifm_index
-1], dl
->sdl_data
, dl
->sdl_nlen
);
286 ifs
[ifm
->ifm_index
-1][dl
->sdl_nlen
] = '\0';
287 if (route_nifs
< ifm
->ifm_index
)
288 route_nifs
= ifm
->ifm_index
;
291 } else if (log_IsKept(LogDEBUG
))
292 log_Printf(LogDEBUG
, "Skipping out-of-range interface %d!\n",
298 if (log_IsKept(LogDEBUG
) && !debug_done
) {
301 log_Printf(LogDEBUG
, "Found the following interfaces:\n");
302 for (f
= 0; f
< route_nifs
; f
++)
304 log_Printf(LogDEBUG
, " Index %d, name \"%s\"\n", f
+1, ifs
[f
]);
308 if (idx
< 1 || idx
> route_nifs
|| ifs
[idx
-1] == NULL
)
309 return NumStr(idx
, NULL
, 0);
315 route_ParseHdr(struct rt_msghdr
*rtm
, struct sockaddr
*sa
[RTAX_MAX
])
320 wp
= (char *)(rtm
+ 1);
322 for (rtax
= 0; rtax
< RTAX_MAX
; rtax
++)
323 if (rtm
->rtm_addrs
& (1 << rtax
)) {
324 sa
[rtax
] = (struct sockaddr
*)wp
;
325 wp
+= ROUNDUP(sa
[rtax
]->sa_len
);
326 if (sa
[rtax
]->sa_family
== 0)
327 sa
[rtax
] = NULL
; /* ??? */
333 route_Show(struct cmdargs
const *arg
)
335 struct rt_msghdr
*rtm
;
336 struct sockaddr
*sa
[RTAX_MAX
];
345 mib
[4] = NET_RT_DUMP
;
347 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
348 log_Printf(LogERROR
, "route_Show: sysctl: estimate: %s\n", strerror(errno
));
354 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
355 log_Printf(LogERROR
, "route_Show: sysctl: getroute: %s\n", strerror(errno
));
361 prompt_Printf(arg
->prompt
, "%-20s%-20sFlags Netif\n",
362 "Destination", "Gateway");
363 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
364 rtm
= (struct rt_msghdr
*)cp
;
366 route_ParseHdr(rtm
, sa
);
368 if (sa
[RTAX_DST
] && sa
[RTAX_GATEWAY
]) {
369 p_sockaddr(arg
->prompt
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
], 20);
370 p_sockaddr(arg
->prompt
, sa
[RTAX_GATEWAY
], NULL
, 20);
372 p_flags(arg
->prompt
, rtm
->rtm_flags
, 6);
373 prompt_Printf(arg
->prompt
, " %s\n", Index2Nam(rtm
->rtm_index
));
375 prompt_Printf(arg
->prompt
, "<can't parse routing entry>\n");
382 * Delete routes associated with our interface
385 route_IfDelete(struct bundle
*bundle
, int all
)
387 struct rt_msghdr
*rtm
;
388 struct sockaddr
*sa
[RTAX_MAX
];
389 struct ncprange range
;
395 log_Printf(LogDEBUG
, "route_IfDelete (%d)\n", bundle
->iface
->index
);
401 mib
[4] = NET_RT_DUMP
;
403 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
404 log_Printf(LogERROR
, "route_IfDelete: sysctl: estimate: %s\n",
413 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
414 log_Printf(LogERROR
, "route_IfDelete: sysctl: getroute: %s\n",
421 for (pass
= 0; pass
< 2; pass
++) {
423 * We do 2 passes. The first deletes all cloned routes. The second
424 * deletes all non-cloned routes. This is done to avoid
425 * potential errors from trying to delete route X after route Y where
426 * route X was cloned from route Y (and is no longer there 'cos it
427 * may have gone with route Y).
429 if (RTF_WASCLONED
== 0 && pass
== 0)
430 /* So we can't tell ! */
432 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
433 rtm
= (struct rt_msghdr
*)cp
;
434 route_ParseHdr(rtm
, sa
);
435 if (rtm
->rtm_index
== bundle
->iface
->index
&&
436 sa
[RTAX_DST
] && sa
[RTAX_GATEWAY
] &&
437 (sa
[RTAX_DST
]->sa_family
== AF_INET
439 || sa
[RTAX_DST
]->sa_family
== AF_INET6
442 (all
|| (rtm
->rtm_flags
& RTF_GATEWAY
))) {
443 if (log_IsKept(LogDEBUG
)) {
446 ncprange_setsa(&range
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
447 ncpaddr_setsa(&gw
, sa
[RTAX_GATEWAY
]);
448 snprintf(gwstr
, sizeof gwstr
, "%s", ncpaddr_ntoa(&gw
));
449 log_Printf(LogDEBUG
, "Found %s %s\n", ncprange_ntoa(&range
), gwstr
);
451 if (sa
[RTAX_GATEWAY
]->sa_family
== AF_INET
||
453 sa
[RTAX_GATEWAY
]->sa_family
== AF_INET6
||
455 sa
[RTAX_GATEWAY
]->sa_family
== AF_LINK
) {
456 if ((pass
== 0 && (rtm
->rtm_flags
& RTF_WASCLONED
)) ||
457 (pass
== 1 && !(rtm
->rtm_flags
& RTF_WASCLONED
))) {
458 ncprange_setsa(&range
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
459 rt_Set(bundle
, RTM_DELETE
, &range
, NULL
, 0, 0);
461 log_Printf(LogDEBUG
, "route_IfDelete: Skip it (pass %d)\n", pass
);
464 "route_IfDelete: Can't remove routes for family %d\n",
465 sa
[RTAX_GATEWAY
]->sa_family
);
474 * Update the MTU on all routes for the given interface
477 route_UpdateMTU(struct bundle
*bundle
)
479 struct rt_msghdr
*rtm
;
480 struct sockaddr
*sa
[RTAX_MAX
];
486 log_Printf(LogDEBUG
, "route_UpdateMTU (%d)\n", bundle
->iface
->index
);
492 mib
[4] = NET_RT_DUMP
;
494 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
495 log_Printf(LogERROR
, "route_IfDelete: sysctl: estimate: %s\n",
504 if (sysctl(mib
, 6, sp
, &needed
, NULL
, 0) < 0) {
505 log_Printf(LogERROR
, "route_IfDelete: sysctl: getroute: %s\n",
512 for (cp
= sp
; cp
< ep
; cp
+= rtm
->rtm_msglen
) {
513 rtm
= (struct rt_msghdr
*)cp
;
514 route_ParseHdr(rtm
, sa
);
515 if (sa
[RTAX_DST
] && (sa
[RTAX_DST
]->sa_family
== AF_INET
517 || sa
[RTAX_DST
]->sa_family
== AF_INET6
520 sa
[RTAX_GATEWAY
] && rtm
->rtm_index
== bundle
->iface
->index
) {
521 if (log_IsKept(LogTCPIP
)) {
522 ncprange_setsa(&dst
, sa
[RTAX_DST
], sa
[RTAX_NETMASK
]);
523 log_Printf(LogTCPIP
, "route_UpdateMTU: Netif: %d (%s), dst %s,"
524 " mtu %lu\n", rtm
->rtm_index
, Index2Nam(rtm
->rtm_index
),
525 ncprange_ntoa(&dst
), bundle
->iface
->mtu
);
527 rt_Update(bundle
, sa
[RTAX_DST
], sa
[RTAX_GATEWAY
], sa
[RTAX_NETMASK
]);
535 GetIfIndex(char *name
)
540 while (route_nifs
== -1 || idx
< route_nifs
)
541 if (strcmp(Index2Nam(idx
), name
) == 0)
549 route_Change(struct bundle
*bundle
, struct sticky_route
*r
,
550 const struct ncpaddr
*me
, const struct ncpaddr
*peer
)
554 for (; r
; r
= r
->next
) {
555 ncprange_getaddr(&r
->dst
, &dst
);
556 if (ncpaddr_family(me
) == AF_INET
) {
557 if ((r
->type
& ROUTE_DSTMYADDR
) && !ncpaddr_equal(&dst
, me
)) {
558 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
559 ncprange_sethost(&r
->dst
, me
);
560 if (r
->type
& ROUTE_GWHISADDR
)
561 ncpaddr_copy(&r
->gw
, peer
);
562 } else if ((r
->type
& ROUTE_DSTHISADDR
) && !ncpaddr_equal(&dst
, peer
)) {
563 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
564 ncprange_sethost(&r
->dst
, peer
);
565 if (r
->type
& ROUTE_GWHISADDR
)
566 ncpaddr_copy(&r
->gw
, peer
);
567 } else if ((r
->type
& ROUTE_DSTDNS0
) && !ncpaddr_equal(&dst
, peer
)) {
568 if (bundle
->ncp
.ipcp
.ns
.dns
[0].s_addr
== INADDR_NONE
)
570 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
571 if (r
->type
& ROUTE_GWHISADDR
)
572 ncpaddr_copy(&r
->gw
, peer
);
573 } else if ((r
->type
& ROUTE_DSTDNS1
) && !ncpaddr_equal(&dst
, peer
)) {
574 if (bundle
->ncp
.ipcp
.ns
.dns
[1].s_addr
== INADDR_NONE
)
576 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
577 if (r
->type
& ROUTE_GWHISADDR
)
578 ncpaddr_copy(&r
->gw
, peer
);
579 } else if ((r
->type
& ROUTE_GWHISADDR
) && !ncpaddr_equal(&r
->gw
, peer
))
580 ncpaddr_copy(&r
->gw
, peer
);
582 } else if (ncpaddr_family(me
) == AF_INET6
) {
583 if ((r
->type
& ROUTE_DSTMYADDR6
) && !ncpaddr_equal(&dst
, me
)) {
584 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
585 ncprange_sethost(&r
->dst
, me
);
586 if (r
->type
& ROUTE_GWHISADDR
)
587 ncpaddr_copy(&r
->gw
, peer
);
588 } else if ((r
->type
& ROUTE_DSTHISADDR6
) && !ncpaddr_equal(&dst
, peer
)) {
589 rt_Set(bundle
, RTM_DELETE
, &r
->dst
, NULL
, 1, 0);
590 ncprange_sethost(&r
->dst
, peer
);
591 if (r
->type
& ROUTE_GWHISADDR
)
592 ncpaddr_copy(&r
->gw
, peer
);
593 } else if ((r
->type
& ROUTE_GWHISADDR6
) && !ncpaddr_equal(&r
->gw
, peer
))
594 ncpaddr_copy(&r
->gw
, peer
);
597 rt_Set(bundle
, RTM_ADD
, &r
->dst
, &r
->gw
, 1, 0);
602 route_Add(struct sticky_route
**rp
, int type
, const struct ncprange
*dst
,
603 const struct ncpaddr
*gw
)
605 struct sticky_route
*r
;
606 int dsttype
= type
& ROUTE_DSTANY
;
610 if ((dsttype
&& dsttype
== ((*rp
)->type
& ROUTE_DSTANY
)) ||
611 (!dsttype
&& ncprange_equal(&(*rp
)->dst
, dst
))) {
612 /* Oops, we already have this route - unlink it */
613 free(r
); /* impossible really */
621 r
= (struct sticky_route
*)malloc(sizeof(struct sticky_route
));
623 log_Printf(LogERROR
, "route_Add: Out of memory!\n");
629 ncprange_copy(&r
->dst
, dst
);
630 ncpaddr_copy(&r
->gw
, gw
);
635 route_Delete(struct sticky_route
**rp
, int type
, const struct ncprange
*dst
)
637 struct sticky_route
*r
;
638 int dsttype
= type
& ROUTE_DSTANY
;
640 for (; *rp
; rp
= &(*rp
)->next
) {
641 if ((dsttype
&& dsttype
== ((*rp
)->type
& ROUTE_DSTANY
)) ||
642 (!dsttype
&& ncprange_equal(dst
, &(*rp
)->dst
))) {
652 route_DeleteAll(struct sticky_route
**rp
)
654 struct sticky_route
*r
, *rn
;
656 for (r
= *rp
; r
; r
= rn
) {
664 route_ShowSticky(struct prompt
*p
, struct sticky_route
*r
, const char *tag
,
667 int tlen
= strlen(tag
);
669 if (tlen
+ 2 > indent
)
670 prompt_Printf(p
, "%s:\n%*s", tag
, indent
, "");
672 prompt_Printf(p
, "%s:%*s", tag
, indent
- tlen
- 1, "");
674 for (; r
; r
= r
->next
) {
675 prompt_Printf(p
, "%*sadd ", tlen
? 0 : indent
, "");
677 if (r
->type
& ROUTE_DSTMYADDR
)
678 prompt_Printf(p
, "MYADDR");
679 else if (r
->type
& ROUTE_DSTMYADDR6
)
680 prompt_Printf(p
, "MYADDR6");
681 else if (r
->type
& ROUTE_DSTHISADDR
)
682 prompt_Printf(p
, "HISADDR");
683 else if (r
->type
& ROUTE_DSTHISADDR6
)
684 prompt_Printf(p
, "HISADDR6");
685 else if (r
->type
& ROUTE_DSTDNS0
)
686 prompt_Printf(p
, "DNS0");
687 else if (r
->type
& ROUTE_DSTDNS1
)
688 prompt_Printf(p
, "DNS1");
689 else if (ncprange_isdefault(&r
->dst
))
690 prompt_Printf(p
, "default");
692 prompt_Printf(p
, "%s", ncprange_ntoa(&r
->dst
));
694 if (r
->type
& ROUTE_GWHISADDR
)
695 prompt_Printf(p
, " HISADDR\n");
696 else if (r
->type
& ROUTE_GWHISADDR6
)
697 prompt_Printf(p
, " HISADDR6\n");
699 prompt_Printf(p
, " %s\n", ncpaddr_ntoa(&r
->gw
));
704 struct rt_msghdr m_rtm
;
709 memcpy_roundup(char *cp
, const void *data
, size_t len
)
713 padlen
= ROUNDUP(len
);
714 memcpy(cp
, data
, len
);
716 memset(cp
+ len
, '\0', padlen
- len
);
721 #if defined(__KAME__) && !defined(NOINET6)
723 add_scope(struct sockaddr
*sa
, int ifindex
)
725 struct sockaddr_in6
*sa6
;
727 if (sa
->sa_family
!= AF_INET6
)
729 sa6
= (struct sockaddr_in6
*)sa
;
730 if (!IN6_IS_ADDR_LINKLOCAL(&sa6
->sin6_addr
) &&
731 !IN6_IS_ADDR_MC_LINKLOCAL(&sa6
->sin6_addr
))
733 if (*(u_int16_t
*)&sa6
->sin6_addr
.s6_addr
[2] != 0)
735 *(u_int16_t
*)&sa6
->sin6_addr
.s6_addr
[2] = htons(ifindex
);
740 rt_Set(struct bundle
*bundle
, int cmd
, const struct ncprange
*dst
,
741 const struct ncpaddr
*gw
, int bang
, int quiet
)
747 struct sockaddr_storage sadst
, samask
, sagw
;
751 cmdstr
= (cmd
== RTM_ADD
? "Add!" : "Delete!");
753 cmdstr
= (cmd
== RTM_ADD
? "Add" : "Delete");
754 s
= ID0socket(PF_ROUTE
, SOCK_RAW
, 0);
756 log_Printf(LogERROR
, "rt_Set: socket(): %s\n", strerror(errno
));
759 memset(&rtmes
, '\0', sizeof rtmes
);
760 rtmes
.m_rtm
.rtm_version
= RTM_VERSION
;
761 rtmes
.m_rtm
.rtm_type
= cmd
;
762 rtmes
.m_rtm
.rtm_addrs
= RTA_DST
;
763 rtmes
.m_rtm
.rtm_seq
= ++bundle
->routing_seq
;
764 rtmes
.m_rtm
.rtm_pid
= getpid();
765 rtmes
.m_rtm
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
767 if (cmd
== RTM_ADD
) {
768 if (bundle
->ncp
.cfg
.sendpipe
> 0) {
769 rtmes
.m_rtm
.rtm_rmx
.rmx_sendpipe
= bundle
->ncp
.cfg
.sendpipe
;
770 rtmes
.m_rtm
.rtm_inits
|= RTV_SPIPE
;
772 if (bundle
->ncp
.cfg
.recvpipe
> 0) {
773 rtmes
.m_rtm
.rtm_rmx
.rmx_recvpipe
= bundle
->ncp
.cfg
.recvpipe
;
774 rtmes
.m_rtm
.rtm_inits
|= RTV_RPIPE
;
778 ncprange_getsa(dst
, &sadst
, &samask
);
779 #if defined(__KAME__) && !defined(NOINET6)
780 add_scope((struct sockaddr
*)&sadst
, bundle
->iface
->index
);
784 cp
+= memcpy_roundup(cp
, &sadst
, sadst
.ss_len
);
785 if (cmd
== RTM_ADD
) {
787 log_Printf(LogERROR
, "rt_Set: Program error\n");
791 ncpaddr_getsa(gw
, &sagw
);
792 #if defined(__KAME__) && !defined(NOINET6)
793 add_scope((struct sockaddr
*)&sagw
, bundle
->iface
->index
);
795 if (ncpaddr_isdefault(gw
)) {
797 log_Printf(LogERROR
, "rt_Set: Cannot add a route with"
798 " gateway 0.0.0.0\n");
802 cp
+= memcpy_roundup(cp
, &sagw
, sagw
.ss_len
);
803 rtmes
.m_rtm
.rtm_addrs
|= RTA_GATEWAY
;
807 if (!ncprange_ishost(dst
)) {
808 cp
+= memcpy_roundup(cp
, &samask
, samask
.ss_len
);
809 rtmes
.m_rtm
.rtm_addrs
|= RTA_NETMASK
;
812 nb
= cp
- (char *)&rtmes
;
813 rtmes
.m_rtm
.rtm_msglen
= nb
;
814 wb
= ID0write(s
, &rtmes
, nb
);
816 log_Printf(LogTCPIP
, "rt_Set failure:\n");
817 log_Printf(LogTCPIP
, "rt_Set: Cmd = %s\n", cmdstr
);
818 log_Printf(LogTCPIP
, "rt_Set: Dst = %s\n", ncprange_ntoa(dst
));
820 log_Printf(LogTCPIP
, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw
));
822 if (cmd
== RTM_ADD
&& (rtmes
.m_rtm
.rtm_errno
== EEXIST
||
823 (rtmes
.m_rtm
.rtm_errno
== 0 && errno
== EEXIST
))) {
825 log_Printf(LogWARN
, "Add route failed: %s already exists\n",
827 result
= 0; /* Don't add to our dynamic list */
829 rtmes
.m_rtm
.rtm_type
= cmd
= RTM_CHANGE
;
830 if ((wb
= ID0write(s
, &rtmes
, nb
)) < 0)
833 } else if (cmd
== RTM_DELETE
&&
834 (rtmes
.m_rtm
.rtm_errno
== ESRCH
||
835 (rtmes
.m_rtm
.rtm_errno
== 0 && errno
== ESRCH
))) {
837 log_Printf(LogWARN
, "Del route failed: %s: Non-existent\n",
839 } else if (rtmes
.m_rtm
.rtm_errno
== 0) {
840 if (!quiet
|| errno
!= ENETUNREACH
)
841 log_Printf(LogWARN
, "%s route failed: %s: errno: %s\n", cmdstr
,
842 ncprange_ntoa(dst
), strerror(errno
));
844 log_Printf(LogWARN
, "%s route failed: %s: %s\n",
845 cmdstr
, ncprange_ntoa(dst
), strerror(rtmes
.m_rtm
.rtm_errno
));
848 if (log_IsKept(LogDEBUG
)) {
852 snprintf(gwstr
, sizeof gwstr
, "%s", ncpaddr_ntoa(gw
));
854 snprintf(gwstr
, sizeof gwstr
, "<none>");
855 log_Printf(LogDEBUG
, "wrote %d: cmd = %s, dst = %s, gateway = %s\n",
856 wb
, cmdstr
, ncprange_ntoa(dst
), gwstr
);
864 rt_Update(struct bundle
*bundle
, const struct sockaddr
*dst
,
865 const struct sockaddr
*gw
, const struct sockaddr
*mask
)
867 struct ncprange ncpdst
;
872 s
= ID0socket(PF_ROUTE
, SOCK_RAW
, 0);
874 log_Printf(LogERROR
, "rt_Update: socket(): %s\n", strerror(errno
));
878 memset(&rtmes
, '\0', sizeof rtmes
);
879 rtmes
.m_rtm
.rtm_version
= RTM_VERSION
;
880 rtmes
.m_rtm
.rtm_type
= RTM_CHANGE
;
881 rtmes
.m_rtm
.rtm_addrs
= 0;
882 rtmes
.m_rtm
.rtm_seq
= ++bundle
->routing_seq
;
883 rtmes
.m_rtm
.rtm_pid
= getpid();
884 rtmes
.m_rtm
.rtm_flags
= RTF_UP
| RTF_STATIC
;
886 if (bundle
->ncp
.cfg
.sendpipe
> 0) {
887 rtmes
.m_rtm
.rtm_rmx
.rmx_sendpipe
= bundle
->ncp
.cfg
.sendpipe
;
888 rtmes
.m_rtm
.rtm_inits
|= RTV_SPIPE
;
891 if (bundle
->ncp
.cfg
.recvpipe
> 0) {
892 rtmes
.m_rtm
.rtm_rmx
.rmx_recvpipe
= bundle
->ncp
.cfg
.recvpipe
;
893 rtmes
.m_rtm
.rtm_inits
|= RTV_RPIPE
;
896 rtmes
.m_rtm
.rtm_rmx
.rmx_mtu
= bundle
->iface
->mtu
;
897 rtmes
.m_rtm
.rtm_inits
|= RTV_MTU
;
901 rtmes
.m_rtm
.rtm_addrs
|= RTA_DST
;
902 p
+= memcpy_roundup(p
, dst
, dst
->sa_len
);
905 rtmes
.m_rtm
.rtm_addrs
|= RTA_GATEWAY
;
906 p
+= memcpy_roundup(p
, gw
, gw
->sa_len
);
908 rtmes
.m_rtm
.rtm_addrs
|= RTA_NETMASK
;
909 p
+= memcpy_roundup(p
, mask
, mask
->sa_len
);
912 rtmes
.m_rtm
.rtm_msglen
= p
- (char *)&rtmes
;
914 wb
= ID0write(s
, &rtmes
, rtmes
.m_rtm
.rtm_msglen
);
916 ncprange_setsa(&ncpdst
, dst
, mask
);
918 log_Printf(LogTCPIP
, "rt_Update failure:\n");
919 log_Printf(LogTCPIP
, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst
));
921 if (rtmes
.m_rtm
.rtm_errno
== 0)
922 log_Printf(LogWARN
, "%s: Change route failed: errno: %s\n",
923 ncprange_ntoa(&ncpdst
), strerror(errno
));
925 log_Printf(LogWARN
, "%s: Change route failed: %s\n",
926 ncprange_ntoa(&ncpdst
), strerror(rtmes
.m_rtm
.rtm_errno
));