Ejemplo n.º 1
0
int
if_managelink(struct dhcpcd_ctx *ctx)
{
	/* route and ifwatchd like a msg buf size of 2048 */
	char msg[2048], *p, *e, *cp;
	ssize_t bytes;
	struct rt_msghdr *rtm;
	struct if_announcemsghdr *ifan;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa, *rti_info[RTAX_MAX];
	int len;
	struct sockaddr_dl sdl;
	struct interface *ifp;
#ifdef INET
	struct rt rt;
#endif
#ifdef INET6
	struct rt6 rt6;
	struct in6_addr ia6;
	struct sockaddr_in6 *sin6;
	int ifa_flags;
#endif

	bytes = read(ctx->link_fd, msg, sizeof(msg));
	if (bytes == -1)
		return -1;
	if (bytes == 0)
		return 0;
	e = msg + bytes;
	for (p = msg; p < e; p += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)(void *)p;
		// Ignore messages generated by us
		if (rtm->rtm_pid == getpid())
			break;
		switch(rtm->rtm_type) {
#ifdef RTM_IFANNOUNCE
		case RTM_IFANNOUNCE:
			ifan = (struct if_announcemsghdr *)(void *)p;
			switch(ifan->ifan_what) {
			case IFAN_ARRIVAL:
				dhcpcd_handleinterface(ctx, 1,
				    ifan->ifan_name);
				break;
			case IFAN_DEPARTURE:
				dhcpcd_handleinterface(ctx, -1,
				    ifan->ifan_name);
				break;
			}
			break;
#endif
		case RTM_IFINFO:
			ifm = (struct if_msghdr *)(void *)p;
			if ((ifp = if_findindex(ctx, ifm->ifm_index)) == NULL)
				break;
			switch (ifm->ifm_data.ifi_link_state) {
			case LINK_STATE_DOWN:
				len = LINK_DOWN;
				break;
			case LINK_STATE_UP:
				len = LINK_UP;
				break;
			default:
				/* handle_carrier will re-load
				 * the interface flags and check for
				 * IFF_RUNNING as some drivers that
				 * don't handle link state also don't
				 * set IFF_RUNNING when this routing
				 * message is generated.
				 * As such, it is a race ...*/
				len = LINK_UNKNOWN;
				break;
			}
			dhcpcd_handlecarrier(ctx, len,
			    (unsigned int)ifm->ifm_flags, ifp->name);
			break;
		case RTM_DELETE:
			if (~rtm->rtm_addrs &
			    (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
				break;
			cp = (char *)(void *)(rtm + 1);
			sa = (struct sockaddr *)(void *)cp;
			get_addrs(rtm->rtm_addrs, cp, rti_info);
			switch (sa->sa_family) {
#ifdef INET
			case AF_INET:
				memset(&rt, 0, sizeof(rt));
				rt.iface = NULL;
				COPYOUT(rt.dest, rti_info[RTAX_DST]);
				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
				COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
				ipv4_routedeleted(ctx, &rt);
				break;
#endif
#ifdef INET6
			case AF_INET6:
				memset(&rt6, 0, sizeof(rt6));
				rt6.iface = NULL;
				COPYOUT6(rt6.dest, rti_info[RTAX_DST]);
				COPYOUT6(rt6.net, rti_info[RTAX_NETMASK]);
				COPYOUT6(rt6.gate, rti_info[RTAX_GATEWAY]);
				ipv6_routedeleted(ctx, &rt6);
				break;
#endif
			}
#ifdef RTM_CHGADDR
		case RTM_CHGADDR:	/* FALLTHROUGH */
#endif
		case RTM_DELADDR:	/* FALLTHROUGH */
		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)p;
			if ((ifp = if_findindex(ctx, ifam->ifam_index)) == NULL)
				break;
			cp = (char *)(void *)(ifam + 1);
			get_addrs(ifam->ifam_addrs, cp, rti_info);
			if (rti_info[RTAX_IFA] == NULL)
				break;
			switch (rti_info[RTAX_IFA]->sa_family) {
			case AF_LINK:
#ifdef RTM_CHGADDR
				if (rtm->rtm_type != RTM_CHGADDR)
					break;
#else
				if (rtm->rtm_type != RTM_NEWADDR)
					break;
#endif
				memcpy(&sdl, rti_info[RTAX_IFA],
				    rti_info[RTAX_IFA]->sa_len);
				dhcpcd_handlehwaddr(ctx, ifp->name,
				    (const unsigned char*)CLLADDR(&sdl),
				    sdl.sdl_alen);
				break;
#ifdef INET
			case AF_INET:
			case 255: /* FIXME: Why 255? */
				COPYOUT(rt.dest, rti_info[RTAX_IFA]);
				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
				COPYOUT(rt.gate, rti_info[RTAX_BRD]);
				ipv4_handleifa(ctx, rtm->rtm_type,
				    NULL, ifp->name,
				    &rt.dest, &rt.net, &rt.gate);
				break;
#endif
#ifdef INET6
			case AF_INET6:
				sin6 = (struct sockaddr_in6*)(void *)
				    rti_info[RTAX_IFA];
				ia6 = sin6->sin6_addr;
#ifdef __KAME__
				if (IN6_IS_ADDR_LINKLOCAL(&ia6))
					ia6.s6_addr[2] = ia6.s6_addr[3] = '\0';
#endif
				if (rtm->rtm_type == RTM_NEWADDR) {
					ifa_flags = if_addrflags6(&ia6, ifp);
					if (ifa_flags == -1)
						break;
				} else
					ifa_flags = 0;
				ipv6_handleifa(ctx, rtm->rtm_type, NULL,
				    ifp->name, &ia6, ifa_flags);
				break;
#endif
			}
			break;
		}
	}

	return 0;
}
Ejemplo n.º 2
0
static int
link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
{
	size_t len;
	struct rtattr *rta;
	struct ifaddrmsg *ifa;
	struct priv *priv;
#ifdef INET
	struct in_addr addr, net, brd;
#endif
#ifdef INET6
	struct in6_addr addr6;
#endif

	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
		return 0;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if (len < sizeof(*ifa)) {
		errno = EBADMSG;
		return -1;
	}

	/* Ignore messages we sent. */
	priv = (struct priv*)ctx->priv;
	if (nlm->nlmsg_pid == priv->route_pid)
		return 0;

	ifa = NLMSG_DATA(nlm);
	if ((ifp = if_findindex(ctx->ifaces, ifa->ifa_index)) == NULL) {
		/* We don't know about the interface the address is for
		 * so it's not really an error */
		return 1;
	}
	rta = (struct rtattr *)IFA_RTA(ifa);
	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
	switch (ifa->ifa_family) {
#ifdef INET
	case AF_INET:
		addr.s_addr = brd.s_addr = INADDR_ANY;
		inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				if (ifp->flags & IFF_POINTOPOINT) {
					memcpy(&brd.s_addr, RTA_DATA(rta),
					    sizeof(brd.s_addr));
				}
				break;
			case IFA_BROADCAST:
				memcpy(&brd.s_addr, RTA_DATA(rta),
				    sizeof(brd.s_addr));
				break;
			case IFA_LOCAL:
				memcpy(&addr.s_addr, RTA_DATA(rta),
				    sizeof(addr.s_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv4_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
		    &addr, &net, &brd, ifa->ifa_flags, (pid_t)nlm->nlmsg_pid);
		break;
#endif
#ifdef INET6
	case AF_INET6:
		memset(&addr6, 0, sizeof(addr6));
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				memcpy(&addr6.s6_addr, RTA_DATA(rta),
				       sizeof(addr6.s6_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
		    &addr6, ifa->ifa_prefixlen, ifa->ifa_flags,
		    (pid_t)nlm->nlmsg_pid);
		break;
#endif
	}
	return 0;
}
Ejemplo n.º 3
0
static int
link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
    struct nlmsghdr *nlm)
{
	int r;
	size_t len;
	struct rtattr *rta, *hwaddr;
	struct ifinfomsg *ifi;
	char ifn[IF_NAMESIZE + 1];

	r = link_route(ctx, ifp, nlm);
	if (r != 0)
		return r;
	r = link_addr(ctx, ifp, nlm);
	if (r != 0)
		return r;
#ifdef INET6
	r = link_neigh(ctx, ifp, nlm);
	if (r != 0)
		return r;
#endif

	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
		return 0;
	len = nlm->nlmsg_len - sizeof(*nlm);
	if ((size_t)len < sizeof(*ifi)) {
		errno = EBADMSG;
		return -1;
	}
	ifi = NLMSG_DATA(nlm);
	if (ifi->ifi_flags & IFF_LOOPBACK)
		return 0;
	rta = (void *)((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
	*ifn = '\0';
	hwaddr = NULL;

	while (RTA_OK(rta, len)) {
		switch (rta->rta_type) {
		case IFLA_WIRELESS:
			/* Ignore wireless messages */
			if (nlm->nlmsg_type == RTM_NEWLINK &&
			    ifi->ifi_change == 0)
				return 0;
			break;
		case IFLA_IFNAME:
			strlcpy(ifn, (char *)RTA_DATA(rta), sizeof(ifn));
			break;
		case IFLA_ADDRESS:
			hwaddr = rta;
			break;
		}
		rta = RTA_NEXT(rta, len);
	}

	if (nlm->nlmsg_type == RTM_DELLINK) {
		/* If are listening to a dev manager, let that remove
		 * the interface rather than the kernel. */
		if (dev_listening(ctx) < 1)
			dhcpcd_handleinterface(ctx, -1, ifn);
		return 0;
	}

	/* Virtual interfaces may not get a valid hardware address
	 * at this point.
	 * To trigger a valid hardware address pickup we need to pretend
	 * that that don't exist until they have one. */
	if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
		dhcpcd_handleinterface(ctx, -1, ifn);
		return 0;
	}

	/* Check for a new interface */
	ifp = if_findindex(ctx->ifaces, (unsigned int)ifi->ifi_index);
	if (ifp == NULL) {
		/* If are listening to a dev manager, let that announce
		 * the interface rather than the kernel. */
		if (dev_listening(ctx) < 1)
			dhcpcd_handleinterface(ctx, 1, ifn);
		return 0;
	}

	/* Handle interface being renamed */
	if (strcmp(ifp->name, ifn) != 0) {
		dhcpcd_handleinterface(ctx, -1, ifn);
		dhcpcd_handleinterface(ctx, 1, ifn);
		return 0;
	}

	/* Re-read hardware address and friends */
	if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
		uint8_t l;

		l = l2addr_len(ifi->ifi_type);
		if (hwaddr->rta_len == RTA_LENGTH(l))
			dhcpcd_handlehwaddr(ctx, ifn, RTA_DATA(hwaddr), l);
	}

	dhcpcd_handlecarrier(ctx,
	    ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
	    ifi->ifi_flags, ifn);
	return 0;
}
Ejemplo n.º 4
0
static int
if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
{
	size_t len;
	struct rtmsg *rtm;
	struct rtattr *rta;
	unsigned int ifindex;
	struct sockaddr *sa;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if (len < sizeof(*rtm)) {
		errno = EBADMSG;
		return -1;
	}
	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
	if (rtm->rtm_table != RT_TABLE_MAIN)
		return -1;

	memset(rt, 0, sizeof(*rt));
	if (rtm->rtm_type == RTN_UNREACHABLE)
		rt->rt_flags |= RTF_REJECT;

	rta = (struct rtattr *)RTM_RTA(rtm);
	len = RTM_PAYLOAD(nlm);
	while (RTA_OK(rta, len)) {
		sa = NULL;
		switch (rta->rta_type) {
		case RTA_DST:
			sa = &rt->rt_dest;
			break;
		case RTA_GATEWAY:
			sa = &rt->rt_gateway;
			break;
		case RTA_PREFSRC:
			sa = &rt->rt_ifa;
			break;
		case RTA_OIF:
			ifindex = *(unsigned int *)RTA_DATA(rta);
			rt->rt_ifp = if_findindex(ctx->ifaces, ifindex);
			break;
		case RTA_PRIORITY:
			rt->rt_metric = *(unsigned int *)RTA_DATA(rta);
			break;
		case RTA_METRICS:
		{
			struct rtattr *r2;
			size_t l2;

			l2 = rta->rta_len;
			r2 = (struct rtattr *)RTA_DATA(rta);
			while (RTA_OK(r2, l2)) {
				switch (r2->rta_type) {
				case RTAX_MTU:
					rt->rt_mtu = *(unsigned int *)RTA_DATA(r2);
					break;
				}
				r2 = RTA_NEXT(r2, l2);
			}
			break;
		}
		}

		if (sa != NULL) {
			socklen_t salen;

			sa->sa_family = rtm->rtm_family;
			salen = sa_addrlen(sa);
			memcpy((char *)sa + sa_addroffset(sa), RTA_DATA(rta),
			    MIN(salen, RTA_PAYLOAD(rta)));
		}

		rta = RTA_NEXT(rta, len);
	}

	/* If no RTA_DST set the unspecified address for the family. */
	if (rt->rt_dest.sa_family == AF_UNSPEC)
		rt->rt_dest.sa_family = rtm->rtm_family;

	rt->rt_netmask.sa_family = rtm->rtm_family;
	sa_fromprefix(&rt->rt_netmask, rtm->rtm_dst_len);
	if (sa_is_allones(&rt->rt_netmask))
		rt->rt_flags |= RTF_HOST;

	#if 0
	if (rt->rtp_ifp == NULL && rt->src.s_addr != INADDR_ANY) {
		struct ipv4_addr *ap;

		/* For some reason the default route comes back with the
		 * loopback interface in RTA_OIF? Lets find it by
		 * preferred source address */
		if ((ap = ipv4_findaddr(ctx, &rt->src)))
			rt->iface = ap->iface;
	}
	#endif

	if (rt->rt_ifp == NULL) {
		errno = ESRCH;
		return -1;
	}
	return 0;
}