예제 #1
0
/* Add/Delete IP rule to/from a specific IP/network */
int
netlink_rule(ip_rule_t *iprule, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len    = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags  = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
	req.n.nlmsg_type   = cmd ? RTM_NEWRULE : RTM_DELRULE;
	req.r.rtm_family   = IP_FAMILY(iprule->addr);
	if (iprule->table < 256)
		req.r.rtm_table = iprule->table ? iprule->table : RT_TABLE_MAIN;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), FRA_TABLE, iprule->table);
	}
	req.r.rtm_type     = RTN_UNSPEC;
	req.r.rtm_scope    = RT_SCOPE_UNIVERSE;
	req.r.rtm_flags    = 0;

	if (cmd) {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_type     = RTN_UNICAST;
	}

	/* Set rule entry */
	if (iprule->dir == VRRP_RULE_FROM) {
		req.r.rtm_src_len = iprule->mask;
		add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->addr);
	} else if (iprule->dir == VRRP_RULE_TO) {
		req.r.rtm_dst_len = iprule->mask;
		add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->addr);
	}

	if (netlink_talk(&nl_cmd, &req.n) < 0)
		status = -1;
	return status;
}
예제 #2
0
/* Add/Delete IP route to/from a specific interface */
static int
netlink_route(ip_route_t *iproute, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;

	char buf[1024];
	struct rtattr *rta = (void*)buf;
	struct rtnexthop *rtnh;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
	req.n.nlmsg_type  = cmd ? RTM_NEWROUTE : RTM_DELROUTE;
	req.r.rtm_family  = (iproute->dst) ? IP_FAMILY(iproute->dst) :
			    (iproute->src) ? IP_FAMILY(iproute->src) :
			    AF_INET;
	if (iproute->table < 256)
		req.r.rtm_table   = iproute->table ? iproute->table : RT_TABLE_MAIN;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table);
	}
	req.r.rtm_scope   = RT_SCOPE_NOWHERE;

	if (cmd == IPROUTE_ADD) {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_scope = iproute->scope;
		req.r.rtm_type = RTN_UNICAST;
	}
	if (iproute->blackhole)
		req.r.rtm_type = RTN_BLACKHOLE;

	/* Set routing entry */
	if (iproute->dst) {
		req.r.rtm_dst_len = iproute->dmask;
		add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst);
	}
	if ((!iproute->blackhole) && (!iproute->gw2))
		add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->gw);
	if (iproute->gw && iproute->gw2) {
		rta->rta_type = RTA_MULTIPATH;
		rta->rta_len = RTA_LENGTH(0);
		rtnh = RTA_DATA(rta);
#define MULTIPATH_ADD_GW(x) \
	memset(rtnh, 0, sizeof(*rtnh)); \
	rtnh->rtnh_len = sizeof(*rtnh); \
	if (iproute->index) rtnh->rtnh_ifindex = iproute->index; \
	rta->rta_len += rtnh->rtnh_len;	\
	add_addr2rta(rta, 1024, RTA_GATEWAY, x); \
	rtnh->rtnh_len += sizeof(struct rtattr) + IP_SIZE(x); \
	rtnh = RTNH_NEXT(rtnh);
		MULTIPATH_ADD_GW(iproute->gw);
		MULTIPATH_ADD_GW(iproute->gw2);
		addattr_l(&req.n, sizeof(req), RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}
	if ((iproute->index) && (!iproute->gw2))
		addattr32(&req.n, sizeof(req), RTA_OIF, iproute->index);
	if (iproute->src)
		add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->src);
	if (iproute->metric)
		addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric);

	/* This returns ESRCH if the address of via address doesn't exist */
	/* ENETDOWN if dev p33p1.40 for example is down */
	if (netlink_talk(&nl_cmd, &req.n) < 0)
		status = -1;
	return status;
}
예제 #3
0
/* Add/Delete IP route to/from a specific interface */
static int
netlink_route(ip_route_t *iproute, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[RTM_SIZE];
	} req;
	char buf[RTA_SIZE];
	struct rtattr *rta = (void*)buf;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
	if (cmd == IPROUTE_DEL) {
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type  = RTM_DELROUTE;
	}
	else {
		req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
		if (cmd == IPROUTE_REPLACE)
			req.n.nlmsg_flags |= NLM_F_REPLACE;
		req.n.nlmsg_type  = RTM_NEWROUTE;
	}

	rta->rta_type = RTA_METRICS;
	rta->rta_len = RTA_LENGTH(0);

	req.r.rtm_family = iproute->family;
	if (iproute->table < 256)
		req.r.rtm_table = iproute->table;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table);
	}

	if (cmd == IPROUTE_DEL) {
		req.r.rtm_scope = RT_SCOPE_NOWHERE;
		if (iproute->mask & IPROUTE_BIT_TYPE)
			req.r.rtm_type = iproute->type;
	}
	else {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
		req.r.rtm_type = iproute->type;
	}

	if (iproute->mask & IPROUTE_BIT_PROTOCOL)
		req.r.rtm_protocol = iproute->protocol;

	if (iproute->mask & IPROUTE_BIT_SCOPE)
		req.r.rtm_scope = iproute->scope;

	if (iproute->dst) {
		req.r.rtm_dst_len = iproute->dst->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst);
	}

	if (iproute->src) {
		req.r.rtm_src_len = iproute->src->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_SRC, iproute->src);
	}

	if (iproute->pref_src)
		add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->pref_src);

