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