route.c revision 31354
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.27 1997/11/22 03:37:44 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 const char *cp; 151 struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 152 struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 153 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 154 155 switch (phost->sa_family) { 156 case AF_INET: 157 if (!phost) 158 cp = ""; 159 else if (ihost->sin_addr.s_addr == INADDR_ANY) 160 cp = "default"; 161 else if (!mask) 162 cp = inet_ntoa(ihost->sin_addr); 163 else { 164 u_int msk = ntohl(mask->sin_addr.s_addr); 165 u_int tst; 166 int bits; 167 int len; 168 struct sockaddr_in net; 169 170 for (tst = 1, bits=32; tst; tst <<= 1, bits--) 171 if (msk & tst) 172 break; 173 174 for (tst <<=1; tst; tst <<= 1) 175 if (!(msk & tst)) 176 break; 177 178 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 179 sprintf(buf, "%s", inet_ntoa(net.sin_addr)); 180 for (len = strlen(buf); len > 3; buf[len-=2] = '\0') 181 if (strcmp(buf+len-2, ".0")) 182 break; 183 184 if (tst) /* non-contiguous :-( */ 185 sprintf(buf+strlen(buf),"&0x%08x", msk); 186 else 187 sprintf(buf+strlen(buf), "/%d", bits); 188 cp = buf; 189 } 190 break; 191 192 case AF_LINK: 193 if (!dl) 194 cp = ""; 195 else if (dl->sdl_nlen == 0 && dl->sdl_alen == 0 && dl->sdl_slen == 0) { 196 sprintf(buf, "link#%d", dl->sdl_index); 197 cp = buf; 198 } else if (dl->sdl_type == IFT_ETHER && dl->sdl_alen && 199 dl->sdl_alen < sizeof(buf)/3) { 200 int f; 201 u_char *MAC; 202 203 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 204 for (f = 0; f < dl->sdl_alen; f++) 205 sprintf(buf+f*3, "%02x:", MAC[f]); 206 buf[f*3-1] = '\0'; 207 cp = buf; 208 } else 209 cp = "???"; 210 break; 211 212 default: 213 cp = "???"; 214 break; 215 } 216 217 fprintf(VarTerm, "%-*s ", width-1, cp); 218} 219 220struct bits { 221 u_long b_mask; 222 char b_val; 223} bits[] = { 224 225 { RTF_UP, 'U' }, 226 { RTF_GATEWAY, 'G' }, 227 { RTF_HOST, 'H' }, 228 { RTF_REJECT, 'R' }, 229 { RTF_DYNAMIC, 'D' }, 230 { RTF_MODIFIED, 'M' }, 231 { RTF_DONE, 'd' }, 232 { RTF_CLONING, 'C' }, 233 { RTF_XRESOLVE, 'X' }, 234 { RTF_LLINFO, 'L' }, 235 { RTF_STATIC, 'S' }, 236 { RTF_PROTO1, '1' }, 237 { RTF_PROTO2, '2' }, 238 { RTF_BLACKHOLE, 'B' }, 239#ifdef __FreeBSD__ 240 { RTF_WASCLONED, 'W' }, 241 { RTF_PRCLONING, 'c' }, 242 { RTF_PROTO3, '3' }, 243 { RTF_BROADCAST, 'b' }, 244#endif 245 { 0, '\0' } 246}; 247 248static void 249p_flags(u_long f, const char *format) 250{ 251 if (VarTerm) { 252 char name[33], *flags; 253 register struct bits *p = bits; 254 255 for (flags = name; p->b_mask; p++) 256 if (p->b_mask & f) 257 *flags++ = p->b_val; 258 *flags = '\0'; 259 fprintf(VarTerm, format, name); 260 } 261} 262 263static const char * 264Index2Nam(int idx) 265{ 266 static char ifs[50][6]; 267 static int nifs, debug_done; 268 269 if (!nifs) { 270 int mib[6], needed, len; 271 char *buf, *ptr, *end; 272 struct sockaddr_dl *dl; 273 struct if_msghdr *ifm; 274 275 mib[0] = CTL_NET; 276 mib[1] = PF_ROUTE; 277 mib[2] = 0; 278 mib[3] = 0; 279 mib[4] = NET_RT_IFLIST; 280 mib[5] = 0; 281 282 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 283 LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); 284 return "???"; 285 } 286 if ((buf = malloc(needed)) == NULL) 287 return "???"; 288 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 289 free(buf); 290 return "???"; 291 } 292 end = buf + needed; 293 294 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 295 ifm = (struct if_msghdr *)ptr; 296 dl = (struct sockaddr_dl *)(ifm + 1); 297 if (ifm->ifm_index > 0 && ifm->ifm_index <= sizeof(ifs)/sizeof(ifs[0]) 298 && ifs[ifm->ifm_index-1][0] == '\0') { 299 if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1) 300 len = sizeof(ifs[0])-1; 301 strncpy(ifs[ifm->ifm_index-1], dl->sdl_data, len); 302 ifs[ifm->ifm_index-1][len] = '\0'; 303 if (len && nifs < ifm->ifm_index) 304 nifs = ifm->ifm_index; 305 } else if (LogIsKept(LogDEBUG)) 306 LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n", 307 ifm->ifm_index); 308 } 309 free(buf); 310 } 311 312 if (LogIsKept(LogDEBUG) && !debug_done) { 313 int f; 314 315 LogPrintf(LogDEBUG, "Found the following interfaces:\n"); 316 for (f = 0; f < nifs; f++) 317 if (*ifs[f] != '\0') 318 LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 319 debug_done = 1; 320 } 321 322 if (idx < 1 || idx > nifs || ifs[idx-1][0] == '\0') 323 return "???"; 324 325 return ifs[idx-1]; 326} 327 328int 329ShowRoute(struct cmdargs const *arg) 330{ 331 struct rt_msghdr *rtm; 332 struct sockaddr *sa_dst, *sa_gw, *sa_mask; 333 char *sp, *ep, *cp, *wp; 334 int needed; 335 int mib[6]; 336 337 if (!VarTerm) 338 return 1; 339 340 mib[0] = CTL_NET; 341 mib[1] = PF_ROUTE; 342 mib[2] = 0; 343 mib[3] = 0; 344 mib[4] = NET_RT_DUMP; 345 mib[5] = 0; 346 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 347 LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 348 return (1); 349 } 350 if (needed < 0) 351 return (1); 352 sp = malloc(needed); 353 if (sp == NULL) 354 return (1); 355 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 356 LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 357 free(sp); 358 return (1); 359 } 360 ep = sp + needed; 361 362 fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); 363 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 364 rtm = (struct rt_msghdr *) cp; 365 wp = (char *)(rtm+1); 366 367 if (rtm->rtm_addrs & RTA_DST) { 368 sa_dst = (struct sockaddr *)wp; 369 wp += sa_dst->sa_len; 370 } else 371 sa_dst = NULL; 372 373 if (rtm->rtm_addrs & RTA_GATEWAY) { 374 sa_gw = (struct sockaddr *)wp; 375 wp += sa_gw->sa_len; 376 } else 377 sa_gw = NULL; 378 379 if (rtm->rtm_addrs & RTA_NETMASK) { 380 sa_mask = (struct sockaddr *)wp; 381 wp += sa_mask->sa_len; 382 } else 383 sa_mask = NULL; 384 385 p_sockaddr(sa_dst, sa_mask, 20); 386 p_sockaddr(sa_gw, NULL, 20); 387 388 p_flags(rtm->rtm_flags, "%-6.6s "); 389 fprintf(VarTerm, "%s\n", Index2Nam(rtm->rtm_index)); 390 } 391 free(sp); 392 return 0; 393} 394 395/* 396 * Delete routes associated with our interface 397 */ 398void 399DeleteIfRoutes(int all) 400{ 401 struct rt_msghdr *rtm; 402 struct sockaddr *sa; 403 struct in_addr sa_dst, sa_gw, sa_mask; 404 int needed; 405 char *sp, *cp, *ep; 406 u_char *wp; 407 int mib[6]; 408 409 LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 410 411 mib[0] = CTL_NET; 412 mib[1] = PF_ROUTE; 413 mib[2] = 0; 414 mib[3] = 0; 415 mib[4] = NET_RT_DUMP; 416 mib[5] = 0; 417 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 418 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 419 strerror(errno)); 420 return; 421 } 422 if (needed < 0) 423 return; 424 425 sp = malloc(needed); 426 if (sp == NULL) 427 return; 428 429 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 430 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 431 strerror(errno)); 432 free(sp); 433 return; 434 } 435 ep = sp + needed; 436 437 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 438 rtm = (struct rt_msghdr *) cp; 439 sa = (struct sockaddr *) (rtm + 1); 440 LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s), flags: %x," 441 " dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 442 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 443 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 444 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 445 rtm->rtm_index == IfIndex && 446 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 447 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 448 wp = (u_char *) cp + rtm->rtm_msglen; 449 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 450 if (sa->sa_family == AF_INET) { 451 LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 452 sa_gw.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 453 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 454 if (rtm->rtm_addrs & RTA_NETMASK) 455 sa_mask.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 456 else 457 sa_mask.s_addr = 0xffffffff; 458 if (sa_dst.s_addr == INADDR_ANY) 459 sa_mask.s_addr = INADDR_ANY; 460 LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(sa_dst)); 461 LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(sa_gw)); 462 LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 463 OsSetRoute(RTM_DELETE, sa_dst, sa_gw, sa_mask); 464 } else 465 LogPrintf(LogDEBUG, "DeleteIfRoutes: Can't remove an AF_LINK !\n"); 466 } 467 } 468 free(sp); 469} 470 471int 472GetIfIndex(char *name) 473{ 474 int idx; 475 const char *got; 476 477 idx = 1; 478 while (strcmp(got = Index2Nam(idx), "???")) 479 if (!strcmp(got, name)) 480 return IfIndex = idx; 481 else 482 idx++; 483 return -1; 484} 485