//#ifdef _HAVE_RTA_NEWDST_
//	if (iproute->as_to)
//		add_addr2req(&req.n, sizeof(req), RTA_NEWDST, iproute->as_to);
//#endif

	if (iproute->via) {
		if (iproute->via->ifa.ifa_family == iproute->family)
			add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->via);
#ifdef _HAVE_RTA_VIA_
		else
			add_addr_fam2req(&req.n, sizeof(req), RTA_VIA, iproute->via);
#endif
	}

#ifdef _HAVE_RTA_ENCAP_
	if (iproute->encap.type != LWTUNNEL_ENCAP_NONE) {
		char encap_buf[ENCAP_RTA_SIZE];
		struct rtattr *encap_rta = (void *)encap_buf;

		encap_rta->rta_type = RTA_ENCAP;
		encap_rta->rta_len = RTA_LENGTH(0);
		add_encap(encap_rta, sizeof(encap_buf), &iproute->encap);

		if (encap_rta->rta_len > RTA_LENGTH(0))
			addraw_l(&req.n, sizeof(encap_buf), RTA_DATA(encap_rta), RTA_PAYLOAD(encap_rta));
	}
#endif

	if (iproute->mask & IPROUTE_BIT_DSFIELD)
		req.r.rtm_tos = iproute->tos;
	
	if (iproute->oif)
		addattr32(&req.n, sizeof(req), RTA_OIF, iproute->oif->ifindex);

	if (iproute->mask & IPROUTE_BIT_METRIC)
		addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric);

	req.r.rtm_flags = iproute->flags;

	if (iproute->realms)
		addattr32(&req.n, sizeof(req), RTA_FLOW, iproute->realms);

#ifdef _HAVE_RTA_EXPIRES_
	if (iproute->mask & IPROUTE_BIT_EXPIRES)
		addattr32(&req.n, sizeof(req), RTA_EXPIRES, iproute->expires);
#endif

#ifdef RTAX_CC_ALGO
	if (iproute->congctl)
		rta_addattr_l(rta, sizeof(buf), RTAX_CC_ALGO, iproute->congctl, strlen(iproute->congctl));
#endif

	if (iproute->mask & IPROUTE_BIT_RTT)
		rta_addattr32(rta, sizeof(buf), RTAX_RTT, iproute->rtt);

	if (iproute->mask & IPROUTE_BIT_RTTVAR)
		rta_addattr32(rta, sizeof(buf), RTAX_RTTVAR, iproute->rttvar);

	if (iproute->mask & IPROUTE_BIT_RTO_MIN)
		rta_addattr32(rta, sizeof(buf), RTAX_RTO_MIN, iproute->rto_min);

#ifdef RTAX_FEATURES
	if (iproute->features)
		rta_addattr32(rta, sizeof(buf), RTAX_FEATURES, iproute->features);
