libnftnl 1.2.9
nft-ct-expectation-add.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2019 by Stéphane Veyret <sveyret@gmail.com>
4 */
5
6#include <time.h>
7#include <string.h>
8#include <netinet/in.h>
9
10#include <linux/netfilter.h>
11
12#include <obj.h>
13#include <libmnl/libmnl.h>
14
15static uint16_t parse_family(char *str, const char *option)
16{
17 if (strcmp(str, "ip") == 0)
18 return NFPROTO_IPV4;
19 else if (strcmp(str, "ip6") == 0)
20 return NFPROTO_IPV6;
21 else if (strcmp(str, "inet") == 0)
22 return NFPROTO_INET;
23 else if (strcmp(str, "arp") == 0)
24 return NFPROTO_INET;
25 fprintf(stderr, "Unknown %s: ip, ip6, inet, arp\n", option);
26 exit(EXIT_FAILURE);
27}
28
29static uint8_t parse_l4proto(char *str)
30{
31 if (strcmp(str, "udp") == 0)
32 return IPPROTO_UDP;
33 else if (strcmp(str, "tcp") == 0)
34 return IPPROTO_TCP;
35 else {
36 fprintf(stderr, "Unknown l4proto: tcp, udp\n");
37 exit(EXIT_FAILURE);
38 }
39 return IPPROTO_TCP;
40}
41
42static struct nftnl_obj *obj_parse(int argc, char *argv[])
43{
44 uint16_t family, l3proto, dport;
45 uint8_t l4proto, size;
46 struct nftnl_obj *t;
47 uint32_t timeout;
48
49 t = nftnl_obj_alloc();
50 if (t == NULL) {
51 perror("OOM");
52 return NULL;
53 }
54
55 family = parse_family(argv[1], "family");
56 nftnl_obj_set_u32(t, NFTNL_OBJ_FAMILY, family);
57 nftnl_obj_set_u32(t, NFTNL_OBJ_TYPE, NFT_OBJECT_CT_EXPECT);
58 nftnl_obj_set_str(t, NFTNL_OBJ_TABLE, argv[2]);
59 nftnl_obj_set_str(t, NFTNL_OBJ_NAME, argv[3]);
60
61 if (argc > 8) {
62 l3proto = parse_family(argv[8], "l3proto");
63 nftnl_obj_set_u16(t, NFTNL_OBJ_CT_EXPECT_L3PROTO, l3proto);
64 }
65 l4proto = parse_l4proto(argv[4]);
66 nftnl_obj_set_u8(t, NFTNL_OBJ_CT_EXPECT_L4PROTO, l4proto);
67 dport = atoi(argv[5]);
68 nftnl_obj_set_u16(t, NFTNL_OBJ_CT_EXPECT_DPORT, dport);
69 timeout = atol(argv[6]);
70 nftnl_obj_set_u32(t, NFTNL_OBJ_CT_EXPECT_TIMEOUT, timeout);
71 size = atoi(argv[7]);
72 nftnl_obj_set_u8(t, NFTNL_OBJ_CT_EXPECT_SIZE, size);
73
74 return t;
75}
76
77int main(int argc, char *argv[])
78{
79 uint32_t portid, seq, obj_seq, family;
80 char buf[MNL_SOCKET_BUFFER_SIZE];
81 struct mnl_nlmsg_batch *batch;
82 struct mnl_socket *nl;
83 struct nlmsghdr *nlh;
84 struct nftnl_obj *t;
85 int ret;
86
87 if (argc < 8 || argc > 9) {
88 fprintf(stderr, "%s <family> <table> <name> <l4proto> <dport> <timeout> <size> [l3proto]\n", argv[0]);
89 exit(EXIT_FAILURE);
90 }
91
92 t = obj_parse(argc, argv);
93 if (t == NULL) {
94 exit(EXIT_FAILURE);
95 }
96
97 seq = time(NULL);
98 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
99
100 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
101 mnl_nlmsg_batch_next(batch);
102
103 obj_seq = seq;
104 family = nftnl_obj_get_u32(t, NFTNL_OBJ_FAMILY);
105 nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
106 NFT_MSG_NEWOBJ, family,
107 NLM_F_ACK | NLM_F_CREATE, seq++);
108 nftnl_obj_nlmsg_build_payload(nlh, t);
109 nftnl_obj_free(t);
110 mnl_nlmsg_batch_next(batch);
111
112 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
113 mnl_nlmsg_batch_next(batch);
114
115 nl = mnl_socket_open(NETLINK_NETFILTER);
116 if (nl == NULL) {
117 perror("mnl_socket_open");
118 exit(EXIT_FAILURE);
119 }
120
121 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
122 perror("mnl_socket_bind");
123 exit(EXIT_FAILURE);
124 }
125 portid = mnl_socket_get_portid(nl);
126
127 if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
128 mnl_nlmsg_batch_size(batch)) < 0) {
129 perror("mnl_socket_send");
130 exit(EXIT_FAILURE);
131 }
132
133 mnl_nlmsg_batch_stop(batch);
134
135 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
136 while (ret > 0) {
137 ret = mnl_cb_run(buf, ret, obj_seq, portid, NULL, NULL);
138 if (ret <= 0)
139 break;
140 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
141 }
142 if (ret == -1) {
143 perror("error");
144 exit(EXIT_FAILURE);
145 }
146 mnl_socket_close(nl);
147
148 return EXIT_SUCCESS;
149}