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