Ejemplo n.º 1
0
int
if_route6(const struct rt6 *rt, int action)
{
	union sockunion {
		struct sockaddr sa;
		struct sockaddr_in6 sin;
		struct sockaddr_dl sdl;
		struct sockaddr_storage ss;
	} su;
	struct rtm
	{
		struct rt_msghdr hdr;
		char buffer[sizeof(su) * 4];
	} rtm;
	char *bp = rtm.buffer;
	size_t l;
	int retval = 0;
	const struct ipv6_addr_l *lla;

/* KAME based systems want to store the scope inside the sin6_addr
 * for link local addreses */
#ifdef __KAME__
#define SCOPE {								      \
		if (IN6_IS_ADDR_LINKLOCAL(&su.sin.sin6_addr)) {		      \
			uint16_t scope = htons(su.sin.sin6_scope_id);	      \
			memcpy(&su.sin.sin6_addr.s6_addr[2], &scope,	      \
			    sizeof(scope));				      \
			su.sin.sin6_scope_id = 0;			      \
		}							      \
	}
#else
#define SCOPE
#endif

#define ADDSU {								      \
		l = RT_ROUNDUP(su.sa.sa_len);				      \
		memcpy(bp, &su, l);					      \
		bp += l;						      \
	}
#define ADDADDRS(addr, scope) {						      \
		memset(&su, 0, sizeof(su));				      \
		su.sin.sin6_family = AF_INET6;				      \
		su.sin.sin6_len = sizeof(su.sin);			      \
		(&su.sin)->sin6_addr = *addr;				      \
		su.sin.sin6_scope_id = scope;				      \
		SCOPE;							      \
		ADDSU;							      \
	}
#define ADDADDR(addr) ADDADDRS(addr, 0)

	memset(&rtm, 0, sizeof(rtm));
	rtm.hdr.rtm_version = RTM_VERSION;
	rtm.hdr.rtm_seq = 1;
	if (action == 0)
		rtm.hdr.rtm_type = RTM_CHANGE;
	else if (action > 0)
		rtm.hdr.rtm_type = RTM_ADD;
	else
		rtm.hdr.rtm_type = RTM_DELETE;

	rtm.hdr.rtm_flags = RTF_UP;
	/* None interface subnet routes are static. */
	if (IN6_IS_ADDR_UNSPECIFIED(&rt->dest) &&
	    IN6_IS_ADDR_UNSPECIFIED(&rt->net))
		rtm.hdr.rtm_flags |= RTF_GATEWAY;
#ifdef RTF_CLONING
	else
		rtm.hdr.rtm_flags |= RTF_CLONING;
#endif

	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
	if (action >= 0)
		rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;

	ADDADDR(&rt->dest);
	if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) {
		lla = ipv6_linklocal(rt->iface);
		if (lla == NULL) /* unlikely as we need a LL to get here */
			return -1;
		ADDADDRS(&lla->addr, rt->iface->index);
	} else {
		lla = NULL;
		ADDADDRS(&rt->gate, rt->iface->index);
	}

	if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
		if (rtm.hdr.rtm_flags & RTF_GATEWAY) {
			memset(&su, 0, sizeof(su));
			su.sin.sin6_family = AF_INET6;
			ADDSU;
		} else
			ADDADDR(&rt->net);
	}

	if (rtm.hdr.rtm_addrs & RTA_IFP) {
		/* Make us a link layer socket for the host gateway */
		memset(&su, 0, sizeof(su));
		su.sdl.sdl_len = sizeof(struct sockaddr_dl);
		link_addr(rt->iface->name, &su.sdl);
		ADDSU;
	}

	if (rtm.hdr.rtm_addrs & RTA_IFA) {
		if (lla == NULL) {
			lla = ipv6_linklocal(rt->iface);
			if (lla == NULL) /* unlikely */
				return -1;
		}
		ADDADDRS(&lla->addr, rt->iface->index);
	}

