void ifinit(void) { struct interface ifs, *ifp; int s; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq ifreq, *ifr; struct sockaddr_in *sin; u_long i; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); close(s); return; } ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { syslog(LOG_ERR, "ioctl (get interface configuration)"); close(s); return; } ifr = ifc.ifc_req; lookforinterfaces = 0; cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + sizeof(ifr->ifr_ifru)) { ifr = (struct ifreq *)cp; bzero((char *)&ifs, sizeof(ifs)); ifs.int_addr = ifr->ifr_addr; ifreq = *ifr; if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get interface flags)", ifr->ifr_name); continue; } ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; if ((ifs.int_flags & IFF_UP) == 0 || ifr->ifr_addr.sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } /* argh, this'll have to change sometime */ if (ifs.int_addr.sa_family != AF_INET) continue; if (ifs.int_flags & IFF_POINTOPOINT) { if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get dstaddr)", ifr->ifr_name); continue; } if (ifr->ifr_addr.sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } ifs.int_dstaddr = ifreq.ifr_dstaddr; } /* * already known to us? * This allows multiple point-to-point links * to share a source address (possibly with one * other link), but assumes that there will not be * multiple links with the same destination address. */ if (ifs.int_flags & IFF_POINTOPOINT) { if (if_ifwithdstaddr(&ifs.int_dstaddr)) continue; } else if (if_ifwithaddr(&ifs.int_addr)) continue; if (ifs.int_flags & IFF_LOOPBACK) { ifs.int_flags |= IFF_PASSIVE; foundloopback = 1; loopaddr = ifs.int_addr; for (ifp = ifnet; ifp; ifp = ifp->int_next) if (ifp->int_flags & IFF_POINTOPOINT) add_ptopt_localrt(ifp); } if (ifs.int_flags & IFF_BROADCAST) { if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get broadaddr)", ifr->ifr_name); continue; } ifs.int_broadaddr = ifreq.ifr_broadaddr; } #ifdef SIOCGIFMETRIC if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get metric)", ifr->ifr_name); ifs.int_metric = 0; } else ifs.int_metric = ifreq.ifr_metric; #else ifs.int_metric = 0; #endif /* * Use a minimum metric of one; * treat the interface metric (default 0) * as an increment to the hop count of one. */ ifs.int_metric++; if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get netmask)", ifr->ifr_name); continue; } sin = (struct sockaddr_in *)&ifreq.ifr_addr; ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); sin = (struct sockaddr_in *)&ifs.int_addr; i = ntohl(sin->sin_addr.s_addr); if (IN_CLASSA(i)) ifs.int_netmask = IN_CLASSA_NET; else if (IN_CLASSB(i)) ifs.int_netmask = IN_CLASSB_NET; else ifs.int_netmask = IN_CLASSC_NET; ifs.int_net = i & ifs.int_netmask; ifs.int_subnet = i & ifs.int_subnetmask; if (ifs.int_subnetmask != ifs.int_netmask) ifs.int_flags |= IFF_SUBNET; ifp = (struct interface *)malloc(sizeof (struct interface)); if (ifp == 0) { printf("routed: out of memory\n"); break; } *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ if ((ifs.int_flags & IFF_LOOPBACK) == 0 && ((ifs.int_flags & IFF_POINTOPOINT) == 0 || if_ifwithaddr(&ifs.int_dstaddr) == 0)) externalinterfaces++; /* * If we have a point-to-point link, we want to act * as a supplier even if it's our only interface, * as that's the only way our peer on the other end * can tell that the link is up. */ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) supplier = 1; ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); if (ifp->int_name == 0) { fprintf(stderr, "routed: ifinit: out of memory\n"); syslog(LOG_ERR, "routed: ifinit: out of memory\n"); close(s); return; } strcpy(ifp->int_name, ifr->ifr_name); *ifnext = ifp; ifnext = &ifp->int_next; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; close(s); }
/* * This is called at startup and after that, every CHECK_INTERVAL seconds or * when a SIGHUP is received. */ void initifs(void) { static char *buf = NULL; static uint_t maxbufsize = 0; int bufsize; int numifs; struct lifnum lifn; struct lifconf lifc; struct lifreq lifr; struct lifreq *lifrp; int n; struct interface ifs; struct interface *ifp; int netmaskchange = 0; boolean_t changes = _B_FALSE; lifn.lifn_family = AF_INET6; lifn.lifn_flags = 0; if (ioctl(iocsoc, SIOCGLIFNUM, (char *)&lifn) < 0) { syslog(LOG_ERR, "initifs: ioctl (get interface numbers): %m"); return; } numifs = lifn.lifn_count; bufsize = numifs * sizeof (struct lifreq); if (buf == NULL || bufsize > maxbufsize) { if (buf != NULL) free(buf); maxbufsize = bufsize; buf = (char *)malloc(maxbufsize); if (buf == NULL) { syslog(LOG_ERR, "initifs: out of memory"); return; } } lifc.lifc_family = AF_INET6; lifc.lifc_flags = 0; lifc.lifc_len = bufsize; lifc.lifc_buf = buf; if (ioctl(iocsoc, SIOCGLIFCONF, (char *)&lifc) < 0) { syslog(LOG_ERR, "initifs: ioctl (get interface configuration): %m"); return; } /* * Mark all of the currently known interfaces in order to determine * which of the these interfaces no longer exist. */ for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) ifp->int_flags |= RIP6_IFF_MARKED; lifrp = lifc.lifc_req; for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { bzero((char *)&ifs, sizeof (ifs)); (void) strncpy(lifr.lifr_name, lifrp->lifr_name, sizeof (lifr.lifr_name)); if (ioctl(iocsoc, SIOCGLIFFLAGS, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get interface flags): %m"); continue; } if (!(lifr.lifr_flags & IFF_IPV6) || !(lifr.lifr_flags & IFF_MULTICAST) || (lifr.lifr_flags & IFF_LOOPBACK)) continue; ifp = if_ifwithname(lifr.lifr_name); if (ifp != NULL) ifp->int_flags &= ~RIP6_IFF_MARKED; if (lifr.lifr_flags & IFF_POINTOPOINT) ifs.int_flags |= RIP6_IFF_POINTOPOINT; if (lifr.lifr_flags & IFF_NORTEXCH) ifs.int_flags |= RIP6_IFF_NORTEXCH; if (lifr.lifr_flags & IFF_PRIVATE) ifs.int_flags |= RIP6_IFF_PRIVATE; if (lifr.lifr_flags & IFF_UP) { ifs.int_flags |= RIP6_IFF_UP; } else { if (ifp != NULL) { if (ifp->int_flags & RIP6_IFF_UP) { /* * If there is an transition from up to * down for an exisiting interface, * increment the counter. */ ifp->int_transitions++; changes = _B_TRUE; } if_purge(ifp); } continue; } if (ifs.int_flags & RIP6_IFF_POINTOPOINT) { /* * For point-to-point interfaces, retrieve both the * local and the remote addresses. */ if (ioctl(iocsoc, SIOCGLIFADDR, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get interface address): " "%m"); continue; } ifs.int_addr = ((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr; if (ioctl(iocsoc, SIOCGLIFDSTADDR, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get destination address): " "%m"); continue; } ifs.int_dstaddr = ((struct sockaddr_in6 *) &lifr.lifr_dstaddr)->sin6_addr; ifs.int_prefix_length = IPV6_ABITS; } else { /* * For other interfaces, retreieve the prefix (including * the prefix length. */ if (ioctl(iocsoc, SIOCGLIFSUBNET, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get subnet prefix): %m"); continue; } /* * This should never happen but check for it in any case * since the kernel stores it as an signed integer. */ if (lifr.lifr_addrlen < 0 || lifr.lifr_addrlen > IPV6_ABITS) { syslog(LOG_ERR, "initifs: ioctl (get subnet prefix) " "returned invalid prefix length of %d", lifr.lifr_addrlen); continue; } ifs.int_prefix_length = lifr.lifr_addrlen; ifs.int_addr = ((struct sockaddr_in6 *) &lifr.lifr_subnet)->sin6_addr; } if (ioctl(iocsoc, SIOCGLIFMETRIC, (char *)&lifr) < 0 || lifr.lifr_metric < 0) ifs.int_metric = 1; else ifs.int_metric = lifr.lifr_metric + 1; if (ioctl(iocsoc, SIOCGLIFINDEX, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get index): %m"); continue; } ifs.int_ifindex = lifr.lifr_index; if (ioctl(iocsoc, SIOCGLIFMTU, (char *)&lifr) < 0) { syslog(LOG_ERR, "initifs: ioctl (get mtu): %m"); continue; } /* * If the interface's recorded MTU doesn't make sense, use * IPV6_MIN_MTU instead. */ if (lifr.lifr_mtu < IPV6_MIN_MTU) ifs.int_mtu = IPV6_MIN_MTU; else ifs.int_mtu = lifr.lifr_mtu; if (ifp != NULL) { /* * RIP6_IFF_NORTEXCH flag change by itself shouldn't * cause an if_purge() call, which also purges all the * routes heard off this interface. So, let's suppress * changes of RIP6_IFF_NORTEXCH in the following * comparisons. */ if (ifp->int_prefix_length == ifs.int_prefix_length && ((ifp->int_flags | RIP6_IFF_NORTEXCH) == (ifs.int_flags | RIP6_IFF_NORTEXCH)) && ifp->int_metric == ifs.int_metric && ifp->int_ifindex == ifs.int_ifindex) { /* * Now let's make sure we capture the latest * value of RIP6_IFF_NORTEXCH flag. */ if (ifs.int_flags & RIP6_IFF_NORTEXCH) ifp->int_flags |= RIP6_IFF_NORTEXCH; else ifp->int_flags &= ~RIP6_IFF_NORTEXCH; if (!(ifp->int_flags & RIP6_IFF_POINTOPOINT) && IN6_ARE_ADDR_EQUAL(&ifp->int_addr, &ifs.int_addr)) continue; if ((ifp->int_flags & RIP6_IFF_POINTOPOINT) && IN6_ARE_ADDR_EQUAL(&ifp->int_dstaddr, &ifs.int_dstaddr)) continue; } if_purge(ifp); if (ifp->int_prefix_length != ifs.int_prefix_length) netmaskchange = 1; ifp->int_addr = ifs.int_addr; ifp->int_dstaddr = ifs.int_dstaddr; ifp->int_metric = ifs.int_metric; /* * If there is an transition from down to up for an * exisiting interface, increment the counter. */ if (!(ifp->int_flags & RIP6_IFF_UP) && (ifs.int_flags & RIP6_IFF_UP)) ifp->int_transitions++; ifp->int_flags |= ifs.int_flags; ifp->int_prefix_length = ifs.int_prefix_length; /* * If the interface index has changed, we may need to * set up the listen socket again. */ if (ifp->int_ifindex != ifs.int_ifindex) { if (ifp->int_sock != -1) { resetup_listen_sock(ifp, ifs.int_ifindex); } ifp->int_ifindex = ifs.int_ifindex; } ifp->int_mtu = ifs.int_mtu; } else { char *cp; int log_num; ifp = (struct interface *) malloc(sizeof (struct interface)); if (ifp == NULL) { syslog(LOG_ERR, "initifs: out of memory"); return; } *ifp = ifs; ifp->int_name = ifp->int_ifbase = NULL; ifp->int_name = (char *)malloc((size_t)strlen(lifr.lifr_name) + 1); if (ifp->int_name == NULL) { free(ifp); syslog(LOG_ERR, "initifs: out of memory"); return; } (void) strcpy(ifp->int_name, lifr.lifr_name); ifp->int_ifbase = (char *)malloc((size_t)strlen(lifr.lifr_name) + 1); if (ifp->int_ifbase == NULL) { free(ifp->int_name); free(ifp); syslog(LOG_ERR, "initifs: out of memory"); return; } (void) strcpy(ifp->int_ifbase, lifr.lifr_name); cp = (char *)index(ifp->int_ifbase, IF_SEPARATOR); if (cp != NULL) { /* * Verify that the value following the separator * is an integer greater than zero (the only * possible value for a logical interface). */ log_num = atoi((char *)(cp + 1)); if (log_num <= 0) { free(ifp->int_ifbase); free(ifp->int_name); free(ifp); syslog(LOG_ERR, "initifs: interface name %s could " "not be parsed", ifp->int_name); return; } *cp = '\0'; } else { log_num = 0; } if (log_num == 0) { ifp->int_sock = setup_listen_sock(ifp->int_ifindex); } else { ifp->int_sock = -1; } ifp->int_next = ifnet; ifnet = ifp; traceinit(ifp); } addrouteforif(ifp); changes = _B_TRUE; } /* * Any remaining interfaces that are still marked and which were in an * up state (RIP6_IFF_UP) need to removed from the routing table. */ for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { if ((ifp->int_flags & (RIP6_IFF_MARKED | RIP6_IFF_UP)) == (RIP6_IFF_MARKED | RIP6_IFF_UP)) { if_purge(ifp); ifp->int_flags &= ~RIP6_IFF_MARKED; changes = _B_TRUE; } } if (netmaskchange) rtchangeall(); if (supplier & changes) dynamic_update((struct interface *)NULL); }
void gwkludge(void) { struct sockaddr_in dst, gate; FILE *fp; char *type, *dname, *gname, *qual, buf[BUFSIZ]; struct interface *ifp; int metric, n; struct rt_entry route; fp = fopen(_PATH_GATEWAYS, "r"); if (fp == NULL) return; qual = buf; dname = buf + 64; gname = buf + ((BUFSIZ - 64) / 3); type = buf + (((BUFSIZ - 64) * 2) / 3); memset(&dst, 0, sizeof (dst)); memset(&gate, 0, sizeof (gate)); memset(&route, 0, sizeof(route)); /* format: {net | host} XX gateway XX metric DD [passive | external]\n */ #define readentry(fp) \ fscanf((fp), "%s %s gateway %s metric %d %s\n", \ type, dname, gname, &metric, qual) for (;;) { if ((n = readentry(fp)) == EOF) break; /* * Lusertrap. Vendors should ship the line * * CONFIGME CONFIGME gateway CONFIGME metric 1 * */ if (strcmp(type,"CONFIGME")==0) { fprintf(stderr,"Not starting gated. Please configure first.\n"); exit(1); } if (!getnetorhostname(type, dname, &dst)) continue; if (!gethostnameornumber(gname, &gate)) continue; if (metric == 0) /* XXX */ metric = 1; if (strcmp(qual, "passive") == 0) { /* * Passive entries aren't placed in our tables, * only the kernel's, so we don't copy all of the * external routing information within a net. * Internal machines should use the default * route to a suitable gateway (like us). */ route.rt_dst = *(struct sockaddr *) &dst; route.rt_router = *(struct sockaddr *) &gate; route.rt_flags = RTF_UP; if (strcmp(type, "host") == 0) route.rt_flags |= RTF_HOST; if (metric) route.rt_flags |= RTF_GATEWAY; (void) rtioctl(ADD, &route.rt_rt); continue; } if (strcmp(qual, "external") == 0) { /* * Entries marked external are handled * by other means, e.g. EGP, * and are placed in our tables only * to prevent overriding them * with something else. */ rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, metric, RTS_EXTERNAL|RTS_PASSIVE); continue; } /* assume no duplicate entries */ externalinterfaces++; ifp = (struct interface *)malloc(sizeof (*ifp)); memset(ifp, 0, sizeof (*ifp)); ifp->int_flags = IFF_REMOTE; /* can't identify broadcast capability */ ifp->int_net = inet_netof_subnet(dst.sin_addr); if (strcmp(type, "host") == 0) { ifp->int_flags |= IFF_POINTOPOINT; ifp->int_dstaddr = *((struct sockaddr *)&dst); } ifp->int_addr = *((struct sockaddr *)&gate); ifp->int_metric = metric; ifp->int_next = ifnet; ifnet = ifp; addrouteforif(ifp); } fclose(fp); }
/* * Find the network interfaces which have configured themselves. * If the interface is present but not yet up (for example an * ARPANET IMP), set the lookforinterfaces flag so we'll * come back later and look again. */ void ifinit(void) { struct interface ifs, *ifp; size_t needed; int mib[6], no_ipxaddr = 0, flags = 0; char *buf, *cplim, *cp; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl = NULL; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_IPX; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) lookforinterfaces = 0; cplim = buf + needed; for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { ifm = (struct if_msghdr *)cp; if (ifm->ifm_type == RTM_IFINFO) { bzero(&ifs, sizeof(ifs)); ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE; if ((flags & IFF_UP) == 0 || no_ipxaddr) lookforinterfaces = 1; sdl = (struct sockaddr_dl *) (ifm + 1); sdl->sdl_data[sdl->sdl_nlen] = 0; no_ipxaddr = 1; continue; } if (ifm->ifm_type != RTM_NEWADDR) quit("ifinit: out of sync"); if ((flags & IFF_UP) == 0) continue; ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); if (ifaaddr == 0) { syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); continue; } ifs.int_addr = *ifaaddr; if (ifs.int_addr.sa_family != AF_IPX) continue; no_ipxaddr = 0; if (ifs.int_flags & IFF_POINTOPOINT) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get dstaddr)", sdl->sdl_data); continue; } if (brdaddr->sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_BROADCAST) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get broadaddr)", sdl->sdl_data); continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_LOOPBACK) { ifs.int_dstaddr = ifs.int_addr; } /* * already known to us? * what makes a POINTOPOINT if unique is its dst addr, * NOT its source address */ if ( ((ifs.int_flags & IFF_POINTOPOINT) && if_ifwithdstaddr(&ifs.int_dstaddr)) || ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && if_ifwithaddr(&ifs.int_addr))) continue; ifp = (struct interface *) malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); if (ifp == NULL) { syslog(LOG_ERR, "IPXrouted: out of memory\n"); lookforinterfaces = 1; break; } *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || if_ifwithaddr(&ifs.int_dstaddr) == 0) externalinterfaces++; /* * If we have a point-to-point link, we want to act * as a supplier even if it's our only interface, * as that's the only way our peer on the other end * can tell that the link is up. */ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) supplier = 1; ifp->int_name = (char *)(ifp + 1); strcpy(ifp->int_name, sdl->sdl_data); ifp->int_metric = ifam->ifam_metric; ifp->int_next = ifnet; ifnet = ifp; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; free(buf); }