Esempio n. 1
0
static int get_response(struct nlmsghdr *n, void *arg)
{
	struct genlmsghdr *ghdr;
	struct l2tp_data *data = arg;
	struct l2tp_parm *p = &data->config;
	struct rtattr *attrs[L2TP_ATTR_MAX + 1];
	struct rtattr *nla_stats;
	int len;

	/* Validate message and parse attributes */
	if (n->nlmsg_type == NLMSG_ERROR)
		return -EBADMSG;

	ghdr = NLMSG_DATA(n);
	len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
	if (len < 0)
		return -1;

	parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);

	if (attrs[L2TP_ATTR_PW_TYPE])
		p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
	if (attrs[L2TP_ATTR_ENCAP_TYPE])
		p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
	if (attrs[L2TP_ATTR_OFFSET])
		p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]);
	if (attrs[L2TP_ATTR_DATA_SEQ])
		p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]);
	if (attrs[L2TP_ATTR_CONN_ID])
		p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
	if (attrs[L2TP_ATTR_PEER_CONN_ID])
		p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
	if (attrs[L2TP_ATTR_SESSION_ID])
		p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
	if (attrs[L2TP_ATTR_PEER_SESSION_ID])
		p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
	if (attrs[L2TP_ATTR_L2SPEC_TYPE])
		p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
	if (attrs[L2TP_ATTR_L2SPEC_LEN])
		p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);

	if (attrs[L2TP_ATTR_UDP_CSUM])
		p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]);

	p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX];
	p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX];

	if (attrs[L2TP_ATTR_COOKIE])
		memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
		       p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));

	if (attrs[L2TP_ATTR_PEER_COOKIE])
		memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
		       p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));

	if (attrs[L2TP_ATTR_RECV_SEQ])
		p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]);
	if (attrs[L2TP_ATTR_SEND_SEQ])
		p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]);

	if (attrs[L2TP_ATTR_RECV_TIMEOUT])
		p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
	if (attrs[L2TP_ATTR_IP_SADDR]) {
		p->local_ip.family = AF_INET;
		p->local_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]);
		p->local_ip.bytelen = 4;
		p->local_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP_DADDR]) {
		p->peer_ip.family = AF_INET;
		p->peer_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]);
		p->peer_ip.bytelen = 4;
		p->peer_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP6_SADDR]) {
		p->local_ip.family = AF_INET6;
		memcpy(&p->local_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_SADDR]),
			p->local_ip.bytelen = 16);
		p->local_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP6_DADDR]) {
		p->peer_ip.family = AF_INET6;
		memcpy(&p->peer_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_DADDR]),
			p->peer_ip.bytelen = 16);
		p->peer_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_UDP_SPORT])
		p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
	if (attrs[L2TP_ATTR_UDP_DPORT])
		p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
	if (attrs[L2TP_ATTR_MTU])
		p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]);
	if (attrs[L2TP_ATTR_IFNAME])
		p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);

	nla_stats = attrs[L2TP_ATTR_STATS];
	if (nla_stats) {
		struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];

		parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);

		if (tb[L2TP_ATTR_TX_PACKETS])
			data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
		if (tb[L2TP_ATTR_TX_BYTES])
			data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
		if (tb[L2TP_ATTR_TX_ERRORS])
			data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
		if (tb[L2TP_ATTR_RX_PACKETS])
			data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
		if (tb[L2TP_ATTR_RX_BYTES])
			data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
		if (tb[L2TP_ATTR_RX_ERRORS])
			data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
		if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
			data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
		if (tb[L2TP_ATTR_RX_OOS_PACKETS])
			data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
	}

	return 0;
}
Esempio n. 2
0
int genl_ctrl_resolve_family(const char *family)
{
	struct rtnl_handle rth;
	struct nlmsghdr *nlh;
	struct genlmsghdr *ghdr;
	int ret = 0;
	struct {
		struct nlmsghdr         n;
		char                    buf[4096];
	} req;

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

	nlh = &req.n;
	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	nlh->nlmsg_type = GENL_ID_CTRL;

	ghdr = NLMSG_DATA(&req.n);
	ghdr->cmd = CTRL_CMD_GETFAMILY;

	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
		fprintf(stderr, "Cannot open generic netlink socket\n");
		exit(1);
	}

	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);

	if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
		fprintf(stderr, "Error talking to the kernel\n");
		goto errout;
	}

	{
		struct rtattr *tb[CTRL_ATTR_MAX + 1];
		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
		int len = nlh->nlmsg_len;
		struct rtattr *attrs;

		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
			goto errout;
		}

		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
			fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
			goto errout;
		}

		len -= NLMSG_LENGTH(GENL_HDRLEN);

		if (len < 0) {
			fprintf(stderr, "wrong controller message len %d\n", len);
			return -1;
		}

		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);

		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
			fprintf(stderr, "Missing family id TLV\n");
			goto errout;
		}

		ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
	}

errout:
	rtnl_close(&rth);
	return ret;
}
Esempio n. 3
0
static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct qdisc_util *q = NULL;
	struct tc_estimator est;
	struct {
		struct tc_sizespec	szopts;
		__u16			*data;
	} stab;
	char  d[16];
	char  k[16];
	struct {
		struct nlmsghdr 	n;
		struct tcmsg 		t;
		char   			buf[TCA_BUF_MAX];
	} req;

	memset(&req, 0, sizeof(req));
	memset(&stab, 0, sizeof(stab));
	memset(&est, 0, sizeof(est));
	memset(&d, 0, sizeof(d));
	memset(&k, 0, sizeof(k));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.t.tcm_family = AF_UNSPEC;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			if (d[0])
				duparg("dev", *argv);
			strncpy(d, *argv, sizeof(d)-1);
		} else if (strcmp(*argv, "handle") == 0) {
			__u32 handle;
			if (req.t.tcm_handle)
				duparg("handle", *argv);
			NEXT_ARG();
			if (get_qdisc_handle(&handle, *argv))
				invarg("invalid qdisc ID", *argv);
			req.t.tcm_handle = handle;
		} else if (strcmp(*argv, "root") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_ROOT;
#ifdef TC_H_INGRESS
		} else if (strcmp(*argv, "ingress") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_INGRESS;
			strncpy(k, "ingress", sizeof(k)-1);
			q = get_qdisc_kind(k);
			req.t.tcm_handle = 0xffff0000;

			argc--; argv++;
			break;
#endif
		} else if (strcmp(*argv, "parent") == 0) {
			__u32 handle;
			NEXT_ARG();
			if (req.t.tcm_parent)
				duparg("parent", *argv);
			if (get_tc_classid(&handle, *argv))
				invarg("invalid parent ID", *argv);
			req.t.tcm_parent = handle;
		} else if (matches(*argv, "estimator") == 0) {
			if (parse_estimator(&argc, &argv, &est))
				return -1;
		} else if (matches(*argv, "stab") == 0) {
			if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
				return -1;
			continue;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			strncpy(k, *argv, sizeof(k)-1);

			q = get_qdisc_kind(k);
			argc--; argv++;
			break;
		}
		argc--; argv++;
	}

	if (k[0])
		addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
	if (est.ewma_log)
		addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));

	if (q) {
		if (q->parse_qopt) {
			if (q->parse_qopt(q, argc, argv, &req.n))
				return 1;
		} else if (argc) {
			fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
			return -1;
		}
	} else {
		if (argc) {
			if (matches(*argv, "help") == 0)
				usage();

			fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
			return -1;
		}
	}

	if (check_size_table_opts(&stab.szopts)) {
		struct rtattr *tail;

		if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
			fprintf(stderr, "failed to calculate size table.\n");
			return -1;
		}

		tail = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
		addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
			  sizeof(stab.szopts));
		if (stab.data)
			addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
				  stab.szopts.tsize * sizeof(__u16));
		tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
		if (stab.data)
			free(stab.data);
	}

	if (d[0])  {
		int idx;

 		ll_init_map(&rth);

		if ((idx = ll_name_to_index(d)) == 0) {
			fprintf(stderr, "Cannot find device \"%s\"\n", d);
			return 1;
		}
		req.t.tcm_ifindex = idx;
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		return 2;

	return 0;
}
Esempio n. 4
0
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
			 struct nlmsghdr *n)
{
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
		char buf[1024];
	} req;
	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
	struct rtattr *tb[IFLA_MAX + 1];
	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
	__u16 iflags = 0;
	__u16 oflags = 0;
	unsigned ikey = 0;
	unsigned okey = 0;
	unsigned saddr = 0;
	unsigned daddr = 0;
	unsigned link = 0;
	__u8 pmtudisc = 1;
	__u8 ttl = 0;
	__u8 tos = 0;
	int len;

	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
		memset(&req, 0, sizeof(req));

		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type = RTM_GETLINK;
		req.i.ifi_family = preferred_family;
		req.i.ifi_index = ifi->ifi_index;

		if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
get_failed:
			fprintf(stderr,
				"Failed to get existing tunnel info.\n");
			return -1;
		}

		len = req.n.nlmsg_len;
		len -= NLMSG_LENGTH(sizeof(*ifi));
		if (len < 0)
			goto get_failed;

		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);

		if (!tb[IFLA_LINKINFO])
			goto get_failed;

		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (!linkinfo[IFLA_INFO_DATA])
			goto get_failed;

		parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
				    linkinfo[IFLA_INFO_DATA]);

		if (greinfo[IFLA_GRE_IKEY])
			ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);

		if (greinfo[IFLA_GRE_OKEY])
			okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);

		if (greinfo[IFLA_GRE_IFLAGS])
			iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);

		if (greinfo[IFLA_GRE_OFLAGS])
			oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);

		if (greinfo[IFLA_GRE_LOCAL])
			saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);

		if (greinfo[IFLA_GRE_REMOTE])
			daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);

		if (greinfo[IFLA_GRE_PMTUDISC])
			pmtudisc = *(__u8 *)RTA_DATA(
				greinfo[IFLA_GRE_PMTUDISC]);

		if (greinfo[IFLA_GRE_TTL])
			ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);

		if (greinfo[IFLA_GRE_TOS])
			tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);

		if (greinfo[IFLA_GRE_LINK])
			link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
	}

	while (argc > 0) {
		if (!matches(*argv, "key")) {
			unsigned uval;

			NEXT_ARG();
			iflags |= GRE_KEY;
			oflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0) < 0) {
					fprintf(stderr,
						"Invalid value for \"key\"\n");
					exit(-1);
				}
				uval = htonl(uval);
			}

			ikey = okey = uval;
		} else if (!matches(*argv, "ikey")) {
			unsigned uval;

			NEXT_ARG();
			iflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0)<0) {
					fprintf(stderr, "invalid value of \"ikey\"\n");
					exit(-1);
				}
				uval = htonl(uval);
			}
			ikey = uval;
		} else if (!matches(*argv, "okey")) {
			unsigned uval;

			NEXT_ARG();
			oflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0)<0) {
					fprintf(stderr, "invalid value of \"okey\"\n");
					exit(-1);
				}
				uval = htonl(uval);
			}
			okey = uval;
		} else if (!matches(*argv, "seq")) {
			iflags |= GRE_SEQ;
			oflags |= GRE_SEQ;
		} else if (!matches(*argv, "iseq")) {
			iflags |= GRE_SEQ;
		} else if (!matches(*argv, "oseq")) {
			oflags |= GRE_SEQ;
		} else if (!matches(*argv, "csum")) {
			iflags |= GRE_CSUM;
			oflags |= GRE_CSUM;
		} else if (!matches(*argv, "icsum")) {
			iflags |= GRE_CSUM;
		} else if (!matches(*argv, "ocsum")) {
			oflags |= GRE_CSUM;
		} else if (!matches(*argv, "nopmtudisc")) {
			pmtudisc = 0;
		} else if (!matches(*argv, "pmtudisc")) {
			pmtudisc = 1;
		} else if (!matches(*argv, "remote")) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				daddr = get_addr32(*argv);
		} else if (!matches(*argv, "local")) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				saddr = get_addr32(*argv);
		} else if (!matches(*argv, "dev")) {
			NEXT_ARG();
			link = tnl_ioctl_get_ifindex(*argv);
			if (link == 0)
				exit(-1);
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL\n", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255\n", *argv);
				ttl = uval;
			}
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "tclass") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else 
			usage();
		argc--; argv++;
	}

	if (!ikey && IN_MULTICAST(ntohl(daddr))) {
		ikey = daddr;
		iflags |= GRE_KEY;
	}
	if (!okey && IN_MULTICAST(ntohl(daddr))) {
		okey = daddr;
		oflags |= GRE_KEY;
	}
	if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
		fprintf(stderr, "Broadcast tunnel requires a source address.\n");
		return -1;
	}

	addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
	addattr32(n, 1024, IFLA_GRE_OKEY, okey);
	addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
	addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
	addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
	addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
	addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
	if (link)
		addattr32(n, 1024, IFLA_GRE_LINK, link);
	addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
	addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);

	return 0;
}
Esempio n. 5
0
/*
 * The controller sends one nlmsg per family
*/
static int print_ctrl(const struct sockaddr_nl *who,
		      struct rtnl_ctrl_data *ctrl,
		      struct nlmsghdr *n, void *arg)
{
	struct rtattr *tb[CTRL_ATTR_MAX + 1];
	struct genlmsghdr *ghdr = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *attrs;
	FILE *fp = (FILE *) arg;
	__u32 ctrl_v = 0x1;

