route.c revision 31343
1258945Sroberto/* 2258945Sroberto * PPP Routing related Module 3258945Sroberto * 4258945Sroberto * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5258945Sroberto * 6258945Sroberto * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7258945Sroberto * 8258945Sroberto * Redistribution and use in source and binary forms are permitted 9258945Sroberto * provided that the above copyright notice and this paragraph are 10258945Sroberto * duplicated in all such forms and that any documentation, 11258945Sroberto * advertising materials, and other materials related to such 12258945Sroberto * distribution and use acknowledge that the software was developed 13258945Sroberto * by the Internet Initiative Japan, Inc. The name of the 14258945Sroberto * IIJ may not be used to endorse or promote products derived 15258945Sroberto * from this software without specific prior written permission. 16258945Sroberto * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17258945Sroberto * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18258945Sroberto * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19258945Sroberto * 20258945Sroberto * $Id: route.c,v 1.26 1997/11/15 02:15:56 brian Exp $ 21258945Sroberto * 22258945Sroberto */ 23258945Sroberto 24258945Sroberto#include <sys/param.h> 25258945Sroberto#include <sys/time.h> 26258945Sroberto#include <sys/socket.h> 27258945Sroberto#include <net/if_types.h> 28258945Sroberto#include <net/route.h> 29258945Sroberto#include <net/if.h> 30258945Sroberto#include <netinet/in_systm.h> 31258945Sroberto#include <netinet/in.h> 32258945Sroberto#include <arpa/inet.h> 33258945Sroberto#include <net/if_dl.h> 34258945Sroberto 35258945Sroberto#include <errno.h> 36258945Sroberto#include <machine/endian.h> 37258945Sroberto#include <stdio.h> 38258945Sroberto#include <stdlib.h> 39258945Sroberto#include <string.h> 40258945Sroberto#include <sys/ioctl.h> 41258945Sroberto#include <sys/sysctl.h> 42258945Sroberto#include <unistd.h> 43258945Sroberto 44258945Sroberto#include "command.h" 45258945Sroberto#include "mbuf.h" 46258945Sroberto#include "log.h" 47258945Sroberto#include "loadalias.h" 48258945Sroberto#include "defs.h" 49258945Sroberto#include "vars.h" 50258945Sroberto#include "id.h" 51258945Sroberto#include "route.h" 52258945Sroberto 53258945Srobertostatic int IfIndex; 54258945Sroberto 55258945Srobertostruct rtmsg { 56258945Sroberto struct rt_msghdr m_rtm; 57258945Sroberto char m_space[64]; 58258945Sroberto}; 59258945Sroberto 60258945Srobertostatic int seqno; 61258945Sroberto 62258945Srobertovoid 63258945SrobertoOsSetRoute(int cmd, 64258945Sroberto struct in_addr dst, 65258945Sroberto struct in_addr gateway, 66258945Sroberto struct in_addr mask) 67258945Sroberto{ 68258945Sroberto struct rtmsg rtmes; 69258945Sroberto int s, nb, wb; 70258945Sroberto char *cp; 71258945Sroberto const char *cmdstr; 72258945Sroberto u_long *lp; 73258945Sroberto struct sockaddr_in rtdata; 74258945Sroberto 75258945Sroberto cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76258945Sroberto s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 77258945Sroberto if (s < 0) { 78258945Sroberto LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 79258945Sroberto return; 80258945Sroberto } 81258945Sroberto memset(&rtmes, '\0', sizeof(rtmes)); 82258945Sroberto rtmes.m_rtm.rtm_version = RTM_VERSION; 83258945Sroberto rtmes.m_rtm.rtm_type = cmd; 84258945Sroberto rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 85258945Sroberto rtmes.m_rtm.rtm_seq = ++seqno; 86258945Sroberto rtmes.m_rtm.rtm_pid = getpid(); 87258945Sroberto rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 88258945Sroberto 89258945Sroberto memset(&rtdata, '\0', sizeof(rtdata)); 90258945Sroberto rtdata.sin_len = 16; 91258945Sroberto rtdata.sin_family = AF_INET; 92258945Sroberto rtdata.sin_port = 0; 93258945Sroberto rtdata.sin_addr = dst; 94258945Sroberto 95258945Sroberto cp = rtmes.m_space; 96258945Sroberto memcpy(cp, &rtdata, 16); 97258945Sroberto cp += 16; 98258945Sroberto if (gateway.s_addr) { 99258945Sroberto rtdata.sin_addr = gateway; 100258945Sroberto memcpy(cp, &rtdata, 16); 101258945Sroberto cp += 16; 102258945Sroberto rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 103258945Sroberto } 104258945Sroberto if (dst.s_addr == INADDR_ANY) 105258945Sroberto mask.s_addr = INADDR_ANY; 106258945Sroberto 107258945Sroberto lp = (u_long *) cp; 108258945Sroberto 109258945Sroberto if (mask.s_addr) { 110258945Sroberto *lp++ = 8; 111258945Sroberto cp += sizeof(int); 112258945Sroberto *lp = mask.s_addr; 113258945Sroberto } else 114258945Sroberto *lp = 0; 115258945Sroberto cp += sizeof(u_long); 116258945Sroberto 117258945Sroberto nb = cp - (char *) &rtmes; 118258945Sroberto rtmes.m_rtm.rtm_msglen = nb; 119258945Sroberto wb = write(s, &rtmes, nb); 120258945Sroberto if (wb < 0) { 121258945Sroberto LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 122258945Sroberto LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 123258945Sroberto LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 124258945Sroberto switch (rtmes.m_rtm.rtm_errno) { 125258945Sroberto case EEXIST: 126258945Sroberto LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 127258945Sroberto break; 128258945Sroberto case ESRCH: 129258945Sroberto LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 130258945Sroberto break; 131258945Sroberto case 0: 132258945Sroberto LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); 133258945Sroberto break; 134258945Sroberto 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; 268 269 if (!nifs) { 270 int mib[6], needed, len; 271 char *buf, *ptr, *end; 272 struct if_msghdr *n; 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 ptr = buf; 296 while (ptr < end) { 297 ifm = (struct if_msghdr *)ptr; 298 299 if (ifm->ifm_type != RTM_IFINFO) { 300 free(buf); 301 return "???"; 302 } 303 dl = (struct sockaddr_dl *)(ifm + 1); 304 ptr += ifm->ifm_msglen; 305 while (ptr < end) { 306 n = (struct if_msghdr *)ptr; 307 if (n->ifm_type != RTM_NEWADDR) 308 break; 309 ptr += n->ifm_msglen; 310 } 311 if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1) 312 len = sizeof(ifs[0])-1; 313 strncpy(ifs[nifs], dl->sdl_data, len); 314 ifs[nifs++][len] = '\0'; 315 if (nifs == sizeof(ifs)/sizeof(ifs[0])) 316 break; 317 } 318 free(buf); 319 } 320 321#ifdef __FreeBSD__ 322 idx--; /* We start at 1, not 0 */ 323#endif 324 if (idx < 0 || idx >= nifs) 325 return "???"; 326 return ifs[idx]; 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#ifdef __FreeBSD__ 479 idx = 1; /* We start at 1, not 0 */ 480#else 481 idx = 0; 482#endif 483 484 while (strcmp(got = Index2Nam(idx), "???")) 485 if (!strcmp(got, name)) 486 return IfIndex = idx; 487 else 488 idx++; 489 return -1; 490} 491