Beispiel #1
0
void __build_tuple_ip(struct nfnlhdr *req, 
		      size_t size,
		      const struct __nfct_tuple *t)
{
	struct nfattr *nest;

	nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP);

	switch(t->l3protonum) {
	case AF_INET:
	        nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4,
			       sizeof(u_int32_t));
		nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
			       sizeof(u_int32_t));
		break;
	case AF_INET6:
		nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_SRC, &t->src.v6,
			       sizeof(struct in6_addr));
		nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_DST, &t->dst.v6,
			       sizeof(struct in6_addr));
		break;
	default:
		break;
	}

	nfnl_nest_end(&req->nlh, nest);
}
static void build_tuple_proto(struct nfnlhdr *req, int size,
                              struct nfct_tuple *t)
{
	nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4,
		       sizeof(u_int32_t));
	nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
		       sizeof(u_int32_t));
}
static void build_tuple_proto(struct nfnlhdr *req, int size, 
			      struct nfct_tuple *t)
{
	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT,
		       &t->l4src.sctp.port, sizeof(u_int16_t));
	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT,
		       &t->l4dst.sctp.port, sizeof(u_int16_t));
}
static void build_tuple_proto(struct nfnlhdr *req, int size,
			      struct nfct_tuple *t)
{
	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE,
		       &t->l4dst.icmp.code, sizeof(u_int8_t));
	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE,
		       &t->l4dst.icmp.type, sizeof(u_int8_t));
	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID,
		       &t->l4src.icmp.id, sizeof(u_int16_t));
}
Beispiel #5
0
void __build_nat(struct nfnlhdr *req,
		 size_t size,
		 const struct __nfct_nat *nat)
{
	nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP,
		       &nat->min_ip, sizeof(u_int32_t));
}
Beispiel #6
0
/**
 * nfnl_addattr8 - Add uint8_t attribute to nlmsghdr
 *
 * @n: netlink message header to which attribute is to be added
 * @maxlen: maximum length of netlink message header
 * @type: type of new attribute
 * @data: content of new attribute
 */
