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