Exemplo n.º 1
0
/*
 * 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);
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
/* 
 * 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;
}