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