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