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