#endif

	if (iproute->mask & IPROUTE_BIT_MTU)
		rta_addattr32(rta, sizeof(buf), RTAX_MTU, iproute->mtu);

	if (iproute->mask & IPROUTE_BIT_WINDOW)
		rta_addattr32(rta, sizeof(buf), RTAX_WINDOW, iproute->window);

	if (iproute->mask & IPROUTE_BIT_SSTHRESH)
		rta_addattr32(rta, sizeof(buf), RTAX_SSTHRESH, iproute->ssthresh);

	if (iproute->mask & IPROUTE_BIT_CWND)
		rta_addattr32(rta, sizeof(buf), RTAX_CWND, iproute->cwnd);

	if (iproute->mask & IPROUTE_BIT_ADVMSS)
		rta_addattr32(rta, sizeof(buf), RTAX_ADVMSS, iproute->advmss);

	if (iproute->mask & IPROUTE_BIT_REORDERING)
		rta_addattr32(rta, sizeof(buf), RTAX_REORDERING, iproute->reordering);

	if (iproute->mask & IPROUTE_BIT_HOPLIMIT)
		rta_addattr32(rta, sizeof(buf), RTAX_HOPLIMIT, iproute->hoplimit);

	if (iproute->mask & IPROUTE_BIT_INITCWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITCWND, iproute->initcwnd);

#ifdef RTAX_INITRWND
	if (iproute->mask & IPROUTE_BIT_INITRWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITRWND, iproute->initrwnd);
#endif

#ifdef RTAX_QUICKACK
	if (iproute->mask & IPROUTE_BIT_QUICKACK)
		rta_addattr32(rta, sizeof(buf), RTAX_QUICKACK, iproute->quickack);
#endif

#ifdef _HAVE_RTA_PREF_
	if (iproute->mask & IPROUTE_BIT_PREF)
		addattr8(&req.n, sizeof(req), RTA_PREF, iproute->pref);
#endif

	if (rta->rta_len > RTA_LENGTH(0)) {
		if (iproute->lock)
			rta_addattr32(rta, sizeof(buf), RTAX_LOCK, iproute->lock);
		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}

	if (!LIST_ISEMPTY(iproute->nhs))
		add_nexthops(iproute, &req.n, &req.r);

#ifdef DEBUG_NETLINK_MSG
	size_t i, j;
	uint8_t *p;
	char lbuf[3072];
	char *op = lbuf;

	log_message(LOG_INFO, "rtmsg buffer used %lu, rtattr buffer used %d", req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)), rta->rta_len);

	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "nlmsghdr %p(%u):", &req.n, req.n.nlmsg_len);
	for (i = 0, p = (uint8_t*)&req.n; i < sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));
	log_message(LOG_INFO, "%s\n", lbuf);

	op = lbuf;
	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "rtmsg %p(%lu):", &req.r, req.n.nlmsg_len - sizeof(struct nlmsghdr));
	for (i = 0, p = (uint8_t*)&req.r; i < + req.n.nlmsg_len - sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));

	for (j = 0; lbuf + j < op; j+= MAX_LOG_MSG)
		log_message(LOG_INFO, "%.*\n", MAX_LOG_MSG, lbuf+j);
