libnetfilter_conntrack  1.0.6
nssocket.c
1 #include <arpa/inet.h>
2 #include <assert.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sched.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/mount.h>
10 #include <sys/param.h>
11 #include <sys/socket.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <time.h>
16 #include <unistd.h>
17 
18 #include <libmnl/libmnl.h>
19 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
20 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
21 #include "config.h"
22 #include "nssocket.h"
23 
24 int fdpair[2];
25 #define PARENT_FD (fdpair[0])
26 #define CHILD_FD (fdpair[1])
27 
28 pid_t child_pid;
29 
30 void add_child(pid_t pid)
31 {
32  /* XXX: check excess MAX_CHILD */
33  children[nchild++] = pid;
34 }
35 
36 static int get_unaligned_int(const void *s)
37 {
38  int x;
39  memcpy(&x, s, sizeof(x));
40  return x;
41 }
42 
43 static void put_unaligned_int(void *d, int x)
44 {
45  memcpy(d, &x, sizeof(x));
46 }
47 
48 /*
49  * message exchange via socketpair using send/recv msg()
50  *
51  * - use cdata:
52  * cdata represents a file descriptor
53  * cmd[0] means -errno
54  *
55  * - without cdata:
56  * cmd[0] means:
57  * > 0: command
58  * == 0: sync, echo
59  * < 0: -errno
60  *
61  * it's an given fact that tx() and rx() never fail.
62  */
63 ssize_t tx(int fd, int *cmd, uint8_t cmdlen, int cdata)
64 {
65  struct msghdr msg;
66  struct iovec iov[cmdlen];
67  size_t cmsglen = CMSG_SPACE(sizeof(int));
68  char control[CMSG_SPACE(sizeof(int))];
69  struct cmsghdr *cmsg;
70  int i;
71 
72  memset(&msg, 0, sizeof(struct msghdr));
73  memset(iov, 0, sizeof(struct iovec) * cmdlen);
74 
75  msg.msg_iov = iov;
76  msg.msg_iovlen = cmdlen;
77  for (i = 0; i < cmdlen; i++) {
78  iov[i].iov_len = sizeof(int);
79  iov[i].iov_base = &cmd[i];
80  }
81  if (cdata) {
82  msg.msg_control = control;
83  msg.msg_controllen = cmsglen;
84  cmsg = CMSG_FIRSTHDR(&msg);
85  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
86  cmsg->cmsg_level = SOL_SOCKET;
87  cmsg->cmsg_type = SCM_RIGHTS;
88  put_unaligned_int(CMSG_DATA(cmsg), cdata);
89  }
90 
91  return sendmsg(fd, &msg, 0);
92 }
93 
94 ssize_t rx(int fd, int *cmd, uint8_t cmdlen, int *cdata)
95 {
96  struct msghdr msg;
97  struct iovec iov[cmdlen];
98  size_t cmsglen = CMSG_SPACE(sizeof(int));
99  char control[CMSG_SPACE(sizeof(int))];
100  struct cmsghdr *cmsg;
101  ssize_t ret;
102  int i;
103 
104  memset(&msg, 0, sizeof(struct msghdr));
105  memset(iov, 0, sizeof(struct iovec));
106 
107  msg.msg_iov = iov;
108  msg.msg_iovlen = cmdlen;
109  for (i = 0; i < cmdlen; i++) {
110  iov[i].iov_len = sizeof(int);
111  iov[i].iov_base = &cmd[i];
112  }
113  if (cdata != NULL) {
114  msg.msg_control = control;
115  msg.msg_controllen = cmsglen;
116  }
117 
118  ret = recvmsg(fd, &msg, 0);
119  if (ret == -1) {
120  perror("recvmsg");
121  return ret;
122  }
123 
124  if (cdata == NULL)
125  return ret;
126 
127  cmsg = CMSG_FIRSTHDR(&msg);
128  if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int))
129  || cmsg->cmsg_level != SOL_SOCKET
130  || cmsg->cmsg_type != SCM_RIGHTS) {
131  errno = EBADMSG;
132  return -1;
133  }
134  *cdata = get_unaligned_int(CMSG_DATA(cmsg));
135 
136  return ret;
137 }
138 
139 int tx_cmd(int fd, int cmd)
140 {
141  return tx(fd, &cmd, 1, 0);
142 }
143 
144 int rx_cmd(int fd)
145 {
146  int cmd;
147  if (rx((fd), &cmd, 1, NULL) == -1)
148  return -1;
149  return cmd;
150 }
151 
152 int tx_fd(int fd1, int fd2, int e)
153 {
154  return tx(fd1, &e, 1, fd2);
155 }
156 
157 int rx_fd(int fd1)
158 {
159  int e, fd2;
160 
161  if (rx(fd1, &e, 1, &fd2) == -1)
162  return -1;
163 
164  errno = -e;
165  return fd2;
166 }
167 
168 /*
169  * copy from ip/ipnetns.c::iproute2
170  */
171 #ifndef HAVE_SETNS
172 #include <sys/syscall.h>
173 static int setns(int fd, int nstype)
174 {
175 #ifdef __NR_setns
176  return syscall(__NR_setns, fd, nstype);
177 #else
178  errno = ENOSYS;
179  return -1;
180 #endif
181 }
182 #endif /* HAVE_SETNS */
183 
184 #define NETNS_RUN_DIR "/var/run/netns"
185 static int netns_setup(const char *name)
186 {
187  /* Setup the proper environment for apps that are not netns
188  * aware, and execute a program in that environment.
189  */
190  char net_path[MAXPATHLEN];
191  int netns;
192 
193  snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
194  netns = open(net_path, O_RDONLY | O_CLOEXEC);
195  if (netns < 0) {
196  fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
197  name, strerror(errno));
198  return -1;
199  }
200 
201  if (setns(netns, CLONE_NEWNET) < 0) {
202  fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
203  name, strerror(errno));
204  return -1;
205  }
206 
207  if (unshare(CLONE_NEWNS) < 0) {
208  fprintf(stderr, "unshare failed: %s\n", strerror(errno));
209  return -1;
210  }
211  /* Don't let any mounts propagate back to the parent */
212  if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
213  fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
214  strerror(errno));
215  return -1;
216  }
217  /* Mount a version of /sys that describes the network namespace */
218  if (umount2("/sys", MNT_DETACH) < 0) {
219  fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
220  return -1;
221  }
222  if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
223  fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
224  return -1;
225  }
226 
227  return 0;
228 }
229 
230 static void child(const char *nsname)
231 {
232  int cmd = CMD_SYNC;
233  int params[3]; /* XXX: magic number, see enum CALL_ */
234  int sockfd;
235 
236  if (netns_setup(nsname) == -1)
237  child_exit("netns_setup", EXIT_FAILURE);
238 
239  /* sync with parent */
240  if (tx_cmd(CHILD_FD, CMD_SYNC) == -1)
241  child_exit("tx_cmd", EXIT_FAILURE);
242 
243  /* waiting cmd */
244  while (1) {
245  debug_ns("child waiting for cmd...\n");
246  cmd = rx_cmd(CHILD_FD);
247  switch (cmd) {
248  case CMD_DONE:
249  debug_ns("child received CMD_DONE - exiting\n");
250  close(CHILD_FD);
251  child_exit("receive CMD_DONE", EXIT_SUCCESS);
252  break;
253  case CMD_SOCKET:
254  if (rx(CHILD_FD, params, 3, NULL) == -1)
255  child_exit("rx", EXIT_FAILURE);
256  debug_ns("child received CMD_SOCKET -"
257  " domain: %d, type: %d, protocol: %d\n",
258  params[0], params[1], params[2]);
259  sockfd = socket(params[0], params[1], params[2]);
260  if (tx_fd(CHILD_FD, sockfd, -errno) == -1)
261  child_exit("tx_fd", EXIT_FAILURE);
262  break;
263  default:
264  debug_ns("child received unknown cmd: %d\n", cmd);
265  child_exit("receive unknown cmd", EXIT_FAILURE);
266  break;
267  }
268  }
269 }
270 
271 /*
272  * kill all the other registered child by SIGKILL
273  *
274  * SIGCHLD will not be raised if child has killed in SIGABRT handler
275  */
276 static void sigchld_handler(int signum)
277 {
278  pid_t pid;
279  int status, i, fail = 0;
280 
281  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
282  debug_ns("receive SIGCHLD - pid: %d\n", pid);
283  if (WIFEXITED(status))
284  fail |= WEXITSTATUS(status);
285  else if (WIFSIGNALED(status) || WCOREDUMP(status))
286  fail |= status;
287  if (pid == child_pid)
288  child_pid = 0;
289  for (i = 0; i < nchild; i++)
290  if (children[i] == pid)
291  children[i] = 0;
292  else
293  kill(children[i], SIGKILL);
294  }
295  if (pid == -1 && errno != ECHILD)
296  fail |= errno;
297 
298  /* overdoing? kill myself
299  * if (fail) kill(0, SIGKILL);
300  */
301 }
302 
303 /*
304  * core public API
305  */
306 int init_nssocket(const char *nsname)
307 {
308  pid_t pid;
309  struct sigaction sa;
310 
311  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1)
312  return -1;
313 
314  sigemptyset(&sa.sa_mask);
315  sa.sa_handler = sigchld_handler;
316  sa.sa_flags = SA_NOCLDSTOP;
317  if (sigaction(SIGCHLD, &sa, NULL) == -1)
318  return -1;
319 
320  fflush(stdout);
321  pid = fork();
322  switch (pid) {
323  case -1:
324  return -1;
325  break;
326  case 0:
327  child(nsname); /* not return */
328  break;
329  default:
330  child_pid = pid;
331  add_child(pid);
332  if (rx_cmd(PARENT_FD) < 0) {
333  parent_fail("rx_cmd");
334  return -1;
335  }
336  break;
337  }
338 
339  return 0;
340 }
341 
342 int fini_nssocket(void)
343 {
344  int status;
345  sigset_t block_mask;
346  pid_t pid;
347 
348  sigemptyset(&block_mask);
349  sigaddset(&block_mask, SIGCHLD);
350  if (sigprocmask(SIG_SETMASK, &block_mask, NULL) == -1)
351  return -1;
352  tx_cmd(PARENT_FD, CMD_DONE);
353  close(PARENT_FD);
354  pid = waitpid(child_pid, &status, 0);
355  child_pid = 0;
356  if (pid < 0)
357  return -1;
358  if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
359  return 0;
360 
361  return status;
362 }
363 
364 int nssocket(int domain, int type, int protocol)
365 {
366  int cmd[] = {CMD_SOCKET, domain, type, protocol};
367 
368  if (child_pid == 0 || kill(child_pid, 0) == -1) {
369  errno = ECHILD;
370  return -1;
371  }
372  tx(PARENT_FD, cmd, 4, 0);
373  return rx_fd(PARENT_FD);
374 }
375 
376 /*
377  * utils API
378  */
379 int debug_nfct_cb(const struct nlmsghdr *nlh, void *data)
380 {
381  struct nf_conntrack *ct;
382  uint32_t type = NFCT_T_UNKNOWN;
383  char buf[4096];
384 
385  switch(nlh->nlmsg_type & 0xFF) {
386  case IPCTNL_MSG_CT_NEW:
387  if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
388  type = NFCT_T_NEW;
389  else
390  type = NFCT_T_UPDATE;
391  break;
392  case IPCTNL_MSG_CT_DELETE:
393  type = NFCT_T_DESTROY;
394  break;
395  }
396 
397  ct = nfct_new();
398  if (ct == NULL)
399  return MNL_CB_OK;
400 
401  nfct_nlmsg_parse(nlh, ct);
402  nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_DEFAULT, 0);
403  debug("%s\n", buf);
404  nfct_destroy(ct);
405 
406  return MNL_CB_OK;
407 }
408 
409 struct mnl_socket *mnl_nssocket_open(int bus)
410 {
411  int fd;
412  struct mnl_socket *nl;
413 
414  fd = nssocket(AF_NETLINK, SOCK_RAW, bus);
415  if (fd == -1)
416  return NULL;
417 
418  nl = mnl_socket_fdopen(fd);
419  if (nl == NULL) {
420  close(fd);
421  return NULL;
422  }
423  return nl;
424 }
425 
426 /*
427  * assert utilities
428  */
429 struct nf_conntrack *author_new(const struct nlmsghdr *nlh, void *data)
430 {
431  struct nf_conntrack *ct;
432 
433  assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW);
434  assert(nlh->nlmsg_flags == (NLM_F_CREATE | NLM_F_EXCL));
435  ct = nfct_new();
436  assert(ct != NULL);
437  assert(nfct_nlmsg_parse((nlh), ct) == 0);
438  assert_proto(ct, AF_INET, *(uint8_t *) data);
439  assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR);
440  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY) == 0);
441  timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1;
442 
443  return ct;
444 }
445 
446 struct nf_conntrack *author_update(const struct nlmsghdr *nlh, void *data)
447 {
448  struct nf_conntrack *ct;
449 
450  assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW);
451  assert(nlh->nlmsg_flags == 0);
452  ct = nfct_new();
453  assert(ct != NULL);
454  assert(nfct_nlmsg_parse((nlh), ct) == 0);
455  assert_proto(ct, AF_INET, *(uint8_t *) data);
456  assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR);
457  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY));
458  timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1;
459 
460  return ct;
461 }
462 
463 struct nf_conntrack *author_destroy(const struct nlmsghdr *nlh, void *data)
464 {
465  struct nf_conntrack *ct;
466 
467  assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_DELETE);
468  assert(nlh->nlmsg_flags == 0);
469  ct = nfct_new();
470  assert(ct != NULL);
471  assert(nfct_nlmsg_parse((nlh), ct) == 0);
472  assert_proto(ct, AF_INET, *(uint8_t *) data);
473  assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR);
474  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY));
475 
476  return ct;
477 }
478 
479 void assert_proto(const struct nf_conntrack *ct,
480  uint8_t l3proto, uint8_t l4proto)
481 {
482  assert(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) == l3proto);
483  assert(nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO) == l3proto);
484  assert(nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO) == l4proto);
485  assert(nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO) == l4proto);
486 }
487 
488 void assert_inaddr(const struct nf_conntrack *ct,
489  const char *src, const char *dst)
490 {
491  struct in_addr addr;
492  assert(inet_aton((src), &addr) != 0);
493  assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_SRC) == addr.s_addr);
494  assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_DST) == addr.s_addr);
495  assert(inet_aton((dst), &addr) != 0);
496  assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_DST) == addr.s_addr);
497  assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_SRC) == addr.s_addr);
498 }
499 
500 void assert_port(const struct nf_conntrack *ct,
501  uint16_t src, uint16_t dst)
502 {
503  if ((src)) {
504  assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_SRC) == htons((src)));
505  assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_DST) == htons((src)));
506  }
507  if ((dst)) {
508  assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_DST) == htons((dst)));
509  assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_SRC) == htons((dst)));
510  }
511 }
512 
513 void assert_typecode(const struct nf_conntrack *ct,
514  uint8_t type, uint8_t code)
515 {
516  assert(nfct_get_attr_u8((ct), ATTR_ICMP_TYPE) == type);
517  assert(nfct_get_attr_u8((ct), ATTR_ICMP_CODE) == code);
518 }
519 
520 int cb_icmp_new(const struct nlmsghdr *nlh, void *data)
521 {
522  struct nf_conntrack *ct = author_new(nlh, data);
523  assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
524  nfct_destroy(ct);
525  return MNL_CB_OK;
526 }
527 
528 int cb_icmp_update(const struct nlmsghdr *nlh, void *data)
529 {
530  struct nf_conntrack *ct = author_update(nlh, data);
531  assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
532  nfct_destroy(ct);
533  return MNL_CB_OK;
534 }
535 
536 int cb_icmp_destroy(const struct nlmsghdr *nlh, void *data)
537 {
538  struct nf_conntrack *ct = author_destroy(nlh, data);
539  assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
540  nfct_destroy(ct);
541  return MNL_CB_OK;
542 }
543 
544 int cb_udp_new(const struct nlmsghdr *nlh, void *data)
545 {
546  struct nf_conntrack *ct = author_new(nlh, data);
547  assert_port(ct, 0, DSTPORT);
548  nfct_destroy(ct);
549  return MNL_CB_OK;
550 }
551 
552 int cb_udp_update(const struct nlmsghdr *nlh, void *data)
553 {
554  struct nf_conntrack *ct = author_update(nlh, data);
555  assert_port(ct, 0, DSTPORT);
556  nfct_destroy(ct);
557  return MNL_CB_OK;
558 }
559 
560 int cb_udp_destroy(const struct nlmsghdr *nlh, void *data)
561 {
562  struct nf_conntrack *ct = author_destroy(nlh, data);
563  assert_port(ct, 0, DSTPORT);
564  nfct_destroy(ct);
565  return MNL_CB_OK;
566 }
567 
568 int cb_tcp_new(const struct nlmsghdr *nlh, void *data)
569 {
570  struct nf_conntrack *ct = author_new(nlh, data);
571  assert_port(ct, 0, DSTPORT);
572  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_SENT);
573  nfct_destroy(ct);
574  return MNL_CB_OK;
575 }
576 
577 int cb_tcp_syn_recv(const struct nlmsghdr *nlh, void *data)
578 {
579  struct nf_conntrack *ct = author_update(nlh, data);
580  assert_port(ct, 0, DSTPORT);
581  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_RECV);
582  nfct_destroy(ct);
583  return MNL_CB_OK;
584 }
585 
586 int cb_tcp_established(const struct nlmsghdr *nlh, void *data)
587 {
588  struct nf_conntrack *ct = author_update(nlh, data);
589  assert_port(ct, 0, DSTPORT);
590  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED);
591  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED));
592  nfct_destroy(ct);
593  return MNL_CB_OK;
594 }
595 
596 int cb_tcp_fin_wait(const struct nlmsghdr *nlh, void *data)
597 {
598  struct nf_conntrack *ct = author_update(nlh, data);
599  assert_port(ct, 0, DSTPORT);
600  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT);
601  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED));
602  nfct_destroy(ct);
603  return MNL_CB_OK;
604 }
605 
606 int cb_tcp_close_wait(const struct nlmsghdr *nlh, void *data)
607 {
608  struct nf_conntrack *ct = author_update(nlh, data);
609  assert_port(ct, 0, DSTPORT);
610  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE_WAIT);
611  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED));
612  nfct_destroy(ct);
613  return MNL_CB_OK;
614 }
615 
616 int cb_tcp_close(const struct nlmsghdr *nlh, void *data)
617 {
618  struct nf_conntrack *ct = author_update(nlh, data);
619  assert_port(ct, 0, DSTPORT);
620  assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE);
621  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED));
622  nfct_destroy(ct);
623  return MNL_CB_OK;
624 }
625 
626 int cb_tcp_destroy(const struct nlmsghdr *nlh, void *data)
627 {
628  struct nf_conntrack *ct = author_destroy(nlh, data);
629  assert_port(ct, 0, DSTPORT);
630  assert(nfct_attr_is_set(ct, ATTR_TCP_STATE) == 0);
631  assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED));
632  nfct_destroy(ct);
633  return MNL_CB_OK;
634 }
635 
636 void tcp_echo(const struct mnl_socket *nl,
637  const char *pre, const char *post)
638 {
639  uint8_t proto = IPPROTO_TCP;
640 
641  sync_fifo(pre);
642  timeout.tv_sec = INIT_TIMEOUT;
643  handle_qacb(nl, true, cb_tcp_new, &proto);
644  handle_qacb(nl, true, cb_tcp_syn_recv, &proto);
645  handle_qacb(nl, true, cb_tcp_established, &proto);
646  handle_qacb(nl, true, cb_tcp_fin_wait, &proto);
647  handle_qacb(nl, true, cb_tcp_close_wait, &proto);
648  handle_qacb(nl, true, cb_tcp_close, &proto);
649  handle_qacb(nl, true, cb_tcp_destroy, &proto);
650  handle_qacb(nl, false, NULL, NULL);
651  sync_fifo(post);
652 }
653 
654 int handle_qacb(const struct mnl_socket *nl, bool should_receive,
655  int(*cb)(const struct nlmsghdr *nlh, void *data), void *data)
656 {
657  char buf[MNL_SOCKET_BUFFER_SIZE];
658  fd_set rfds;
659  int ret, fd = mnl_socket_get_fd(nl);
660  bool receive_nfnl;
661 
662  FD_ZERO(&rfds);
663  FD_SET(fd, &rfds);
664  if (select(fd + 1, &rfds, NULL, NULL, &timeout) < 0)
665  child_exit("select", EXIT_FAILURE);
666  receive_nfnl = FD_ISSET(fd, &rfds);
667  if (should_receive) {
668  assert(receive_nfnl == true);
669  } else {
670  assert(receive_nfnl == false);
671  return MNL_CB_ERROR;
672  }
673 
674  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
675  if (ret == -1)
676  child_exit("mnl_socket_recvfrom", EXIT_FAILURE);
677  mnl_cb_run(buf, ret, 0, 0, debug_nfct_cb, NULL);
678  if (cb != NULL) {
679  ret = mnl_cb_run(buf, ret, 0, 0, cb, data);
680  if (ret == -1)
681  child_exit("mnl_cb_run", EXIT_FAILURE);
682  return ret;
683  }
684 
685  return MNL_CB_OK;
686 }
687 
688 static void sigabrt_handler(int signum)
689 {
690  fini_nssocket();
691 }
692 
693 struct mnl_socket *mnl_event_nssocket(const char *nsname)
694 {
695  struct mnl_socket *nl;
696  struct sigaction sa;
697 
698  sigemptyset(&sa.sa_mask);
699  sa.sa_flags = 0;
700  sa.sa_handler = sigabrt_handler;
701  if (sigaction(SIGABRT, &sa, NULL) == -1)
702  return NULL;
703 
704  if (init_nssocket(nsname) == -1)
705  return NULL;
706 
707  nl = mnl_nssocket_open(NETLINK_NETFILTER);
708  if (nl == NULL)
709  return NULL;
710  if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_NEW |
711  NF_NETLINK_CONNTRACK_UPDATE |
712  NF_NETLINK_CONNTRACK_DESTROY,
713  MNL_SOCKET_AUTOPID) < 0) {
714  parent_fail("mnl_socket_bind");
715  mnl_socket_close(nl);
716  return NULL;
717  }
718 
719  return nl;
720 }
721 
722 void sync_fifo(const char *name)
723 {
724  struct stat statbuf;
725  int fd = open(name, O_WRONLY);
726  if (fd == -1) {
727  parent_fail("open fifo");
728  exit(EXIT_FAILURE);
729  }
730  if (fstat(fd, &statbuf) == -1) {
731  parent_fail("fstat fifo");
732  exit(EXIT_FAILURE);
733  }
734  if (!S_ISFIFO(statbuf.st_mode)) {
735  parent_fail("S_ISFIFO");
736  exit(EXIT_FAILURE);
737  }
738  close(fd);
739 }
uint16_t nfct_get_attr_u16(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)
uint8_t nfct_get_attr_u8(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)
void nfct_destroy(struct nf_conntrack *ct)
Definition: conntrack/api.c:92
int nfct_snprintf(char *buf, unsigned int size, const struct nf_conntrack *ct, const unsigned int msg_type, const unsigned int out_type, const unsigned int out_flags)
uint32_t nfct_get_attr_u32(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)
struct nf_conntrack * nfct_new(void)
Definition: conntrack/api.c:75
int nfct_attr_is_set(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)