1 /*- 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) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 15 * 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 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/socket.h> 33 #include <net/if_types.h> 34 #include <net/route.h> 35 #include <net/if.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> 41 #include <sys/un.h> 42 #include <netdb.h> 43 44 #include <errno.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sys/sysctl.h> 49 #include <termios.h> 50 #include <unistd.h> 51 52 #include "layer.h" 53 #include "defs.h" 54 #include "command.h" 55 #include "mbuf.h" 56 #include "log.h" 57 #include "iplist.h" 58 #include "timer.h" 59 #include "throughput.h" 60 #include "lqr.h" 61 #include "hdlc.h" 62 #include "fsm.h" 63 #include "lcp.h" 64 #include "ccp.h" 65 #include "link.h" 66 #include "slcompress.h" 67 #include "ipcp.h" 68 #include "filter.h" 69 #include "descriptor.h" 70 #include "mp.h" 71 #ifndef NORADIUS 72 #include "radius.h" 73 #endif 74 #include "bundle.h" 75 #include "route.h" 76 #include "prompt.h" 77 #include "iface.h" 78 #include "id.h" 79 80 81 static void 82 p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 83 struct sockaddr *pmask, int width) 84 { 85 char buf[29]; 86 struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 87 struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 88 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 89 90 if (log_IsKept(LogDEBUG)) { 91 char tmp[50]; 92 93 log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 94 log_Printf(LogDEBUG, " Family %d, len %d\n", 95 (int)phost->sa_family, (int)phost->sa_len); 96 inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 97 log_Printf(LogDEBUG, " Addr %s\n", tmp); 98 if (pmask) { 99 inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 100 log_Printf(LogDEBUG, " Mask %s\n", tmp); 101 } 102 } 103 104 switch (phost->sa_family) { 105 case AF_INET: 106 if (!phost) 107 buf[0] = '\0'; 108 else if (ihost4->sin_addr.s_addr == INADDR_ANY) 109 strcpy(buf, "default"); 110 else if (!pmask) 111 strcpy(buf, inet_ntoa(ihost4->sin_addr)); 112 else { 113 u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 114 u_int32_t tst; 115 int bits; 116 int len; 117 struct sockaddr_in net; 118 119 for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 120 if (msk & tst) 121 break; 122 123 for (tst <<= 1; tst; tst <<= 1) 124 if (!(msk & tst)) 125 break; 126 127 net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 128 strcpy(buf, inet_ntoa(net.sin_addr)); 129 for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 130 if (strcmp(buf + len - 2, ".0")) 131 break; 132 133 if (tst) /* non-contiguous :-( */ 134 sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 135 else 136 sprintf(buf + strlen(buf), "/%d", bits); 137 } 138 break; 139 140 case AF_LINK: 141 if (dl->sdl_nlen) 142 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 143 else if (dl->sdl_alen) { 144 if (dl->sdl_type == IFT_ETHER) { 145 if (dl->sdl_alen < sizeof buf / 3) { 146 int f; 147 u_char *MAC; 148 149 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 150 for (f = 0; f < dl->sdl_alen; f++) 151 sprintf(buf+f*3, "%02x:", MAC[f]); 152 buf[f*3-1] = '\0'; 153 } else 154 strcpy(buf, "??:??:??:??:??:??"); 155 } else 156 sprintf(buf, "<IFT type %d>", dl->sdl_type); 157 } else if (dl->sdl_slen) 158 sprintf(buf, "<slen %d?>", dl->sdl_slen); 159 else 160 sprintf(buf, "link#%d", dl->sdl_index); 161 break; 162 163 #ifndef NOINET6 164 case AF_INET6: 165 if (!phost) 166 buf[0] = '\0'; 167 else { 168 const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 169 struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 170 struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 171 int masklen, len; 172 const u_char *c; 173 174 /* XXX: ?????!?!?!!!!! This is horrible ! */ 175 if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 176 IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 177 ihost6->sin6_scope_id = 178 ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 179 *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 180 } 181 182 if (mask6) { 183 const u_char *p, *end; 184 185 p = (const u_char *)&mask6->sin6_addr; 186 end = p + 16; 187 for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 188 masklen += 8; 189 190 if (p < end) { 191 for (c = masks; c < masks + sizeof masks; c++) 192 if (*c == *p) { 193 masklen += c - masks; 194 break; 195 } 196 } 197 } else 198 masklen = 128; 199 200 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 201 snprintf(buf, sizeof buf, "default"); 202 else { 203 getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 204 NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 205 if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 206 snprintf(buf + len, sizeof buf - len, "/%d", masklen); 207 } 208 } 209 break; 210 #endif 211 212 default: 213 sprintf(buf, "<AF type %d>", phost->sa_family); 214 break; 215 } 216 217 prompt_Printf(prompt, "%-*s ", width-1, buf); 218 } 219 220 static struct bits { 221 u_int32_t b_mask; 222 char b_val; 223 } bits[] = { 224 { RTF_UP, 'U' }, 225 { RTF_GATEWAY, 'G' }, 226 { RTF_HOST, 'H' }, 227 { RTF_REJECT, 'R' }, 228 { RTF_DYNAMIC, 'D' }, 229 { RTF_MODIFIED, 'M' }, 230 { RTF_DONE, 'd' }, 231 { RTF_CLONING, 'C' }, 232 { RTF_XRESOLVE, 'X' }, 233 { RTF_LLINFO, 'L' }, 234 { RTF_STATIC, 'S' }, 235 { RTF_PROTO1, '1' }, 236 { RTF_PROTO2, '2' }, 237 { RTF_BLACKHOLE, 'B' }, 238 #ifdef RTF_WASCLONED 239 { RTF_WASCLONED, 'W' }, 240 #endif 241 #ifdef RTF_PRCLONING 242 { RTF_PRCLONING, 'c' }, 243 #endif 244 #ifdef RTF_PROTO3 245 { RTF_PROTO3, '3' }, 246 #endif 247 #ifdef RTF_BROADCAST 248 { RTF_BROADCAST, 'b' }, 249 #endif 250 { 0, '\0' } 251 }; 252 253 #ifndef RTF_WASCLONED 254 #define RTF_WASCLONED (0) 255 #endif 256 257 static void 258 p_flags(struct prompt *prompt, u_int32_t f, int max) 259 { 260 char name[33], *flags; 261 register struct bits *p = bits; 262 263 if (max > sizeof name - 1) 264 max = sizeof name - 1; 265 266 for (flags = name; p->b_mask && flags - name < max; p++) 267 if (p->b_mask & f) 268 *flags++ = p->b_val; 269 *flags = '\0'; 270 prompt_Printf(prompt, "%-*.*s", max, max, name); 271 } 272 273 const char * 274 Index2Nam(int idx) 275 { 276 /* 277 * XXX: Maybe we should select() on the routing socket so that we can 278 * notice interfaces that come & go (PCCARD support). 279 * Or we could even support a signal that resets these so that 280 * the PCCARD insert/remove events can signal ppp. 281 */ 282 static char **ifs; /* Figure these out once */ 283 static int nifs, debug_done; /* Figure out how many once, and debug once */ 284 285 if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 286 int mib[6], have, had; 287 size_t needed; 288 char *buf, *ptr, *end; 289 struct sockaddr_dl *dl; 290 struct if_msghdr *ifm; 291 292 if (ifs) { 293 free(ifs); 294 ifs = NULL; 295 nifs = 0; 296 } 297 debug_done = 0; 298 299 mib[0] = CTL_NET; 300 mib[1] = PF_ROUTE; 301 mib[2] = 0; 302 mib[3] = 0; 303 mib[4] = NET_RT_IFLIST; 304 mib[5] = 0; 305 306 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 307 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 308 strerror(errno)); 309 return NumStr(idx, NULL, 0); 310 } 311 if ((buf = malloc(needed)) == NULL) 312 return NumStr(idx, NULL, 0); 313 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 314 free(buf); 315 return NumStr(idx, NULL, 0); 316 } 317 end = buf + needed; 318 319 have = 0; 320 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 321 ifm = (struct if_msghdr *)ptr; 322 if (ifm->ifm_type != RTM_IFINFO) 323 continue; 324 dl = (struct sockaddr_dl *)(ifm + 1); 325 if (ifm->ifm_index > 0) { 326 if (ifm->ifm_index > have) { 327 char **newifs; 328 329 had = have; 330 have = ifm->ifm_index + 5; 331 if (had) 332 newifs = (char **)realloc(ifs, sizeof(char *) * have); 333 else 334 newifs = (char **)malloc(sizeof(char *) * have); 335 if (!newifs) { 336 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 337 nifs = 0; 338 if (ifs) { 339 free(ifs); 340 ifs = NULL; 341 } 342 free(buf); 343 return NumStr(idx, NULL, 0); 344 } 345 ifs = newifs; 346 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 347 } 348 if (ifs[ifm->ifm_index-1] == NULL) { 349 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 350 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 351 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 352 if (nifs < ifm->ifm_index) 353 nifs = ifm->ifm_index; 354 } 355 } else if (log_IsKept(LogDEBUG)) 356 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 357 ifm->ifm_index); 358 } 359 free(buf); 360 } 361 362 if (log_IsKept(LogDEBUG) && !debug_done) { 363 int f; 364 365 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 366 for (f = 0; f < nifs; f++) 367 if (ifs[f] != NULL) 368 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 369 debug_done = 1; 370 } 371 372 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 373 return NumStr(idx, NULL, 0); 374 375 return ifs[idx-1]; 376 } 377 378 void 379 route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 380 { 381 char *wp; 382 int rtax; 383 384 wp = (char *)(rtm + 1); 385 386 for (rtax = 0; rtax < RTAX_MAX; rtax++) 387 if (rtm->rtm_addrs & (1 << rtax)) { 388 sa[rtax] = (struct sockaddr *)wp; 389 wp += ROUNDUP(sa[rtax]->sa_len); 390 } else 391 sa[rtax] = NULL; 392 } 393 394 int 395 route_Show(struct cmdargs const *arg) 396 { 397 struct rt_msghdr *rtm; 398 struct sockaddr *sa[RTAX_MAX]; 399 char *sp, *ep, *cp; 400 size_t needed; 401 int mib[6]; 402 403 mib[0] = CTL_NET; 404 mib[1] = PF_ROUTE; 405 mib[2] = 0; 406 mib[3] = 0; 407 mib[4] = NET_RT_DUMP; 408 mib[5] = 0; 409 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 410 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 411 return (1); 412 } 413 sp = malloc(needed); 414 if (sp == NULL) 415 return (1); 416 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 417 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 418 free(sp); 419 return (1); 420 } 421 ep = sp + needed; 422 423 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 424 "Destination", "Gateway"); 425 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 426 rtm = (struct rt_msghdr *)cp; 427 428 route_ParseHdr(rtm, sa); 429 430 if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 431 p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 432 p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 433 434 p_flags(arg->prompt, rtm->rtm_flags, 6); 435 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 436 } else 437 prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 438 } 439 free(sp); 440 return 0; 441 } 442 443 /* 444 * Delete routes associated with our interface 445 */ 446 void 447 route_IfDelete(struct bundle *bundle, int all) 448 { 449 struct rt_msghdr *rtm; 450 struct sockaddr *sa[RTAX_MAX]; 451 struct sockaddr_in **in; 452 struct in_addr sa_none; 453 int pass; 454 size_t needed; 455 char *sp, *cp, *ep; 456 int mib[6]; 457 458 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 459 sa_none.s_addr = INADDR_ANY; 460 in = (struct sockaddr_in **)sa; 461 462 mib[0] = CTL_NET; 463 mib[1] = PF_ROUTE; 464 mib[2] = 0; 465 mib[3] = 0; 466 mib[4] = NET_RT_DUMP; 467 mib[5] = 0; 468 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 469 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 470 strerror(errno)); 471 return; 472 } 473 474 sp = malloc(needed); 475 if (sp == NULL) 476 return; 477 478 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 479 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 480 strerror(errno)); 481 free(sp); 482 return; 483 } 484 ep = sp + needed; 485 486 for (pass = 0; pass < 2; pass++) { 487 /* 488 * We do 2 passes. The first deletes all cloned routes. The second 489 * deletes all non-cloned routes. This is done to avoid 490 * potential errors from trying to delete route X after route Y where 491 * route X was cloned from route Y (and is no longer there 'cos it 492 * may have gone with route Y). 493 */ 494 if (RTF_WASCLONED == 0 && pass == 0) 495 /* So we can't tell ! */ 496 continue; 497 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 498 rtm = (struct rt_msghdr *)cp; 499 route_ParseHdr(rtm, sa); 500 if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) { 501 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 502 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 503 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 504 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 505 if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 506 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 507 if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 508 sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 509 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 510 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 511 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 512 pass); 513 rt_Set(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 514 sa_none, sa_none, 0, 0); 515 } else 516 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 517 } else 518 log_Printf(LogDEBUG, 519 "route_IfDelete: Can't remove routes of %d family !\n", 520 sa[RTAX_GATEWAY]->sa_family); 521 } 522 } 523 } 524 } 525 free(sp); 526 } 527 528 529 /* 530 * Update the MTU on all routes for the given interface 531 */ 532 void 533 route_UpdateMTU(struct bundle *bundle) 534 { 535 struct rt_msghdr *rtm; 536 struct sockaddr *sa[RTAX_MAX]; 537 struct sockaddr_in **in; 538 size_t needed; 539 char *sp, *cp, *ep; 540 int mib[6]; 541 542 log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 543 in = (struct sockaddr_in **)sa; 544 545 mib[0] = CTL_NET; 546 mib[1] = PF_ROUTE; 547 mib[2] = 0; 548 mib[3] = 0; 549 mib[4] = NET_RT_DUMP; 550 mib[5] = 0; 551 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 552 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 553 strerror(errno)); 554 return; 555 } 556 557 sp = malloc(needed); 558 if (sp == NULL) 559 return; 560 561 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 562 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 563 strerror(errno)); 564 free(sp); 565 return; 566 } 567 ep = sp + needed; 568 569 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 570 rtm = (struct rt_msghdr *)cp; 571 route_ParseHdr(rtm, sa); 572 if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET && 573 sa[RTAX_GATEWAY] && /* sa[RTAX_NETMASK] && */ 574 rtm->rtm_index == bundle->iface->index && 575 (sa[RTAX_GATEWAY]->sa_family == AF_INET || 576 sa[RTAX_GATEWAY]->sa_family == AF_LINK)) { 577 log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s, mtu %d\n", 578 rtm->rtm_index, Index2Nam(rtm->rtm_index), 579 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr), 580 bundle->iface->mtu); 581 rt_Update(bundle, in[RTAX_DST]->sin_addr, in[RTAX_GATEWAY]->sin_addr); 582 } 583 } 584 585 free(sp); 586 } 587 588 int 589 GetIfIndex(char *name) 590 { 591 int idx; 592 const char *got; 593 594 idx = 1; 595 while (strcmp(got = Index2Nam(idx), "???")) 596 if (!strcmp(got, name)) 597 return idx; 598 else 599 idx++; 600 return -1; 601 } 602 603 void 604 route_Change(struct bundle *bundle, struct sticky_route *r, 605 struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 606 { 607 struct in_addr none, del; 608 609 none.s_addr = INADDR_ANY; 610 for (; r; r = r->next) { 611 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 612 del.s_addr = r->dst.s_addr & r->mask.s_addr; 613 rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 614 r->dst = me; 615 if (r->type & ROUTE_GWHISADDR) 616 r->gw = peer; 617 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 618 del.s_addr = r->dst.s_addr & r->mask.s_addr; 619 rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 620 r->dst = peer; 621 if (r->type & ROUTE_GWHISADDR) 622 r->gw = peer; 623 } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) { 624 del.s_addr = r->dst.s_addr & r->mask.s_addr; 625 rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 626 r->dst = dns[0]; 627 if (r->type & ROUTE_GWHISADDR) 628 r->gw = peer; 629 } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) { 630 del.s_addr = r->dst.s_addr & r->mask.s_addr; 631 rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 632 r->dst = dns[1]; 633 if (r->type & ROUTE_GWHISADDR) 634 r->gw = peer; 635 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 636 r->gw = peer; 637 rt_Set(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 638 } 639 } 640 641 void 642 route_Add(struct sticky_route **rp, int type, struct in_addr dst, 643 struct in_addr mask, struct in_addr gw) 644 { 645 struct sticky_route *r; 646 int dsttype = type & ROUTE_DSTANY; 647 648 r = NULL; 649 while (*rp) { 650 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 651 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 652 /* Oops, we already have this route - unlink it */ 653 free(r); /* impossible really */ 654 r = *rp; 655 *rp = r->next; 656 } else 657 rp = &(*rp)->next; 658 } 659 660 if (!r) 661 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 662 r->type = type; 663 r->next = NULL; 664 r->dst = dst; 665 r->mask = mask; 666 r->gw = gw; 667 *rp = r; 668 } 669 670 void 671 route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 672 { 673 struct sticky_route *r; 674 int dsttype = type & ROUTE_DSTANY; 675 676 for (; *rp; rp = &(*rp)->next) { 677 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 678 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 679 r = *rp; 680 *rp = r->next; 681 free(r); 682 break; 683 } 684 } 685 } 686 687 void 688 route_DeleteAll(struct sticky_route **rp) 689 { 690 struct sticky_route *r, *rn; 691 692 for (r = *rp; r; r = rn) { 693 rn = r->next; 694 free(r); 695 } 696 *rp = NULL; 697 } 698 699 void 700 route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 701 int indent) 702 { 703 int def; 704 int tlen = strlen(tag); 705 706 if (tlen + 2 > indent) 707 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 708 else 709 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 710 711 for (; r; r = r->next) { 712 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 713 714 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 715 tlen = 0; 716 if (r->type & ROUTE_DSTMYADDR) 717 prompt_Printf(p, "MYADDR"); 718 else if (r->type & ROUTE_DSTHISADDR) 719 prompt_Printf(p, "HISADDR"); 720 else if (r->type & ROUTE_DSTDNS0) 721 prompt_Printf(p, "DNS0"); 722 else if (r->type & ROUTE_DSTDNS1) 723 prompt_Printf(p, "DNS1"); 724 else if (!def) 725 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 726 727 if (def) 728 prompt_Printf(p, "default "); 729 else 730 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 731 732 if (r->type & ROUTE_GWHISADDR) 733 prompt_Printf(p, "HISADDR\n"); 734 else 735 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 736 } 737 } 738 739 struct rtmsg { 740 struct rt_msghdr m_rtm; 741 char m_space[64]; 742 }; 743 744 int 745 rt_Set(struct bundle *bundle, int cmd, struct in_addr dst, 746 struct in_addr gateway, struct in_addr mask, int bang, int ssh) 747 { 748 struct rtmsg rtmes; 749 int s, nb, wb; 750 char *cp; 751 const char *cmdstr; 752 struct sockaddr_in rtdata; 753 int result = 1; 754 755 if (bang) 756 cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 757 else 758 cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 759 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 760 if (s < 0) { 761 log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 762 return result; 763 } 764 memset(&rtmes, '\0', sizeof rtmes); 765 rtmes.m_rtm.rtm_version = RTM_VERSION; 766 rtmes.m_rtm.rtm_type = cmd; 767 rtmes.m_rtm.rtm_addrs = RTA_DST; 768 rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 769 rtmes.m_rtm.rtm_pid = getpid(); 770 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 771 772 if (cmd == RTM_ADD) { 773 if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 774 rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 775 rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 776 } 777 if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 778 rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 779 rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 780 } 781 } 782 783 memset(&rtdata, '\0', sizeof rtdata); 784 rtdata.sin_len = sizeof rtdata; 785 rtdata.sin_family = AF_INET; 786 rtdata.sin_port = 0; 787 rtdata.sin_addr = dst; 788 789 cp = rtmes.m_space; 790 memcpy(cp, &rtdata, rtdata.sin_len); 791 cp += rtdata.sin_len; 792 if (cmd == RTM_ADD) { 793 if (gateway.s_addr == INADDR_ANY) { 794 if (!ssh) 795 log_Printf(LogERROR, "rt_Set: Cannot add a route with" 796 " destination 0.0.0.0\n"); 797 close(s); 798 return result; 799 } else { 800 rtdata.sin_addr = gateway; 801 memcpy(cp, &rtdata, rtdata.sin_len); 802 cp += rtdata.sin_len; 803 rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 804 } 805 } 806 807 if (dst.s_addr == INADDR_ANY) 808 mask.s_addr = INADDR_ANY; 809 810 if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 811 rtdata.sin_addr = mask; 812 memcpy(cp, &rtdata, rtdata.sin_len); 813 cp += rtdata.sin_len; 814 rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 815 } 816 817 nb = cp - (char *)&rtmes; 818 rtmes.m_rtm.rtm_msglen = nb; 819 wb = ID0write(s, &rtmes, nb); 820 if (wb < 0) { 821 log_Printf(LogTCPIP, "rt_Set failure:\n"); 822 log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 823 log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", inet_ntoa(dst)); 824 log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", 825 inet_ntoa(gateway)); 826 log_Printf(LogTCPIP, "rt_Set: Mask = %s\n", inet_ntoa(mask)); 827 failed: 828 if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 829 (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 830 if (!bang) { 831 log_Printf(LogWARN, "Add route failed: %s already exists\n", 832 dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 833 result = 0; /* Don't add to our dynamic list */ 834 } else { 835 rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 836 if ((wb = ID0write(s, &rtmes, nb)) < 0) 837 goto failed; 838 } 839 } else if (cmd == RTM_DELETE && 840 (rtmes.m_rtm.rtm_errno == ESRCH || 841 (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 842 if (!bang) 843 log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 844 inet_ntoa(dst)); 845 } else if (rtmes.m_rtm.rtm_errno == 0) { 846 if (!ssh || errno != ENETUNREACH) 847 log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 848 inet_ntoa(dst), strerror(errno)); 849 } else 850 log_Printf(LogWARN, "%s route failed: %s: %s\n", 851 cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 852 } 853 854 log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 855 wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 856 close(s); 857 858 return result; 859 } 860 861 void 862 rt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw) 863 { 864 struct rtmsg rtmes; 865 int s, wb; 866 struct sockaddr_in rtdata; 867 868 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 869 if (s < 0) { 870 log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 871 return; 872 } 873 874 memset(&rtmes, '\0', sizeof rtmes); 875 rtmes.m_rtm.rtm_version = RTM_VERSION; 876 rtmes.m_rtm.rtm_type = RTM_CHANGE; 877 rtmes.m_rtm.rtm_addrs = RTA_DST; 878 rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 879 rtmes.m_rtm.rtm_pid = getpid(); 880 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 881 882 if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 883 rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 884 rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 885 } 886 887 if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 888 rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 889 rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 890 } 891 892 rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 893 rtmes.m_rtm.rtm_inits |= RTV_MTU; 894 895 memset(&rtdata, '\0', sizeof rtdata); 896 rtdata.sin_len = sizeof rtdata; 897 rtdata.sin_family = AF_INET; 898 rtdata.sin_port = 0; 899 rtdata.sin_addr = dst; 900 901 memcpy(rtmes.m_space, &rtdata, rtdata.sin_len); 902 rtmes.m_rtm.rtm_msglen = rtmes.m_space + rtdata.sin_len - (char *)&rtmes; 903 904 wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 905 if (wb < 0) { 906 log_Printf(LogTCPIP, "rt_Update failure:\n"); 907 log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", inet_ntoa(dst)); 908 log_Printf(LogTCPIP, "rt_Update: Gateway = %s\n", inet_ntoa(gw)); 909 910 if (rtmes.m_rtm.rtm_errno == 0) 911 log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 912 inet_ntoa(dst), strerror(errno)); 913 else 914 log_Printf(LogWARN, "%s: Change route failed: %s\n", 915 inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 916 } 917 log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %x, gateway = %x\n", 918 wb, (unsigned)dst.s_addr, (unsigned)gw.s_addr); 919 close(s); 920 } 921