#endif

	/* This returns ESRCH if the address of via address doesn't exist */
	/* ENETDOWN if dev p33p1.40 for example is down */
	if (netlink_talk(&nl_cmd, &req.n) < 0) {
#ifdef _HAVE_RTA_EXPIRES_
		/* If an expiry was set on the route, it may have disappeared already */
		if (cmd != IPADDRESS_DEL || !(iproute->mask & IPROUTE_BIT_EXPIRES))
#endif
			status = -1;
	}

	return status;
}
예제 #4
0
/* Add/Delete IP rule to/from a specific IP/network */
static int
netlink_rule(ip_rule_t *iprule, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct fib_rule_hdr frh;
		char buf[1024];
	} req;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;

	if (cmd != IPRULE_DEL) {
		req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
		req.n.nlmsg_type = RTM_NEWRULE;
		req.frh.action = FR_ACT_UNSPEC;
	}
	else {
		req.frh.action = FR_ACT_UNSPEC;
		req.n.nlmsg_type = RTM_DELRULE;
	}
	req.frh.table = RT_TABLE_UNSPEC;
	req.frh.flags = 0;
	req.frh.tos = iprule->tos;	// Hex value - 0xnn <= 255, or name from rt_dsfield
	req.frh.family = iprule->family;

	if (iprule->action == FR_ACT_TO_TBL
#if HAVE_DECL_FRA_L3MDEV
	    && !iprule->l3mdev
#endif
					   ) {
		if (iprule->table < 256)	// "Table" or "lookup"
			req.frh.table = iprule->table ? iprule->table & 0xff : RT_TABLE_MAIN;
		else {
			req.frh.table = RT_TABLE_UNSPEC;
			addattr32(&req.n, sizeof(req), FRA_TABLE, iprule->table);
		}
	}

	if (iprule->invert)
		req.frh.flags |= FIB_RULE_INVERT;	// "not"

	/* Set rule entry */
	if (iprule->from_addr) {	// can be "default"/"any"/"all" - and to addr => bytelen == bitlen == 0
		add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->from_addr);
		req.frh.src_len = iprule->from_addr->ifa.ifa_prefixlen;
	}
	if (iprule->to_addr) {
		add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->to_addr);
		req.frh.dst_len = iprule->to_addr->ifa.ifa_prefixlen;
	}

	if (iprule->mask & IPRULE_BIT_PRIORITY)	// "priority/order/preference"
		addattr32(&req.n, sizeof(req), FRA_PRIORITY, iprule->priority);

	if (iprule->mask & IPRULE_BIT_FWMARK)	// "fwmark"
		addattr32(&req.n, sizeof(req), FRA_FWMARK, iprule->fwmark);

	if (iprule->mask & IPRULE_BIT_FWMASK)	// "fwmark number followed by /nn"
		addattr32(&req.n, sizeof(req), FRA_FWMASK, iprule->fwmask);

	if (iprule->realms)	// "realms u16[/u16] using rt_realms. after / is 16 msb (src), pre slash is 16 lsb (dest)"
		addattr32(&req.n, sizeof(req), FRA_FLOW, iprule->realms);

#if HAVE_DECL_FRA_SUPPRESS_PREFIXLEN
	if (iprule->suppress_prefix_len != -1)	// "suppress_prefixlength" - only valid if table != 0
		addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, iprule->suppress_prefix_len);
#endif

#if HAVE_DECL_FRA_SUPPRESS_IFGROUP
	if (iprule->mask & IPRULE_BIT_SUP_GROUP)	// "suppress_ifgroup" or "sup_group" int32 - only valid if table !=0
		addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, iprule->suppress_group);
#endif

	if (iprule->iif)	// "dev/iif"
		addattr_l(&req.n, sizeof(req), FRA_IFNAME, iprule->iif, strlen(iprule->iif->ifname)+1);

#if HAVE_DECL_FRA_OIFNAME
	if (iprule->oif)	// "oif"
		addattr_l(&req.n, sizeof(req), FRA_OIFNAME, iprule->oif, strlen(iprule->oif->ifname)+1);
#endif

#if HAVE_DECL_FRA_TUN_ID
	if (iprule->tunnel_id)
		addattr64(&req.n, sizeof(req), FRA_TUN_ID, htobe64(iprule->tunnel_id));
#endif

#if HAVE_DECL_FRA_UID_RANGE
	if (iprule->mask & IPRULE_BIT_UID_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &iprule->uid_range, sizeof(iprule->uid_range));
#endif

#if HAVE_DECL_FRA_L3MDEV
	if (iprule->l3mdev)
		addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1);
#endif

#if HAVE_DECL_FRA_PROTOCOL
	if (iprule->mask & IPRULE_BIT_PROTOCOL)
		addattr8(&req.n, sizeof(req), FRA_PROTOCOL, iprule->protocol);
#endif

#if HAVE_DECL_FRA_IP_PROTO
	if (iprule->mask & IPRULE_BIT_IP_PROTO)
		addattr8(&req.n, sizeof(req), FRA_IP_PROTO, iprule->ip_proto);
#endif

#if HAVE_DECL_FRA_SPORT_RANGE
	if (iprule->mask & IPRULE_BIT_SPORT_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &iprule->src_port, sizeof(iprule->src_port));
#endif

#if HAVE_DECL_FRA_DPORT_RANGE
	if (iprule->mask & IPRULE_BIT_DPORT_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &iprule->dst_port, sizeof(iprule->dst_port));
#endif

	if (iprule->action == FR_ACT_GOTO) {	// "goto"
		addattr32(&req.n, sizeof(req), FRA_GOTO, iprule->goto_target);
		req.frh.action = FR_ACT_GOTO;
	}

	req.frh.action = iprule->action;

	if (netlink_talk(&nl_cmd, &req.n) < 0)
		status = -1;

	return status;
}