libnftnl  1.2.9
nft-chain-add.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
7 
8 #include <stdlib.h>
9 #include <time.h>
10 #include <string.h>
11 #include <netinet/in.h>
12 
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nf_tables.h>
15 
16 #include <libmnl/libmnl.h>
17 #include <libnftnl/chain.h>
18 
19 static struct nftnl_chain *chain_add_parse(int argc, char *argv[])
20 {
21  struct nftnl_chain *t;
22  int hooknum = 0;
23 
24  if (argc == 6) {
25  /* This is a base chain, set the hook number */
26  if (strcmp(argv[4], "NF_INET_LOCAL_IN") == 0)
27  hooknum = NF_INET_LOCAL_IN;
28  else if (strcmp(argv[4], "NF_INET_LOCAL_OUT") == 0)
29  hooknum = NF_INET_LOCAL_OUT;
30  else if (strcmp(argv[4], "NF_INET_PRE_ROUTING") == 0)
31  hooknum = NF_INET_PRE_ROUTING;
32  else if (strcmp(argv[4], "NF_INET_POST_ROUTING") == 0)
33  hooknum = NF_INET_POST_ROUTING;
34  else if (strcmp(argv[4], "NF_INET_FORWARD") == 0)
35  hooknum = NF_INET_FORWARD;
36  else {
37  fprintf(stderr, "Unknown hook: %s\n", argv[4]);
38  return NULL;
39  }
40  }
41 
42  t = nftnl_chain_alloc();
43  if (t == NULL) {
44  perror("OOM");
45  return NULL;
46  }
47  nftnl_chain_set_str(t, NFTNL_CHAIN_TABLE, argv[2]);
48  nftnl_chain_set_str(t, NFTNL_CHAIN_NAME, argv[3]);
49  if (argc == 6) {
50  nftnl_chain_set_u32(t, NFTNL_CHAIN_HOOKNUM, hooknum);
51  nftnl_chain_set_u32(t, NFTNL_CHAIN_PRIO, atoi(argv[5]));
52  }
53 
54  return t;
55 }
56 
57 int main(int argc, char *argv[])
58 {
59  struct mnl_socket *nl;
60  char buf[MNL_SOCKET_BUFFER_SIZE];
61  struct nlmsghdr *nlh;
62  uint32_t portid, seq, chain_seq;
63  int ret, family;
64  struct nftnl_chain *t;
65  struct mnl_nlmsg_batch *batch;
66 
67  if (argc != 4 && argc != 6) {
68  fprintf(stderr, "Usage: %s <family> <table> <chain> "
69  "[<hooknum> <prio>]\n",
70  argv[0]);
71  exit(EXIT_FAILURE);
72  }
73 
74  if (strcmp(argv[1], "ip") == 0)
75  family = NFPROTO_IPV4;
76  else if (strcmp(argv[1], "ip6") == 0)
77  family = NFPROTO_IPV6;
78  else if (strcmp(argv[1], "inet") == 0)
79  family = NFPROTO_INET;
80  else if (strcmp(argv[1], "bridge") == 0)
81  family = NFPROTO_BRIDGE;
82  else if (strcmp(argv[1], "arp") == 0)
83  family = NFPROTO_ARP;
84  else {
85  fprintf(stderr, "Unknown family: ip, ip6, inet, bridge, arp\n");
86  exit(EXIT_FAILURE);
87  }
88 
89  t = chain_add_parse(argc, argv);
90  if (t == NULL)
91  exit(EXIT_FAILURE);
92 
93  seq = time(NULL);
94  batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
95 
96  nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
97  mnl_nlmsg_batch_next(batch);
98 
99  chain_seq = seq;
100  nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
101  NFT_MSG_NEWCHAIN, family,
102  NLM_F_CREATE | NLM_F_ACK, seq++);
103  nftnl_chain_nlmsg_build_payload(nlh, t);
104  nftnl_chain_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, chain_seq, portid, NULL, NULL);
133  if (ret <= 0)
134  break;
135  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
136  }
137  if (ret == -1) {
138  perror("error");
139  exit(EXIT_FAILURE);
140  }
141  mnl_socket_close(nl);
142 
143  return EXIT_SUCCESS;
144 }