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 
15 static 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 
29 static 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 
42 static 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 
77 int 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 }