	if (n->nlmsg_type !=  GENL_ID_CTRL) {
		fprintf(stderr, "Not a controller message, nlmsg_len=%d "
			"nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
		return 0;
	}

	if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
	    ghdr->cmd != CTRL_CMD_DELFAMILY &&
	    ghdr->cmd != CTRL_CMD_NEWFAMILY &&
	    ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
		return 0;
	}

	len -= NLMSG_LENGTH(GENL_HDRLEN);

	if (len < 0) {
		fprintf(stderr, "wrong controller message len %d\n", len);
		return -1;
	}

	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);

	if (tb[CTRL_ATTR_FAMILY_NAME]) {
		char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
		fprintf(fp, "\nName: %s\n",name);
	}
	if (tb[CTRL_ATTR_FAMILY_ID]) {
		__u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
		fprintf(fp, "\tID: 0x%x ",*id);
	}
	if (tb[CTRL_ATTR_VERSION]) {
		__u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
		fprintf(fp, " Version: 0x%x ",*v);
		ctrl_v = *v;
	}
	if (tb[CTRL_ATTR_HDRSIZE]) {
		__u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
		fprintf(fp, " header size: %d ",*h);
	}
	if (tb[CTRL_ATTR_MAXATTR]) {
		__u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
		fprintf(fp, " max attribs: %d ",*ma);
	}
	/* end of family definitions .. */
	fprintf(fp,"\n");
	if (tb[CTRL_ATTR_OPS]) {
		struct rtattr *tb2[GENL_MAX_FAM_OPS];
		int i=0;
		parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
		fprintf(fp, "\tcommands supported: \n");
		for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
			if (tb2[i]) {
				fprintf(fp, "\t\t#%d: ", i);
				if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
					fprintf(fp, "Error printing command\n");
				}
				/* for next command */
				fprintf(fp,"\n");
			}
		}

		/* end of family::cmds definitions .. */
		fprintf(fp,"\n");
	}

	if (tb[CTRL_ATTR_MCAST_GROUPS]) {
		struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
		int i;

		parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
				    tb[CTRL_ATTR_MCAST_GROUPS]);
		fprintf(fp, "\tmulticast groups:\n");

		for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
			if (tb2[i]) {
				fprintf(fp, "\t\t#%d: ", i);
				if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
					fprintf(fp, "Error printing group\n");
				/* for next group */
				fprintf(fp,"\n");
			}
		}

		/* end of family::groups definitions .. */
		fprintf(fp,"\n");
	}

	fflush(fp);
	return 0;
}
Esempio n. 6
0
/**
 * In case one binds to 0.0.0.0/INADDR_ANY and wants to know which source
 * address will be used when sending a message this function can be used.
 * It will ask the routing code of the kernel for the PREFSRC
 */
int source_for_dest(const struct in_addr *dest, struct in_addr *loc_source)
{
	int fd, rc;
	struct rtmsg *r;
	struct rtattr *rta;
        struct {
		struct nlmsghdr         n;
		struct rtmsg            r;
		char                    buf[1024];
        } req;

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

	fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
	if (fd < 0) {
		perror("nl socket");
		return -1;
	}

	/* Send a rtmsg and ask for a response */
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        req.n.nlmsg_type = RTM_GETROUTE;
        req.n.nlmsg_seq = 1;

	/* Prepare the routing request */
        req.r.rtm_family = AF_INET;

	/* set the dest */
	rta = NLMSG_TAIL(&req.n);
	rta->rta_type = RTA_DST;
	rta->rta_len = RTA_LENGTH(sizeof(*dest));
	memcpy(RTA_DATA(rta), dest, sizeof(*dest));

	/* update sizes for dest */
	req.r.rtm_dst_len = sizeof(*dest) * 8;
	req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(rta->rta_len);

	rc = send(fd, &req, req.n.nlmsg_len, 0);
	if (rc != req.n.nlmsg_len) {
		perror("short write");
		close(fd);
		return -2;
	}


	/* now receive a response and parse it */
	rc = recv(fd, &req, sizeof(req), 0);
	if (rc <= 0) {
		perror("short read");
		close(fd);
		return -3;
	}

	if (!NLMSG_OK(&req.n, rc) || req.n.nlmsg_type != RTM_NEWROUTE) {
		close(fd);
		return -4;
	}

	r = NLMSG_DATA(&req.n);
	rc -= NLMSG_LENGTH(sizeof(*r));
	rta = RTM_RTA(r);
	while (RTA_OK(rta, rc)) {
		if (rta->rta_type != RTA_PREFSRC) {
			rta = RTA_NEXT(rta, rc);
			continue;
		}

		/* we are done */
		memcpy(loc_source, RTA_DATA(rta), RTA_PAYLOAD(rta));
		close(fd);
		return 0;
	}

	close(fd);
	return -5;
}
Esempio n. 7
0
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct rtmsg *r = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[RTA_MAX+1];
	char abuf[256];
	int host_len;
	__u32 table;
	SPRINT_BUF(b1);
	static int hz;

	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
		fprintf(stderr, "Not a route: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}
	if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
		return 0;
	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	host_len = af_bit_len(r->rtm_family);

	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
	table = rtm_get_table(r, tb);

	if (!filter_nlmsg(n, tb, host_len))
		return 0;

	if (filter.flushb) {
		struct nlmsghdr *fn;
		if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
			if (flush_update())
				return -1;
		}
		fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
		memcpy(fn, n, n->nlmsg_len);
		fn->nlmsg_type = RTM_DELROUTE;
		fn->nlmsg_flags = NLM_F_REQUEST;
		fn->nlmsg_seq = ++rth.seq;
		filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
		filter.flushed++;
		if (show_stats < 2)
			return 0;
	}

	if (n->nlmsg_type == RTM_DELROUTE)
		fprintf(fp, "Deleted ");
	if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type)
		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));

	if (tb[RTA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "%s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "0/%d ", r->rtm_dst_len);
	} else {
		fprintf(fp, "default ");
	}
	if (tb[RTA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%u ", r->rtm_src_len);
	}
	if (tb[RTA_NEWDST]) {
		fprintf(fp, "as to %s ", format_host(r->rtm_family,
						  RTA_PAYLOAD(tb[RTA_NEWDST]),
						  RTA_DATA(tb[RTA_NEWDST]),
						  abuf, sizeof(abuf))
			);
	}
	if (r->rtm_tos && filter.tosmask != -1) {
		SPRINT_BUF(b1);
		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
	}

	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
		fprintf(fp, "via %s ",
			format_host(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
				    RTA_DATA(tb[RTA_GATEWAY]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_VIA]) {
		size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
		struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
		fprintf(fp, "via %s %s ",
			family_name(via->rtvia_family),
			format_host(via->rtvia_family, len, via->rtvia_addr,
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_OIF] && filter.oifmask != -1)
		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));

	if (!(r->rtm_flags&RTM_F_CLONED)) {
		if ((table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
			fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
			fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
			fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
	}
	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
		/* Do not use format_host(). It is our local addr
		   and symbolic name will not be useful.
		 */
		fprintf(fp, " src %s ",
			rt_addr_n2a(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
				    RTA_DATA(tb[RTA_PREFSRC]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_PRIORITY])
		fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
	if (r->rtm_flags & RTNH_F_DEAD)
		fprintf(fp, "dead ");
	if (r->rtm_flags & RTNH_F_ONLINK)
		fprintf(fp, "onlink ");
	if (r->rtm_flags & RTNH_F_PERVASIVE)
		fprintf(fp, "pervasive ");
	if (r->rtm_flags & RTNH_F_EXTERNAL)
		fprintf(fp, "offload ");
	if (r->rtm_flags & RTM_F_NOTIFY)
		fprintf(fp, "notify ");
	if (tb[RTA_MARK]) {
		unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]);
		if (mark) {
			if (mark >= 16)
				fprintf(fp, " mark 0x%x", mark);
			else
				fprintf(fp, " mark %u", mark);
		}
	}

	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
		__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
		__u32 from = to>>16;
		to &= 0xFFFF;
		fprintf(fp, "realm%s ", from ? "s" : "");
		if (from) {
			fprintf(fp, "%s/",
				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
		}
		fprintf(fp, "%s ",
			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
	}
Esempio n. 8
0
int
netlink_link_add_vmac(vrrp_t *vrrp)
{
	struct rtattr *linkinfo;
	struct rtattr *data;
	unsigned int base_ifindex;
	interface_t *ifp;
	interface_t *base_ifp;
	char ifname[IFNAMSIZ];
	struct {
		struct nlmsghdr n;
		struct ifinfomsg ifi;
		char buf[256];
	} req;

	if (!vrrp->ifp || __test_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags) || !vrrp->vrid)
		return -1;

	if (vrrp->family == AF_INET6)
		ll_addr[4] = 0x02;
	else
		ll_addr[4] = 0x01;

	ll_addr[ETH_ALEN-1] = vrrp->vrid;

	memset(&req, 0, sizeof (req));
	memset(ifname, 0, IFNAMSIZ);
	strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1);

	/*
	 * Check to see if this vmac interface was created
	 * by a previous instance.
	 */
	if ((ifp = if_get_by_ifname(ifname))) {
		/* Check to see whether this interface has wrong mac ? */
		if (memcmp((const void *) ifp->hw_addr,
			   (const void *) ll_addr, ETH_ALEN) != 0) {
			/* We have found a VIF but the vmac do not match */
			log_message(LOG_INFO, "vmac: Removing old VMAC interface %s due to conflicting "
					      "interface MAC for vrrp_instance %s!!!"
					    , vrrp->vmac_ifname, vrrp->iname);

			/* Request that NETLINK remove the VIF interface first */
			memset(&req, 0, sizeof (req));
			req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
			req.n.nlmsg_flags = NLM_F_REQUEST;
			req.n.nlmsg_type = RTM_DELLINK;
			req.ifi.ifi_family = AF_INET;
			req.ifi.ifi_index = IF_INDEX(ifp);

			if (netlink_talk(&nl_cmd, &req.n) < 0) {
				log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for "
						      "vrrp_instance %s!!!"
						    , vrrp->vmac_ifname, vrrp->iname);
				return -1;
			}

			/* Interface successfully removed, now recreate */
		}
	}

	/* Request that NETLINK create the VIF interface */
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
	req.n.nlmsg_type = RTM_NEWLINK;
	req.ifi.ifi_family = AF_INET;

	/* macvlan settings */
	linkinfo = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
	addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)macvlan_ll_kind, strlen(macvlan_ll_kind));
	data = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);

	/*
	 * In private mode, macvlan will receive frames with same MAC addr
	 * as configured on the interface.
	 */
	addattr32(&req.n, sizeof(req), IFLA_MACVLAN_MODE,
		  MACVLAN_MODE_PRIVATE);
	data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
	linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
	addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t));
	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname));
	addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, ll_addr, ETH_ALEN);

	if (netlink_talk(&nl_cmd, &req.n) < 0) {
		log_message(LOG_INFO, "vmac: Error creating VMAC interface %s for vrrp_instance %s!!!"
				    , ifname, vrrp->iname);
		return -1;
	}

	log_message(LOG_INFO, "vmac: Success creating VMAC interface %s for vrrp_instance %s"
			    , ifname, vrrp->iname);

	/*
	 * Update interface queue and vrrp instance interface binding.
	 */
	netlink_interface_lookup();
	ifp = if_get_by_ifname(ifname);
	if (!ifp)
		return -1;
	base_ifp = vrrp->ifp;
	base_ifindex = vrrp->ifp->ifindex;
	ifp->flags = vrrp->ifp->flags; /* Copy base interface flags */
	vrrp->ifp = ifp;
	vrrp->ifp->base_ifindex = base_ifindex;
	vrrp->ifp->vmac = 1;
	vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); /* For use on delete */

	if (vrrp->family == AF_INET) {
		/* Set the necessary kernel parameters to make macvlans work for us */
		set_interface_parameters(ifp, base_ifp);

		/* We don't want IPv6 running on the interface unless we have some IPv6
		 * eVIPs, so disable it if not needed */
		if (!vrrp->evip_add_ipv6)
			link_disable_ipv6(ifp);
	}
	if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) {
		// We don't want a link-local address auto assigned - see RFC5798 paragraph 7.4.
		// If we have a sufficiently recent kernel, we can stop a link local address
		// based on the MAC address being automatically assigned. If not, then we have
		// to delete the generated address after bringing the interface up (see below).
#ifdef IFLA_INET6_ADDR_GEN_MODE		/* Since Linux 3.17 */
		memset(&req, 0, sizeof (req));
		req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
		req.n.nlmsg_flags = NLM_F_REQUEST ;
		req.n.nlmsg_type = RTM_NEWLINK;
		req.ifi.ifi_family = AF_UNSPEC;
		req.ifi.ifi_index = vrrp->vmac_ifindex;

		u_char val = IN6_ADDR_GEN_MODE_NONE;
		struct rtattr* spec;

		spec = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), IFLA_AF_SPEC, NULL,0);
		data = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), AF_INET6, NULL,0);
		addattr_l(&req.n, sizeof(req), IFLA_INET6_ADDR_GEN_MODE, &val, sizeof(val));
		data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
		spec->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)spec;

		if (netlink_talk(&nl_cmd, &req.n) < 0)
			log_message(LOG_INFO, "vmac: Error setting ADDR_GEN_MODE to NONE");