int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, uint8_t data)
{
	assert(n);
	assert(maxlen > 0);
	assert(type >= 0);

	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
}
Beispiel #7
0
void __build_tuple_proto(struct nfnlhdr *req,
			 size_t size,
			 const struct __nfct_tuple *t)
{
	struct nfattr *nest;

	nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO);

	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum,
		       sizeof(u_int8_t));

	switch(t->protonum) {
	case IPPROTO_UDP:
	case IPPROTO_TCP:
	case IPPROTO_SCTP:
	case IPPROTO_DCCP:
	case IPPROTO_GRE:
	case IPPROTO_UDPLITE:
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT,
			       &t->l4src.tcp.port, sizeof(u_int16_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT,
			       &t->l4dst.tcp.port, sizeof(u_int16_t));
		break;

	case IPPROTO_ICMP:
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE,
			       &t->l4dst.icmp.code, sizeof(u_int8_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE,
			       &t->l4dst.icmp.type, sizeof(u_int8_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID,
			       &t->l4src.icmp.id, sizeof(u_int16_t));
		break;

	case IPPROTO_ICMPV6:
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_CODE,
			       &t->l4dst.icmp.code, sizeof(u_int8_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_TYPE,
			       &t->l4dst.icmp.type, sizeof(u_int8_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_ID,
			       &t->l4src.icmp.id, sizeof(u_int16_t));
		break;

	default:
		break;
	}

	nfnl_nest_end(&req->nlh, nest);
}
Beispiel #8
0
void __build_protonat(struct nfnlhdr *req,
		      size_t size,
		      const struct nf_conntrack *ct,
		      const struct __nfct_nat *nat)
{
	struct nfattr *nest;

	nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO);

	switch (ct->tuple[__DIR_ORIG].protonum) {
	case IPPROTO_TCP:
	case IPPROTO_UDP:
		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MIN,
			       &nat->l4min.tcp.port, sizeof(u_int16_t));
		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MAX,
			       &nat->l4max.tcp.port, sizeof(u_int16_t));
		break;
	}
	nfnl_nest_end(&req->nlh, nest);
}
Beispiel #9
0
void __build_helper_name(struct nfnlhdr *req,
			 size_t size,
			 const struct nf_conntrack *ct)
{
	struct nfattr *nest;

	nest = nfnl_nest(&req->nlh, size, CTA_HELP);
	nfnl_addattr_l(&req->nlh,
		       size, 
		       CTA_HELP_NAME,
		       ct->helper_name,
		       strlen(ct->helper_name));
	nfnl_nest_end(&req->nlh, nest);
}
Beispiel #10
0
/* build a NFULNL_MSG_CONFIG message */
static int
__build_send_cfg_msg(struct nflog_handle *h, u_int8_t command,
		     u_int16_t queuenum, u_int8_t pf)
{
	char buf[NFNL_HEADER_LEN
		+NFA_LENGTH(sizeof(struct nfulnl_msg_config_cmd))];
	struct nfulnl_msg_config_cmd cmd;
	struct nlmsghdr *nmh = (struct nlmsghdr *) buf;

	nfnl_fill_hdr(h->nfnlssh, nmh, 0, pf, queuenum,
		      NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);

	cmd.command = command;
	nfnl_addattr_l(nmh, sizeof(buf), NFULA_CFG_CMD, &cmd, sizeof(cmd));

	return nfnl_talk(h->nfnlh, nmh, 0, 0, NULL, NULL, NULL);
}
Beispiel #11
0
int nflog_set_mode(struct nflog_g_handle *gh,
		   u_int8_t mode, u_int32_t range)
{
	char buf[NFNL_HEADER_LEN
		+NFA_LENGTH(sizeof(struct nfulnl_msg_config_mode))];
	struct nfulnl_msg_config_mode params;
	struct nlmsghdr *nmh = (struct nlmsghdr *) buf;

	nfnl_fill_hdr(gh->h->nfnlssh, nmh, 0, AF_UNSPEC, gh->id,
		      NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);

	params.copy_range = htonl(range);	/* copy_range is short */
	params.copy_mode = mode;
	nfnl_addattr_l(nmh, sizeof(buf), NFULA_CFG_MODE, &params,
		       sizeof(params));

	return nfnl_talk(gh->h->nfnlh, nmh, 0, 0, NULL, NULL, NULL);
}
/* build a NFULNL_MSG_CONFIG message */
static int
__build_send_cfg_msg(struct nflog_handle *h, uint8_t command,
		     uint16_t groupnum, uint8_t pf)
{
	union {
		char buf[NFNL_HEADER_LEN
			+NFA_LENGTH(sizeof(struct nfulnl_msg_config_cmd))];
		struct nlmsghdr nmh;
	} u;
	struct nfulnl_msg_config_cmd cmd;

	nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, pf, groupnum,
		      NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);

	cmd.command = command;
	nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_CMD, &cmd, sizeof(cmd));

	return nfnl_query(h->nfnlh, &u.nmh);
}
/**
 * nflog_set_mode - set the amount of packet data that nflog copies to userspace
 * \param qh Netfilter log handle obtained by call to nflog_bind_group().
 * \param mode the part of the packet that we are interested in
 * \param range size of the packet that we want to get
 *
 * Sets the amount of data to be copied to userspace for each packet logged
 * to the given group.
 *
 * - NFULNL_COPY_NONE - do not copy any data
 * - NFULNL_COPY_META - copy only packet metadata
 * - NFULNL_COPY_PACKET - copy entire packet
 *
 * \return -1 on error; >= otherwise.
 */
