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