#endif

		if (vrrp->family == AF_INET6) {
			/* Add link-local address. If a source address has been specified, use it,
			 * else use link-local address from underlying interface to vmac if there is one,
			 * otherwise construct a link-local address based on underlying interface's
			 * MAC address.
			 * This is so that VRRP advertisements will be sent from a non-VIP address, but
			 * using the VRRP MAC address */
			ip_address_t ipaddress;

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

			ipaddress.ifp = ifp;
			if (vrrp->saddr.ss_family == AF_INET6)
				ipaddress.u.sin6_addr = ((struct sockaddr_in6*)&vrrp->saddr)->sin6_addr;
			else if (base_ifp->sin6_addr.s6_addr32[0])
				ipaddress.u.sin6_addr = base_ifp->sin6_addr;
			else
				make_link_local_address(&ipaddress.u.sin6_addr, base_ifp->hw_addr);
			ipaddress.ifa.ifa_family = AF_INET6;
			ipaddress.ifa.ifa_prefixlen = 64;
			ipaddress.ifa.ifa_index = vrrp->vmac_ifindex;

			if (netlink_ipaddress(&ipaddress, IPADDRESS_ADD) != 1)
				log_message(LOG_INFO, "Adding link-local address to vmac failed");

			/* Save the address as source for vrrp packets */
			if (vrrp->saddr.ss_family == AF_UNSPEC)
				inet_ip6tosockaddr(&ipaddress.u.sin6_addr, &vrrp->saddr);
			inet_ip6scopeid(vrrp->vmac_ifindex, &vrrp->saddr);
		}
	}

	/* bring it UP ! */
	__set_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags);
	netlink_link_up(vrrp);

#ifndef IFLA_INET6_ADDR_GEN_MODE
	if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) {
		/* Delete the automatically created link-local address based on the
		 * MAC address if we weren't able to configure the interface not to
		 * create the address (see above).
		 * This isn't ideal, since the invalid address will exist momentarily,
		 * but is there any better way to do it? probably not otherwise
		 * ADDR_GEN_MODE wouldn't have been added to the kernel. */
		ip_address_t ipaddress;

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

		ipaddress.u.sin6_addr = base_ifp->sin6_addr;
		make_link_local_address(&ipaddress.u.sin6_addr, ll_addr);
		ipaddress.ifa.ifa_family = AF_INET6;
		ipaddress.ifa.ifa_prefixlen = 64;
		ipaddress.ifa.ifa_index = vrrp->vmac_ifindex;

		if (netlink_ipaddress(&ipaddress, IPADDRESS_DEL) != 1)
			log_message(LOG_INFO, "Deleting auto link-local address from vmac failed");
	}
#endif

	return 1;
}
Esempio n. 9
0
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct rtmsg *r = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[RTA_MAX+1];
	char abuf[256];
	inet_prefix dst;
	inet_prefix src;
	inet_prefix prefsrc;
	inet_prefix via;
	int host_len = -1;
	static int ip6_multiple_tables;
	__u32 table;
	SPRINT_BUF(b1);
	static int hz;

	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
		fprintf(stderr, "Not a route: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}
	if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
		return 0;
	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (r->rtm_family == AF_INET6)
		host_len = 128;
	else if (r->rtm_family == AF_INET)
		host_len = 32;
	else if (r->rtm_family == AF_DECnet)
		host_len = 16;
	else if (r->rtm_family == AF_IPX)
		host_len = 80;

	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
	table = rtm_get_table(r, tb);

	if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
		ip6_multiple_tables = 1;

	if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
		return 0;

	if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
		if (filter.tb) {
			if (filter.tb == RT_TABLE_LOCAL) {
				if (r->rtm_type != RTN_LOCAL)
					return 0;
			} else if (filter.tb == RT_TABLE_MAIN) {
				if (r->rtm_type == RTN_LOCAL)
					return 0;
			} else {
				return 0;
			}
		}
	} else {
		if (filter.tb > 0 && filter.tb != table)
			return 0;
	}
	if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
		return 0;
	if ((filter.scope^r->rtm_scope)&filter.scopemask)
		return 0;
	if ((filter.type^r->rtm_type)&filter.typemask)
		return 0;
	if ((filter.tos^r->rtm_tos)&filter.tosmask)
		return 0;
	if (filter.rdst.family &&
	    (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
		return 0;
	if (filter.mdst.family &&
	    (r->rtm_family != filter.mdst.family ||
	     (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
		return 0;
	if (filter.rsrc.family &&
	    (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
		return 0;
	if (filter.msrc.family &&
	    (r->rtm_family != filter.msrc.family ||
	     (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
		return 0;
	if (filter.rvia.family && r->rtm_family != filter.rvia.family)
		return 0;
	if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
		return 0;

	memset(&dst, 0, sizeof(dst));
	dst.family = r->rtm_family;
	if (tb[RTA_DST])
		memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8);
	if (filter.rsrc.family || filter.msrc.family) {
		memset(&src, 0, sizeof(src));
		src.family = r->rtm_family;
		if (tb[RTA_SRC])
			memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8);
	}
	if (filter.rvia.bitlen>0) {
		memset(&via, 0, sizeof(via));
		via.family = r->rtm_family;
		if (tb[RTA_GATEWAY])
			memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
	}
	if (filter.rprefsrc.bitlen>0) {
		memset(&prefsrc, 0, sizeof(prefsrc));
		prefsrc.family = r->rtm_family;
		if (tb[RTA_PREFSRC])
			memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
	}

	if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
		return 0;
	if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
	    inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
		return 0;

	if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
		return 0;
	if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
	    inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
		return 0;

	if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen))
		return 0;
	if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen))
		return 0;
	if (filter.realmmask) {
		__u32 realms = 0;
		if (tb[RTA_FLOW])
			realms = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
		if ((realms^filter.realm)&filter.realmmask)
			return 0;
	}
	if (filter.iifmask) {
		int iif = 0;
		if (tb[RTA_IIF])
			iif = *(int*)RTA_DATA(tb[RTA_IIF]);
		if ((iif^filter.iif)&filter.iifmask)
			return 0;
	}
	if (filter.oifmask) {
		int oif = 0;
		if (tb[RTA_OIF])
			oif = *(int*)RTA_DATA(tb[RTA_OIF]);
		if ((oif^filter.oif)&filter.oifmask)
			return 0;
	}
	if (filter.flushb &&
	    r->rtm_family == AF_INET6 &&
	    r->rtm_dst_len == 0 &&
	    r->rtm_type == RTN_UNREACHABLE &&
	    tb[RTA_PRIORITY] &&
	    *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
		return 0;

	if (filter.flushb) {
		struct nlmsghdr *fn;
		if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
			if (flush_update())
				return -1;
		}
		fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
		memcpy(fn, n, n->nlmsg_len);
		fn->nlmsg_type = RTM_DELROUTE;
		fn->nlmsg_flags = NLM_F_REQUEST;
		fn->nlmsg_seq = ++rth.seq;
		filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
		filter.flushed++;
		if (show_stats < 2)
			return 0;
	}

	if (n->nlmsg_type == RTM_DELROUTE)
		fprintf(fp, "Deleted ");
	if (r->rtm_type != RTN_UNICAST && !filter.type)
		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));

	if (tb[RTA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_DST]),
							 RTA_DATA(tb[RTA_DST]),
							 abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "%s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_DST]),
						       RTA_DATA(tb[RTA_DST]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "0/%d ", r->rtm_dst_len);
	} else {
		fprintf(fp, "default ");
	}
	if (tb[RTA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[RTA_SRC]),
							 RTA_DATA(tb[RTA_SRC]),
							 abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[RTA_SRC]),
						       RTA_DATA(tb[RTA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%u ", r->rtm_src_len);
	}
	if (r->rtm_tos && filter.tosmask != -1) {
		SPRINT_BUF(b1);
		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
	}

	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
		fprintf(fp, "via %s ",
			format_host(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
				    RTA_DATA(tb[RTA_GATEWAY]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_OIF] && filter.oifmask != -1)
		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));

	if (!(r->rtm_flags&RTM_F_CLONED)) {
		if (table != RT_TABLE_MAIN && !filter.tb)
			fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
		if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1)
			fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
		if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1)
			fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
	}
	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
		/* Do not use format_host(). It is our local addr
		   and symbolic name will not be useful.
		 */
		fprintf(fp, " src %s ",
			rt_addr_n2a(r->rtm_family,
				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
				    RTA_DATA(tb[RTA_PREFSRC]),
				    abuf, sizeof(abuf)));
	}
	if (tb[RTA_PRIORITY])
		fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
	if (r->rtm_flags & RTNH_F_DEAD)
		fprintf(fp, "dead ");
	if (r->rtm_flags & RTNH_F_ONLINK)
		fprintf(fp, "onlink ");
	if (r->rtm_flags & RTNH_F_PERVASIVE)
		fprintf(fp, "pervasive ");
	if (r->rtm_flags & RTM_F_NOTIFY)
		fprintf(fp, "notify ");

	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
		__u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
		__u32 from = to>>16;
		to &= 0xFFFF;
		fprintf(fp, "realm%s ", from ? "s" : "");
		if (from) {
			fprintf(fp, "%s/",
				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
		}
		fprintf(fp, "%s ",
			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
	}
Esempio n. 10
0
static void
format_netlink(struct nlmsghdr *msg)
{
	struct rtattr *tb[ACPI_GENL_ATTR_MAX + 1];
	struct genlmsghdr *ghdr = NLMSG_DATA(msg);
	int len;
	struct rtattr *attrs;
	
	len = msg->nlmsg_len;
	
	/* if this message doesn't have the proper family ID, drop it */
	if (msg->nlmsg_type != acpi_ids_getfamily()) {
		if (logevents) {
			acpid_log(LOG_INFO, "wrong netlink family ID.\n");
		}
		return;
	}

	len -= NLMSG_LENGTH(GENL_HDRLEN);

	if (len < 0) {
		acpid_log(LOG_WARNING,
			"wrong netlink controller message len: %d\n", len);
		return;
	}

	attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
	/* parse the attributes in this message */
	parse_rtattr(tb, ACPI_GENL_ATTR_MAX, attrs, len);

	/* if there's an ACPI event attribute... */
	if (tb[ACPI_GENL_ATTR_EVENT]) {
		/* get the actual event struct */
		struct acpi_genl_event *event =
				RTA_DATA(tb[ACPI_GENL_ATTR_EVENT]);
		char buf[64];

		/* format it */
		snprintf(buf, sizeof(buf), "%s %s %08x %08x",
			event->device_class, event->bus_id, event->type, event->data);

		/* if we're locked, don't process the event */
		if (locked()) {
			if (logevents) {
				acpid_log(LOG_INFO,
					"lockfile present, not processing "
					"netlink event \"%s\"\n", buf);
			}
			return;
		}

		if (logevents)
			acpid_log(LOG_INFO,
				"received netlink event \"%s\"\n", buf);

		/* send the event off to the handler */
		acpid_handle_event(buf);

		if (logevents)
			acpid_log(LOG_INFO,
				"completed netlink event \"%s\"\n", buf);
	}
}
Esempio n. 11
0
static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
{
    char    buf[8192];
    struct sockaddr_nl nladdr;
    struct iovec iov = { buf, sizeof(buf) };
    struct ifaddrmsg *m;
    struct rtattr * rta_tb[IFA_MAX+1];
    struct ifaddrs *I;

    while (1) {
        int status;
        struct nlmsghdr *h;

        struct msghdr msg = {
            (void*)&nladdr, sizeof(nladdr),
            &iov,   1,
            NULL,   0,
            0
        };

        status = recvmsg(fd, &msg, 0);

        if (status < 0)
            continue;

        if (status == 0)
            return;

        if (nladdr.nl_pid) /* Message not from kernel */
            continue;

        h = (struct nlmsghdr*)buf;
        while (NLMSG_OK(h, status)) {
            if (h->nlmsg_seq != seq)
                goto skip_it;

            if (h->nlmsg_type == NLMSG_DONE)
                return;

            if (h->nlmsg_type == NLMSG_ERROR)
                return;

            if (h->nlmsg_type != RTM_NEWADDR)
                goto skip_it;

            m = NLMSG_DATA(h);

            if (m->ifa_family != AF_INET &&
                    m->ifa_family != AF_INET6)
                goto skip_it;

            if (m->ifa_flags&IFA_F_TENTATIVE)
                goto skip_it;

            memset(rta_tb, 0, sizeof(rta_tb));
            parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));

            if (rta_tb[IFA_LOCAL] == NULL)
                rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
            if (rta_tb[IFA_LOCAL] == NULL)
                goto skip_it;

            I = malloc(sizeof(struct ifaddrs));
            if (!I)
                return;
            memset(I, 0, sizeof(*I));

            I->ifa_ifindex = m->ifa_index;
            I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
            I->ifa_addr->sa_family = m->ifa_family;
            if (m->ifa_family == AF_INET) {
                struct sockaddr_in *sin = (void*)I->ifa_addr;
                memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
            } else {
                struct sockaddr_in6 *sin = (void*)I->ifa_addr;
                memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
                if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
                    sin->sin6_scope_id = I->ifa_ifindex;
            }
            I->ifa_next = *ifa;
            *ifa = I;

skip_it:
            h = NLMSG_NEXT(h, status);
        }
        if (msg.msg_flags & MSG_TRUNC)
            continue;
    }
    return;
}
Esempio n. 12
0
static int xfrm_policy_keep(const struct sockaddr_nl *who,
			    struct nlmsghdr *n,
			    void *arg)
{
	struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
	struct rtnl_handle *rth = xb->rth;
	struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[XFRMA_MAX+1];
	__u8 ptype = XFRM_POLICY_TYPE_MAIN;
	struct nlmsghdr *new_n;
	struct xfrm_userpolicy_id *xpid;

	if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) {
		fprintf(stderr, "Not a policy: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}

	len -= NLMSG_LENGTH(sizeof(*xpinfo));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len);

	if (tb[XFRMA_POLICY_TYPE]) {
		struct xfrm_userpolicy_type *upt;

		if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
			fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
			return -1;
		}
		upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
		ptype = upt->type;
	}

	if (!xfrm_policy_filter_match(xpinfo, ptype))
		return 0;

	if (xb->offset > xb->size) {
		fprintf(stderr, "Policy buffer overflow\n");
		return -1;
	}

	new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
	new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid));
	new_n->nlmsg_flags = NLM_F_REQUEST;
	new_n->nlmsg_type = XFRM_MSG_DELPOLICY;
	new_n->nlmsg_seq = ++rth->seq;

	xpid = NLMSG_DATA(new_n);
	memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel));
	xpid->dir = xpinfo->dir;
	xpid->index = xpinfo->index;

	xb->offset += new_n->nlmsg_len;
	xb->nlmsg_count ++;

	return 0;
}
Esempio n. 13
0
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr			n;
		struct xfrm_userpolicy_info	xpinfo;
		char				buf[RTA_BUF_SIZE];
	} req;
	char *dirp = NULL;
	char *selp = NULL;
	char *ptypep = NULL;
	char *sctxp = NULL;
	struct xfrm_userpolicy_type upt;
	char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
	int tmpls_len = 0;
	struct xfrm_mark mark = {0, 0};
	struct {
		struct xfrm_user_sec_ctx sctx;
		char	str[CTX_BUF_SIZE];
	} ctx;

	memset(&req, 0, sizeof(req));
	memset(&upt, 0, sizeof(upt));
	memset(&tmpls_buf, 0, sizeof(tmpls_buf));
	memset(&ctx, 0, sizeof(ctx));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xpinfo.sel.family = preferred_family;

	req.xpinfo.lft.soft_byte_limit = XFRM_INF;
	req.xpinfo.lft.hard_byte_limit = XFRM_INF;
	req.xpinfo.lft.soft_packet_limit = XFRM_INF;
	req.xpinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "dir") == 0) {
			if (dirp)
				duparg("dir", *argv);
			dirp = *argv;

			NEXT_ARG();
			xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);
		} else if (strcmp(*argv, "ctx") == 0) {
			char *context;

			if (sctxp)
				duparg("ctx", *argv);
			sctxp = *argv;
			NEXT_ARG();
			context = *argv;
			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
		} else if (strcmp(*argv, "mark") == 0) {
			xfrm_parse_mark(&mark, &argc, &argv);
		} else if (strcmp(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.index, *argv, 0))
				invarg("\"INDEX\" is invalid", *argv);
		} else if (strcmp(*argv, "ptype") == 0) {
			if (ptypep)
				duparg("ptype", *argv);
			ptypep = *argv;

			NEXT_ARG();
			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
		} else if (strcmp(*argv, "action") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "allow") == 0)
				req.xpinfo.action = XFRM_POLICY_ALLOW;
			else if (strcmp(*argv, "block") == 0)
				req.xpinfo.action = XFRM_POLICY_BLOCK;
			else
				invarg("\"action\" value is invalid\n", *argv);
		} else if (strcmp(*argv, "priority") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.priority, *argv, 0))
				invarg("\"PRIORITY\" is invalid", *argv);
		} else if (strcmp(*argv, "flag") == 0) {
			NEXT_ARG();
			xfrm_policy_flag_parse(&req.xpinfo.flags, &argc,
					       &argv);
		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "tmpl") == 0) {
			struct xfrm_user_tmpl *tmpl;

			if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) {
				fprintf(stderr, "Too many tmpls: buffer overflow\n");
				exit(1);
			}
			tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len);

			tmpl->family = preferred_family;
			tmpl->aalgos = (~(__u32)0);
			tmpl->ealgos = (~(__u32)0);
			tmpl->calgos = (~(__u32)0);

			NEXT_ARG();
			xfrm_tmpl_parse(tmpl, &argc, &argv);

			tmpls_len += sizeof(*tmpl);
		} else {
			if (selp)
				duparg("unknown", *argv);
			selp = *argv;

			xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv);
			if (preferred_family == AF_UNSPEC)
				preferred_family = req.xpinfo.sel.family;
		}

		argc--; argv++;
	}

	if (!dirp) {
		fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
		exit(1);
	}

	if (ptypep) {
		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
			  (void *)&upt, sizeof(upt));
	}

	if (tmpls_len > 0) {
		addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
			  (void *)tmpls_buf, tmpls_len);
	}

	if (mark.m & mark.v) {
		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
				  (void *)&mark, sizeof(mark));
		if (r < 0) {
			fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
			exit(1);
		}
	}

	if (sctxp) {
		addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
			  (void *)&ctx, ctx.sctx.len);
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xpinfo.sel.family == AF_UNSPEC)
		req.xpinfo.sel.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Esempio n. 14
