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