libmnl  1.0.3
nf-log.c
1 /* This example is placed in the public domain. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <time.h>
7 #include <arpa/inet.h>
8 
9 #include <libmnl/libmnl.h>
10 #include <linux/netfilter.h>
11 #include <linux/netfilter/nfnetlink.h>
12 
13 #ifndef aligned_be64
14 #define aligned_be64 u_int64_t __attribute__((aligned(8)))
15 #endif
16 
17 #include <linux/netfilter/nfnetlink_log.h>
18 
19 static int parse_attr_cb(const struct nlattr *attr, void *data)
20 {
21  const struct nlattr **tb = data;
22  int type = mnl_attr_get_type(attr);
23 
24  /* skip unsupported attribute in user-space */
25  if (mnl_attr_type_valid(attr, NFULA_MAX) < 0)
26  return MNL_CB_OK;
27 
28  switch(type) {
29  case NFULA_MARK:
30  case NFULA_IFINDEX_INDEV:
31  case NFULA_IFINDEX_OUTDEV:
32  case NFULA_IFINDEX_PHYSINDEV:
33  case NFULA_IFINDEX_PHYSOUTDEV:
34  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
35  perror("mnl_attr_validate");
36  return MNL_CB_ERROR;
37  }
38  break;
39  case NFULA_TIMESTAMP:
40  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
41  sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
42  perror("mnl_attr_validate");
43  return MNL_CB_ERROR;
44  }
45  break;
46  case NFULA_HWADDR:
47  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
48  sizeof(struct nfulnl_msg_packet_hw)) < 0) {
49  perror("mnl_attr_validate");
50  return MNL_CB_ERROR;
51  }
52  break;
53  case NFULA_PREFIX:
54  if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
55  perror("mnl_attr_validate");
56  return MNL_CB_ERROR;
57  }
58  break;
59  case NFULA_PAYLOAD:
60  break;
61  }
62  tb[type] = attr;
63  return MNL_CB_OK;
64 }
65 
66 static int log_cb(const struct nlmsghdr *nlh, void *data)
67 {
68  struct nlattr *tb[NFULA_MAX+1] = {};
69  struct nfulnl_msg_packet_hdr *ph = NULL;
70  const char *prefix = NULL;
71  uint32_t mark = 0;
72 
73  mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
74  if (tb[NFULA_PACKET_HDR])
75  ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
76  if (tb[NFULA_PREFIX])
77  prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
78  if (tb[NFULA_MARK])
79  mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
80 
81  printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n",
82  prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook,
83  mark);
84 
85  return MNL_CB_OK;
86 }
87 
88 static struct nlmsghdr *
89 nflog_build_cfg_pf_request(char *buf, uint8_t command)
90 {
91  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
92  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
93  nlh->nlmsg_flags = NLM_F_REQUEST;
94 
95  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
96  nfg->nfgen_family = AF_INET;
97  nfg->version = NFNETLINK_V0;
98 
99  struct nfulnl_msg_config_cmd cmd = {
100  .command = command,
101  };
102  mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
103 
104  return nlh;
105 }
106 
107 static struct nlmsghdr *
108 nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
109 {
110  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
111  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
112  nlh->nlmsg_flags = NLM_F_REQUEST;
113 
114  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
115  nfg->nfgen_family = AF_INET;
116  nfg->version = NFNETLINK_V0;
117  nfg->res_id = htons(qnum);
118 
119  struct nfulnl_msg_config_cmd cmd = {
120  .command = command,
121  };
122  mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
123 
124  return nlh;
125 }
126 
127 static struct nlmsghdr *
128 nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum)
129 {
130  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
131  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
132  nlh->nlmsg_flags = NLM_F_REQUEST;
133 
134  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
135  nfg->nfgen_family = AF_UNSPEC;
136  nfg->version = NFNETLINK_V0;
137  nfg->res_id = htons(qnum);
138 
139  struct nfulnl_msg_config_mode params = {
140  .copy_range = htonl(range),
141  .copy_mode = mode,
142  };
143  mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
144 
145  return nlh;
146 }
147 
148 int main(int argc, char *argv[])
149 {
150  struct mnl_socket *nl;
151  char buf[MNL_SOCKET_BUFFER_SIZE];
152  struct nlmsghdr *nlh;
153  int ret;
154  unsigned int portid, qnum;
155 
156  if (argc != 2) {
157  printf("Usage: %s [queue_num]\n", argv[0]);
158  exit(EXIT_FAILURE);
159  }
160  qnum = atoi(argv[1]);
161 
162  nl = mnl_socket_open(NETLINK_NETFILTER);
163  if (nl == NULL) {
164  perror("mnl_socket_open");
165  exit(EXIT_FAILURE);
166  }
167 
168  if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
169  perror("mnl_socket_bind");
170  exit(EXIT_FAILURE);
171  }
172  portid = mnl_socket_get_portid(nl);
173 
174  nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
175 
176  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
177  perror("mnl_socket_send");
178  exit(EXIT_FAILURE);
179  }
180 
181  nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
182 
183  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
184  perror("mnl_socket_send");
185  exit(EXIT_FAILURE);
186  }
187 
188  nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
189 
190  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
191  perror("mnl_socket_send");
192  exit(EXIT_FAILURE);
193  }
194 
195  nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
196 
197  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
198  perror("mnl_socket_send");
199  exit(EXIT_FAILURE);
200  }
201 
202  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
203  if (ret == -1) {
204  perror("mnl_socket_recvfrom");
205  exit(EXIT_FAILURE);
206  }
207  while (ret > 0) {
208  ret = mnl_cb_run(buf, ret, 0, portid, log_cb, NULL);
209  if (ret < 0){
210  perror("mnl_cb_run");
211  exit(EXIT_FAILURE);
212  }
213 
214  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
215  if (ret == -1) {
216  perror("mnl_socket_recvfrom");
217  exit(EXIT_FAILURE);
218  }
219  }
220 
221  mnl_socket_close(nl);
222 
223  return 0;
224 }
int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t len)
Definition: attr.c:238
int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data)
Definition: attr.c:265
void * mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
Definition: nlmsg.c:105
uint16_t mnl_attr_get_type(const struct nlattr *attr)
Definition: attr.c:38
struct mnl_socket * mnl_socket_open(int type)
Definition: socket.c:113
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
Definition: socket.c:100
ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t siz)
Definition: socket.c:206
void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
Definition: attr.c:414
void * mnl_attr_get_payload(const struct nlattr *attr)
Definition: attr.c:75
int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data)
Definition: callback.c:152
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
Definition: socket.c:141
int mnl_socket_close(struct mnl_socket *nl)
Definition: socket.c:246
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t maxtype)
Definition: attr.c:134
struct nlmsghdr * mnl_nlmsg_put_header(void *buf)
Definition: nlmsg.c:82
ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *req, size_t siz)
Definition: socket.c:181
const char * mnl_attr_get_str(const struct nlattr *attr)
Definition: attr.c:397
uint32_t mnl_attr_get_u32(const struct nlattr *attr)
Definition: attr.c:369
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
Definition: attr.c:214