0
	char *indexp = NULL;
	char *ptypep = NULL;
	char *sctxp = NULL;
	struct xfrm_userpolicy_type upt;
	struct xfrm_mark mark = {0, 0};
	struct {
		struct xfrm_user_sec_ctx sctx;
		char    str[CTX_BUF_SIZE];
	} ctx;


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

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY;

	while (argc > 0) {
		if (strcmp(*argv, "dir") == 0) {
			if (dirp)
				duparg("dir", *argv);
			dirp = *argv;

			NEXT_ARG();
			xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv);

		} else if (strcmp(*argv, "ctx") == 0) {
			char *context;
Esempio n. 15
0
int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct rtmsg *r = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	int host_len = -1;
	__u32 table;
	struct rtattr * tb[FRA_MAX+1];
	char abuf[256];
	SPRINT_BUF(b1);

	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
		return 0;

	len -= NLMSG_LENGTH(sizeof(*r));
	if (len < 0)
		return -1;

	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);

	if (r->rtm_family == AF_INET)
		host_len = 32;
	else if (r->rtm_family == AF_INET6)
		host_len = 128;
	else if (r->rtm_family == AF_DECnet)
		host_len = 16;
	else if (r->rtm_family == AF_IPX)
		host_len = 80;

	if (n->nlmsg_type == RTM_DELRULE)
		fprintf(fp, "Deleted ");

	if (tb[FRA_PRIORITY])
		fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY]));
	else
		fprintf(fp, "0:\t");

	if (r->rtm_flags & FIB_RULE_INVERT)
		fprintf(fp, "not ");

	if (tb[FRA_SRC]) {
		if (r->rtm_src_len != host_len) {
			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[FRA_SRC]),
							 RTA_DATA(tb[FRA_SRC]),
							 abuf, sizeof(abuf)),
				r->rtm_src_len
				);
		} else {
			fprintf(fp, "from %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[FRA_SRC]),
						       RTA_DATA(tb[FRA_SRC]),
						       abuf, sizeof(abuf))
				);
		}
	} else if (r->rtm_src_len) {
		fprintf(fp, "from 0/%d ", r->rtm_src_len);
	} else {
		fprintf(fp, "from all ");
	}

	if (tb[FRA_DST]) {
		if (r->rtm_dst_len != host_len) {
			fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
							 RTA_PAYLOAD(tb[FRA_DST]),
							 RTA_DATA(tb[FRA_DST]),
							 abuf, sizeof(abuf)),
				r->rtm_dst_len
				);
		} else {
			fprintf(fp, "to %s ", format_host(r->rtm_family,
						       RTA_PAYLOAD(tb[FRA_DST]),
						       RTA_DATA(tb[FRA_DST]),
						       abuf, sizeof(abuf)));
		}
	} else if (r->rtm_dst_len) {
		fprintf(fp, "to 0/%d ", r->rtm_dst_len);
	}

	if (r->rtm_tos) {
		SPRINT_BUF(b1);
		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
	}

 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
		__u32 mark = 0, mask = 0;

		if (tb[FRA_FWMARK])
			mark = rta_getattr_u32(tb[FRA_FWMARK]);

		if (tb[FRA_FWMASK] &&
		    (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
			fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
		else
			fprintf(fp, "fwmark 0x%x ", mark);
	}

	if (tb[FRA_IFNAME]) {
		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
		if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
			fprintf(fp, "[detached] ");
	}

	if (tb[FRA_OIFNAME]) {
		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
		if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
			fprintf(fp, "[detached] ");
	}

	table = rtm_get_table(r, tb);
	if (table)
		fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));

	if (tb[FRA_FLOW]) {
		__u32 to = rta_getattr_u32(tb[FRA_FLOW]);
		__u32 from = to>>16;
		to &= 0xFFFF;
		if (from) {
			fprintf(fp, "realms %s/",
				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
		}
		fprintf(fp, "%s ",
			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
	}

	if (r->rtm_type == RTN_NAT) {
		if (tb[RTA_GATEWAY]) {
			fprintf(fp, "map-to %s ",
				format_host(r->rtm_family,
					    RTA_PAYLOAD(tb[RTA_GATEWAY]),
					    RTA_DATA(tb[RTA_GATEWAY]),
					    abuf, sizeof(abuf)));
		} else
			fprintf(fp, "masquerade");
	} else if (r->rtm_type == FR_ACT_GOTO) {
		fprintf(fp, "goto ");
		if (tb[FRA_GOTO])
			fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
		else
			fprintf(fp, "none");
		if (r->rtm_flags & FIB_RULE_UNRESOLVED)
			fprintf(fp, " [unresolved]");
	} else if (r->rtm_type == FR_ACT_NOP)
		fprintf(fp, "nop");
	else if (r->rtm_type != RTN_UNICAST)
		fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));

	fprintf(fp, "\n");
	fflush(fp);
	return 0;
}
Esempio n. 16
0
/*
 * Adds or deletes an IP address on an interface.
 *
 * Action is one of:
 * - RTM_NEWADDR (to add a new address)
 * - RTM_DELADDR (to delete an existing address)
 *
 * Returns zero on success and negative errno on failure.
 */
