1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)startup.c 5.16 (Berkeley) 04/02/89"; 20 #endif /* not lint */ 21 22 /* 23 * Routing Table Management Daemon 24 */ 25 #include "defs.h" 26 #include <sys/ioctl.h> 27 #include <net/if.h> 28 #include <syslog.h> 29 #include "pathnames.h" 30 31 struct interface *ifnet; 32 struct interface **ifnext = &ifnet; 33 int lookforinterfaces = 1; 34 int externalinterfaces = 0; /* # of remote and local interfaces */ 35 int foundloopback; /* valid flag for loopaddr */ 36 struct sockaddr loopaddr; /* our address on loopback */ 37 38 /* 39 * Find the network interfaces which have configured themselves. 40 * If the interface is present but not yet up (for example an 41 * ARPANET IMP), set the lookforinterfaces flag so we'll 42 * come back later and look again. 43 */ 44 ifinit() 45 { 46 struct interface ifs, *ifp; 47 int s, n; 48 char buf[BUFSIZ]; 49 struct ifconf ifc; 50 struct ifreq ifreq, *ifr; 51 struct sockaddr_in *sin; 52 u_long i; 53 54 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 55 syslog(LOG_ERR, "socket: %m"); 56 close(s); 57 return; 58 } 59 ifc.ifc_len = sizeof (buf); 60 ifc.ifc_buf = buf; 61 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { 62 syslog(LOG_ERR, "ioctl (get interface configuration)"); 63 close(s); 64 return; 65 } 66 ifr = ifc.ifc_req; 67 lookforinterfaces = 0; 68 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 69 bzero((char *)&ifs, sizeof(ifs)); 70 ifs.int_addr = ifr->ifr_addr; 71 ifreq = *ifr; 72 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 73 syslog(LOG_ERR, "%s: ioctl (get interface flags)", 74 ifr->ifr_name); 75 continue; 76 } 77 ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; 78 if ((ifs.int_flags & IFF_UP) == 0 || 79 ifr->ifr_addr.sa_family == AF_UNSPEC) { 80 lookforinterfaces = 1; 81 continue; 82 } 83 /* argh, this'll have to change sometime */ 84 if (ifs.int_addr.sa_family != AF_INET) 85 continue; 86 if (ifs.int_flags & IFF_POINTOPOINT) { 87 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { 88 syslog(LOG_ERR, "%s: ioctl (get dstaddr)", 89 ifr->ifr_name); 90 continue; 91 } 92 if (ifr->ifr_addr.sa_family == AF_UNSPEC) { 93 lookforinterfaces = 1; 94 continue; 95 } 96 ifs.int_dstaddr = ifreq.ifr_dstaddr; 97 } 98 /* 99 * already known to us? 100 * This allows multiple point-to-point links 101 * to share a source address (possibly with one 102 * other link), but assumes that there will not be 103 * multiple links with the same destination address. 104 */ 105 if (ifs.int_flags & IFF_POINTOPOINT) { 106 if (if_ifwithdstaddr(&ifs.int_dstaddr)) 107 continue; 108 } else if (if_ifwithaddr(&ifs.int_addr)) 109 continue; 110 if (ifs.int_flags & IFF_LOOPBACK) { 111 ifs.int_flags |= IFF_PASSIVE; 112 foundloopback = 1; 113 loopaddr = ifs.int_addr; 114 for (ifp = ifnet; ifp; ifp = ifp->int_next) 115 if (ifp->int_flags & IFF_POINTOPOINT) 116 add_ptopt_localrt(ifp); 117 } 118 if (ifs.int_flags & IFF_BROADCAST) { 119 if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 120 syslog(LOG_ERR, "%s: ioctl (get broadaddr)", 121 ifr->ifr_name); 122 continue; 123 } 124 #ifndef sun 125 ifs.int_broadaddr = ifreq.ifr_broadaddr; 126 #else 127 ifs.int_broadaddr = ifreq.ifr_addr; 128 #endif 129 } 130 #ifdef SIOCGIFMETRIC 131 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { 132 syslog(LOG_ERR, "%s: ioctl (get metric)", 133 ifr->ifr_name); 134 ifs.int_metric = 0; 135 } else 136 ifs.int_metric = ifreq.ifr_metric; 137 #else 138 ifs.int_metric = 0; 139 #endif 140 /* 141 * Use a minimum metric of one; 142 * treat the interface metric (default 0) 143 * as an increment to the hop count of one. 144 */ 145 ifs.int_metric++; 146 if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 147 syslog(LOG_ERR, "%s: ioctl (get netmask)", 148 ifr->ifr_name); 149 continue; 150 } 151 sin = (struct sockaddr_in *)&ifreq.ifr_addr; 152 ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); 153 sin = (struct sockaddr_in *)&ifs.int_addr; 154 i = ntohl(sin->sin_addr.s_addr); 155 if (IN_CLASSA(i)) 156 ifs.int_netmask = IN_CLASSA_NET; 157 else if (IN_CLASSB(i)) 158 ifs.int_netmask = IN_CLASSB_NET; 159 else 160 ifs.int_netmask = IN_CLASSC_NET; 161 ifs.int_net = i & ifs.int_netmask; 162 ifs.int_subnet = i & ifs.int_subnetmask; 163 if (ifs.int_subnetmask != ifs.int_netmask) 164 ifs.int_flags |= IFF_SUBNET; 165 ifp = (struct interface *)malloc(sizeof (struct interface)); 166 if (ifp == 0) { 167 printf("routed: out of memory\n"); 168 break; 169 } 170 *ifp = ifs; 171 /* 172 * Count the # of directly connected networks 173 * and point to point links which aren't looped 174 * back to ourself. This is used below to 175 * decide if we should be a routing ``supplier''. 176 */ 177 if ((ifs.int_flags & IFF_LOOPBACK) == 0 && 178 ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 179 if_ifwithaddr(&ifs.int_dstaddr) == 0)) 180 externalinterfaces++; 181 /* 182 * If we have a point-to-point link, we want to act 183 * as a supplier even if it's our only interface, 184 * as that's the only way our peer on the other end 185 * can tell that the link is up. 186 */ 187 if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 188 supplier = 1; 189 ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); 190 if (ifp->int_name == 0) { 191 fprintf(stderr, "routed: ifinit: out of memory\n"); 192 syslog(LOG_ERR, "routed: ifinit: out of memory\n"); 193 close(s); 194 return; 195 } 196 strcpy(ifp->int_name, ifr->ifr_name); 197 *ifnext = ifp; 198 ifnext = &ifp->int_next; 199 traceinit(ifp); 200 addrouteforif(ifp); 201 } 202 if (externalinterfaces > 1 && supplier < 0) 203 supplier = 1; 204 close(s); 205 } 206 207 /* 208 * Add route for interface if not currently installed. 209 * Create route to other end if a point-to-point link, 210 * otherwise a route to this (sub)network. 211 * INTERNET SPECIFIC. 212 */ 213 addrouteforif(ifp) 214 register struct interface *ifp; 215 { 216 struct sockaddr_in net; 217 struct sockaddr *dst; 218 int state; 219 register struct rt_entry *rt; 220 221 if (ifp->int_flags & IFF_POINTOPOINT) 222 dst = &ifp->int_dstaddr; 223 else { 224 bzero((char *)&net, sizeof (net)); 225 net.sin_family = AF_INET; 226 net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); 227 dst = (struct sockaddr *)&net; 228 } 229 rt = rtfind(dst); 230 if (rt && 231 (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) 232 return; 233 if (rt) 234 rtdelete(rt); 235 /* 236 * If interface on subnetted network, 237 * install route to network as well. 238 * This is meant for external viewers. 239 */ 240 if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { 241 struct in_addr subnet; 242 243 subnet = net.sin_addr; 244 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 245 rt = rtfind(dst); 246 if (rt == 0) 247 rtadd(dst, &ifp->int_addr, ifp->int_metric, 248 ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | 249 RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); 250 else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 251 (RTS_INTERNAL|RTS_SUBNET) && 252 ifp->int_metric < rt->rt_metric) 253 rtchange(rt, &rt->rt_router, ifp->int_metric); 254 net.sin_addr = subnet; 255 } 256 if (ifp->int_transitions++ > 0) 257 syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 258 state = ifp->int_flags & 259 (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); 260 if (ifp->int_flags & IFF_POINTOPOINT && 261 (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & 262 ifp->int_netmask) != ifp->int_net) 263 state &= ~RTS_SUBNET; 264 if (ifp->int_flags & IFF_LOOPBACK) 265 state |= RTS_EXTERNAL; 266 rtadd(dst, &ifp->int_addr, ifp->int_metric, state); 267 if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) 268 add_ptopt_localrt(ifp); 269 } 270 271 /* 272 * Add route to local end of point-to-point using loopback. 273 * If a route to this network is being sent to neighbors on other nets, 274 * mark this route as subnet so we don't have to propagate it too. 275 */ 276 add_ptopt_localrt(ifp) 277 register struct interface *ifp; 278 { 279 struct rt_entry *rt; 280 struct sockaddr *dst; 281 struct sockaddr_in net; 282 int state; 283 284 state = RTS_INTERFACE | RTS_PASSIVE; 285 286 /* look for route to logical network */ 287 bzero((char *)&net, sizeof (net)); 288 net.sin_family = AF_INET; 289 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 290 dst = (struct sockaddr *)&net; 291 rt = rtfind(dst); 292 if (rt && rt->rt_state & RTS_INTERNAL) 293 state |= RTS_SUBNET; 294 295 dst = &ifp->int_addr; 296 if (rt = rtfind(dst)) { 297 if (rt && rt->rt_state & RTS_INTERFACE) 298 return; 299 rtdelete(rt); 300 } 301 rtadd(dst, &loopaddr, 1, state); 302 } 303 304 /* 305 * As a concession to the ARPANET we read a list of gateways 306 * from /etc/gateways and add them to our tables. This file 307 * exists at each ARPANET gateway and indicates a set of ``remote'' 308 * gateways (i.e. a gateway which we can't immediately determine 309 * if it's present or not as we can do for those directly connected 310 * at the hardware level). If a gateway is marked ``passive'' 311 * in the file, then we assume it doesn't have a routing process 312 * of our design and simply assume it's always present. Those 313 * not marked passive are treated as if they were directly 314 * connected -- they're added into the interface list so we'll 315 * send them routing updates. 316 * 317 * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP. 318 */ 319 gwkludge() 320 { 321 struct sockaddr_in dst, gate; 322 FILE *fp; 323 char *type, *dname, *gname, *qual, buf[BUFSIZ]; 324 struct interface *ifp; 325 int metric, n; 326 struct rt_entry route; 327 328 fp = fopen(_PATH_GATEWAYS, "r"); 329 if (fp == NULL) 330 return; 331 qual = buf; 332 dname = buf + 64; 333 gname = buf + ((BUFSIZ - 64) / 3); 334 type = buf + (((BUFSIZ - 64) * 2) / 3); 335 bzero((char *)&dst, sizeof (dst)); 336 bzero((char *)&gate, sizeof (gate)); 337 bzero((char *)&route, sizeof(route)); 338 /* format: {net | host} XX gateway XX metric DD [passive | external]\n */ 339 #define readentry(fp) \ 340 fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 341 type, dname, gname, &metric, qual) 342 for (;;) { 343 if ((n = readentry(fp)) == EOF) 344 break; 345 if (!getnetorhostname(type, dname, &dst)) 346 continue; 347 if (!gethostnameornumber(gname, &gate)) 348 continue; 349 if (metric == 0) /* XXX */ 350 metric = 1; 351 if (strcmp(qual, "passive") == 0) { 352 /* 353 * Passive entries aren't placed in our tables, 354 * only the kernel's, so we don't copy all of the 355 * external routing information within a net. 356 * Internal machines should use the default 357 * route to a suitable gateway (like us). 358 */ 359 route.rt_dst = *(struct sockaddr *) &dst; 360 route.rt_router = *(struct sockaddr *) &gate; 361 route.rt_flags = RTF_UP; 362 if (strcmp(type, "host") == 0) 363 route.rt_flags |= RTF_HOST; 364 if (metric) 365 route.rt_flags |= RTF_GATEWAY; 366 (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); 367 continue; 368 } 369 if (strcmp(qual, "external") == 0) { 370 /* 371 * Entries marked external are handled 372 * by other means, e.g. EGP, 373 * and are placed in our tables only 374 * to prevent overriding them 375 * with something else. 376 */ 377 rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE); 378 continue; 379 } 380 /* assume no duplicate entries */ 381 externalinterfaces++; 382 ifp = (struct interface *)malloc(sizeof (*ifp)); 383 bzero((char *)ifp, sizeof (*ifp)); 384 ifp->int_flags = IFF_REMOTE; 385 /* can't identify broadcast capability */ 386 ifp->int_net = inet_netof(dst.sin_addr); 387 if (strcmp(type, "host") == 0) { 388 ifp->int_flags |= IFF_POINTOPOINT; 389 ifp->int_dstaddr = *((struct sockaddr *)&dst); 390 } 391 ifp->int_addr = *((struct sockaddr *)&gate); 392 ifp->int_metric = metric; 393 ifp->int_next = ifnet; 394 ifnet = ifp; 395 addrouteforif(ifp); 396 } 397 fclose(fp); 398 } 399 400 getnetorhostname(type, name, sin) 401 char *type, *name; 402 struct sockaddr_in *sin; 403 { 404 405 if (strcmp(type, "net") == 0) { 406 struct netent *np = getnetbyname(name); 407 int n; 408 409 if (np == 0) 410 n = inet_network(name); 411 else { 412 if (np->n_addrtype != AF_INET) 413 return (0); 414 n = np->n_net; 415 /* 416 * getnetbyname returns right-adjusted value. 417 */ 418 if (n < 128) 419 n <<= IN_CLASSA_NSHIFT; 420 else if (n < 65536) 421 n <<= IN_CLASSB_NSHIFT; 422 else 423 n <<= IN_CLASSC_NSHIFT; 424 } 425 sin->sin_family = AF_INET; 426 sin->sin_addr = inet_makeaddr(n, INADDR_ANY); 427 return (1); 428 } 429 if (strcmp(type, "host") == 0) { 430 struct hostent *hp = gethostbyname(name); 431 432 if (hp == 0) 433 sin->sin_addr.s_addr = inet_addr(name); 434 else { 435 if (hp->h_addrtype != AF_INET) 436 return (0); 437 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 438 } 439 sin->sin_family = AF_INET; 440 return (1); 441 } 442 return (0); 443 } 444 445 gethostnameornumber(name, sin) 446 char *name; 447 struct sockaddr_in *sin; 448 { 449 struct hostent *hp; 450 451 hp = gethostbyname(name); 452 if (hp) { 453 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 454 sin->sin_family = hp->h_addrtype; 455 return (1); 456 } 457 sin->sin_addr.s_addr = inet_addr(name); 458 sin->sin_family = AF_INET; 459 return (sin->sin_addr.s_addr != -1); 460 } 461