int nflog_set_mode(struct nflog_g_handle *gh,
		   uint8_t mode, uint32_t range)
{
	union {
		char buf[NFNL_HEADER_LEN
			+NFA_LENGTH(sizeof(struct nfulnl_msg_config_mode))];
		struct nlmsghdr nmh;
	} u;
	struct nfulnl_msg_config_mode params;

	nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
		      NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);

	params.copy_range = htonl(range);	/* copy_range is short */
	params.copy_mode = mode;
	nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_MODE, &params,
		       sizeof(params));

	return nfnl_query(gh->h->nfnlh, &u.nmh);
}
Beispiel #14
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
	int fd = -1;
	struct nlmsghdr *h;
	int status;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) &req.n,
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	const struct sockaddr_in * dst4;
	const struct sockaddr_in6 * dst6;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;
	req.r.rtm_table = 0;
	req.r.rtm_protocol = 0;
	req.r.rtm_scope = 0;
	req.r.rtm_type = 0;
	req.r.rtm_src_len = 0;
	req.r.rtm_dst_len = 0;
	req.r.rtm_tos = 0;

	{
		char dst_str[128];
		sockaddr_to_string(dst, dst_str, sizeof(dst_str));
		syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
	}
	/* add address */
	if(dst->sa_family == AF_INET) {
		dst4 = (const struct sockaddr_in *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
		req.r.rtm_dst_len = 32;
	} else {
		dst6 = (const struct sockaddr_in6 *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
		req.r.rtm_dst_len = 128;
	}

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd < 0) {
		syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
		return -1;
	}

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req.n.nlmsg_seq = 1;
	iov.iov_len = req.n.nlmsg_len;

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

	if (status < 0) {
		syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
		goto error;
	}

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

	for(;;) {
		iov.iov_len = sizeof(req);
		status = recvmsg(fd, &msg, 0);
		if(status < 0) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
			syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
			goto error;
		}
		if(status == 0) {
			syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
			goto error;
		}
		for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
			int len = h->nlmsg_len;
			int l = len - sizeof(*h);

			if (l<0 || len>status) {
				if (msg.msg_flags & MSG_TRUNC) {
					syslog(LOG_ERR, "Truncated message");
				}
				syslog(LOG_ERR, "malformed message: len=%d", len);
				goto error;
			}

			if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
				syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
				/* Don't forget to skip that message. */
				status -= NLMSG_ALIGN(len);
				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
				continue;
			}

			if(h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
				syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
				goto error;
			}
			if(h->nlmsg_type == RTM_NEWROUTE) {
				struct rtattr * rta;
				int len = h->nlmsg_len;
				len -= NLMSG_LENGTH(sizeof(struct rtmsg));
				for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
					unsigned char * data = RTA_DATA(rta);
					if(rta->rta_type == RTA_PREFSRC) {
						if(src_len && src) {
							if(*src_len < RTA_PAYLOAD(rta)) {
								syslog(LOG_WARNING, "cannot copy src: %u<%lu",
								       (unsigned)*src_len, RTA_PAYLOAD(rta));
								goto error;
							}
							*src_len = RTA_PAYLOAD(rta);
							memcpy(src, data, RTA_PAYLOAD(rta));
						}
					} else if(rta->rta_type == RTA_OIF) {
						if(index)
							memcpy(index, data, sizeof(int));
					}
				}
				close(fd);
				return 0;
			}
			status -= NLMSG_ALIGN(len);
			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
		}
	}
	syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
