route.c revision 31541
1/* 2 * PPP Routing related Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: route.c,v 1.28 1997/11/22 13:46:02 brian Exp $ 21 * 22 */ 23 24#include <sys/param.h> 25#include <sys/time.h> 26#include <sys/socket.h> 27#include <net/if_types.h> 28#include <net/route.h> 29#include <net/if.h> 30#include <netinet/in_systm.h> 31#include <netinet/in.h> 32#include <arpa/inet.h> 33#include <net/if_dl.h> 34 35#include <errno.h> 36#include <machine/endian.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <sys/ioctl.h> 41#include <sys/sysctl.h> 42#include <unistd.h> 43 44#include "command.h" 45#include "mbuf.h" 46#include "log.h" 47#include "loadalias.h" 48#include "defs.h" 49#include "vars.h" 50#include "id.h" 51#include "route.h" 52 53static int IfIndex; 54 55struct rtmsg { 56 struct rt_msghdr m_rtm; 57 char m_space[64]; 58}; 59 60static int seqno; 61 62void 63OsSetRoute(int cmd, 64 struct in_addr dst, 65 struct in_addr gateway, 66 struct in_addr mask) 67{ 68 struct rtmsg rtmes; 69 int s, nb, wb; 70 char *cp; 71 const char *cmdstr; 72 u_long *lp; 73 struct sockaddr_in rtdata; 74 75 cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 77 if (s < 0) { 78 LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 79 return; 80 } 81 memset(&rtmes, '\0', sizeof(rtmes)); 82 rtmes.m_rtm.rtm_version = RTM_VERSION; 83 rtmes.m_rtm.rtm_type = cmd; 84 rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 85 rtmes.m_rtm.rtm_seq = ++seqno; 86 rtmes.m_rtm.rtm_pid = getpid(); 87 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 88 89 memset(&rtdata, '\0', sizeof(rtdata)); 90 rtdata.sin_len = 16; 91 rtdata.sin_family = AF_INET; 92 rtdata.sin_port = 0; 93 rtdata.sin_addr = dst; 94 95 cp = rtmes.m_space; 96 memcpy(cp, &rtdata, 16); 97 cp += 16; 98 if (gateway.s_addr) { 99 rtdata.sin_addr = gateway; 100 memcpy(cp, &rtdata, 16); 101 cp += 16; 102 rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 103 } 104 if (dst.s_addr == INADDR_ANY) 105 mask.s_addr = INADDR_ANY; 106 107 lp = (u_long *) cp; 108 109 if (mask.s_addr) { 110 *lp++ = 8; 111 cp += sizeof(int); 112 *lp = mask.s_addr; 113 } else 114 *lp = 0; 115 cp += sizeof(u_long); 116 117 nb = cp - (char *) &rtmes; 118 rtmes.m_rtm.rtm_msglen = nb; 119 wb = write(s, &rtmes, nb); 120 if (wb < 0) { 121 LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 122 LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 123 LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 124 switch (rtmes.m_rtm.rtm_errno) { 125 case EEXIST: 126 LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 127 break; 128 case ESRCH: 129 LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 130 break; 131 case 0: 132 LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); 133 break; 134 case ENOBUFS: 135 default: 136 LogPrintf(LogTCPIP, "%s route failed: %s\n", 137 cmdstr, strerror(rtmes.m_rtm.rtm_errno)); 138 break; 139 } 140 } 141 LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 142 wb, cmdstr, dst.s_addr, gateway.s_addr); 143 close(s); 144} 145 146static void 147p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) 148{ 149 char buf[29]; 150 struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 151 struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 152 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 153 154 switch (phost->sa_family) { 155 case AF_INET: 156 if (!phost) 157 buf[0] = '\0'; 158 else if (ihost->sin_addr.s_addr == INADDR_ANY) 159 strcpy(buf, "default"); 160 else if (!mask) 161 strcpy(buf, inet_ntoa(ihost->sin_addr)); 162 else { 163 u_int msk = ntohl(mask->sin_addr.s_addr); 164 u_int tst; 165 int bits; 166 int len; 167 struct sockaddr_in net; 168 169 for (tst = 1, bits=32; tst; tst <<= 1, bits--) 170 if (msk & tst) 171 break; 172 173 for (tst <<=1; tst; tst <<= 1) 174 if (!(msk & tst)) 175 break; 176 177 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 178 sprintf(buf, "%s", inet_ntoa(net.sin_addr)); 179 for (len = strlen(buf); len > 3; buf[len-=2] = '\0') 180 if (strcmp(buf+len-2, ".0")) 181 break; 182 183 if (tst) /* non-contiguous :-( */ 184 sprintf(buf+strlen(buf),"&0x%08x", msk); 185 else 186 sprintf(buf+strlen(buf), "/%d", bits); 187 } 188 break; 189 190 case AF_LINK: 191 if (dl->sdl_nlen) 192 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 193 else if (dl->sdl_alen) 194 if (dl->sdl_type == IFT_ETHER) 195 if (dl->sdl_alen < sizeof(buf)/3) { 196 int f; 197 u_char *MAC; 198 199 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 200 for (f = 0; f < dl->sdl_alen; f++) 201 sprintf(buf+f*3, "%02x:", MAC[f]); 202 buf[f*3-1] = '\0'; 203 } else 204 sprintf(buf, "??:??:??:??:??:??"); 205 else 206 sprintf(buf, "<IFT type %d>", dl->sdl_type); 207 else if (dl->sdl_slen) 208 sprintf(buf, "<slen %d?>", dl->sdl_slen); 209 else 210 sprintf(buf, "link#%d", dl->sdl_index); 211 break; 212 213 default: 214 sprintf(buf, "<AF type %d>", phost->sa_family); 215 break; 216 } 217 218 fprintf(VarTerm, "%-*s ", width-1, buf); 219} 220 221struct bits { 222 u_long b_mask; 223 char b_val; 224} bits[] = { 225 226 { RTF_UP, 'U' }, 227 { RTF_GATEWAY, 'G' }, 228 { RTF_HOST, 'H' }, 229 { RTF_REJECT, 'R' }, 230 { RTF_DYNAMIC, 'D' }, 231 { RTF_MODIFIED, 'M' }, 232 { RTF_DONE, 'd' }, 233 { RTF_CLONING, 'C' }, 234 { RTF_XRESOLVE, 'X' }, 235 { RTF_LLINFO, 'L' }, 236 { RTF_STATIC, 'S' }, 237 { RTF_PROTO1, '1' }, 238 { RTF_PROTO2, '2' }, 239 { RTF_BLACKHOLE, 'B' }, 240#ifdef __FreeBSD__ 241 { RTF_WASCLONED, 'W' }, 242 { RTF_PRCLONING, 'c' }, 243 { RTF_PROTO3, '3' }, 244 { RTF_BROADCAST, 'b' }, 245#endif 246 { 0, '\0' } 247}; 248 249static void 250p_flags(u_long f, const char *format) 251{ 252 if (VarTerm) { 253 char name[33], *flags; 254 register struct bits *p = bits; 255 256 for (flags = name; p->b_mask; p++) 257 if (p->b_mask & f) 258 *flags++ = p->b_val; 259 *flags = '\0'; 260 fprintf(VarTerm, format, name); 261 } 262} 263 264static const char * 265Index2Nam(int idx) 266{ 267 static char ifs[50][6]; 268 static int nifs, debug_done; 269 270 if (!nifs) { 271 int mib[6], needed, len; 272 char *buf, *ptr, *end; 273 struct sockaddr_dl *dl; 274 struct if_msghdr *ifm; 275 276 mib[0] = CTL_NET; 277 mib[1] = PF_ROUTE; 278 mib[2] = 0; 279 mib[3] = 0; 280 mib[4] = NET_RT_IFLIST; 281 mib[5] = 0; 282 283 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 284 LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); 285 return "???"; 286 } 287 if ((buf = malloc(needed)) == NULL) 288 return "???"; 289 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 290 free(buf); 291 return "???"; 292 } 293 end = buf + needed; 294 295 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 296 ifm = (struct if_msghdr *)ptr; 297 dl = (struct sockaddr_dl *)(ifm + 1); 298 if (ifm->ifm_index > 0 && ifm->ifm_index <= sizeof(ifs)/sizeof(ifs[0]) 299 && ifs[ifm->ifm_index-1][0] == '\0') { 300 if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1) 301 len = sizeof(ifs[0])-1; 302 strncpy(ifs[ifm->ifm_index-1], dl->sdl_data, len); 303 ifs[ifm->ifm_index-1][len] = '\0'; 304 if (len && nifs < ifm->ifm_index) 305 nifs = ifm->ifm_index; 306 } else if (LogIsKept(LogDEBUG)) 307 LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n", 308 ifm->ifm_index); 309 } 310 free(buf); 311 } 312 313 if (LogIsKept(LogDEBUG) && !debug_done) { 314 int f; 315 316 LogPrintf(LogDEBUG, "Found the following interfaces:\n"); 317 for (f = 0; f < nifs; f++) 318 if (*ifs[f] != '\0') 319 LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 320 debug_done = 1; 321 } 322 323 if (idx < 1 || idx > nifs || ifs[idx-1][0] == '\0') 324 return "???"; 325 326 return ifs[idx-1]; 327} 328 329int 330ShowRoute(struct cmdargs const *arg) 331{ 332 struct rt_msghdr *rtm; 333 struct sockaddr *sa_dst, *sa_gw, *sa_mask; 334 char *sp, *ep, *cp, *wp; 335 int needed; 336 int mib[6]; 337 338 if (!VarTerm) 339 return 1; 340 341 mib[0] = CTL_NET; 342 mib[1] = PF_ROUTE; 343 mib[2] = 0; 344 mib[3] = 0; 345 mib[4] = NET_RT_DUMP; 346 mib[5] = 0; 347 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 348 LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 349 return (1); 350 } 351 if (needed < 0) 352 return (1); 353 sp = malloc(needed); 354 if (sp == NULL) 355 return (1); 356 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 357 LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 358 free(sp); 359 return (1); 360 } 361 ep = sp + needed; 362 363 fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); 364 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 365 rtm = (struct rt_msghdr *) cp; 366 wp = (char *)(rtm+1); 367 368 if (rtm->rtm_addrs & RTA_DST) { 369 sa_dst = (struct sockaddr *)wp; 370 wp += sa_dst->sa_len; 371 } else 372 sa_dst = NULL; 373 374 if (rtm->rtm_addrs & RTA_GATEWAY) { 375 sa_gw = (struct sockaddr *)wp; 376 wp += sa_gw->sa_len; 377 } else 378 sa_gw = NULL; 379 380 if (rtm->rtm_addrs & RTA_NETMASK) { 381 sa_mask = (struct sockaddr *)wp; 382 wp += sa_mask->sa_len; 383 } else 384 sa_mask = NULL; 385 386 p_sockaddr(sa_dst, sa_mask, 20); 387 p_sockaddr(sa_gw, NULL, 20); 388 389 p_flags(rtm->rtm_flags, "%-6.6s "); 390 fprintf(VarTerm, "%s\n", Index2Nam(rtm->rtm_index)); 391 } 392 free(sp); 393 return 0; 394} 395 396/* 397 * Delete routes associated with our interface 398 */ 399void 400DeleteIfRoutes(int all) 401{ 402 struct rt_msghdr *rtm; 403 struct sockaddr *sa; 404 struct in_addr sa_dst, sa_gw, sa_mask; 405 int needed; 406 char *sp, *cp, *ep; 407 u_char *wp; 408 int mib[6]; 409 410 LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 411 412 mib[0] = CTL_NET; 413 mib[1] = PF_ROUTE; 414 mib[2] = 0; 415 mib[3] = 0; 416 mib[4] = NET_RT_DUMP; 417 mib[5] = 0; 418 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 419 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 420 strerror(errno)); 421 return; 422 } 423 if (needed < 0) 424 return; 425 426 sp = malloc(needed); 427 if (sp == NULL) 428 return; 429 430 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 431 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 432 strerror(errno)); 433 free(sp); 434 return; 435 } 436 ep = sp + needed; 437 438 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 439 rtm = (struct rt_msghdr *) cp; 440 sa = (struct sockaddr *) (rtm + 1); 441 LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s), flags: %x," 442 " dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 443 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 444 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 445 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 446 rtm->rtm_index == IfIndex && 447 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 448 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 449 wp = (u_char *) cp + rtm->rtm_msglen; 450 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 451 if (sa->sa_family == AF_INET) { 452 LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 453 sa_gw.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 454 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 455 if (rtm->rtm_addrs & RTA_NETMASK) 456 sa_mask.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 457 else 458 sa_mask.s_addr = 0xffffffff; 459 if (sa_dst.s_addr == INADDR_ANY) 460 sa_mask.s_addr = INADDR_ANY; 461 LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(sa_dst)); 462 LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(sa_gw)); 463 LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 464 OsSetRoute(RTM_DELETE, sa_dst, sa_gw, sa_mask); 465 } else 466 LogPrintf(LogDEBUG, "DeleteIfRoutes: Can't remove an AF_LINK !\n"); 467 } 468 } 469 free(sp); 470} 471 472int 473GetIfIndex(char *name) 474{ 475 int idx; 476 const char *got; 477 478 idx = 1; 479 while (strcmp(got = Index2Nam(idx), "???")) 480 if (!strcmp(got, name)) 481 return IfIndex = idx; 482 else 483 idx++; 484 return -1; 485} 486