int ifc_act_on_address(int action, const char *name, const char *address,
                       int prefixlen) {
    int ifindex, s, len, ret;
    struct sockaddr_storage ss;
    void *addr;
    size_t addrlen;
    struct {
        struct nlmsghdr n;
        struct ifaddrmsg r;
        // Allow for IPv6 address, headers, and padding.
        char attrbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
                     NLMSG_ALIGN(sizeof(struct rtattr)) +
                     NLMSG_ALIGN(INET6_ADDRLEN)];
    } req;
    struct rtattr *rta;
    struct nlmsghdr *nh;
    struct nlmsgerr *err;
    char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
             NLMSG_ALIGN(sizeof(struct nlmsgerr)) +
             NLMSG_ALIGN(sizeof(struct nlmsghdr))];

    // Get interface ID.
    ifindex = if_nametoindex(name);
    if (ifindex == 0) {
        return -errno;
    }

    // Convert string representation to sockaddr_storage.
    ret = string_to_ip(address, &ss);
    if (ret) {
        return ret;
    }

    // Determine address type and length.
    if (ss.ss_family == AF_INET) {
        struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
        addr = &sin->sin_addr;
        addrlen = INET_ADDRLEN;
    } else if (ss.ss_family == AF_INET6) {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
        addr = &sin6->sin6_addr;
        addrlen = INET6_ADDRLEN;
    } else {
        return -EAFNOSUPPORT;
    }

    // Fill in netlink structures.
    memset(&req, 0, sizeof(req));

    // Netlink message header.
    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
    req.n.nlmsg_type = action;
    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
    req.n.nlmsg_pid = getpid();

    // Interface address message header.
    req.r.ifa_family = ss.ss_family;
    req.r.ifa_prefixlen = prefixlen;
    req.r.ifa_index = ifindex;

    // Routing attribute. Contains the actual IP address.
    rta = (struct rtattr *) (((char *) &req) + NLMSG_ALIGN(req.n.nlmsg_len));
    rta->rta_type = IFA_LOCAL;
    rta->rta_len = RTA_LENGTH(addrlen);
    req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen);
    memcpy(RTA_DATA(rta), addr, addrlen);

    s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (send(s, &req, req.n.nlmsg_len, 0) < 0) {
        close(s);
        return -errno;
    }

    len = recv(s, buf, sizeof(buf), 0);
    close(s);
    if (len < 0) {
        return -errno;
    }

    // Parse the acknowledgement to find the return code.
    nh = (struct nlmsghdr *) buf;
    if (!NLMSG_OK(nh, (unsigned) len) || nh->nlmsg_type != NLMSG_ERROR) {
        return -EINVAL;
    }
    err = NLMSG_DATA(nh);

    // Return code is negative errno.
    return err->error;
}
Esempio n. 17
0
static int
nl_getmsg (int sd, int request, int seq, struct nlmsghdr **nlhp, int *done)
{
  struct nlmsghdr *nh;
  size_t bufsize = 65536, lastbufsize = 0;
  void *buff = NULL;
  int result = 0, read_size;
  int msg_flags;
  pid_t pid = getpid ();
  for (;;)
    {
      void *newbuff = realloc (buff, bufsize);
      if (newbuff == NULL || bufsize < lastbufsize)
	{
	  result = -1;
	  break;
	}
      buff = newbuff;
      result = read_size =
	nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags);
      if (read_size < 0 || (msg_flags & MSG_TRUNC))
	{
	  lastbufsize = bufsize;
	  bufsize *= 2;
	  continue;
	}
      if (read_size == 0)
	break;
      nh = (struct nlmsghdr *) buff;
      for (nh = (struct nlmsghdr *) buff;
	   NLMSG_OK (nh, read_size);
	   nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size))
	{
	  if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
	    continue;
	  if (nh->nlmsg_type == NLMSG_DONE)
	    {
	      (*done)++;
	      break;		/* ok */
	    }
	  if (nh->nlmsg_type == NLMSG_ERROR)
	    {
	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh);
	      result = -1;
	      if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
		__set_errno (EIO);
	      else
		__set_errno (-nlerr->error);
	      break;
	    }
	}
      break;
    }
  if (result < 0)
    if (buff)
      {
	int saved_errno = errno;
	free (buff);
	__set_errno (saved_errno);
      }
  *nlhp = (struct nlmsghdr *) buff;
  return result;
}
Esempio n. 18
0
int checkIpAddrTableChanges(PMIB_IPADDRTABLE pNew, PMIB_IPADDRTABLE pOld)
{
  enum {
    IP_ADD,
    IP_DEL,
    IP_CHG,
  };
  int i, max, ret = 0;

  if (!pNew || !pOld)
    {
      return(0);
    }

  max = (pNew->dwNumEntries > pOld->dwNumEntries) ? pNew->dwNumEntries :
        pOld->dwNumEntries;

  /* printf("IP table: ["); */
  for (i = 0; i < max; i++)
    {
      /* printf("%u.%u.%u.%u(%d) ", NIPQUAD(pNew->table[i].dwAddr), */
      /*	(int)pNew->table[i].dwIndex); */
#ifdef __WIN32__
      if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) ||
          (pNew->table[i].wType != pOld->table[i].wType))
        {
          if ((pNew->table[i].wType & MIB_IPADDR_DELETED) ||
              ((pNew->table[i].wType &
                MIB_IPADDR_DISCONNECTED)))
            {
              netlink_send_addr(1, pOld->table[i].dwAddr,
                                pOld->table[i].dwIndex);
            }
#else
      if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) ||
          (pNew->table[i].unused2 != pOld->table[i].unused2))
        {
          /* unused2 is wType */
          /* Address deleted due to flags */
          if ((pNew->table[i].unused2 & MIB_IPADDR_DELETED) ||
              ((pNew->table[i].unused2 &
                MIB_IPADDR_DISCONNECTED)))
            {
              netlink_send_addr(1, pOld->table[i].dwAddr,
                                pOld->table[i].dwIndex);
            }
#endif
          /* Address deleted, replaced by 0.0.0.0 */
          else if ((pNew->table[i].dwAddr == 0) &&
                   (pOld->table[i].dwAddr) &&
                   (pOld->table[i].dwIndex ==
                    pNew->table[i].dwIndex))
            {
              netlink_send_addr(1, pOld->table[i].dwAddr,
                                pOld->table[i].dwIndex);
            }
          /* New address */
          else
            {
              /* first delete old address, if any */
              if ((pOld->table[i].dwAddr) &&
                  (pOld->table[i].dwIndex ==
                   pNew->table[i].dwIndex))
                {
                  netlink_send_addr(
                    1,
                    pOld->table[i].dwAddr,
                    pOld->table[i].
                    dwIndex);
                }
              /* send new address */
              netlink_send_addr(0, pNew->table[i].dwAddr,
                                pNew->table[i].dwIndex);
            }
          ret = 1;
        }
    }
  /* printf("]\n"); */
  return(ret);
}

/*
 * 0 = add, 1 = deleted
 */
int netlink_send_addr(int add_del, DWORD addr, DWORD ifindex)
{
  char buff[512];
  int len;
  struct nlmsghdr *msg;
  struct ifaddrmsg *ifa;
  struct rtattr *rta;
  __u32 *p_addr;

  /* ignore 0.0.0.0 and 1.x.x.x */
  if ((addr == 0) || (addr == g_tap_lsi))
    {
      return(0);
    }

  /* printf("Address %u.%u.%u.%u has been ", NIPQUAD(addr));
   *  printf("%s.\n", add_del ? "deleted" : "added"); */

  /* netlink message header */
  memset(buff, 0, sizeof(buff));
  msg = (struct nlmsghdr*) &buff[0];
  len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) +
                      sizeof(__u32));
  msg->nlmsg_len = NLMSG_ALIGN(len);
  msg->nlmsg_type = add_del ? RTM_DELADDR : RTM_NEWADDR;
  msg->nlmsg_flags = 0;
  msg->nlmsg_seq = 0;
  msg->nlmsg_pid = 0;

  /* interface address message */
  ifa = (struct ifaddrmsg*) NLMSG_DATA(msg);
  ifa->ifa_family = AF_INET;
  ifa->ifa_prefixlen = 32;
  ifa->ifa_flags = IFA_F_PERMANENT;
  ifa->ifa_scope = IFA_LOCAL;
  ifa->ifa_index = ifindex;

  /* route attributes */
  rta = IFA_RTA(ifa);
  rta->rta_len = RTA_LENGTH(sizeof(__u32));
  rta->rta_type = IFA_LOCAL;
  p_addr = (__u32*)(rta + 1);
  *p_addr = addr;       /* host byte order */

#ifdef __WIN32__
  if (send(netlsp[0], buff, len, 0) < 0)
    {
#else
  if (write(netlsp[0], buff, len) < 0)
    {
#endif
      printf("netlink_send_addr() write error: %s", strerror(errno));
      return(-1);
    }

  return(0);
}

int sendIpAddrTable(PMIB_IPADDRTABLE pTable)
{
  char buff[1024];
  int len, total_len = 0, status, i;
  struct nlmsghdr *msg;
  struct ifaddrmsg *ifa;
  struct rtattr *rta;
  __u32 *p_addr;

  if (!pTable)
    {
      return(-1);
    }

  memset(buff, 0, sizeof(buff));
  status = sizeof(buff);
  len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) +
                      sizeof(__u32));
  msg = (struct nlmsghdr *) buff;
  /* due to timing, 1.0.0.1 is not in Window's IP table yet,
   * but is needed by hipd for the ACQUIRE, so here we add
   * it manually */
  msg->nlmsg_len = NLMSG_ALIGN(len);
  total_len += len;
  msg->nlmsg_type = NLMSG_NOOP;
  msg->nlmsg_flags = 0;
  msg->nlmsg_seq = 0;
  msg->nlmsg_pid = 0;
  ifa = (struct ifaddrmsg*) NLMSG_DATA(msg);
  ifa->ifa_family = AF_INET;
  ifa->ifa_prefixlen = 32;
  ifa->ifa_flags = IFA_F_PERMANENT;
  ifa->ifa_scope = IFA_LOCAL;
  ifa->ifa_index = 65542;
  rta = IFA_RTA(ifa);
  rta->rta_len = RTA_LENGTH(sizeof(__u32));
  rta->rta_type = IFA_LOCAL;
  p_addr = (__u32*)(rta + 1);
  *p_addr = g_tap_lsi;
  msg = NLMSG_NEXT(msg, status);
  /* step through IP address table and add to netlink dump message */
  for (i = 0; i < (int)pTable->dwNumEntries; i++)
    {
      /* omit 0.0.0.0; (1.0.0.1 is needed for ACQUIRE mechanism) */
      if (pTable->table[i].dwAddr == 0)
        {
          continue;
        }

      msg->nlmsg_len = NLMSG_ALIGN(len);
      total_len += len;
      msg->nlmsg_type = NLMSG_NOOP;
      msg->nlmsg_flags = 0;
      msg->nlmsg_seq = 0;
      msg->nlmsg_pid = 0;

      /* interface address message */
      ifa = (struct ifaddrmsg*) NLMSG_DATA(msg);
      ifa->ifa_family = AF_INET;
      ifa->ifa_prefixlen = 32;
      ifa->ifa_flags = IFA_F_PERMANENT;
      ifa->ifa_scope = IFA_LOCAL;
      ifa->ifa_index = pTable->table[i].dwIndex;

      /* route attributes */
      rta = IFA_RTA(ifa);
      rta->rta_len = RTA_LENGTH(sizeof(__u32));
      rta->rta_type = IFA_LOCAL;
      p_addr = (__u32*)(rta + 1);
      *p_addr = pTable->table[i].dwAddr;

      msg = NLMSG_NEXT(msg, status);
    }

  /* finish with a done message */
  msg->nlmsg_len = NLMSG_LENGTH(0);
  msg->nlmsg_type = NLMSG_DONE;
  msg->nlmsg_flags = 0;
  msg->nlmsg_seq = 0;
  msg->nlmsg_pid = 0;
  total_len += msg->nlmsg_len;

#ifdef __WIN32__
  send(netlsp[0], buff, total_len, 0);
#else
  write(netlsp[0], buff, total_len);
