/**
 * nfacct_nlmsg_build_payload - build payload from accounting object
 * \param nlh: netlink message that you want to use to add the payload.
 * \param nfacct: pointer to a accounting object
 */
void nfacct_nlmsg_build_payload(struct nlmsghdr *nlh, struct nfacct *nfacct)
{
	if (nfacct->bitset & (1 << NFACCT_ATTR_NAME))
		mnl_attr_put_strz(nlh, NFACCT_NAME, nfacct->name);

	if (nfacct->bitset & (1 << NFACCT_ATTR_PKTS))
		mnl_attr_put_u64(nlh, NFACCT_PKTS, htobe64(nfacct->pkts));

	if (nfacct->bitset & (1 << NFACCT_ATTR_BYTES))
		mnl_attr_put_u64(nlh, NFACCT_BYTES, htobe64(nfacct->bytes));
}
Exemplo n.º 2
0
static int
nfct_build_protoinfo(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
{
	struct nlattr *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 = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP);
		if (test_bit(ATTR_TCP_STATE, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE,
					ct->protoinfo.tcp.state);
		}
		if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) &&
		    test_bit(ATTR_TCP_MASK_ORIG, ct->head.set)) {
			mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
				     sizeof(struct nf_ct_tcp_flags),
				     &ct->protoinfo.tcp.flags[0]);
		}
		if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) &&
		    test_bit(ATTR_TCP_MASK_REPL, ct->head.set)) {
			mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_REPLY,
				     sizeof(struct nf_ct_tcp_flags),
				     &ct->protoinfo.tcp.flags[1]);
		}
		if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
					ct->protoinfo.tcp.wscale[__DIR_ORIG]);
		}
		if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_REPLY,
					ct->protoinfo.tcp.wscale[__DIR_REPL]);
		}
		mnl_attr_nest_end(nlh, nest_proto);
		mnl_attr_nest_end(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 = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_SCTP);

		if (test_bit(ATTR_SCTP_STATE, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_SCTP_STATE,
					ct->protoinfo.sctp.state);
		}
		if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set)) {
			mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
				htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG]));
		}
		if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set)) {
			mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_REPLY,
				htonl(ct->protoinfo.sctp.vtag[__DIR_REPL]));
		}
		mnl_attr_nest_end(nlh, nest_proto);
		mnl_attr_nest_end(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 = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_DCCP);
		if (test_bit(ATTR_DCCP_STATE, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_STATE,
					ct->protoinfo.dccp.state);
		}
		if (test_bit(ATTR_DCCP_ROLE, ct->head.set)) {
			mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_ROLE,
					ct->protoinfo.dccp.role);
		}
		if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) {
			uint64_t handshake_seq =
				be64toh(ct->protoinfo.dccp.handshake_seq);

			mnl_attr_put_u64(nlh, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
					 handshake_seq);
		}
		mnl_attr_nest_end(nlh, nest_proto);
		mnl_attr_nest_end(nlh, nest);
	default:
		break;
	}
	return 0;
}
Exemplo n.º 3
0
static struct nlmsghdr *pack_nlmsg(void *buf, int len, const char *format, va_list ap)
{
	struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
	void *p;
	char *s;
	size_t slen;
	int remains;

	while (*format != '\0') {
		remains = len - (int)nlh->nlmsg_len
			- MY_ATTR_ALIGN(sizeof(struct nlattr));
		switch (*format) {
		case 'B': /* byte */
			if (MY_ATTR_ALIGN(sizeof(uint8_t)) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			/* gcc warning: 'uint8_t' is promoted
			 * to 'int' when passed through '...' */
			mnl_attr_put_u8(nlh, MNL_TYPE_U8,
					(uint8_t)va_arg(ap, int));
			break;
		case 'H': /* 2byte */
			if (MY_ATTR_ALIGN(sizeof(uint16_t)) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			/* gcc warning: 'uint16_t' is promoted
			 * to 'int' when passed through '...' */
			mnl_attr_put_u16(nlh, MNL_TYPE_U16,
					 (uint16_t)va_arg(ap, int));
			break;
		case 'I': /* 4byte */
			if (MY_ATTR_ALIGN(sizeof(uint32_t)) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			mnl_attr_put_u32(nlh, MNL_TYPE_U32,
					 va_arg(ap, uint32_t));
			break;
		case 'K': /* 8byte */
			if (MY_ATTR_ALIGN(sizeof(uint64_t)) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			mnl_attr_put_u64(nlh, MNL_TYPE_U64,
					 va_arg(ap, uint64_t));
			break;
		case 'p': /* pointer */
			if (MY_ATTR_ALIGN(sizeof(void *)) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			p = va_arg(ap, void *);
			mnl_attr_put(nlh, MNL_TYPE_BINARY, sizeof(void *), &p);
			break;
		case 'z': /* null string */
			s = va_arg(ap, char *);
			slen = strlen(s);
			if (MY_ATTR_ALIGN(slen + 1) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			mnl_attr_put(nlh, MNL_TYPE_NUL_STRING, slen + 1, s);
			break;
		case 'y': /* bytes with size */
			format++;
			if (*format != '#') {
				errno = EINVAL;
				return NULL;
			}
			p = va_arg(ap, void *);
			slen = va_arg(ap, size_t);
			if (MY_ATTR_ALIGN(slen) > remains) {
				errno = EOVERFLOW;
				return NULL;
			}

			mnl_attr_put(nlh, MNL_TYPE_STRING, slen, p);
			break;
		default:
			errno = EINVAL;
			return NULL;

		}
		format++;
	}

	return nlh;
}