route.c revision 31121
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.24 1997/11/09 14:18:50 brian Exp $ 21 * 22 */ 23 24#include <sys/param.h> 25#include <sys/time.h> 26#include <sys/socket.h> 27#include <net/route.h> 28#include <net/if.h> 29#include <netinet/in_systm.h> 30#include <netinet/in.h> 31#include <arpa/inet.h> 32 33#include <errno.h> 34#include <machine/endian.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <sys/ioctl.h> 39#include <sys/sysctl.h> 40#include <unistd.h> 41 42#include "mbuf.h" 43#include "log.h" 44#include "loadalias.h" 45#include "command.h" 46#include "defs.h" 47#include "vars.h" 48#include "id.h" 49#include "route.h" 50 51static int IfIndex; 52 53struct rtmsg { 54 struct rt_msghdr m_rtm; 55 char m_space[64]; 56}; 57 58static int seqno; 59 60void 61OsSetRoute(int cmd, 62 struct in_addr dst, 63 struct in_addr gateway, 64 struct in_addr mask) 65{ 66 struct rtmsg rtmes; 67 int s, nb, wb; 68 char *cp, *cmdstr; 69 u_long *lp; 70 struct sockaddr_in rtdata; 71 72 cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 73 s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 74 if (s < 0) { 75 LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 76 return; 77 } 78 memset(&rtmes, '\0', sizeof(rtmes)); 79 rtmes.m_rtm.rtm_version = RTM_VERSION; 80 rtmes.m_rtm.rtm_type = cmd; 81 rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 82 rtmes.m_rtm.rtm_seq = ++seqno; 83 rtmes.m_rtm.rtm_pid = getpid(); 84 rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 85 86 memset(&rtdata, '\0', sizeof(rtdata)); 87 rtdata.sin_len = 16; 88 rtdata.sin_family = AF_INET; 89 rtdata.sin_port = 0; 90 rtdata.sin_addr = dst; 91 92 cp = rtmes.m_space; 93 memcpy(cp, &rtdata, 16); 94 cp += 16; 95 if (gateway.s_addr) { 96 rtdata.sin_addr = gateway; 97 memcpy(cp, &rtdata, 16); 98 cp += 16; 99 rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 100 } 101 if (dst.s_addr == INADDR_ANY) 102 mask.s_addr = INADDR_ANY; 103 104 lp = (u_long *) cp; 105 106 if (mask.s_addr) { 107 *lp++ = 8; 108 cp += sizeof(int); 109 *lp = mask.s_addr; 110 } else 111 *lp = 0; 112 cp += sizeof(u_long); 113 114 nb = cp - (char *) &rtmes; 115 rtmes.m_rtm.rtm_msglen = nb; 116 wb = write(s, &rtmes, nb); 117 if (wb < 0) { 118 LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 119 LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 120 LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 121 switch (rtmes.m_rtm.rtm_errno) { 122 case EEXIST: 123 LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 124 break; 125 case ESRCH: 126 LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 127 break; 128 case 0: 129 LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); 130 break; 131 case ENOBUFS: 132 default: 133 LogPrintf(LogTCPIP, "%s route failed: %s\n", 134 cmdstr, strerror(rtmes.m_rtm.rtm_errno)); 135 break; 136 } 137 } 138 LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 139 wb, cmdstr, dst.s_addr, gateway.s_addr); 140 close(s); 141} 142 143static void 144p_sockaddr(struct sockaddr * sa, int width) 145{ 146 if (VarTerm) { 147 register char *cp; 148 register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa; 149 150 cp = (sock_in->sin_addr.s_addr == 0) ? "default" : 151 inet_ntoa(sock_in->sin_addr); 152 fprintf(VarTerm, "%-*.*s ", width, width, cp); 153 } 154} 155 156struct bits { 157 short b_mask; 158 char b_val; 159} bits[] = { 160 161 { 162 RTF_UP, 'U' 163 }, 164 { 165 RTF_GATEWAY, 'G' 166 }, 167 { 168 RTF_HOST, 'H' 169 }, 170 { 171 RTF_DYNAMIC, 'D' 172 }, 173 { 174 RTF_MODIFIED, 'M' 175 }, 176 { 177 RTF_CLONING, 'C' 178 }, 179 { 180 RTF_XRESOLVE, 'X' 181 }, 182 { 183 RTF_LLINFO, 'L' 184 }, 185 { 186 RTF_REJECT, 'R' 187 }, 188 { 189 0 190 } 191}; 192 193static void 194p_flags(int f, char *format) 195{ 196 if (VarTerm) { 197 char name[33], *flags; 198 register struct bits *p = bits; 199 200 for (flags = name; p->b_mask; p++) 201 if (p->b_mask & f) 202 *flags++ = p->b_val; 203 *flags = '\0'; 204 fprintf(VarTerm, format, name); 205 } 206} 207 208int 209ShowRoute() 210{ 211 struct rt_msghdr *rtm; 212 struct sockaddr *sa; 213 char *sp, *ep, *cp; 214 u_char *wp; 215 int *lp; 216 int needed, nb; 217 u_long mask; 218 int mib[6]; 219 220 if (!VarTerm) 221 return 1; 222 223 mib[0] = CTL_NET; 224 mib[1] = PF_ROUTE; 225 mib[2] = 0; 226 mib[3] = 0; 227 mib[4] = NET_RT_DUMP; 228 mib[5] = 0; 229 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 230 LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 231 return (1); 232 } 233 if (needed < 0) 234 return (1); 235 sp = malloc(needed); 236 if (sp == NULL) 237 return (1); 238 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 239 LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 240 free(sp); 241 return (1); 242 } 243 ep = sp + needed; 244 245 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 246 rtm = (struct rt_msghdr *) cp; 247 sa = (struct sockaddr *) (rtm + 1); 248 mask = 0xffffffff; 249 if (rtm->rtm_addrs == RTA_DST) 250 p_sockaddr(sa, 36); 251 else { 252 wp = (u_char *) cp + rtm->rtm_msglen; 253 p_sockaddr(sa, 16); 254 if (sa->sa_len == 0) 255 sa->sa_len = sizeof(long); 256 sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 257 p_sockaddr(sa, 18); 258 lp = (int *) (sa->sa_len + (char *) sa); 259 if ((char *) lp < (char *) wp && *lp) { 260 LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp); 261 wp = (u_char *) (lp + 1); 262 mask = 0; 263 for (nb = *(char *) lp; nb > 4; nb--) { 264 mask <<= 8; 265 mask |= *wp++; 266 } 267 for (nb = 8 - *(char *) lp; nb > 0; nb--) 268 mask <<= 8; 269 } 270 } 271 fprintf(VarTerm, "0x%08lx ", mask); 272 p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s "); 273 fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 274 } 275 free(sp); 276 return 0; 277} 278 279/* 280 * Delete routes associated with our interface 281 */ 282void 283DeleteIfRoutes(int all) 284{ 285 struct rt_msghdr *rtm; 286 struct sockaddr *sa; 287 struct in_addr dstnet, gateway, maddr; 288 int needed; 289 char *sp, *cp, *ep; 290 u_long mask; 291 int *lp, nb; 292 u_char *wp; 293 int mib[6]; 294 295 LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 296 297 mib[0] = CTL_NET; 298 mib[1] = PF_ROUTE; 299 mib[2] = 0; 300 mib[3] = 0; 301 mib[4] = NET_RT_DUMP; 302 mib[5] = 0; 303 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 304 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 305 strerror(errno)); 306 return; 307 } 308 if (needed < 0) 309 return; 310 311 sp = malloc(needed); 312 if (sp == NULL) 313 return; 314 315 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 316 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 317 strerror(errno)); 318 free(sp); 319 return; 320 } 321 ep = sp + needed; 322 323 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 324 rtm = (struct rt_msghdr *) cp; 325 sa = (struct sockaddr *) (rtm + 1); 326 LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 327 " dstnet: %s\n", 328 rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 329 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 330 if (rtm->rtm_addrs != RTA_DST && 331 (rtm->rtm_index == IfIndex) && 332 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 333 LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 334 dstnet = ((struct sockaddr_in *) sa)->sin_addr; 335 wp = (u_char *) cp + rtm->rtm_msglen; 336 if (sa->sa_len == 0) 337 sa->sa_len = sizeof(long); 338 sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 339 gateway = ((struct sockaddr_in *) sa)->sin_addr; 340 lp = (int *) (sa->sa_len + (char *) sa); 341 mask = 0; 342 if ((char *) lp < (char *) wp && *lp) { 343 LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n", 344 rtm->rtm_flags, *lp); 345 wp = (u_char *) (lp + 1); 346 for (nb = *lp; nb > 4; nb--) { 347 mask <<= 8; 348 mask |= *wp++; 349 } 350 for (nb = 8 - *lp; nb > 0; nb--) 351 mask <<= 8; 352 } 353 LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet)); 354 LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 355 LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 356 if (dstnet.s_addr == INADDR_ANY) 357 mask = INADDR_ANY; 358 maddr.s_addr = htonl(mask); 359 OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 360 } 361 } 362 free(sp); 363} 364 365 /* 366 * 960603 - Modified to use dynamic buffer allocator as in ifconfig 367 */ 368 369int 370GetIfIndex(char *name) 371{ 372 char *buffer; 373 struct ifreq *ifrp; 374 int s, len, elen, newIfIndex; 375 struct ifconf ifconfs; 376 377 /* struct ifreq reqbuf[256]; -- obsoleted :) */ 378 int oldbufsize, bufsize = sizeof(struct ifreq); 379 380 s = socket(AF_INET, SOCK_DGRAM, 0); 381 if (s < 0) { 382 LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno)); 383 return (-1); 384 } 385 buffer = malloc(bufsize); /* allocate first buffer */ 386 ifconfs.ifc_len = bufsize; /* Initial setting */ 387 388 /* 389 * Iterate through here until we don't get many more data 390 */ 391 392 do { 393 oldbufsize = ifconfs.ifc_len; 394 bufsize += 1 + sizeof(struct ifreq); 395 buffer = realloc((void *) buffer, bufsize); /* Make it bigger */ 396 LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 397 ifconfs.ifc_len = bufsize; 398 ifconfs.ifc_buf = buffer; 399 if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 400 LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n", 401 strerror(errno)); 402 close(s); 403 free(buffer); 404 return (-1); 405 } 406 } while (ifconfs.ifc_len > oldbufsize); 407 408 ifrp = ifconfs.ifc_req; 409 410 newIfIndex = 1; 411 for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 412 elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 413 if (ifrp->ifr_addr.sa_family == AF_LINK) { 414 LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 415 newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 416 ifrp->ifr_addr.sa_family, elen); 417 if (strcmp(ifrp->ifr_name, name) == 0) { 418 IfIndex = newIfIndex; 419 close(s); 420 free(buffer); 421 return (newIfIndex); 422 } 423 newIfIndex++; 424 } 425 len -= elen; 426 ifrp = (struct ifreq *) ((char *) ifrp + elen); 427 ifrp++; 428 } 429 430 close(s); 431 free(buffer); 432 return (-1); 433} 434