#endif
  return(total_len);
}
Esempio n. 19
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;
}
Esempio n. 20
0
static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
		       void *arg)
{
	FILE *fp = (FILE *) arg;
	struct genlmsghdr *ghdr;
	struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a;
	int len = n->nlmsg_len;
	char abuf[256];
	inet_prefix addr;
	int family, i, atype;

	if (n->nlmsg_type != genl_family)
		return -1;

	len -= NLMSG_LENGTH(GENL_HDRLEN);
	if (len < 0)
		return -1;

	ghdr = NLMSG_DATA(n);
	if (ghdr->cmd != TCP_METRICS_CMD_GET)
		return 0;

	parse_rtattr(attrs, TCP_METRICS_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
		     len);

	a = attrs[TCP_METRICS_ATTR_ADDR_IPV4];
	if (a) {
		if (f.addr.family && f.addr.family != AF_INET)
			return 0;
		memcpy(&addr.data, RTA_DATA(a), 4);
		addr.bytelen = 4;
		family = AF_INET;
		atype = TCP_METRICS_ATTR_ADDR_IPV4;
	} else {
		a = attrs[TCP_METRICS_ATTR_ADDR_IPV6];
		if (a) {
			if (f.addr.family && f.addr.family != AF_INET6)
				return 0;
			memcpy(&addr.data, RTA_DATA(a), 16);
			addr.bytelen = 16;
			family = AF_INET6;
			atype = TCP_METRICS_ATTR_ADDR_IPV6;
		} else
			return 0;
	}

	if (f.addr.family && f.addr.bitlen >= 0 &&
	    inet_addr_match(&addr, &f.addr, f.addr.bitlen))
		return 0;

	if (f.flushb) {
		struct nlmsghdr *fn;
		TCPM_REQUEST(req2, 128, TCP_METRICS_CMD_DEL, NLM_F_REQUEST);

		addattr_l(&req2.n, sizeof(req2), atype, &addr.data,
			  addr.bytelen);

		if (NLMSG_ALIGN(f.flushp) + req2.n.nlmsg_len > f.flushe) {
			if (flush_update())
				return -1;
		}
		fn = (struct nlmsghdr *) (f.flushb + NLMSG_ALIGN(f.flushp));
		memcpy(fn, &req2.n, req2.n.nlmsg_len);
		fn->nlmsg_seq = ++grth.seq;
		f.flushp = (((char *) fn) + req2.n.nlmsg_len) - f.flushb;
		f.flushed++;
		if (show_stats < 2)
			return 0;
	}

	if (f.cmd & (CMD_DEL | CMD_FLUSH))
		fprintf(fp, "Deleted ");

	fprintf(fp, "%s",
		format_host(family, RTA_PAYLOAD(a), &addr.data,
			    abuf, sizeof(abuf)));

	a = attrs[TCP_METRICS_ATTR_AGE];
	if (a) {
		__u64 val = rta_getattr_u64(a);

		fprintf(fp, " age %llu.%03llusec",
			val / 1000, val % 1000);
	}

	a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP];
	if (a) {
		__s32 val = (__s32) rta_getattr_u32(a);
		__u32 tsval;

		a = attrs[TCP_METRICS_ATTR_TW_TSVAL];
		tsval = a ? rta_getattr_u32(a) : 0;
		fprintf(fp, " tw_ts %u/%dsec ago", tsval, val);
	}

	a = attrs[TCP_METRICS_ATTR_VALS];
	if (a) {
		struct rtattr *m[TCP_METRIC_MAX + 1 + 1];

		parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);

		for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
			__u32 val;

			a = m[i + 1];
			if (!a)
				continue;
			if (metric_name[i])
				fprintf(fp, " %s ", metric_name[i]);
			else
				fprintf(fp, " metric_%d ", i);
			val = rta_getattr_u32(a);
			switch (i) {
			case TCP_METRIC_RTT:
				fprintf(fp, "%lluus", (val * 1000ULL) >> 3);
				break;
			case TCP_METRIC_RTTVAR:
				fprintf(fp, "%lluus", (val * 1000ULL) >> 2);
				break;
			case TCP_METRIC_SSTHRESH:
			case TCP_METRIC_CWND:
			case TCP_METRIC_REORDERING:
			default:
				fprintf(fp, "%u", val);
				break;
			}
		}
	}

	a = attrs[TCP_METRICS_ATTR_FOPEN_MSS];
	if (a)
		fprintf(fp, " fo_mss %u", rta_getattr_u16(a));

	a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS];
	if (a) {
		__u16 syn_loss = rta_getattr_u16(a);
		__u64 ts;

		a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS];
		ts = a ? rta_getattr_u64(a) : 0;

		fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago",
			syn_loss, ts / 1000, ts % 1000);
	}

	a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE];
	if (a) {
		char cookie[32 + 1];
		unsigned char *ptr = RTA_DATA(a);
		int i, max = RTA_PAYLOAD(a);

		if (max > 16)
			max = 16;
		cookie[0] = 0;
		for (i = 0; i < max; i++)
			sprintf(cookie + i + i, "%02x", ptr[i]);
		fprintf(fp, " fo_cookie %s", cookie);
	}

	fprintf(fp, "\n");

	fflush(fp);
	return 0;
}
Esempio n. 21
0
int rtnl_dump_filter(struct rtnl_handle *rth,
		     rtnl_filter_t filter,
		     void *arg1,
		     rtnl_filter_t junk,
		     void *arg2)
{
	char	buf[16384];
	struct sockaddr_nl nladdr;
	struct iovec iov = { buf, sizeof(buf) };

	while (1) {
		int status;
		struct nlmsghdr *h;

		struct msghdr msg = {
			(void*)&nladdr, sizeof(nladdr),
			&iov,	1,
			NULL,	0,
			0
		};

		status = recvmsg(rth->fd, &msg, 0);

		if (status < 0) {
			if (errno == EINTR)
				continue;
			perror("OVERRUN");
			continue;
		}
		if (status == 0) {
			fprintf(stderr, "EOF on netlink\n");
			return -1;
		}
		if (msg.msg_namelen != sizeof(nladdr)) {
			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
			exit(1);
		}

		h = (struct nlmsghdr*)buf;
		while (NLMSG_OK(h, status)) {
			int err;

			if (nladdr.nl_pid != 0 ||
			    h->nlmsg_pid != rth->local.nl_pid ||
			    h->nlmsg_seq != rth->dump) {
				if (junk) {
					err = junk(&nladdr, h, arg2);
					if (err < 0)
						return err;
				}
				goto skip_it;
			}

			if (h->nlmsg_type == NLMSG_DONE)
				return 0;
			if (h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
					fprintf(stderr, "ERROR truncated\n");
				} else {
					errno = -err->error;
					perror("RTNETLINK answers");
				}
				return -1;
			}
			err = filter(&nladdr, h, arg1);
			if (err < 0)
				return err;

skip_it:
			h = NLMSG_NEXT(h, status);
		}
		if (msg.msg_flags & MSG_TRUNC) {
			fprintf(stderr, "Message truncated\n");
			continue;
		}
		if (status) {
			fprintf(stderr, "!!!Remnant of size %d\n", status);
			exit(1);
		}
	}
}
/*
 * scamper_rtsock_getifindex
 *
 * figure out the outgoing interface id / route using linux netlink
 *
 * this works on Linux systems with netlink compiled into the kernel.
 * i think netlink comes compiled into the kernel with most distributions
 * these days.
 *
 * the man pages netlink(3), netlink(7), rtnetlink(3), and rtnetlink(7)
 * give an overview of the functions and structures used in here, but the
 * documentation in those man pages is pretty crap.
 * you'd be better off studying netlink.h and rtnetlink.h
 */
static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst)
{
  struct nlmsghdr *nlmsg;
  struct rtmsg    *rtmsg;
  struct rtattr   *rta;
  int              error;
  int              dst_len;
  uint8_t          buf[1024];
  int              af;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(dst))
    {
      dst_len  = 4;
      af       = AF_INET;
    }
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst))
    {
      dst_len  = 16;
      af       = AF_INET6;
    }
  else
    {
      return -1;
    }

  /*
   * fill out a route request.
   * we use the standard netlink header, with a route msg subheader
   * to query for the outgoing interface.
   * the message includes one attribute - the destination address
   * we are querying the route for.
   */
  memset(buf, 0, sizeof(buf));
  nlmsg  = (struct nlmsghdr *)buf;
  nlmsg->nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
  nlmsg->nlmsg_type  = RTM_GETROUTE;
  nlmsg->nlmsg_flags = NLM_F_REQUEST;
  nlmsg->nlmsg_seq   = seq;
  nlmsg->nlmsg_pid   = pid;

  /* netlink wants the bit length of each address */
  rtmsg = NLMSG_DATA(nlmsg);
  rtmsg->rtm_family  = af;
  rtmsg->rtm_flags   = 0;
  rtmsg->rtm_dst_len = dst_len * 8;

  rta = (struct rtattr *)(buf + NLMSG_ALIGN(nlmsg->nlmsg_len));
  rta->rta_type = RTA_DST;
  rta->rta_len  = RTA_LENGTH(dst_len);
  nlmsg->nlmsg_len += RTA_LENGTH(dst_len);
  memcpy(RTA_DATA(rta), dst->addr, dst_len);

  /* send the request */
  if((error = send(fd, buf, nlmsg->nlmsg_len, 0)) != nlmsg->nlmsg_len)
    {
      printerror(errno, strerror, __func__, "could not send");
      return -1;
    }

  return 0;
}
Esempio n. 23
0
static int communicate_kernel(struct ip_classify_msg *request,int type)
{
	int                 sock;
	int                 recv_len;
	int                 respond_size;
	void                *respond;
	struct msghdr       msg;
	struct iovec        iov;
	struct sockaddr_nl  remote;
	struct sockaddr_nl  local;
	struct nlmsghdr     * nlhdr;
	struct nlmsghdr     * rnlhdr=NULL;
	socklen_t           remote_addr_len;
    int                 res, ret = -1;

	sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP_CLASSIFY); 

	if(sock < 0)
    {
		DEBUGP("create socket error\n");
		return ret;
	}

	memset(&local, 0, sizeof(struct sockaddr_nl));

	local.nl_family = AF_NETLINK;
	local.nl_pid = getpid();
	local.nl_groups = 0; 

	if(bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_nl)) != 0)
    {
		DEBUGP("bind socket error\n");
		goto exit;
	}

	memset(&remote, 0, sizeof(struct sockaddr_nl));
	remote.nl_family = AF_NETLINK;
	remote.nl_pid    = 0;
	remote.nl_groups = 0;

	memset(&msg, 0, sizeof(struct msghdr));

	nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct ip_classify_msg)));

	memcpy(NLMSG_DATA(nlhdr), (char *)request, sizeof(struct ip_classify_msg));

	nlhdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ip_classify_msg));
	nlhdr->nlmsg_pid = getpid();  
	nlhdr->nlmsg_flags = NLM_F_REQUEST;
	nlhdr->nlmsg_type = type;

	iov.iov_base = (void *)nlhdr;
	iov.iov_len = nlhdr->nlmsg_len;

	msg.msg_name = (void *)&remote;
	msg.msg_namelen = sizeof(remote);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	res = sendmsg(sock, &msg, 0);
	if (res == -1) 
    {
		 DEBUGP("sendmsg error\n");
		 goto exit;
	}

	remote_addr_len = sizeof(struct sockaddr_nl);
	respond_size    = sizeof(struct ip_classify_respond_info);
	respond         = malloc(respond_size);

	memset(respond, 0, respond_size);
	recv_len = recvfrom(sock, respond, respond_size,
	       0, (struct sockaddr*)&remote, &remote_addr_len);

	if(recv_len == -1)
    {
		DEBUGP("recvmsg error\n");
		goto exit;
	}

	rnlhdr = (struct nlmsghdr *)respond;
	switch(rnlhdr->nlmsg_type)
    {
		case IP_CLASSIFY_DONE:
            ret = 0;
			break;
        
		case IP_CLASSIFY_ERROR:
			DEBUGP("ip-classify command error\n");
			break;
		
		case IP_CLASSIFY_MEMERR:
			DEBUGP("ip-classify malloc memery error\n");
			break;
			
		default:
			DEBUGP("ip-classify error, error type : %u\n", rnlhdr->nlmsg_type);
			break;
	}

