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