libnftnl  1.1.4
nft-rule-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 <stdlib.h>
11 #include <time.h>
12 #include <string.h>
13 #include <stddef.h> /* for offsetof */
14 #include <netinet/in.h>
15 #include <netinet/ip.h>
16 #include <netinet/tcp.h>
17 #include <arpa/inet.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <errno.h>
21 
22 #include <linux/netfilter.h>
23 #include <linux/netfilter/nfnetlink.h>
24 #include <linux/netfilter/nf_tables.h>
25 
26 #include <libmnl/libmnl.h>
27 #include <libnftnl/rule.h>
28 #include <libnftnl/expr.h>
29 
30 static uint16_t parse_family(char *str, const char *option)
31 {
32  if (strcmp(str, "ip") == 0)
33  return NFPROTO_IPV4;
34  else if (strcmp(str, "ip6") == 0)
35  return NFPROTO_IPV6;
36  else if (strcmp(str, "inet") == 0)
37  return NFPROTO_INET;
38  else if (strcmp(str, "arp") == 0)
39  return NFPROTO_INET;
40  fprintf(stderr, "Unknown %s: ip, ip6, inet, arp\n", option);
41  exit(EXIT_FAILURE);
42 }
43 
44 static void add_ct_expect(struct nftnl_rule *r, const char *obj_name)
45 {
46  struct nftnl_expr *e;
47 
48  e = nftnl_expr_alloc("objref");
49  if (e == NULL) {
50  perror("expr objref oom");
51  exit(EXIT_FAILURE);
52  }
53  nftnl_expr_set_str(e, NFTNL_EXPR_OBJREF_IMM_NAME, obj_name);
54  nftnl_expr_set_u32(e, NFTNL_EXPR_OBJREF_IMM_TYPE, NFT_OBJECT_CT_EXPECT);
55 
56  nftnl_rule_add_expr(r, e);
57 }
58 
59 static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
60  const char *chain, const char *handle,
61  const char *obj_name)
62 {
63  struct nftnl_rule *r = NULL;
64  uint64_t handle_num;
65 
66  r = nftnl_rule_alloc();
67  if (r == NULL) {
68  perror("OOM");
69  exit(EXIT_FAILURE);
70  }
71 
72  nftnl_rule_set(r, NFTNL_RULE_TABLE, table);
73  nftnl_rule_set(r, NFTNL_RULE_CHAIN, chain);
74  nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
75 
76  if (handle != NULL) {
77  handle_num = atoll(handle);
78  nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num);
79  }
80 
81  add_ct_expect(r, obj_name);
82 
83  return r;
84 }
85 
86 int main(int argc, char *argv[])
87 {
88  char buf[MNL_SOCKET_BUFFER_SIZE];
89  struct mnl_nlmsg_batch *batch;
90  uint32_t seq = time(NULL);
91  struct mnl_socket *nl;
92  struct nftnl_rule *r;
93  struct nlmsghdr *nlh;
94  uint8_t family;
95  int ret;
96 
97  if (argc < 5 || argc > 6) {
98  fprintf(stderr,
99  "Usage: %s <family> <table> <chain> [<handle>] <name>\n",
100  argv[0]);
101  exit(EXIT_FAILURE);
102  }
103  family = parse_family(argv[1], "family");
104 
105  if (argc < 6)
106  r = setup_rule(family, argv[2], argv[3], NULL, argv[4]);
107  else
108  r = setup_rule(family, argv[2], argv[3], argv[4], argv[5]);
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 
121  batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
122 
123  nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
124  mnl_nlmsg_batch_next(batch);
125 
126  nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
127  NFT_MSG_NEWRULE,
128  nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY),
129  NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
130  seq++);
131 
132  nftnl_rule_nlmsg_build_payload(nlh, r);
133  nftnl_rule_free(r);
134  mnl_nlmsg_batch_next(batch);
135 
136  nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
137  mnl_nlmsg_batch_next(batch);
138 
139  ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
140  mnl_nlmsg_batch_size(batch));
141  if (ret == -1) {
142  perror("mnl_socket_sendto");
143  exit(EXIT_FAILURE);
144  }
145 
146  mnl_nlmsg_batch_stop(batch);
147 
148  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
149  if (ret == -1) {
150  perror("mnl_socket_recvfrom");
151  exit(EXIT_FAILURE);
152  }
153 
154  ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
155  if (ret < 0) {
156  perror("mnl_cb_run");
157  exit(EXIT_FAILURE);
158  }
159 
160  mnl_socket_close(nl);
161 
162  return EXIT_SUCCESS;
163 }