18a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <stdio.h>
28a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <stdlib.h>
38a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <string.h>
48a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <time.h>
58a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
68a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <libmnl/libmnl.h>
78a44513648da0c5f5551f96b329cf56b66f5b303pkanwar#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
88a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
98a44513648da0c5f5551f96b329cf56b66f5b303pkanwarstruct callback_args {
108a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct mnl_socket *nl;
118a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	unsigned int seq;
128a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	int bit;
138a44513648da0c5f5551f96b329cf56b66f5b303pkanwar};
148a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
158a44513648da0c5f5551f96b329cf56b66f5b303pkanwarstatic void set_label(struct nf_conntrack *ct, struct callback_args *cbargs)
168a44513648da0c5f5551f96b329cf56b66f5b303pkanwar{
178a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nfct_bitmask *b = (void *) nfct_get_attr(ct, ATTR_CONNLABELS);
188a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	int bit = cbargs->bit;
198a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	char buf[MNL_SOCKET_BUFFER_SIZE];
208a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nlmsghdr *nlh;
218a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nfgenmsg *nfh;
228a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
238a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (b) {
248a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		if (bit < 0)
258a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			b = nfct_bitmask_new(0);
268a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		else if (nfct_bitmask_test_bit(b, bit))
278a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			return;
288a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	} else {
298a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		b = nfct_bitmask_new(0);
308a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
318a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
328a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (!b)
338a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		return;
348a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (bit >= 0)
358a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		nfct_bitmask_set_bit(b, bit);
368a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfct_set_attr(ct, ATTR_CONNLABELS, b);
378a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
388a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (bit >= 0) {
398a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		b = nfct_bitmask_new(bit);
408a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		if (b) {
418a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			nfct_bitmask_set_bit(b, bit);
428a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			nfct_set_attr(ct, ATTR_CONNLABELS_MASK, b);
438a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		}
448a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
458a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
468a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	cbargs->seq++;
478a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
488a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh = mnl_nlmsg_put_header(buf);
498a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
508a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
518a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_seq = cbargs->seq;
528a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
538a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
548a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->nfgen_family = nfct_get_attr_u8(ct, ATTR_L3PROTO);
558a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->version = NFNETLINK_V0;
568a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->res_id = 0;
578a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
588a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfct_nlmsg_build(nlh, ct);
598a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
608a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (mnl_socket_sendto(cbargs->nl, nlh, nlh->nlmsg_len) < 0)
618a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		perror("mnl_socket_sendto");
628a44513648da0c5f5551f96b329cf56b66f5b303pkanwar}
638a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
648a44513648da0c5f5551f96b329cf56b66f5b303pkanwarstatic int data_cb(const struct nlmsghdr *nlh, void *data)
658a44513648da0c5f5551f96b329cf56b66f5b303pkanwar{
668a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nf_conntrack *ct;
678a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	char buf[4096];
688a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
698a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	ct = nfct_new();
708a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (ct == NULL)
718a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		return MNL_CB_OK;
728a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
738a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfct_nlmsg_parse(nlh, ct);
748a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
758a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0);
768a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	printf("%s\n", buf);
778a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
788a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	set_label(ct, data);
798a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
808a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfct_destroy(ct);
818a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
828a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	return MNL_CB_OK;
838a44513648da0c5f5551f96b329cf56b66f5b303pkanwar}
848a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
858a44513648da0c5f5551f96b329cf56b66f5b303pkanwarstatic void show_labels(struct nfct_labelmap *l)
868a44513648da0c5f5551f96b329cf56b66f5b303pkanwar{
878a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	unsigned int i = 0;
888a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	const char *name;
898a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
908a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (l) {
918a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		fputs("usage: program label, configured labels are:\n", stderr);
928a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		while ((name = nfct_labelmap_get_name(l, i))) {
938a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			if (*name)
948a44513648da0c5f5551f96b329cf56b66f5b303pkanwar				fprintf(stderr, "%s -> bit %d\n", name, i);
958a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			i++;
968a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		}
978a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	} else {
988a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		fputs("no labels configured, usage: program bit\n", stderr);
998a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1008a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	exit(1);
1018a44513648da0c5f5551f96b329cf56b66f5b303pkanwar}
1028a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1038a44513648da0c5f5551f96b329cf56b66f5b303pkanwarstatic struct mnl_socket *sock_nl_create(void)
1048a44513648da0c5f5551f96b329cf56b66f5b303pkanwar{
1058a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct mnl_socket *nl;
1068a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1078a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nl = mnl_socket_open(NETLINK_NETFILTER);
1088a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (nl == NULL) {
1098a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		perror("mnl_socket_open");
1108a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		exit(EXIT_FAILURE);
1118a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1128a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1138a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
1148a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		perror("mnl_socket_bind");
1158a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		exit(EXIT_FAILURE);
1168a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1178a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1188a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	return nl;
1198a44513648da0c5f5551f96b329cf56b66f5b303pkanwar}
1208a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1218a44513648da0c5f5551f96b329cf56b66f5b303pkanwarint main(int argc, char *argv[])
1228a44513648da0c5f5551f96b329cf56b66f5b303pkanwar{
1238a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct mnl_socket *nl;
1248a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nlmsghdr *nlh;
1258a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nfgenmsg *nfh;
1268a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	char buf[MNL_SOCKET_BUFFER_SIZE];
1278a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	unsigned int seq, portid;
1288a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct callback_args cbargs;
1298a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	int ret;
1308a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	struct nfct_labelmap *l = nfct_labelmap_new(NULL);
1318a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1328a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (argc < 2)
1338a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		show_labels(l);
1348a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1358a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	cbargs.bit = l ? nfct_labelmap_get_bit(l, argv[1]) : -1;
1368a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1378a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (cbargs.bit < 0) {
1388a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		cbargs.bit = atoi(argv[1]);
1398a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		if (cbargs.bit == 0 && argv[1][0] != '0')
1408a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			show_labels(l);
1418a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1428a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1438a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (cbargs.bit < 0)
1448a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		puts("will clear all labels");
1458a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	else
1468a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		printf("will set label bit %d\n", cbargs.bit);
1478a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1488a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nl = sock_nl_create();
1498a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	portid = mnl_socket_get_portid(nl);
1508a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1518a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh = mnl_nlmsg_put_header(buf);
1528a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
1538a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
1548a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nlh->nlmsg_seq = seq = time(NULL);
1558a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1568a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
1578a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->nfgen_family = AF_UNSPEC;
1588a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->version = NFNETLINK_V0;
1598a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	nfh->res_id = 0;
1608a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1618a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1628a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
1638a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (ret == -1) {
1648a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		perror("mnl_socket_sendto");
1658a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		exit(EXIT_FAILURE);
1668a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1678a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1688a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
1698a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1708a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1718a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	cbargs.nl = sock_nl_create();
1728a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	cbargs.seq = seq;
1738a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1748a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	while (ret > 0) {
1758a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &cbargs);
1768a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		if (ret <= MNL_CB_STOP)
1778a44513648da0c5f5551f96b329cf56b66f5b303pkanwar			break;
1788a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
1798a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1808a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (ret == -1) {
1818a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		perror("mnl_socket_recvfrom");
1828a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		exit(EXIT_FAILURE);
1838a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	}
1848a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1858a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	if (l)
1868a44513648da0c5f5551f96b329cf56b66f5b303pkanwar		nfct_labelmap_destroy(l);
1878a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	mnl_socket_close(nl);
1888a44513648da0c5f5551f96b329cf56b66f5b303pkanwar
1898a44513648da0c5f5551f96b329cf56b66f5b303pkanwar	return 0;
1908a44513648da0c5f5551f96b329cf56b66f5b303pkanwar}
191