error:
	if(fd >= 0)
		close(fd);
	return -1;
}
Beispiel #15
0
static void __build_helper_name(struct nfnlhdr *req, size_t size,
			 const struct nf_expect *exp)
{
	nfnl_addattr_l(&req->nlh, size, CTA_EXPECT_HELP_NAME,
			exp->helper_name, strlen(exp->helper_name));
}
static void __build_protoinfo(struct nfnlhdr *req, size_t size,
			      const struct nf_conntrack *ct)
{
	struct nfattr *nest, *nest_proto;

	switch(ct->head.orig.protonum) {
	case IPPROTO_TCP:
		/* Preliminary attribute check to avoid sending an empty
		 * CTA_PROTOINFO_TCP nest, which results in EINVAL in
		 * Linux kernel <= 2.6.25. */
		if (!(test_bit(ATTR_TCP_STATE, ct->head.set) ||
		      test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) ||
		      test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) ||
		      test_bit(ATTR_TCP_MASK_ORIG, ct->head.set) ||
		      test_bit(ATTR_TCP_MASK_REPL, ct->head.set) ||
		      test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set) ||
		      test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))) {
			break;
		}
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP);
		if (test_bit(ATTR_TCP_STATE, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_STATE,
				       &ct->protoinfo.tcp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) &&
		    test_bit(ATTR_TCP_MASK_ORIG, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
				       &ct->protoinfo.tcp.flags[0], 
				       sizeof(struct nf_ct_tcp_flags));
		if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) &&
		    test_bit(ATTR_TCP_MASK_REPL, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_FLAGS_REPLY,
				       &ct->protoinfo.tcp.flags[1], 
				       sizeof(struct nf_ct_tcp_flags));
		if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
				       &ct->protoinfo.tcp.wscale[__DIR_ORIG],
				       sizeof(u_int8_t));
		if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_WSCALE_REPLY,
				       &ct->protoinfo.tcp.wscale[__DIR_REPL],
				       sizeof(u_int8_t));
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
		break;
	case IPPROTO_SCTP:
		/* See comment above on TCP. */
		if (!(test_bit(ATTR_SCTP_STATE, ct->head.set) ||
		      test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set) ||
		      test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))) {
			break;
		}
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_SCTP);
		if (test_bit(ATTR_SCTP_STATE, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_SCTP_STATE,
				       &ct->protoinfo.sctp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set))
			nfnl_addattr32(&req->nlh, size,
				    CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
				    htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG]));
		if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))
			nfnl_addattr32(&req->nlh, size,
				    CTA_PROTOINFO_SCTP_VTAG_REPLY,
				    htonl(ct->protoinfo.sctp.vtag[__DIR_REPL]));
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
		break;
	case IPPROTO_DCCP:
		/* See comment above on TCP. */
		if (!(test_bit(ATTR_DCCP_STATE, ct->head.set) ||
		      test_bit(ATTR_DCCP_ROLE, ct->head.set) ||
		      test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set))) {
			break;
		}
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_DCCP);
		if (test_bit(ATTR_DCCP_STATE, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_STATE,
				       &ct->protoinfo.dccp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_DCCP_ROLE, ct->head.set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_ROLE,
				       &ct->protoinfo.dccp.role,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) {
			/* FIXME: use __cpu_to_be64() instead which is the
			 * correct operation. This is a semantic abuse but
			 * we have no function to do it in libnfnetlink. */
			u_int64_t handshake_seq =
				__be64_to_cpu(ct->protoinfo.dccp.handshake_seq);

			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
				       &handshake_seq,
				       sizeof(u_int64_t));
		}
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
	default:
		break;
	}
}
Beispiel #17
0
static void __build_protoinfo(struct nfnlhdr *req, size_t size,
			      const struct nf_conntrack *ct)
{
	struct nfattr *nest, *nest_proto;

	switch(ct->tuple[__DIR_ORIG].protonum) {
	case IPPROTO_TCP:
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP);
		if (test_bit(ATTR_TCP_STATE, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_STATE,
				       &ct->protoinfo.tcp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->set) &&
		    test_bit(ATTR_TCP_MASK_ORIG, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
				       &ct->protoinfo.tcp.flags[0], 
				       sizeof(u_int16_t));
		if (test_bit(ATTR_TCP_FLAGS_REPL, ct->set) &&
		    test_bit(ATTR_TCP_MASK_REPL, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_TCP_FLAGS_REPLY,
				       &ct->protoinfo.tcp.flags[1], 
				       sizeof(u_int16_t));
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
		break;
	case IPPROTO_SCTP:
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_SCTP);
		if (test_bit(ATTR_SCTP_STATE, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_SCTP_STATE,
				       &ct->protoinfo.sctp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->set))
			nfnl_addattr32(&req->nlh, size,
				    CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
				    htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG]));
		if (test_bit(ATTR_SCTP_VTAG_REPL, ct->set))
			nfnl_addattr32(&req->nlh, size,
				    CTA_PROTOINFO_SCTP_VTAG_REPLY,
				    htonl(ct->protoinfo.sctp.vtag[__DIR_REPL]));
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
		break;
	case IPPROTO_DCCP:
		nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
		nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_DCCP);
		if (test_bit(ATTR_DCCP_STATE, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_STATE,
				       &ct->protoinfo.dccp.state,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_DCCP_ROLE, ct->set))
			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_ROLE,
				       &ct->protoinfo.dccp.role,
				       sizeof(u_int8_t));
		if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->set)) {
			/* FIXME: use __cpu_to_be64() instead which is the
			 * correct operation. This is a semantic abuse but
			 * we have no function to do it in libnfnetlink. */
			u_int64_t handshake_seq =
				__be64_to_cpu(ct->protoinfo.dccp.handshake_seq);

			nfnl_addattr_l(&req->nlh, size,
				       CTA_PROTOINFO_DCCP_SEQ,
				       &handshake_seq,
				       sizeof(u_int64_t));
		}
		nfnl_nest_end(&req->nlh, nest_proto);
		nfnl_nest_end(&req->nlh, nest);
	default:
		break;
	}
}
static int osf_load_line(char *buffer, int len, int del)
{
	int i, cnt = 0;
	char obuf[MAXOPTSTRLEN];
	struct xt_osf_user_finger f;
	char *pbeg, *pend;
	char buf[NFNL_HEADER_LEN + NFA_LENGTH(sizeof(struct xt_osf_user_finger))];
	struct nlmsghdr *nmh = (struct nlmsghdr *) buf;

	memset(&f, 0, sizeof(struct xt_osf_user_finger));

	ulog("Loading '%s'.\n", buffer);

	for (i = 0; i < len && buffer[i] != '\0'; ++i) {
		if (buffer[i] == ':')
			cnt++;
	}

	if (cnt != 8) {
		ulog("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len);
		return -EINVAL;
	}

	memset(obuf, 0, sizeof(obuf));

	pbeg = buffer;
	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		if (pbeg[0] == 'S') {
			f.wss.wc = OSF_WSS_MSS;
			if (pbeg[1] == '%')
				f.wss.val = strtoul(&pbeg[2], NULL, 10);
			else if (pbeg[1] == '*')
				f.wss.val = 0;
			else
				f.wss.val = strtoul(&pbeg[1], NULL, 10);
		} else if (pbeg[0] == 'T') {
			f.wss.wc = OSF_WSS_MTU;
			if (pbeg[1] == '%')
				f.wss.val = strtoul(&pbeg[2], NULL, 10);
			else if (pbeg[1] == '*')
				f.wss.val = 0;
			else
				f.wss.val = strtoul(&pbeg[1], NULL, 10);
		} else if (pbeg[0] == '%') {
			f.wss.wc = OSF_WSS_MODULO;
			f.wss.val = strtoul(&pbeg[1], NULL, 10);
		} else if (isdigit(pbeg[0])) {
			f.wss.wc = OSF_WSS_PLAIN;
			f.wss.val = strtoul(&pbeg[0], NULL, 10);
		}

		pbeg = pend + 1;
	}
	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		f.ttl = strtoul(pbeg, NULL, 10);
		pbeg = pend + 1;
	}
	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		f.df = strtoul(pbeg, NULL, 10);
		pbeg = pend + 1;
	}
	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		f.ss = strtoul(pbeg, NULL, 10);
		pbeg = pend + 1;
	}

	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg);
		pbeg = pend + 1;
	}

	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		if (pbeg[0] == '@' || pbeg[0] == '*')
			cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1);
		else
			cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
		pbeg = pend + 1;
	}

	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg);
		pbeg = pend + 1;
	}

	pend = xt_osf_strchr(pbeg, OSFPDEL);
	if (pend) {
		*pend = '\0';
		cnt =
		    snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
		pbeg = pend + 1;
	}

	xt_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));

	memset(buf, 0, sizeof(buf));

	if (del)
		nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
	else
		nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);

	nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));

	return nfnl_talk(nfnlh, nmh, 0, 0, NULL, NULL, NULL);
}
Beispiel #19
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
#if __linux__
	int fd = -1;
	struct nlmsghdr *h;
	int status;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) &req.n,
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	const struct sockaddr_in * dst4;
	const struct sockaddr_in6 * dst6;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;
	req.r.rtm_table = 0;
	req.r.rtm_protocol = 0;
	req.r.rtm_scope = 0;
	req.r.rtm_type = 0;
	req.r.rtm_src_len = 0;
	req.r.rtm_dst_len = 0;
	req.r.rtm_tos = 0;

	{
		char dst_str[128];
		sockaddr_to_string(dst, dst_str, sizeof(dst_str));
		syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
	}
	/* add address */
	if(dst->sa_family == AF_INET) {
		dst4 = (const struct sockaddr_in *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
		req.r.rtm_dst_len = 32;
	} else {
		dst6 = (const struct sockaddr_in6 *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
		req.r.rtm_dst_len = 128;
	}

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd < 0) {
		syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
		return -1;
	}

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req.n.nlmsg_seq = 1;
	iov.iov_len = req.n.nlmsg_len;

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

	if (status < 0) {
		syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
		goto error;
	}

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

	for(;;) {
		iov.iov_len = sizeof(req);
		status = recvmsg(fd, &msg, 0);
		if(status < 0) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
			syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
			goto error;
		}
		if(status == 0) {
			syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
			goto error;
		}
		for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
			int len = h->nlmsg_len;
			int l = len - sizeof(*h);

			if (l<0 || len>status) {
				if (msg.msg_flags & MSG_TRUNC) {
					syslog(LOG_ERR, "Truncated message");
				}
				syslog(LOG_ERR, "malformed message: len=%d", len);
				goto error;
			}

			if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
				syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
				/* Don't forget to skip that message. */
				status -= NLMSG_ALIGN(len);
				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
				continue;
			}

			if(h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
				syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
				goto error;
			}
			if(h->nlmsg_type == RTM_NEWROUTE) {
				struct rtattr * rta;
				int len = h->nlmsg_len;
				len -= NLMSG_LENGTH(sizeof(struct rtmsg));
				for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
					unsigned char * data = RTA_DATA(rta);
					if(rta->rta_type == RTA_PREFSRC) {
						if(src_len && src) {
							if(*src_len < RTA_PAYLOAD(rta)) {
								syslog(LOG_WARNING, "cannot copy src: %u<%lu",
								       (unsigned)*src_len, (unsigned long)RTA_PAYLOAD(rta));
								goto error;
							}
							*src_len = RTA_PAYLOAD(rta);
							memcpy(src, data, RTA_PAYLOAD(rta));
						}
					} else if(rta->rta_type == RTA_OIF) {
						if(index)
							memcpy(index, data, sizeof(int));
					}
				}
				close(fd);
				return 0;
			}
			status -= NLMSG_ALIGN(len);
			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
		}
	}
	syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
