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