exit:
	close(sock);
	if(respond)
	{
		free(respond);
	}
    
	if(nlhdr)
	{
		free(nlhdr);
	}

	return  ret;
}
static void rtsock_parsemsg(uint8_t *buf, size_t len)
{
  struct nlmsghdr *nlmsg;
  struct nlmsgerr *nlerr;
  struct rtmsg    *rtmsg;
  struct rtattr   *rta;
  void            *gwa = NULL;
  int              ifindex = -1;
  scamper_addr_t  *gw = NULL;
  rtsock_pair_t   *pair = NULL;
  scamper_route_t *route = NULL;

  if(len < sizeof(struct nlmsghdr))
    {
      scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr));
      return;
    }

  nlmsg = (struct nlmsghdr *)buf;

  /* if the message isn't addressed to this pid, drop it */
  if(nlmsg->nlmsg_pid != pid)
    return;

  if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL)
    return;
  route = pair->route;
  rtsock_pair_free(pair);

  if(nlmsg->nlmsg_type == RTM_NEWROUTE)
    {
      rtmsg = NLMSG_DATA(nlmsg);

      /* this is the payload length of the response packet */
      len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));

      /* hunt through the payload for the RTA_OIF entry */
      rta = RTM_RTA(rtmsg);
      while(RTA_OK(rta, len))
	{
	  switch(rta->rta_type)
	    {
	    case RTA_OIF:
	      ifindex = *(unsigned *)RTA_DATA(rta);
	      break;

	    case RTA_GATEWAY:
	      gwa = RTA_DATA(rta);
	      break;
	    }
	  rta = RTA_NEXT(rta, len);
	}

      if(gwa != NULL)
	{
	  if(rtmsg->rtm_family == AF_INET)
	    gw = scamper_addrcache_get_ipv4(addrcache, gwa);
	  else if(rtmsg->rtm_family == AF_INET6)
	    gw = scamper_addrcache_get_ipv6(addrcache, gwa);
	  else
	    route->error = EINVAL;
	}
    }
  else if(nlmsg->nlmsg_type == NLMSG_ERROR)
    {
      nlerr = NLMSG_DATA(nlmsg);
      route->error = nlerr->error;
    }
  else goto skip;

  route->gw = gw;
  route->ifindex = ifindex;
  route->cb(route);

  return;

 skip:
  if(route != NULL) scamper_route_free(route);
  return;
}
Esempio n. 25
0
static int ctrl_list(int cmd, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct nlmsghdr *nlh;
	struct genlmsghdr *ghdr;
	int ret = -1;
	char d[GENL_NAMSIZ];
	struct {
		struct nlmsghdr         n;
		char                    buf[4096];
	} req;

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

	nlh = &req.n;
	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	nlh->nlmsg_type = GENL_ID_CTRL;

	ghdr = NLMSG_DATA(&req.n);
	ghdr->cmd = CTRL_CMD_GETFAMILY;

	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
		fprintf(stderr, "Cannot open generic netlink socket\n");
		exit(1);
	}

	if (cmd == CTRL_CMD_GETFAMILY) {
		if (argc != 2) {
			fprintf(stderr, "Wrong number of params\n");
			return -1;
		}

		if (matches(*argv, "name") == 0) {
			NEXT_ARG();
			strncpy(d, *argv, sizeof (d) - 1);
			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
				  d, strlen(d) + 1);
		} else if (matches(*argv, "id") == 0) {
			__u16 id;
			NEXT_ARG();
			if (get_u16(&id, *argv, 0)) {
				fprintf(stderr, "Illegal \"id\"\n");
				goto ctrl_done;
			}

			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);

		} else {
			fprintf(stderr, "Wrong params\n");
			goto ctrl_done;
		}

		if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
			fprintf(stderr, "Error talking to the kernel\n");
			goto ctrl_done;
		}

		if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
			fprintf(stderr, "Dump terminated\n");
			goto ctrl_done;
		}

	}

	if (cmd == CTRL_CMD_UNSPEC) {
		nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
		nlh->nlmsg_seq = rth.dump = ++rth.seq;

		if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
			perror("Failed to send dump request\n");
			goto ctrl_done;
		}

		rtnl_dump_filter(&rth, print_ctrl2, stdout);

        }

	ret = 0;
ctrl_done:
	rtnl_close(&rth);
	return ret;
}
Esempio n. 26
0
	std::vector<ip_route> enum_routes(io_service& ios, error_code& ec)
	{
		std::vector<ip_route> ret;
		TORRENT_UNUSED(ios);

#ifdef TORRENT_BUILD_SIMULATOR

		TORRENT_UNUSED(ec);

		ip_route r;
		r.destination = address_v4();
		r.netmask = address_v4::from_string("255.255.255.0");
		address_v4::bytes_type b = ios.get_ip().to_v4().to_bytes();
		b[3] = 1;
		r.gateway = address_v4(b);
		strcpy(r.name, "eth0");
		r.mtu = ios.sim().config().path_mtu(ios.get_ip(), ios.get_ip());
		ret.push_back(r);

#elif TORRENT_USE_SYSCTL
/*
		struct rt_msg
		{
			rt_msghdr m_rtm;
			char buf[512];
		};

		rt_msg m;
		int len = sizeof(rt_msg);
		bzero(&m, len);
		m.m_rtm.rtm_type = RTM_GET;
		m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
		m.m_rtm.rtm_version = RTM_VERSION;
		m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
		m.m_rtm.rtm_seq = 0;
		m.m_rtm.rtm_msglen = len;

		int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
		if (s == -1)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			return std::vector<ip_route>();
		}

		int n = write(s, &m, len);
		if (n == -1)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			close(s);
			return std::vector<ip_route>();
		}
		else if (n != len)
		{
			ec = boost::asio::error::operation_not_supported;
			close(s);
			return std::vector<ip_route>();
		}
		bzero(&m, len);

		n = read(s, &m, len);
		if (n == -1)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			close(s);
			return std::vector<ip_route>();
		}

		for (rt_msghdr* ptr = &m.m_rtm; (char*)ptr < ((char*)&m.m_rtm) + n; ptr = (rt_msghdr*)(((char*)ptr) + ptr->rtm_msglen))
		{
			std::cout << " rtm_msglen: " << ptr->rtm_msglen << std::endl;
			std::cout << " rtm_type: " << ptr->rtm_type << std::endl;
			if (ptr->rtm_errno)
			{
				ec = error_code(ptr->rtm_errno, boost::asio::error::system_category);
				return std::vector<ip_route>();
			}
			if (m.m_rtm.rtm_flags & RTF_UP == 0
				|| m.m_rtm.rtm_flags & RTF_GATEWAY == 0)
			{
				ec = boost::asio::error::operation_not_supported;
				return address_v4::any();
			}
			if (ptr->rtm_addrs & RTA_DST == 0
				|| ptr->rtm_addrs & RTA_GATEWAY == 0
				|| ptr->rtm_addrs & RTA_NETMASK == 0)
			{
				ec = boost::asio::error::operation_not_supported;
				return std::vector<ip_route>();
			}
			if (ptr->rtm_msglen > len - ((char*)ptr - ((char*)&m.m_rtm)))
			{
				ec = boost::asio::error::operation_not_supported;
				return std::vector<ip_route>();
			}
			int min_len = sizeof(rt_msghdr) + 2 * sizeof(sockaddr_in);
			if (m.m_rtm.rtm_msglen < min_len)
			{
				ec = boost::asio::error::operation_not_supported;
				return std::vector<ip_route>();
			}

			ip_route r;
			// destination
			char* p = m.buf;
			sockaddr_in* sin = (sockaddr_in*)p;
			r.destination = sockaddr_to_address((sockaddr*)p);

			// gateway
			p += sin->sin_len;
			sin = (sockaddr_in*)p;
			r.gateway = sockaddr_to_address((sockaddr*)p);

			// netmask
			p += sin->sin_len;
			sin = (sockaddr_in*)p;
			r.netmask = sockaddr_to_address((sockaddr*)p);
			ret.push_back(r);
		}
		close(s);
*/
	int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_UNSPEC, NET_RT_DUMP, 0};

	size_t needed = 0;
#ifdef TORRENT_OS2
	if (__libsocket_sysctl(mib, 6, 0, &needed, 0, 0) < 0)
#else
	if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
#endif
	{
		ec = error_code(errno, boost::asio::error::system_category);
		return std::vector<ip_route>();
	}

	if (needed <= 0)
	{
		return std::vector<ip_route>();
	}

	boost::scoped_array<char> buf(new (std::nothrow) char[needed]);
	if (buf.get() == 0)
	{
		ec = boost::asio::error::no_memory;
		return std::vector<ip_route>();
	}

#ifdef TORRENT_OS2
	if (__libsocket_sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0)
#else
	if (sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0)
#endif
	{
		ec = error_code(errno, boost::asio::error::system_category);
		return std::vector<ip_route>();
	}

	char* end = buf.get() + needed;

	int s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0)
	{
		ec = error_code(errno, boost::asio::error::system_category);
		return std::vector<ip_route>();
	}
	rt_msghdr* rtm;
	for (char* next = buf.get(); next < end; next += rtm->rtm_msglen)
	{
		rtm = reinterpret_cast<rt_msghdr*>(next);
		if (rtm->rtm_version != RTM_VERSION)
			continue;

		ip_route r;
		if (parse_route(s, rtm, &r)) ret.push_back(r);
	}
	close(s);

#elif TORRENT_USE_GETIPFORWARDTABLE
/*
	move this to enum_net_interfaces
		// Load Iphlpapi library
		HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
		if (!iphlp)
		{
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		// Get GetAdaptersInfo() pointer
		typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG);
		GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo");
		if (!GetAdaptersInfo)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		PIP_ADAPTER_INFO adapter_info = 0;
		ULONG out_buf_size = 0;
		if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size);
		if (!adapter_info)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::no_memory;
			return std::vector<ip_route>();
		}

		if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
		{
			for (PIP_ADAPTER_INFO adapter = adapter_info;
				adapter != 0; adapter = adapter->Next)
			{

				ip_route r;
				r.destination = address::from_string(adapter->IpAddressList.IpAddress.String, ec);
				r.gateway = address::from_string(adapter->GatewayList.IpAddress.String, ec);
				r.netmask = address::from_string(adapter->IpAddressList.IpMask.String, ec);
				strncpy(r.name, adapter->AdapterName, sizeof(r.name));

				if (ec)
				{
					ec = error_code();
					continue;
				}
				ret.push_back(r);
			}
		}

		// Free memory
		free(adapter_info);
		FreeLibrary(iphlp);
*/

		// Load Iphlpapi library
		HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
		if (!iphlp)
		{
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		typedef DWORD (WINAPI *GetIfEntry_t)(PMIB_IFROW pIfRow);
		GetIfEntry_t GetIfEntry = (GetIfEntry_t)GetProcAddress(iphlp, "GetIfEntry");
		if (!GetIfEntry)
		{
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

#if _WIN32_WINNT >= 0x0600
		typedef DWORD (WINAPI *GetIpForwardTable2_t)(
			ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2*);
		typedef void (WINAPI *FreeMibTable_t)(PVOID Memory);

		GetIpForwardTable2_t GetIpForwardTable2 = (GetIpForwardTable2_t)GetProcAddress(
			iphlp, "GetIpForwardTable2");
		FreeMibTable_t FreeMibTable = (FreeMibTable_t)GetProcAddress(
			iphlp, "FreeMibTable");
		if (GetIpForwardTable2 && FreeMibTable)
		{
			MIB_IPFORWARD_TABLE2* routes = NULL;
			int res = GetIpForwardTable2(AF_UNSPEC, &routes);
			if (res == NO_ERROR)
			{
				for (int i = 0; i < routes->NumEntries; ++i)
				{
					ip_route r;
					r.gateway = sockaddr_to_address((const sockaddr*)&routes->Table[i].NextHop);
					r.destination = sockaddr_to_address(
						(const sockaddr*)&routes->Table[i].DestinationPrefix.Prefix);
					r.netmask = build_netmask(routes->Table[i].SitePrefixLength
						, routes->Table[i].DestinationPrefix.Prefix.si_family);
					MIB_IFROW ifentry;
					ifentry.dwIndex = routes->Table[i].InterfaceIndex;
					if (GetIfEntry(&ifentry) == NO_ERROR)
					{
						wcstombs(r.name, ifentry.wszName, sizeof(r.name));
						r.mtu = ifentry.dwMtu;
						ret.push_back(r);
					}
				}
			}
			if (routes) FreeMibTable(routes);
			FreeLibrary(iphlp);
			return ret;
		}
#endif

		// Get GetIpForwardTable() pointer
		typedef DWORD (WINAPI *GetIpForwardTable_t)(PMIB_IPFORWARDTABLE pIpForwardTable,PULONG pdwSize,BOOL bOrder);

		GetIpForwardTable_t GetIpForwardTable = (GetIpForwardTable_t)GetProcAddress(
			iphlp, "GetIpForwardTable");
		if (!GetIpForwardTable)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		MIB_IPFORWARDTABLE* routes = NULL;
		ULONG out_buf_size = 0;
		if (GetIpForwardTable(routes, &out_buf_size, FALSE) != ERROR_INSUFFICIENT_BUFFER)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::operation_not_supported;
			return std::vector<ip_route>();
		}

		routes = (MIB_IPFORWARDTABLE*)malloc(out_buf_size);
		if (!routes)
		{
			FreeLibrary(iphlp);
			ec = boost::asio::error::no_memory;
			return std::vector<ip_route>();
		}

		if (GetIpForwardTable(routes, &out_buf_size, FALSE) == NO_ERROR)
		{
			for (int i = 0; i < routes->dwNumEntries; ++i)
			{
				ip_route r;
				r.destination = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardDest);
				r.netmask = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardMask);
				r.gateway = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardNextHop);
				MIB_IFROW ifentry;
				ifentry.dwIndex = routes->table[i].dwForwardIfIndex;
				if (GetIfEntry(&ifentry) == NO_ERROR)
				{
					wcstombs(r.name, ifentry.wszName, sizeof(r.name));
					r.name[sizeof(r.name)-1] = 0;
					r.mtu = ifentry.dwMtu;
					ret.push_back(r);
				}
			}
		}

		// Free memory
		free(routes);
		FreeLibrary(iphlp);
