route.c revision 18885
150477Speter/* 2290494Sbapt * PPP Routing related Module 3290494Sbapt * 412031Sache * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5290083Sbdrewery * 6290494Sbapt * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7290494Sbapt * 8290494Sbapt * Redistribution and use in source and binary forms are permitted 912031Sache * provided that the above copyright notice and this paragraph are 10290494Sbapt * duplicated in all such forms and that any documentation, 11290494Sbapt * advertising materials, and other materials related to such 12302329Sbapt * distribution and use acknowledge that the software was developed 1324275Sache * by the Internet Initiative Japan, Inc. The name of the 14290494Sbapt * IIJ may not be used to endorse or promote products derived 15290494Sbapt * from this software without specific prior written permission. 16290494Sbapt * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17290494Sbapt * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18290494Sbapt * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19290494Sbapt * 20290494Sbapt * $Id: route.c,v 1.8 1996/10/06 13:32:35 jkh Exp $ 21290494Sbapt * 22290494Sbapt */ 23290494Sbapt#include <sys/types.h> 24290494Sbapt#include <machine/endian.h> 25290494Sbapt#include <sys/param.h> 26312336Sbapt#include <sys/socket.h> 27290494Sbapt#include <net/route.h> 28290494Sbapt#include <sys/ioctl.h> 29290494Sbapt#include <net/if.h> 30290494Sbapt#include <errno.h> 31290494Sbapt#include <netinet/in_systm.h> 32290494Sbapt#include <netinet/in.h> 33302329Sbapt#include <arpa/inet.h> 34290494Sbapt#if (BSD >= 199306) 35290494Sbapt#include <sys/sysctl.h> 36290494Sbapt#else 37312336Sbapt#include <sys/kinfo.h> 38290494Sbapt#endif 39290494Sbapt#include <stdlib.h> 40290494Sbapt#include <stdio.h> 41290494Sbapt#include <string.h> 42290494Sbapt#include <unistd.h> 43290494Sbapt#include "log.h" 44312336Sbapt 45312336Sbaptstatic int IfIndex; 46290494Sbapt 47290494Sbaptstruct rtmsg { 48290494Sbapt struct rt_msghdr m_rtm; 49302329Sbapt char m_space[64]; 50302329Sbapt}; 51136596Sru 52298121Sbaptstatic int seqno; 53298121Sbapt 54298121Sbaptvoid 55298121SbaptOsSetRoute(cmd, dst, gateway, mask) 56298121Sbaptint cmd; 57298121Sbaptstruct in_addr dst; 58298121Sbaptstruct in_addr gateway; 59298121Sbaptstruct in_addr mask; 60298121Sbapt{ 61298121Sbapt struct rtmsg rtmes; 62298121Sbapt int s, nb, wb; 63298121Sbapt char *cp; 64298121Sbapt u_long *lp; 65298121Sbapt struct sockaddr_in rtdata; 66298121Sbapt 67298121Sbapt s = socket(PF_ROUTE, SOCK_RAW, 0); 68298121Sbapt if (s < 0) 69298121Sbapt logprintf("socket\n"); 70298121Sbapt 71298121Sbapt bzero(&rtmes, sizeof(rtmes)); 72298121Sbapt rtmes.m_rtm.rtm_version = RTM_VERSION; 73298121Sbapt rtmes.m_rtm.rtm_type = cmd; 74298121Sbapt rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 75298121Sbapt if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 76298121Sbapt rtmes.m_rtm.rtm_seq = ++seqno; 77298121Sbapt rtmes.m_rtm.rtm_pid = getpid(); 78298121Sbapt rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 79298121Sbapt 80298121Sbapt bzero(&rtdata, sizeof(rtdata)); 81298121Sbapt rtdata.sin_len = 16; 82298121Sbapt rtdata.sin_family = AF_INET; 83298121Sbapt rtdata.sin_port = 0; 84298121Sbapt rtdata.sin_addr = dst; 85298121Sbapt 86298121Sbapt cp = rtmes.m_space; 87298121Sbapt bcopy(&rtdata, cp, 16); 88298121Sbapt cp += 16; 89298121Sbapt if (gateway.s_addr) { 90298121Sbapt rtdata.sin_addr = gateway; 91298121Sbapt bcopy(&rtdata, cp, 16); 92298121Sbapt cp += 16; 93298121Sbapt } 94298121Sbapt 95298121Sbapt if (dst.s_addr == INADDR_ANY) 96298121Sbapt mask.s_addr = INADDR_ANY; 97298121Sbapt 98298121Sbapt lp = (u_long *)cp; 99298121Sbapt 100298121Sbapt if (mask.s_addr) { 101298121Sbapt *lp++ = 8; 102298121Sbapt cp += sizeof(int); 103298121Sbapt *lp = mask.s_addr; 104298121Sbapt } else 105298121Sbapt *lp = 0; 106298121Sbapt cp += sizeof(u_long); 107298121Sbapt 108298121Sbapt nb = cp - (char *)&rtmes; 109298121Sbapt rtmes.m_rtm.rtm_msglen = nb; 110298121Sbapt wb = write(s, &rtmes, nb); 111298121Sbapt if (wb < 0) { 112298121Sbapt LogPrintf(LOG_TCPIP_BIT, "Already set route addr dst=%x, gateway=%x\n" 113298121Sbapt ,dst.s_addr, gateway.s_addr); 114298121Sbapt } 115298121Sbapt#ifdef DEBUG 116298121Sbapt logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr); 117298121Sbapt#endif 118298121Sbapt close(s); 119298121Sbapt} 120298121Sbapt 121298121Sbaptstatic void 122298121Sbaptp_sockaddr(sa, width) 123298121Sbaptstruct sockaddr *sa; 124298121Sbaptint width; 125298121Sbapt{ 126312336Sbapt register char *cp; 127312336Sbapt register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 128298121Sbapt 129312336Sbapt cp = (sin->sin_addr.s_addr == 0) ? "default" : 130298121Sbapt inet_ntoa(sin->sin_addr); 131298121Sbapt printf("%-*.*s ", width, width, cp); 132298121Sbapt} 133298121Sbapt 134298121Sbaptstruct bits { 135298121Sbapt short b_mask; 136298121Sbapt char b_val; 137298121Sbapt} bits[] = { 138298121Sbapt { RTF_UP, 'U' }, 139298121Sbapt { RTF_GATEWAY, 'G' }, 140298121Sbapt { RTF_HOST, 'H' }, 141298121Sbapt { RTF_DYNAMIC, 'D' }, 142298121Sbapt { RTF_MODIFIED, 'M' }, 143298121Sbapt { RTF_CLONING, 'C' }, 144298121Sbapt { RTF_XRESOLVE, 'X' }, 145298121Sbapt { RTF_LLINFO, 'L' }, 146298121Sbapt { RTF_REJECT, 'R' }, 147298121Sbapt { 0 } 148298121Sbapt}; 149298121Sbapt 150298121Sbaptstatic void 151298121Sbaptp_flags(f, format) 152298121Sbaptregister int f; 153298121Sbaptchar *format; 154298121Sbapt{ 155298121Sbapt char name[33], *flags; 156298121Sbapt register struct bits *p = bits; 157312336Sbapt 158312336Sbapt for (flags = name; p->b_mask; p++) 159302329Sbapt if (p->b_mask & f) 160302329Sbapt *flags++ = p->b_val; 161312336Sbapt *flags = '\0'; 162312336Sbapt printf(format, name); 163312336Sbapt} 164312336Sbapt 165312336Sbaptint 166312336SbaptShowRoute() 167298121Sbapt{ 168298121Sbapt struct rt_msghdr *rtm; 169292453Sbapt struct sockaddr *sa; 170292453Sbapt char *sp, *ep, *cp; 171292453Sbapt u_char *wp; 172292453Sbapt int *lp; 173292453Sbapt int needed, nb; 174302329Sbapt u_long mask; 175292453Sbapt#if (BSD >= 199306) 176292453Sbapt int mib[6]; 177292453Sbapt#endif 178292453Sbapt 179292453Sbapt#if (BSD >= 199306) 180292453Sbapt mib[0] = CTL_NET; 181292453Sbapt mib[1] = PF_ROUTE; 182292453Sbapt mib[2] = 0; 183292453Sbapt mib[3] = 0; 184292453Sbapt mib[4] = NET_RT_DUMP; 185292453Sbapt mib[5] = 0; 186292453Sbapt if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 187292453Sbapt perror("sysctl-estimate"); 188292453Sbapt return(1); 189292453Sbapt } 190292453Sbapt#else 191292453Sbapt needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0); 192292453Sbapt#endif 193292453Sbapt if (needed < 0) 194292453Sbapt return(1); 195292453Sbapt sp = malloc(needed); 196292453Sbapt if (sp == NULL) 197292453Sbapt return(1); 198292453Sbapt#if (BSD >= 199306) 199292453Sbapt if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 200292453Sbapt perror("sysctl-getroute"); 201292453Sbapt free(sp); 202292453Sbapt return(1); 203292453Sbapt } 204312336Sbapt#else 205292453Sbapt if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) 206292453Sbapt free(sp); 207302329Sbapt return(1); 208292453Sbapt#endif 209136596Sru ep = sp + needed; 210290494Sbapt 211136596Sru for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 212136596Sru rtm = (struct rt_msghdr *)cp; 213292453Sbapt sa = (struct sockaddr *)(rtm + 1); 214292453Sbapt mask = 0xffffffff; 215292453Sbapt if (rtm->rtm_addrs == RTA_DST) 216290494Sbapt p_sockaddr(sa, 36); 217136596Sru else { 218290494Sbapt wp = (u_char *)cp + rtm->rtm_msglen; 219290494Sbapt p_sockaddr(sa, 16); 22023228Swosch if (sa->sa_len == 0) 22112031Sache sa->sa_len = sizeof(long); 222298121Sbapt sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 223298121Sbapt p_sockaddr(sa, 18); 224298125Sbapt lp = (int *)(sa->sa_len + (char *)sa); 225298121Sbapt if ((char *)lp < (char *)wp && *lp) { 226298121Sbapt#ifdef DEBUG 227302329Sbapt logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp); 228298121Sbapt#endif 229298121Sbapt wp = (u_char *)(lp + 1); 230298121Sbapt mask = 0; 23112031Sache 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