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