#undef ADDADDR
#undef ADDSU
#undef SCOPE

	if (action >= 0 && rt->mtu) {
		rtm.hdr.rtm_inits |= RTV_MTU;
		rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
	}

	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
	if (write(r_fd, &rtm, l) == -1)
		retval = -1;
	return retval;
}
Ejemplo n.º 2
0
int
if_route6(const struct rt6 *rt, int action)
{
	union sockunion {
		struct sockaddr sa;
		struct sockaddr_in6 sin;
		struct sockaddr_dl sdl;
		struct sockaddr_storage ss;
	} su;
	struct rtm
	{
		struct rt_msghdr hdr;
		char buffer[sizeof(su) * 5];
	} rtm;
	char *bp = rtm.buffer;
	size_t l;
	int s, retval;
	const struct ipv6_addr *lla;

	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
		return -1;

#define ADDSU {								      \
		l = RT_ROUNDUP(su.sa.sa_len);				      \
		memcpy(bp, &su, l);					      \
		bp += l;						      \
	}
#define ADDADDRS(addr, scope) {						      \
		memset(&su, 0, sizeof(su));				      \
		su.sin.sin6_family = AF_INET6;				      \
		su.sin.sin6_len = sizeof(su.sin);			      \
		(&su.sin)->sin6_addr = *addr;				      \
		if (scope)						      \
			ifa_scope(&su.sin, scope);			      \
		ADDSU;							      \
	}
#define ADDADDR(addr) ADDADDRS(addr, 0)

	memset(&rtm, 0, sizeof(rtm));
	rtm.hdr.rtm_version = RTM_VERSION;
	rtm.hdr.rtm_seq = 1;
	if (action == 0)
		rtm.hdr.rtm_type = RTM_CHANGE;
	else if (action > 0)
		rtm.hdr.rtm_type = RTM_ADD;
	else
		rtm.hdr.rtm_type = RTM_DELETE;
	rtm.hdr.rtm_flags = RTF_UP | (int)rt->flags;
#ifdef RTF_PINNED
	if (rtm.hdr.rtm_type != RTM_ADD)
		rtm.hdr.rtm_flags |= RTF_PINNED;
#endif
	rtm.hdr.rtm_addrs = RTA_DST | RTA_NETMASK;
#ifdef SIOCGIFPRIORITY
	rtm.hdr.rtm_priority = rt->metric;
#endif
	/* None interface subnet routes are static. */
	if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
#ifdef RTF_CLONING
		rtm.hdr.rtm_flags |= RTF_CLONING;
#endif
	 } else
		rtm.hdr.rtm_flags |= RTF_GATEWAY | RTF_STATIC;

	if (action >= 0) {
		rtm.hdr.rtm_addrs |= RTA_GATEWAY;
		if (!(rtm.hdr.rtm_flags & RTF_REJECT))
			rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
	}

	ADDADDR(&rt->dest);
	lla = NULL;
	if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
		if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
			if_linkaddr(&su.sdl, rt->iface);
			ADDSU;
		} else {
			ADDADDRS(&rt->gate, rt->iface->index);
		}
	}

	if (rtm.hdr.rtm_addrs & RTA_NETMASK)
		ADDADDR(&rt->net);

	if (rtm.hdr.rtm_addrs & RTA_IFP) {
		if_linkaddr(&su.sdl, rt->iface);
		ADDSU;
	}

	if (rtm.hdr.rtm_addrs & RTA_IFA) {
		if (lla == NULL) {
			lla = ipv6_linklocal(rt->iface);
			if (lla == NULL) /* unlikely */
				return -1;
		}
		ADDADDRS(&lla->addr, rt->iface->index);
	}

#undef ADDADDR
#undef ADDSU

	if (action >= 0 && rt->mtu) {
		rtm.hdr.rtm_inits |= RTV_MTU;
		rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
	}

	rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);

	retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
	close(s);
	return retval;
}