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