/* * 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); }
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); }
/* * Reads kernel interface list and makes a copy for the local use. */ int initialize_interface(void) { size_t needed; int newif = FALSE, mib[6], flags = 0; char *buf, *cplim, *cp; struct interface *ifs, *ifp; struct preflist *plp = NULL; struct sockaddr_dl *sdl; register struct if_msghdr *ifm; register struct ifa_msghdr *ifam; int externalinterfaces = 0; /* I'm afraid of stack overflow. */ /* So work areas are malloc-ed. */ ifs = (struct interface *)malloc(sizeof(struct interface)); if (ifs == NULL) { syslog(LOG_ERR, "work area malloc: %m"); return -1; } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET6; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { free(ifs); syslog(LOG_ERR, "sysctl IFLIST 1 : %m"); return -1; } if ((buf = malloc(needed)) == NULL) { free(ifs); syslog(LOG_ERR, "sysctl IFLIST malloc : %m"); return -1; } if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); free(ifs); syslog(LOG_ERR, "sysctl IFLIST 2 : %m"); return -1; } for (ifp = ifnet; ifp; ifp = ifp->if_next) { for (plp = ifp->if_ip6addr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; for (plp = ifp->if_sladdr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; for (plp = ifp->if_lladdr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; } /* so, ifp is NULL now */ cplim = buf + needed; for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { ifm = (struct if_msghdr *)cp; if (ifm->ifm_type == RTM_IFINFO) { newif = FALSE; ifp = (struct interface *)NULL; if (ifm->ifm_addrs != RTA_IFP) continue; /* sanity check */ sdl = (struct sockaddr_dl *)(ifm + 1); if ((ifp = get_if_by_name(sdl)) == NULL) { /* Hack! */ /* IFF_RUNNING means 'has at least one linklocal' * <CAN_SEND> */ /* IFF_JOINED means 'joined multicast group' * <CAN_RECEIVE> */ flags = ifm->ifm_flags & ~(IFF_RUNNING | IFF_JOINED); if ((flags & IFF_UP) == 0) { ifp = NULL; continue; } bzero(ifs, sizeof(struct interface)); ifp = ifs; /* pointer copy */ newif = TRUE; /* already bzeroed, so trailing 0 is not needed */ strncpy(ifp->if_name, sdl->sdl_data, sdl->sdl_nlen); ifp->if_sdl = *sdl; /* struct copy */ ifp->if_flag = flags; } else { flags = ifm->ifm_flags; if ((flags & IFF_UP) == 0) { if (ifp->if_flag & IFF_JOINED) drop_multicast_group(ifp); ifp->if_flag = flags & ~(IFF_RUNNING | IFF_JOINED); /* if_freeaddresses( ifp ); */ /* free will be done in install_address */ ifp = NULL; continue; } if ((ifp->if_flag & IFF_UP) == 0) { /* wake up */ /* counter reset */ ifp->if_badpkt = ifp->if_badrte = ifp->if_updates = 0; } ifp->if_flag = (flags & ~(IFF_RUNNING | IFF_JOINED)) | (ifp->if_flag & (IFF_RUNNING | IFF_JOINED)); ifp->if_sdl = *sdl; /* maybe MAC address * was changed (?) */ } ifp->if_metrc = ifm->ifm_data.ifi_metric; /* maybe index was changed */ if_index(ifp) = ifm->ifm_index; ifp->if_lmtu = ifm->ifm_data.ifi_mtu; /* sanity check */ if (ifp->if_lmtu < (sizeof(struct rip6) + rt6_hdrlen + sizeof(struct route_entry))) { /* rt6_hdrlen may be HUGER than DEFAULT(576) */ ifp->if_flag &= ~IFF_UP; syslog(LOG_ERR, "Too small MTU"); ifp = NULL; newif = FALSE; } continue; } /* if(RTM_IFINFO) */ if (ifm->ifm_type != RTM_NEWADDR) { free(buf); free(ifs); syslog(LOG_ERR, "sysctl illegal data"); return -1; } if (ifp == NULL) continue; /* ifp without IFF_UP shall reach here */ /* First message is RTM_NEWADDR (not RTM_IFINFO) shall reach here */ ifam = (struct ifa_msghdr *)ifm; rtinfo.rti_addrs = ifam->ifam_addrs; plp = (struct preflist *)malloc(sizeof(struct preflist)); if (plp == NULL) { free(buf); free(ifs); syslog(LOG_ERR, "initialize_interface: malloc failed"); return -1; } bzero((void *)plp, sizeof(struct preflist)); if (get_address(ifam->ifam_addrs, (char *)(ifam + 1), (cp + ifam->ifam_msglen), plp) < 0) { free(plp); /* plp = NULL; */ continue; } if (flags & IFF_POINTOPOINT) { if (if_ifwithdstaddr(plp, ifp)) { /* address already on the interface list ( marked * OLDADDR ) */ free(plp); /* plp = NULL; */ continue; } } else { int i; #define vdst plp->pl_dest.s6_addr #define vsrc1 plp->pl_pref.prf_addr.s6_addr #define vsrc2 plp->pl_mask.s6_addr for (i = 0; i < sizeof(struct in6_addr); i++) vdst[i] = vsrc1[i] & vsrc2[i]; #undef vsrc2 #undef vsrc1 #undef vdst if (if_ifwithaddr(plp, ifp)) { /* address already on the interface list ( marked * OLDADDR ) */ free(plp); /* plp = NULL; */ continue; } } if (newif != FALSE) { if ((ifp = (struct interface *)malloc(sizeof(struct interface))) == NULL) { free(plp); free(buf); free(ifs); syslog(LOG_ERR, "initialize_interface: new if malloc :%m"); return -1; } *ifp = *ifs; /* struct copy */ ifp->if_next = ifnet; ifnet = ifp; newif = FALSE; /* CAUTION: this interface loop has * not been finished */ if ((ifp->if_flag & IFF_LOOPBACK) == 0) externalinterfaces++; } add_address(plp, ifp); /* plp = NULL; */ if (ifp->if_flag & IFF_LOOPBACK) foundloopback = 1; } /* for */ /* Unnumbered P2P check */ for (ifp = ifnet; ifp; ifp = ifp->if_next) { if (ifp->if_flag & IFF_POINTOPOINT && ifp->if_flag & IFF_UP) { for (plp = ifp->if_ip6addr; plp; plp = plp->pl_next) if (plp->pl_flag != PL_DELADDR) if_duplicate(plp, ifp); /* Duplicate address will be zeroed */ for (plp = ifp->if_sladdr; plp; plp = plp->pl_next) if (plp->pl_flag != PL_DELADDR) if_duplicate(plp, ifp); /* Duplicate address will be zeroed */ } } /* Even if we have only one (external) interface, RIPng works */ /* MODE_UNSPEC really needed ? */ if (externalinterfaces == 0) rt6_opmode = MODE_QUIET; free(buf); free(ifs); return 0; }