error:
	if(fd >= 0)
		close(fd);
	return -1;
#else /* __linux__ */
	int found = 0;
	int s;
	int l, i;
	char * p;
	struct sockaddr * sa;
	struct {
	  struct rt_msghdr m_rtm;
	  char       m_space[512];
	} m_rtmsg;
#define rtm m_rtmsg.m_rtm

	if(dst == NULL)
		return -1;
#ifdef __APPLE__
	if(dst->sa_family == AF_INET6) {
		syslog(LOG_ERR, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X...");
		return -1;
	}
#endif
	s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family);
	if(s < 0) {
		syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m");
		return -1;
	}
	memset(&rtm, 0, sizeof(rtm));
	rtm.rtm_type = RTM_GET;
	rtm.rtm_flags = RTF_UP;
	rtm.rtm_version = RTM_VERSION;
	rtm.rtm_seq = 1;
	rtm.rtm_addrs = RTA_DST;	/* destination address */
	memcpy(m_rtmsg.m_space, dst, sizeof(struct sockaddr));
	rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr);
	if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) {
		syslog(LOG_ERR, "write: %m");
		close(s);
		return -1;
	}

	do {
		l = read(s, &m_rtmsg, sizeof(m_rtmsg));
		if(l<0) {
			syslog(LOG_ERR, "read: %m");
			close(s);
			return -1;
		}
		syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d",
		       l, rtm.rtm_seq, rtm.rtm_pid);
	} while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1));
	close(s);
	p = m_rtmsg.m_space;
	if(rtm.rtm_addrs) {
		for(i=1; i<0x8000; i <<= 1) {
			if(i & rtm.rtm_addrs) {
				char tmp[256] = { 0 };
				sa = (struct sockaddr *)p;
				sockaddr_to_string(sa, tmp, sizeof(tmp));
				syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
				       i, SA_LEN(sa), sa->sa_family, tmp);
				if((i == RTA_DST || i == RTA_GATEWAY) &&
				   (src_len && src)) {
					size_t len = 0;
					void * paddr = NULL;
					if(sa->sa_family == AF_INET) {
						paddr = &((struct sockaddr_in *)sa)->sin_addr;
						len = sizeof(struct in_addr);
					} else if(sa->sa_family == AF_INET6) {
						paddr = &((struct sockaddr_in6 *)sa)->sin6_addr;
						len = sizeof(struct in6_addr);
					}
					if(paddr) {
						if(*src_len < len) {
							syslog(LOG_WARNING, "cannot copy src. %u<%u",
							       (unsigned)*src_len, (unsigned)len);
							return -1;
						}
						memcpy(src, paddr, len);
						*src_len = len;
						found = 1;
					}
				}
#ifdef AF_LINK
				if(sa->sa_family == AF_LINK) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					if(index)
						*index = sdl->sdl_index;
				}
#endif
				p += SA_LEN(sa);
			}
		}
	}
	return found ? 0 : -1;
#endif /* __linux__ */
}