#elif TORRENT_USE_NETLINK
		enum { BUFSIZE = 8192 };

		int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
		if (sock < 0)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			return std::vector<ip_route>();
		}

		int seq = 0;

		char msg[BUFSIZE];
		memset(msg, 0, BUFSIZE);
		nlmsghdr* nl_msg = (nlmsghdr*)msg;

		nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
		nl_msg->nlmsg_type = RTM_GETROUTE;
		nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
		nl_msg->nlmsg_seq = seq++;
		nl_msg->nlmsg_pid = getpid();

		if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			close(sock);
			return std::vector<ip_route>();
		}

		int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid());
		if (len < 0)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			close(sock);
			return std::vector<ip_route>();
		}

		int s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s < 0)
		{
			ec = error_code(errno, boost::asio::error::system_category);
			return std::vector<ip_route>();
		}
		for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
		{
			ip_route r;
			if (parse_route(s, nl_msg, &r)) ret.push_back(r);
		}
		close(s);
		close(sock);

#endif
		return ret;
	}
Esempio n. 27
0
int print_qdisc(const struct sockaddr_nl *who,
		       struct nlmsghdr *n,
		       void *arg)
{
	FILE *fp = (FILE*)arg;
	struct tcmsg *t = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr * tb[TCA_MAX+1];
	struct qdisc_util *q;
	char abuf[256];

	if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) {
		fprintf(stderr, "Not a qdisc\n");
		return 0;
	}
	len -= NLMSG_LENGTH(sizeof(*t));
	if (len < 0) {
		fprintf(stderr, "Wrong len %d\n", len);
		return -1;
	}

	if (filter_ifindex && filter_ifindex != t->tcm_ifindex)
		return 0;

	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);

	if (tb[TCA_KIND] == NULL) {
		fprintf(stderr, "print_qdisc: NULL kind\n");
		return -1;
	}

	if (n->nlmsg_type == RTM_DELQDISC)
		fprintf(fp, "deleted ");

	fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16);
	if (filter_ifindex == 0)
		fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
	if (t->tcm_parent == TC_H_ROOT)
		fprintf(fp, "root ");
	else if (t->tcm_parent) {
		print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
		fprintf(fp, "parent %s ", abuf);
	}
	if (t->tcm_info != 1) {
		fprintf(fp, "refcnt %d ", t->tcm_info);
	}
	/* pfifo_fast is generic enough to warrant the hardcoding --JHS */

	if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])))
		q = get_qdisc_kind("prio");
	else
		q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));

	if (tb[TCA_OPTIONS]) {
		if (q)
			q->print_qopt(q, fp, tb[TCA_OPTIONS]);
		else
			fprintf(fp, "[cannot parse qdisc parameters]");
	}
	fprintf(fp, "\n");
	if (show_details && tb[TCA_STAB]) {
		print_size_table(fp, " ", tb[TCA_STAB]);
		fprintf(fp, "\n");
	}
	if (show_stats) {
		struct rtattr *xstats = NULL;

		if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) {
			print_tcstats_attr(fp, tb, " ", &xstats);
			fprintf(fp, "\n");
		}

		if (q && xstats && q->print_xstats) {
			q->print_xstats(q, fp, xstats);
			fprintf(fp, "\n");
		}
	}
	fflush(fp);
	return 0;
}
Esempio n. 28
0
static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
{
	int len;
	char *dev = NULL;
	char *name = NULL;
	char *link = NULL;
	char *type = NULL;
	int group;
	struct link_util *lu = NULL;
	struct iplink_req req;
	int ret;

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

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.i.ifi_family = preferred_family;

	ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
	if (ret < 0)
		return ret;

	argc -= ret;
	argv += ret;

	if (group != -1) {
		if (dev)
			addattr_l(&req.n, sizeof(req), IFLA_GROUP,
					&group, sizeof(group));
		else {
			if (argc) {
				fprintf(stderr, "Garbage instead of arguments "
						"\"%s ...\". Try \"ip link "
						"help\".\n", *argv);
				return -1;
			}
			if (flags & NLM_F_CREATE) {
				fprintf(stderr, "group cannot be used when "
						"creating devices.\n");
				return -1;
			}

			req.i.ifi_index = 0;
			addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
			if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
				exit(2);
			return 0;
		}
	}

	ll_init_map(&rth);

	if (!(flags & NLM_F_CREATE)) {
		if (!dev) {
			fprintf(stderr, "Not enough information: \"dev\" "
					"argument is required.\n");
			exit(-1);
		}

		req.i.ifi_index = ll_name_to_index(dev);
		if (req.i.ifi_index == 0) {
			fprintf(stderr, "Cannot find device \"%s\"\n", dev);
			return -1;
		}
	} else {
		/* Allow "ip link add dev" and "ip link add name" */
		if (!name)
			name = dev;

		if (link) {
			int ifindex;

			ifindex = ll_name_to_index(link);
			if (ifindex == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n",
					link);
				return -1;
			}
			addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
		}
	}

	if (name) {
		len = strlen(name) + 1;
		if (len == 1)
			invarg("\"\" is not a valid device identifier\n", "name");
		if (len > IFNAMSIZ)
			invarg("\"name\" too long\n", name);
		addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
	}

	if (type) {
		struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
			 strlen(type));

		lu = get_link_kind(type);
		if (lu && argc) {
			struct rtattr * data = NLMSG_TAIL(&req.n);
			addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);

			if (lu->parse_opt &&
			    lu->parse_opt(lu, argc, argv, &req.n))
				return -1;

			data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
		} else if (argc) {
			if (matches(*argv, "help") == 0)
				usage();
			fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
					"Try \"ip link help\".\n", *argv);
			return -1;
		}
		linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
	} else if (flags & NLM_F_CREATE) {
		fprintf(stderr, "Not enough information: \"type\" argument "
				"is required\n");
		return -1;
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		exit(2);

	return 0;
}
Esempio n. 29
0
static int iprule_modify(int cmd, int argc, char **argv)
{
	int table_ok = 0;
	struct {
		struct nlmsghdr 	n;
		struct rtmsg 		r;
		char   			buf[1024];
	} req;

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

	req.n.nlmsg_type = cmd;
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.r.rtm_family = preferred_family;
	req.r.rtm_protocol = RTPROT_BOOT;
	req.r.rtm_scope = RT_SCOPE_UNIVERSE;
	req.r.rtm_table = 0;
	req.r.rtm_type = RTN_UNSPEC;
	req.r.rtm_flags = 0;

	if (cmd == RTM_NEWRULE) {
		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
		req.r.rtm_type = RTN_UNICAST;
	}

	while (argc > 0) {
		if (strcmp(*argv, "not") == 0) {
			req.r.rtm_flags |= FIB_RULE_INVERT;
		} else if (strcmp(*argv, "from") == 0) {
			inet_prefix dst;
			NEXT_ARG();
			get_prefix(&dst, *argv, req.r.rtm_family);
			req.r.rtm_src_len = dst.bitlen;
			addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen);
		} else if (strcmp(*argv, "to") == 0) {
			inet_prefix dst;
			NEXT_ARG();
			get_prefix(&dst, *argv, req.r.rtm_family);
			req.r.rtm_dst_len = dst.bitlen;
			addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen);
		} else if (matches(*argv, "preference") == 0 ||
			   matches(*argv, "order") == 0 ||
			   matches(*argv, "priority") == 0) {
			__u32 pref;
			NEXT_ARG();
			if (get_u32(&pref, *argv, 0))
				invarg("preference value is invalid\n", *argv);
			addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref);
		} else if (strcmp(*argv, "tos") == 0 ||
			   matches(*argv, "dsfield") == 0) {
			__u32 tos;
			NEXT_ARG();
			if (rtnl_dsfield_a2n(&tos, *argv))
				invarg("TOS value is invalid\n", *argv);
			req.r.rtm_tos = tos;
		} else if (strcmp(*argv, "fwmark") == 0) {
			char *slash;
			__u32 fwmark, fwmask;
			NEXT_ARG();
			if ((slash = strchr(*argv, '/')) != NULL)
				*slash = '\0';
			if (get_u32(&fwmark, *argv, 0))
				invarg("fwmark value is invalid\n", *argv);
			addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
			if (slash) {
				if (get_u32(&fwmask, slash+1, 0))
					invarg("fwmask value is invalid\n", slash+1);
				addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask);
			}
		} else if (matches(*argv, "realms") == 0) {
			__u32 realm;
			NEXT_ARG();
			if (get_rt_realms(&realm, *argv))
				invarg("invalid realms\n", *argv);
			addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
		} else if (matches(*argv, "table") == 0 ||
			   strcmp(*argv, "lookup") == 0) {
			__u32 tid;
			NEXT_ARG();
			if (rtnl_rttable_a2n(&tid, *argv))
				invarg("invalid table ID\n", *argv);
			if (tid < 256)
				req.r.rtm_table = tid;
			else {
				req.r.rtm_table = RT_TABLE_UNSPEC;
				addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
			}
			table_ok = 1;
		} else if (strcmp(*argv, "dev") == 0 ||
			   strcmp(*argv, "iif") == 0) {
			NEXT_ARG();
			addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1);
		} else if (strcmp(*argv, "oif") == 0) {
			NEXT_ARG();
			addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1);
		} else if (strcmp(*argv, "nat") == 0 ||
			   matches(*argv, "map-to") == 0) {
			NEXT_ARG();
			fprintf(stderr, "Warning: route NAT is deprecated\n");
			addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
			req.r.rtm_type = RTN_NAT;
		} else {
			int type;

			if (strcmp(*argv, "type") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			else if (matches(*argv, "goto") == 0) {
				__u32 target;
				type = FR_ACT_GOTO;
				NEXT_ARG();
				if (get_u32(&target, *argv, 0))
					invarg("invalid target\n", *argv);
				addattr32(&req.n, sizeof(req), FRA_GOTO, target);
			} else if (matches(*argv, "nop") == 0)
				type = FR_ACT_NOP;
			else if (rtnl_rtntype_a2n(&type, *argv))
				invarg("Failed to parse rule type", *argv);
			req.r.rtm_type = type;
			table_ok = 1;
		}
		argc--;
		argv++;
	}

	if (req.r.rtm_family == AF_UNSPEC)
		req.r.rtm_family = AF_INET;

	if (!table_ok && cmd == RTM_NEWRULE)
		req.r.rtm_table = RT_TABLE_MAIN;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		return 2;

	return 0;
}
Esempio n. 30
0
/* Add/Delete IP address to a specific interface_t */
int
netlink_ipaddress(ip_address_t *ipaddress, int cmd)
{
	struct ifa_cacheinfo cinfo;
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct ifaddrmsg ifa;
		char buf[256];
	} req;

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

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifaddrmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = (cmd == IPADDRESS_DEL) ? RTM_DELADDR : RTM_NEWADDR;
	req.ifa = ipaddress->ifa;

	if (IP_IS6(ipaddress)) {
		if (cmd == IPADDRESS_ADD) {
			/* Mark IPv6 address as deprecated (rfc3484) in order to prevent
			 * using VRRP VIP as source address in healthchecking use cases.
			 */
			if (ipaddress->ifa.ifa_prefixlen == 128) {
				memset(&cinfo, 0, sizeof(cinfo));
				cinfo.ifa_prefered = 0;
				cinfo.ifa_valid = INFINITY_LIFE_TIME;

				log_message(LOG_INFO, "%s has a prefix length of 128, setting "
						      "preferred_lft to 0", ipaddresstos(NULL, ipaddress));
				addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
					  sizeof(cinfo));
			}

			/* Disable, per VIP, Duplicate Address Detection algorithm (DAD).
			 * Using the nodad flag has the following benefits:
			 *
			 * (1) The address becomes immediately usable after they're
			 *     configured.
			 * (2) In the case of a temporary layer-2 / split-brain problem
			 *     we can avoid that the active VIP transitions into the
			 *     dadfailed phase and stays there forever - leaving us
			 *     without service. HA/VRRP setups have their own "DAD"-like
			 *     functionality, so it's not really needed from the IPv6 stack.
			 */
#ifdef IFA_F_NODAD
			req.ifa.ifa_flags |= IFA_F_NODAD;
#endif
		}

		addattr_l(&req.n, sizeof(req), IFA_LOCAL,
			  &ipaddress->u.sin6_addr, sizeof(ipaddress->u.sin6_addr));
	} else {
		addattr_l(&req.n, sizeof(req), IFA_LOCAL,
			  &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr));

		if (cmd == IPADDRESS_ADD) {
			if (ipaddress->u.sin.sin_brd.s_addr)
				addattr_l(&req.n, sizeof(req), IFA_BROADCAST,
					  &ipaddress->u.sin.sin_brd, sizeof(ipaddress->u.sin.sin_brd));
		}
		else {
			/* IPADDRESS_DEL */
			addattr_l(&req.n, sizeof(req), IFA_ADDRESS,
				  &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr));
		}
	}

	if (cmd == IPADDRESS_ADD)
		if (ipaddress->label)
			addattr_l(&req.n, sizeof (req), IFA_LABEL,
				  ipaddress->label, strlen(ipaddress->label) + 1);

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

	return status;
}