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