route.c revision 31176
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.25 1997/11/11 22:58:13 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 "mbuf.h" 45#include "log.h" 46#include "loadalias.h" 47#include "command.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, *cmdstr; 71 u_long *lp; 72 struct sockaddr_in rtdata; 73 74 cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 75 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 76 if (s < 0) { 77 LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 78 return; 79 } 80 memset(&rtmes, '\0', sizeof(rtmes)); 81 rtmes.m_rtm.rtm_version = RTM_VERSION; 82 rtmes.m_rtm.rtm_type = cmd; 83 rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 84 rtmes.m_rtm.rtm_seq = ++seqno; 85 rtmes.m_rtm.rtm_pid = getpid(); 86 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 87 88 memset(&rtdata, '\0', sizeof(rtdata)); 89 rtdata.sin_len = 16; 90 rtdata.sin_family = AF_INET; 91 rtdata.sin_port = 0; 92 rtdata.sin_addr = dst; 93 94 cp = rtmes.m_space; 95 memcpy(cp, &rtdata, 16); 96 cp += 16; 97 if (gateway.s_addr) { 98 rtdata.sin_addr = gateway; 99 memcpy(cp, &rtdata, 16); 100 cp += 16; 101 rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 102 } 103 if (dst.s_addr == INADDR_ANY) 104 mask.s_addr = INADDR_ANY; 105 106 lp = (u_long *) cp; 107 108 if (mask.s_addr) { 109 *lp++ = 8; 110 cp += sizeof(int); 111 *lp = mask.s_addr; 112 } else 113 *lp = 0; 114 cp += sizeof(u_long); 115 116 nb = cp - (char *) &rtmes; 117 rtmes.m_rtm.rtm_msglen = nb; 118 wb = write(s, &rtmes, nb); 119 if (wb < 0) { 120 LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 121 LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 122 LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 123 switch (rtmes.m_rtm.rtm_errno) { 124 case EEXIST: 125 LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 126 break; 127 case ESRCH: 128 LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 129 break; 130 case 0: 131 LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); 132 break; 133 case ENOBUFS: 134 default: 135 LogPrintf(LogTCPIP, "%s route failed: %s\n", 136 cmdstr, strerror(rtmes.m_rtm.rtm_errno)); 137 break; 138 } 139 } 140 LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 141 wb, cmdstr, dst.s_addr, gateway.s_addr); 142 close(s); 143} 144 145static void 146p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) 147{ 148 char buf[29], *cp; 149 struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 150 struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 151 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 152 153 switch (phost->sa_family) { 154 case AF_INET: 155 if (!phost) 156 cp = ""; 157 else if (ihost->sin_addr.s_addr == INADDR_ANY) 158 cp = "default"; 159 else if (!mask) 160 cp = inet_ntoa(ihost->sin_addr); 161 else { 162 u_int msk = ntohl(mask->sin_addr.s_addr); 163 u_int tst; 164 int bits; 165 int len; 166 struct sockaddr_in net; 167 168 for (tst = 1, bits=32; tst; tst <<= 1, bits--) 169 if (msk & tst) 170 break; 171 172 for (tst <<=1; tst; tst <<= 1) 173 if (!(msk & tst)) 174 break; 175 176 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 177 sprintf(buf, "%s", inet_ntoa(net.sin_addr)); 178 for (len = strlen(buf); len > 3; buf[len-=2] = '\0') 179 if (strcmp(buf+len-2, ".0")) 180 break; 181 182 if (tst) /* non-contiguous :-( */ 183 sprintf(buf+strlen(buf),"&0x%08x", msk); 184 else 185 sprintf(buf+strlen(buf), "/%d", bits); 186 cp = buf; 187 } 188 break; 189 190 case AF_LINK: 191 if (!dl) 192 cp = ""; 193 else if (dl->sdl_nlen == 0 && dl->sdl_alen == 0 && dl->sdl_slen == 0) { 194 sprintf(buf, "link#%d", dl->sdl_index); 195 cp = buf; 196 } else if (dl->sdl_type == IFT_ETHER && dl->sdl_alen && 197 dl->sdl_alen < sizeof(buf)/3) { 198 int f; 199 u_char *MAC; 200 201 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 202 for (f = 0; f < dl->sdl_alen; f++) 203 sprintf(buf+f*3, "%02x:", MAC[f]); 204 buf[f*3-1] = '\0'; 205 cp = buf; 206 } else 207 cp = "???"; 208 break; 209 210 default: 211 cp = "???"; 212 break; 213 } 214 215 fprintf(VarTerm, "%-*s ", width-1, cp); 216} 217 218struct bits { 219 u_long b_mask; 220 char b_val; 221} bits[] = { 222 223 { RTF_UP, 'U' }, 224 { RTF_GATEWAY, 'G' }, 225 { RTF_HOST, 'H' }, 226 { RTF_REJECT, 'R' }, 227 { RTF_DYNAMIC, 'D' }, 228 { RTF_MODIFIED, 'M' }, 229 { RTF_DONE, 'd' }, 230 { RTF_CLONING, 'C' }, 231 { RTF_XRESOLVE, 'X' }, 232 { RTF_LLINFO, 'L' }, 233 { RTF_STATIC, 'S' }, 234 { RTF_PROTO1, '1' }, 235 { RTF_PROTO2, '2' }, 236 { RTF_BLACKHOLE, 'B' }, 237#ifdef __FreeBSD__ 238 { RTF_WASCLONED, 'W' }, 239 { RTF_PRCLONING, 'c' }, 240 { RTF_PROTO3, '3' }, 241 { RTF_BROADCAST, 'b' }, 242#endif 243 { 0, '\0' } 244}; 245 246static void 247p_flags(u_long f, char *format) 248{ 249 if (VarTerm) { 250 char name[33], *flags; 251 register struct bits *p = bits; 252 253 for (flags = name; p->b_mask; p++) 254 if (p->b_mask & f) 255 *flags++ = p->b_val; 256 *flags = '\0'; 257 fprintf(VarTerm, format, name); 258 } 259} 260 261static char * 262Index2Nam(int idx) 263{ 264 static char ifs[50][6]; 265 static int nifs; 266 267 if (!nifs) { 268 int mib[6], needed, len; 269 char *buf, *ptr, *end; 270 struct if_msghdr *n; 271 struct sockaddr_dl *dl; 272 struct if_msghdr *ifm; 273 274 mib[0] = CTL_NET; 275 mib[1] = PF_ROUTE; 276 mib[2] = 0; 277 mib[3] = 0; 278 mib[4] = NET_RT_IFLIST; 279 mib[5] = 0; 280 281 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 282 LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); 283 return "???"; 284 } 285 if ((buf = malloc(needed)) == NULL) 286 return "???"; 287 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 288 free(buf); 289 return "???"; 290 } 291 end = buf + needed; 292 293 ptr = buf; 294 while (ptr < end) { 295 ifm = (struct if_msghdr *)ptr; 296 297 if (ifm->ifm_type != RTM_IFINFO) { 298 free(buf); 299 return "???"; 300 } 301 dl = (struct sockaddr_dl *)(ifm + 1); 302 ptr += ifm->ifm_msglen; 303 while (ptr < end) { 304 n = (struct if_msghdr *)ptr; 305 if (n->ifm_type != RTM_NEWADDR) 306 break; 307 ptr += n->ifm_msglen; 308 } 309 if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1) 310 len = sizeof(ifs[0])-1; 311 strncpy(ifs[nifs], dl->sdl_data, len); 312 ifs[nifs++][len] = '\0'; 313 if (nifs == sizeof(ifs)/sizeof(ifs[0])) 314 break; 315 } 316 free(buf); 317 } 318 319#ifdef __FreeBSD__ 320 idx--; /* We start at 1, not 0 */ 321#endif 322 if (idx < 0 || idx >= nifs) 323 return "???"; 324 return ifs[idx]; 325} 326 327int 328ShowRoute() 329{ 330 struct rt_msghdr *rtm; 331 struct sockaddr *sa_dst, *sa_gw, *sa_mask; 332 char *sp, *ep, *cp, *wp; 333 int needed; 334 int mib[6]; 335 336 if (!VarTerm) 337 return 1; 338 339 mib[0] = CTL_NET; 340 mib[1] = PF_ROUTE; 341 mib[2] = 0; 342 mib[3] = 0; 343 mib[4] = NET_RT_DUMP; 344 mib[5] = 0; 345 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 346 LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 347 return (1); 348 } 349 if (needed < 0) 350 return (1); 351 sp = malloc(needed); 352 if (sp == NULL) 353 return (1); 354 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 355 LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 356 free(sp); 357 return (1); 358 } 359 ep = sp + needed; 360 361 fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); 362 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 363 rtm = (struct rt_msghdr *) cp; 364 wp = (char *)(rtm+1); 365 366 if (rtm->rtm_addrs & RTA_DST) { 367 sa_dst = (struct sockaddr *)wp; 368 wp += sa_dst->sa_len; 369 } else 370 sa_dst = NULL; 371 372 if (rtm->rtm_addrs & RTA_GATEWAY) { 373 sa_gw = (struct sockaddr *)wp; 374 wp += sa_gw->sa_len; 375 } else 376 sa_gw = NULL; 377 378 if (rtm->rtm_addrs & RTA_NETMASK) { 379 sa_mask = (struct sockaddr *)wp; 380 wp += sa_mask->sa_len; 381 } else 382 sa_mask = NULL; 383 384 p_sockaddr(sa_dst, sa_mask, 20); 385 p_sockaddr(sa_gw, NULL, 20); 386 387 p_flags(rtm->rtm_flags, "%-6.6s "); 388 fprintf(VarTerm, "%s\n", Index2Nam(rtm->rtm_index)); 389 } 390 free(sp); 391 return 0; 392} 393 394/* 395 * Delete routes associated with our interface 396 */ 397void 398DeleteIfRoutes(int all) 399{ 400 struct rt_msghdr *rtm; 401 struct sockaddr *sa; 402 struct in_addr sa_dst, sa_gw, sa_mask; 403 int needed; 404 char *sp, *cp, *ep; 405 u_char *wp; 406 int mib[6]; 407 408 LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 409 410 mib[0] = CTL_NET; 411 mib[1] = PF_ROUTE; 412 mib[2] = 0; 413 mib[3] = 0; 414 mib[4] = NET_RT_DUMP; 415 mib[5] = 0; 416 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 417 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 418 strerror(errno)); 419 return; 420 } 421 if (needed < 0) 422 return; 423 424 sp = malloc(needed); 425 if (sp == NULL) 426 return; 427 428 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 429 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 430 strerror(errno)); 431 free(sp); 432 return; 433 } 434 ep = sp + needed; 435 436 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 437 rtm = (struct rt_msghdr *) cp; 438 sa = (struct sockaddr *) (rtm + 1); 439 LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s), flags: %x," 440 " dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 441 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 442 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 443 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 444 rtm->rtm_index == IfIndex && 445 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 446 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 447 wp = (u_char *) cp + rtm->rtm_msglen; 448 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 449 if (sa->sa_family == AF_INET) { 450 LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 451 sa_gw.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 452 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 453 if (rtm->rtm_addrs & RTA_NETMASK) 454 sa_mask.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 455 else 456 sa_mask.s_addr = 0xffffffff; 457 if (sa_dst.s_addr == INADDR_ANY) 458 sa_mask.s_addr = INADDR_ANY; 459 LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(sa_dst)); 460 LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(sa_gw)); 461 LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 462 OsSetRoute(RTM_DELETE, sa_dst, sa_gw, sa_mask); 463 } else 464 LogPrintf(LogDEBUG, "DeleteIfRoutes: Can't remove an AF_LINK !\n"); 465 } 466 } 467 free(sp); 468} 469 470int 471GetIfIndex(char *name) 472{ 473 int idx; 474 char *got; 475 476#ifdef __FreeBSD__ 477 idx = 1; /* We start at 1, not 0 */ 478#else 479 idx = 0; 480#endif 481 482 while (strcmp(got = Index2Nam(idx), "???")) 483 if (!strcmp(got, name)) 484 return IfIndex = idx; 485 else 486 idx++; 487 return -1; 488} 489