route.c revision 75212
1139749Simp/* 2116258Sharti * PPP Routing related Module 3116258Sharti * 4116258Sharti * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5116258Sharti * 6116258Sharti * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7116258Sharti * 8116258Sharti * Redistribution and use in source and binary forms are permitted 9116258Sharti * provided that the above copyright notice and this paragraph are 10116258Sharti * duplicated in all such forms and that any documentation, 11116258Sharti * advertising materials, and other materials related to such 12116258Sharti * distribution and use acknowledge that the software was developed 13116258Sharti * by the Internet Initiative Japan, Inc. The name of the 14116258Sharti * IIJ may not be used to endorse or promote products derived 15116258Sharti * from this software without specific prior written permission. 16116258Sharti * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17116258Sharti * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18116258Sharti * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19116258Sharti * 20116258Sharti * $FreeBSD: head/usr.sbin/ppp/route.c 75212 2001-04-05 02:23:48Z brian $ 21116258Sharti * 22116258Sharti */ 23116258Sharti 24116258Sharti#include <sys/param.h> 25116258Sharti#include <sys/socket.h> 26116258Sharti#include <net/if_types.h> 27116258Sharti#include <net/route.h> 28116258Sharti#include <net/if.h> 29116258Sharti#include <netinet/in.h> 30116258Sharti#include <arpa/inet.h> 31116258Sharti#include <net/if_dl.h> 32116258Sharti#include <netinet/in_systm.h> 33116258Sharti#include <netinet/ip.h> 34116258Sharti#include <sys/un.h> 35116258Sharti#include <netdb.h> 36116258Sharti 37116258Sharti#include <errno.h> 38116258Sharti#include <stdio.h> 39116258Sharti#include <stdlib.h> 40116258Sharti#include <string.h> 41116258Sharti#include <sys/sysctl.h> 42116258Sharti#include <termios.h> 43116258Sharti#include <unistd.h> 44116258Sharti 45116258Sharti#include "layer.h" 46116258Sharti#include "defs.h" 47116258Sharti#include "command.h" 48116258Sharti#include "mbuf.h" 49116258Sharti#include "log.h" 50116258Sharti#include "iplist.h" 51116258Sharti#include "timer.h" 52116258Sharti#include "throughput.h" 53142384Sharti#include "lqr.h" 54116258Sharti#include "hdlc.h" 55116258Sharti#include "fsm.h" 56142384Sharti#include "lcp.h" 57116258Sharti#include "ccp.h" 58116258Sharti#include "link.h" 59116258Sharti#include "slcompress.h" 60116258Sharti#include "ipcp.h" 61116258Sharti#include "filter.h" 62116258Sharti#include "descriptor.h" 63116258Sharti#include "mp.h" 64116258Sharti#ifndef NORADIUS 65116258Sharti#include "radius.h" 66116258Sharti#endif 67116258Sharti#include "bundle.h" 68116258Sharti#include "route.h" 69116258Sharti#include "prompt.h" 70116258Sharti#include "iface.h" 71116258Sharti#include "id.h" 72116258Sharti 73116258Sharti 74116258Shartistatic void 75116258Shartip_sockaddr(struct prompt *prompt, struct sockaddr *phost, 76116258Sharti struct sockaddr *pmask, int width) 77116258Sharti{ 78116258Sharti char buf[29]; 79116258Sharti struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 80116258Sharti struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 81116258Sharti struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 82116258Sharti 83116258Sharti if (log_IsKept(LogDEBUG)) { 84116258Sharti char tmp[50]; 85116258Sharti 86116258Sharti log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 87116258Sharti log_Printf(LogDEBUG, " Family %d, len %d\n", 88116258Sharti (int)phost->sa_family, (int)phost->sa_len); 89116258Sharti inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 90117546Sharti log_Printf(LogDEBUG, " Addr %s\n", tmp); 91142384Sharti if (pmask) { 92116258Sharti inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 93117552Sharti log_Printf(LogDEBUG, " Mask %s\n", tmp); 94117552Sharti } 95117552Sharti } 96117552Sharti 97117552Sharti switch (phost->sa_family) { 98117552Sharti case AF_INET: 99117552Sharti if (!phost) 100117552Sharti buf[0] = '\0'; 101117552Sharti else if (ihost4->sin_addr.s_addr == INADDR_ANY) 102117552Sharti strcpy(buf, "default"); 103117552Sharti else if (!pmask) 104117552Sharti strcpy(buf, inet_ntoa(ihost4->sin_addr)); 105117552Sharti else { 106117552Sharti u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 107117552Sharti u_int32_t tst; 108117552Sharti int bits; 109117552Sharti int len; 110117552Sharti struct sockaddr_in net; 111117552Sharti 112117552Sharti for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 113116258Sharti if (msk & tst) 114116258Sharti break; 115116258Sharti 116116258Sharti for (tst <<= 1; tst; tst <<= 1) 117116258Sharti if (!(msk & tst)) 118116258Sharti break; 119116258Sharti 120116258Sharti net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 121116258Sharti strcpy(buf, inet_ntoa(net.sin_addr)); 122116258Sharti for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 123116258Sharti if (strcmp(buf + len - 2, ".0")) 124116258Sharti break; 125116258Sharti 126116258Sharti if (tst) /* non-contiguous :-( */ 127116258Sharti sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 128116258Sharti else 129116258Sharti sprintf(buf + strlen(buf), "/%d", bits); 130116258Sharti } 131116258Sharti break; 132116258Sharti 133116258Sharti case AF_LINK: 134116258Sharti if (dl->sdl_nlen) 135116258Sharti snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 136116258Sharti else if (dl->sdl_alen) { 137116258Sharti if (dl->sdl_type == IFT_ETHER) { 138116258Sharti if (dl->sdl_alen < sizeof buf / 3) { 139116258Sharti int f; 140116258Sharti u_char *MAC; 141116258Sharti 142117552Sharti MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 143116258Sharti for (f = 0; f < dl->sdl_alen; f++) 144116258Sharti sprintf(buf+f*3, "%02x:", MAC[f]); 145116258Sharti buf[f*3-1] = '\0'; 146116258Sharti } else 147116258Sharti strcpy(buf, "??:??:??:??:??:??"); 148116258Sharti } else 149116258Sharti sprintf(buf, "<IFT type %d>", dl->sdl_type); 150116258Sharti } else if (dl->sdl_slen) 151116258Sharti sprintf(buf, "<slen %d?>", dl->sdl_slen); 152116258Sharti else 153116258Sharti sprintf(buf, "link#%d", dl->sdl_index); 154116258Sharti break; 155116258Sharti 156116258Sharti#ifndef NOINET6 157116258Sharti case AF_INET6: 158116258Sharti if (!phost) 159116258Sharti buf[0] = '\0'; 160116258Sharti else { 161116258Sharti const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 162116258Sharti struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 163116258Sharti struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 164116258Sharti int masklen, len; 165116258Sharti const u_char *c; 166116258Sharti 167116258Sharti /* XXX: ?????!?!?!!!!! This is horrible ! */ 168116258Sharti if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 169116258Sharti IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 170116258Sharti ihost6->sin6_scope_id = 171116258Sharti ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 172116258Sharti *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 173117552Sharti } 174117552Sharti 175117552Sharti if (mask6) { 176116258Sharti const u_char *p, *end; 177116258Sharti 178116258Sharti p = (const u_char *)&mask6->sin6_addr; 179116258Sharti end = p + 16; 180116258Sharti for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 181116258Sharti masklen += 8; 182116258Sharti 183116258Sharti if (p < end) { 184116258Sharti for (c = masks; c < masks + sizeof masks; c++) 185116258Sharti if (*c == *p) { 186116258Sharti masklen += c - masks; 187116258Sharti break; 188116258Sharti } 189116258Sharti } 190116258Sharti } else 191116258Sharti masklen = 128; 192116258Sharti 193116258Sharti if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 194116258Sharti snprintf(buf, sizeof buf, "default"); 195116258Sharti else { 196116258Sharti getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 197117552Sharti NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 198116258Sharti if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 199116258Sharti snprintf(buf + len, sizeof buf - len, "/%d", masklen); 200116258Sharti } 201116258Sharti } 202116258Sharti break; 203116258Sharti#endif 204 205 default: 206 sprintf(buf, "<AF type %d>", phost->sa_family); 207 break; 208 } 209 210 prompt_Printf(prompt, "%-*s ", width-1, buf); 211} 212 213static struct bits { 214 u_int32_t b_mask; 215 char b_val; 216} bits[] = { 217 { RTF_UP, 'U' }, 218 { RTF_GATEWAY, 'G' }, 219 { RTF_HOST, 'H' }, 220 { RTF_REJECT, 'R' }, 221 { RTF_DYNAMIC, 'D' }, 222 { RTF_MODIFIED, 'M' }, 223 { RTF_DONE, 'd' }, 224 { RTF_CLONING, 'C' }, 225 { RTF_XRESOLVE, 'X' }, 226 { RTF_LLINFO, 'L' }, 227 { RTF_STATIC, 'S' }, 228 { RTF_PROTO1, '1' }, 229 { RTF_PROTO2, '2' }, 230 { RTF_BLACKHOLE, 'B' }, 231#ifdef RTF_WASCLONED 232 { RTF_WASCLONED, 'W' }, 233#endif 234#ifdef RTF_PRCLONING 235 { RTF_PRCLONING, 'c' }, 236#endif 237#ifdef RTF_PROTO3 238 { RTF_PROTO3, '3' }, 239#endif 240#ifdef RTF_BROADCAST 241 { RTF_BROADCAST, 'b' }, 242#endif 243 { 0, '\0' } 244}; 245 246#ifndef RTF_WASCLONED 247#define RTF_WASCLONED (0) 248#endif 249 250static void 251p_flags(struct prompt *prompt, u_int32_t f, int max) 252{ 253 char name[33], *flags; 254 register struct bits *p = bits; 255 256 if (max > sizeof name - 1) 257 max = sizeof name - 1; 258 259 for (flags = name; p->b_mask && flags - name < max; p++) 260 if (p->b_mask & f) 261 *flags++ = p->b_val; 262 *flags = '\0'; 263 prompt_Printf(prompt, "%-*.*s", max, max, name); 264} 265 266const char * 267Index2Nam(int idx) 268{ 269 /* 270 * XXX: Maybe we should select() on the routing socket so that we can 271 * notice interfaces that come & go (PCCARD support). 272 * Or we could even support a signal that resets these so that 273 * the PCCARD insert/remove events can signal ppp. 274 */ 275 static char **ifs; /* Figure these out once */ 276 static int nifs, debug_done; /* Figure out how many once, and debug once */ 277 278 if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 279 int mib[6], have, had; 280 size_t needed; 281 char *buf, *ptr, *end; 282 struct sockaddr_dl *dl; 283 struct if_msghdr *ifm; 284 285 if (ifs) { 286 free(ifs); 287 ifs = NULL; 288 nifs = 0; 289 } 290 debug_done = 0; 291 292 mib[0] = CTL_NET; 293 mib[1] = PF_ROUTE; 294 mib[2] = 0; 295 mib[3] = 0; 296 mib[4] = NET_RT_IFLIST; 297 mib[5] = 0; 298 299 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 300 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 301 strerror(errno)); 302 return NumStr(idx, NULL, 0); 303 } 304 if ((buf = malloc(needed)) == NULL) 305 return NumStr(idx, NULL, 0); 306 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 307 free(buf); 308 return NumStr(idx, NULL, 0); 309 } 310 end = buf + needed; 311 312 have = 0; 313 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 314 ifm = (struct if_msghdr *)ptr; 315 if (ifm->ifm_type != RTM_IFINFO) 316 continue; 317 dl = (struct sockaddr_dl *)(ifm + 1); 318 if (ifm->ifm_index > 0) { 319 if (ifm->ifm_index > have) { 320 char **newifs; 321 322 had = have; 323 have = ifm->ifm_index + 5; 324 if (had) 325 newifs = (char **)realloc(ifs, sizeof(char *) * have); 326 else 327 newifs = (char **)malloc(sizeof(char *) * have); 328 if (!newifs) { 329 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 330 nifs = 0; 331 if (ifs) { 332 free(ifs); 333 ifs = NULL; 334 } 335 free(buf); 336 return NumStr(idx, NULL, 0); 337 } 338 ifs = newifs; 339 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 340 } 341 if (ifs[ifm->ifm_index-1] == NULL) { 342 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 343 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 344 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 345 if (nifs < ifm->ifm_index) 346 nifs = ifm->ifm_index; 347 } 348 } else if (log_IsKept(LogDEBUG)) 349 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 350 ifm->ifm_index); 351 } 352 free(buf); 353 } 354 355 if (log_IsKept(LogDEBUG) && !debug_done) { 356 int f; 357 358 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 359 for (f = 0; f < nifs; f++) 360 if (ifs[f] != NULL) 361 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 362 debug_done = 1; 363 } 364 365 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 366 return NumStr(idx, NULL, 0); 367 368 return ifs[idx-1]; 369} 370 371void 372route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 373{ 374 char *wp; 375 int rtax; 376 377 wp = (char *)(rtm + 1); 378 379 for (rtax = 0; rtax < RTAX_MAX; rtax++) 380 if (rtm->rtm_addrs & (1 << rtax)) { 381 sa[rtax] = (struct sockaddr *)wp; 382 wp += ROUNDUP(sa[rtax]->sa_len); 383 } else 384 sa[rtax] = NULL; 385} 386 387int 388route_Show(struct cmdargs const *arg) 389{ 390 struct rt_msghdr *rtm; 391 struct sockaddr *sa[RTAX_MAX]; 392 char *sp, *ep, *cp; 393 size_t needed; 394 int mib[6]; 395 396 mib[0] = CTL_NET; 397 mib[1] = PF_ROUTE; 398 mib[2] = 0; 399 mib[3] = 0; 400 mib[4] = NET_RT_DUMP; 401 mib[5] = 0; 402 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 403 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 404 return (1); 405 } 406 sp = malloc(needed); 407 if (sp == NULL) 408 return (1); 409 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 410 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 411 free(sp); 412 return (1); 413 } 414 ep = sp + needed; 415 416 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 417 "Destination", "Gateway"); 418 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 419 rtm = (struct rt_msghdr *)cp; 420 421 route_ParseHdr(rtm, sa); 422 423 if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 424 p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 425 p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 426 427 p_flags(arg->prompt, rtm->rtm_flags, 6); 428 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 429 } else 430 prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 431 } 432 free(sp); 433 return 0; 434} 435 436/* 437 * Delete routes associated with our interface 438 */ 439void 440route_IfDelete(struct bundle *bundle, int all) 441{ 442 struct rt_msghdr *rtm; 443 struct sockaddr *sa[RTAX_MAX]; 444 struct sockaddr_in **in; 445 struct in_addr sa_none; 446 int pass; 447 size_t needed; 448 char *sp, *cp, *ep; 449 int mib[6]; 450 451 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 452 sa_none.s_addr = INADDR_ANY; 453 in = (struct sockaddr_in **)sa; 454 455 mib[0] = CTL_NET; 456 mib[1] = PF_ROUTE; 457 mib[2] = 0; 458 mib[3] = 0; 459 mib[4] = NET_RT_DUMP; 460 mib[5] = 0; 461 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 462 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 463 strerror(errno)); 464 return; 465 } 466 467 sp = malloc(needed); 468 if (sp == NULL) 469 return; 470 471 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 472 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 473 strerror(errno)); 474 free(sp); 475 return; 476 } 477 ep = sp + needed; 478 479 for (pass = 0; pass < 2; pass++) { 480 /* 481 * We do 2 passes. The first deletes all cloned routes. The second 482 * deletes all non-cloned routes. This is done to avoid 483 * potential errors from trying to delete route X after route Y where 484 * route X was cloned from route Y (and is no longer there 'cos it 485 * may have gone with route Y). 486 */ 487 if (RTF_WASCLONED == 0 && pass == 0) 488 /* So we can't tell ! */ 489 continue; 490 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 491 rtm = (struct rt_msghdr *)cp; 492 route_ParseHdr(rtm, sa); 493 if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) { 494 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 495 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 496 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 497 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 498 if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 499 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 500 if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 501 sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 502 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 503 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 504 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 505 pass); 506 rt_Set(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 507 sa_none, sa_none, 0, 0); 508 } else 509 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 510 } else 511 log_Printf(LogDEBUG, 512 "route_IfDelete: Can't remove routes of %d family !\n", 513 sa[RTAX_GATEWAY]->sa_family); 514 } 515 } 516 } 517 } 518 free(sp); 519} 520 521 522/* 523 * Update the MTU on all routes for the given interface 524 */ 525void 526route_UpdateMTU(struct bundle *bundle) 527{ 528 struct rt_msghdr *rtm; 529 struct sockaddr *sa[RTAX_MAX]; 530 struct sockaddr_in **in; 531 size_t needed; 532 char *sp, *cp, *ep; 533 int mib[6]; 534 535 log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 536 in = (struct sockaddr_in **)sa; 537 538 mib[0] = CTL_NET; 539 mib[1] = PF_ROUTE; 540 mib[2] = 0; 541 mib[3] = 0; 542 mib[4] = NET_RT_DUMP; 543 mib[5] = 0; 544 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 545 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 546 strerror(errno)); 547 return; 548 } 549 550 sp = malloc(needed); 551 if (sp == NULL) 552 return; 553 554 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 555 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 556 strerror(errno)); 557 free(sp); 558 return; 559 } 560 ep = sp + needed; 561 562 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 563 rtm = (struct rt_msghdr *)cp; 564 route_ParseHdr(rtm, sa); 565 if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET && 566 sa[RTAX_GATEWAY] && /* sa[RTAX_NETMASK] && */ 567 rtm->rtm_index == bundle->iface->index && 568 (sa[RTAX_GATEWAY]->sa_family == AF_INET || 569 sa[RTAX_GATEWAY]->sa_family == AF_LINK)) { 570 log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s, mtu %d\n", 571 rtm->rtm_index, Index2Nam(rtm->rtm_index), 572 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr), 573 bundle->mtu); 574 rt_Update(bundle, in[RTAX_DST]->sin_addr, 575 in[RTAX_GATEWAY]->sin_addr); 576 } 577 } 578 579 free(sp); 580} 581 582int 583GetIfIndex(char *name) 584{ 585 int idx; 586 const char *got; 587 588 idx = 1; 589 while (strcmp(got = Index2Nam(idx), "???")) 590 if (!strcmp(got, name)) 591 return idx; 592 else 593 idx++; 594 return -1; 595} 596 597void 598route_Change(struct bundle *bundle, struct sticky_route *r, 599 struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 600{ 601 struct in_addr none, del; 602 603 none.s_addr = INADDR_ANY; 604 for (; r; r = r->next) { 605 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 606 del.s_addr = r->dst.s_addr & r->mask.s_addr; 607 rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 608 r->dst = me; 609 if (r->type & ROUTE_GWHISADDR) 610 r->gw = peer; 611 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.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 = peer; 615 if (r->type & ROUTE_GWHISADDR) 616 r->gw = peer; 617 } else if ((r->type & ROUTE_DSTDNS0) && 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 = dns[0]; 621 if (r->type & ROUTE_GWHISADDR) 622 r->gw = peer; 623 } else if ((r->type & ROUTE_DSTDNS1) && 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[1]; 627 if (r->type & ROUTE_GWHISADDR) 628 r->gw = peer; 629 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 630 r->gw = peer; 631 rt_Set(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 632 } 633} 634 635void 636route_Add(struct sticky_route **rp, int type, struct in_addr dst, 637 struct in_addr mask, struct in_addr gw) 638{ 639 struct sticky_route *r; 640 int dsttype = type & ROUTE_DSTANY; 641 642 r = NULL; 643 while (*rp) { 644 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 645 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 646 /* Oops, we already have this route - unlink it */ 647 free(r); /* impossible really */ 648 r = *rp; 649 *rp = r->next; 650 } else 651 rp = &(*rp)->next; 652 } 653 654 if (!r) 655 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 656 r->type = type; 657 r->next = NULL; 658 r->dst = dst; 659 r->mask = mask; 660 r->gw = gw; 661 *rp = r; 662} 663 664void 665route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 666{ 667 struct sticky_route *r; 668 int dsttype = type & ROUTE_DSTANY; 669 670 for (; *rp; rp = &(*rp)->next) { 671 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 672 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 673 r = *rp; 674 *rp = r->next; 675 free(r); 676 break; 677 } 678 } 679} 680 681void 682route_DeleteAll(struct sticky_route **rp) 683{ 684 struct sticky_route *r, *rn; 685 686 for (r = *rp; r; r = rn) { 687 rn = r->next; 688 free(r); 689 } 690 *rp = NULL; 691} 692 693void 694route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 695 int indent) 696{ 697 int def; 698 int tlen = strlen(tag); 699 700 if (tlen + 2 > indent) 701 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 702 else 703 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 704 705 for (; r; r = r->next) { 706 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 707 708 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 709 tlen = 0; 710 if (r->type & ROUTE_DSTMYADDR) 711 prompt_Printf(p, "MYADDR"); 712 else if (r->type & ROUTE_DSTHISADDR) 713 prompt_Printf(p, "HISADDR"); 714 else if (r->type & ROUTE_DSTDNS0) 715 prompt_Printf(p, "DNS0"); 716 else if (r->type & ROUTE_DSTDNS1) 717 prompt_Printf(p, "DNS1"); 718 else if (!def) 719 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 720 721 if (def) 722 prompt_Printf(p, "default "); 723 else 724 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 725 726 if (r->type & ROUTE_GWHISADDR) 727 prompt_Printf(p, "HISADDR\n"); 728 else 729 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 730 } 731} 732 733struct rtmsg { 734 struct rt_msghdr m_rtm; 735 char m_space[64]; 736}; 737 738int 739rt_Set(struct bundle *bundle, int cmd, struct in_addr dst, 740 struct in_addr gateway, struct in_addr mask, int bang, int ssh) 741{ 742 struct rtmsg rtmes; 743 int s, nb, wb; 744 char *cp; 745 const char *cmdstr; 746 struct sockaddr_in rtdata; 747 int result = 1; 748 749 if (bang) 750 cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 751 else 752 cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 753 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 754 if (s < 0) { 755 log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 756 return result; 757 } 758 memset(&rtmes, '\0', sizeof rtmes); 759 rtmes.m_rtm.rtm_version = RTM_VERSION; 760 rtmes.m_rtm.rtm_type = cmd; 761 rtmes.m_rtm.rtm_addrs = RTA_DST; 762 rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 763 rtmes.m_rtm.rtm_pid = getpid(); 764 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 765 766 if (cmd == RTM_ADD) { 767 if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 768 rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 769 rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 770 } 771 if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 772 rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 773 rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 774 } 775 } 776 777 memset(&rtdata, '\0', sizeof rtdata); 778 rtdata.sin_len = sizeof rtdata; 779 rtdata.sin_family = AF_INET; 780 rtdata.sin_port = 0; 781 rtdata.sin_addr = dst; 782 783 cp = rtmes.m_space; 784 memcpy(cp, &rtdata, rtdata.sin_len); 785 cp += rtdata.sin_len; 786 if (cmd == RTM_ADD) { 787 if (gateway.s_addr == INADDR_ANY) { 788 if (!ssh) 789 log_Printf(LogERROR, "rt_Set: Cannot add a route with" 790 " destination 0.0.0.0\n"); 791 close(s); 792 return result; 793 } else { 794 rtdata.sin_addr = gateway; 795 memcpy(cp, &rtdata, rtdata.sin_len); 796 cp += rtdata.sin_len; 797 rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 798 } 799 } 800 801 if (dst.s_addr == INADDR_ANY) 802 mask.s_addr = INADDR_ANY; 803 804 if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 805 rtdata.sin_addr = mask; 806 memcpy(cp, &rtdata, rtdata.sin_len); 807 cp += rtdata.sin_len; 808 rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 809 } 810 811 nb = cp - (char *)&rtmes; 812 rtmes.m_rtm.rtm_msglen = nb; 813 wb = ID0write(s, &rtmes, nb); 814 if (wb < 0) { 815 log_Printf(LogTCPIP, "rt_Set failure:\n"); 816 log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 817 log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", inet_ntoa(dst)); 818 log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", 819 inet_ntoa(gateway)); 820 log_Printf(LogTCPIP, "rt_Set: Mask = %s\n", inet_ntoa(mask)); 821failed: 822 if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 823 (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 824 if (!bang) { 825 log_Printf(LogWARN, "Add route failed: %s already exists\n", 826 dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 827 result = 0; /* Don't add to our dynamic list */ 828 } else { 829 rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 830 if ((wb = ID0write(s, &rtmes, nb)) < 0) 831 goto failed; 832 } 833 } else if (cmd == RTM_DELETE && 834 (rtmes.m_rtm.rtm_errno == ESRCH || 835 (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 836 if (!bang) 837 log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 838 inet_ntoa(dst)); 839 } else if (rtmes.m_rtm.rtm_errno == 0) { 840 if (!ssh || errno != ENETUNREACH) 841 log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 842 inet_ntoa(dst), strerror(errno)); 843 } else 844 log_Printf(LogWARN, "%s route failed: %s: %s\n", 845 cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 846 } 847 848 log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 849 wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 850 close(s); 851 852 return result; 853} 854 855void 856rt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw) 857{ 858 struct rtmsg rtmes; 859 int s, wb; 860 struct sockaddr_in rtdata; 861 862 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 863 if (s < 0) { 864 log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 865 return; 866 } 867 868 memset(&rtmes, '\0', sizeof rtmes); 869 rtmes.m_rtm.rtm_version = RTM_VERSION; 870 rtmes.m_rtm.rtm_type = RTM_CHANGE; 871 rtmes.m_rtm.rtm_addrs = RTA_DST; 872 rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 873 rtmes.m_rtm.rtm_pid = getpid(); 874 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 875 876 if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 877 rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 878 rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 879 } 880 881 if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 882 rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 883 rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 884 } 885 886 rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->mtu; 887 rtmes.m_rtm.rtm_inits |= RTV_MTU; 888 889 memset(&rtdata, '\0', sizeof rtdata); 890 rtdata.sin_len = sizeof rtdata; 891 rtdata.sin_family = AF_INET; 892 rtdata.sin_port = 0; 893 rtdata.sin_addr = dst; 894 895 memcpy(rtmes.m_space, &rtdata, rtdata.sin_len); 896 rtmes.m_rtm.rtm_msglen = rtmes.m_space + rtdata.sin_len - (char *)&rtmes; 897 898 wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 899 if (wb < 0) { 900 log_Printf(LogTCPIP, "rt_Update failure:\n"); 901 log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", inet_ntoa(dst)); 902 log_Printf(LogTCPIP, "rt_Update: Gateway = %s\n", inet_ntoa(gw)); 903 904 if (rtmes.m_rtm.rtm_errno == 0) 905 log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 906 inet_ntoa(dst), strerror(errno)); 907 else 908 log_Printf(LogWARN, "%s: Change route failed: %s\n", 909 inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 910 } 911 log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %x, gateway = %x\n", 912 wb, (unsigned)dst.s_addr, (unsigned)gw.s_addr); 913 close(s); 914} 915