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