10 #include <sys/param.h>
11 #include <sys/socket.h>
13 #include <sys/types.h>
18 #include <libmnl/libmnl.h>
19 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
20 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
25 #define PARENT_FD (fdpair[0])
26 #define CHILD_FD (fdpair[1])
30 void add_child(pid_t pid)
33 children[nchild++] = pid;
36 static int get_unaligned_int(
const void *s)
39 memcpy(&x, s,
sizeof(x));
43 static void put_unaligned_int(
void *d,
int x)
45 memcpy(d, &x,
sizeof(x));
63 ssize_t tx(
int fd,
int *cmd, uint8_t cmdlen,
int cdata)
66 struct iovec iov[cmdlen];
67 size_t cmsglen = CMSG_SPACE(
sizeof(
int));
68 char control[CMSG_SPACE(
sizeof(
int))];
72 memset(&msg, 0,
sizeof(
struct msghdr));
73 memset(iov, 0,
sizeof(
struct iovec) * cmdlen);
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];
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);
91 return sendmsg(fd, &msg, 0);
94 ssize_t rx(
int fd,
int *cmd, uint8_t cmdlen,
int *cdata)
97 struct iovec iov[cmdlen];
98 size_t cmsglen = CMSG_SPACE(
sizeof(
int));
99 char control[CMSG_SPACE(
sizeof(
int))];
100 struct cmsghdr *cmsg;
104 memset(&msg, 0,
sizeof(
struct msghdr));
105 memset(iov, 0,
sizeof(
struct iovec));
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];
114 msg.msg_control = control;
115 msg.msg_controllen = cmsglen;
118 ret = recvmsg(fd, &msg, 0);
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) {
134 *cdata = get_unaligned_int(CMSG_DATA(cmsg));
139 int tx_cmd(
int fd,
int cmd)
141 return tx(fd, &cmd, 1, 0);
147 if (rx((fd), &cmd, 1, NULL) == -1)
152 int tx_fd(
int fd1,
int fd2,
int e)
154 return tx(fd1, &e, 1, fd2);
161 if (rx(fd1, &e, 1, &fd2) == -1)
172 #include <sys/syscall.h>
173 static int setns(
int fd,
int nstype)
176 return syscall(__NR_setns, fd, nstype);
184 #define NETNS_RUN_DIR "/var/run/netns"
185 static int netns_setup(
const char *name)
190 char net_path[MAXPATHLEN];
193 snprintf(net_path,
sizeof(net_path),
"%s/%s", NETNS_RUN_DIR, name);
194 netns = open(net_path, O_RDONLY | O_CLOEXEC);
196 fprintf(stderr,
"Cannot open network namespace \"%s\": %s\n",
197 name, strerror(errno));
201 if (setns(netns, CLONE_NEWNET) < 0) {
202 fprintf(stderr,
"setting the network namespace \"%s\" failed: %s\n",
203 name, strerror(errno));
207 if (unshare(CLONE_NEWNS) < 0) {
208 fprintf(stderr,
"unshare failed: %s\n", strerror(errno));
212 if (mount(
"",
"/",
"none", MS_SLAVE | MS_REC, NULL)) {
213 fprintf(stderr,
"\"mount --make-rslave /\" failed: %s\n",
218 if (umount2(
"/sys", MNT_DETACH) < 0) {
219 fprintf(stderr,
"umount of /sys failed: %s\n", strerror(errno));
222 if (mount(name,
"/sys",
"sysfs", 0, NULL) < 0) {
223 fprintf(stderr,
"mount of /sys failed: %s\n",strerror(errno));
230 static void child(
const char *nsname)
236 if (netns_setup(nsname) == -1)
237 child_exit(
"netns_setup", EXIT_FAILURE);
240 if (tx_cmd(CHILD_FD, CMD_SYNC) == -1)
241 child_exit(
"tx_cmd", EXIT_FAILURE);
245 debug_ns(
"child waiting for cmd...\n");
246 cmd = rx_cmd(CHILD_FD);
249 debug_ns(
"child received CMD_DONE - exiting\n");
251 child_exit(
"receive CMD_DONE", EXIT_SUCCESS);
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);
264 debug_ns(
"child received unknown cmd: %d\n", cmd);
265 child_exit(
"receive unknown cmd", EXIT_FAILURE);
276 static void sigchld_handler(
int signum)
279 int status, i, fail = 0;
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))
287 if (pid == child_pid)
289 for (i = 0; i < nchild; i++)
290 if (children[i] == pid)
293 kill(children[i], SIGKILL);
295 if (pid == -1 && errno != ECHILD)
306 int init_nssocket(
const char *nsname)
311 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1)
314 sigemptyset(&sa.sa_mask);
315 sa.sa_handler = sigchld_handler;
316 sa.sa_flags = SA_NOCLDSTOP;
317 if (sigaction(SIGCHLD, &sa, NULL) == -1)
332 if (rx_cmd(PARENT_FD) < 0) {
333 parent_fail(
"rx_cmd");
342 int fini_nssocket(
void)
348 sigemptyset(&block_mask);
349 sigaddset(&block_mask, SIGCHLD);
350 if (sigprocmask(SIG_SETMASK, &block_mask, NULL) == -1)
352 tx_cmd(PARENT_FD, CMD_DONE);
354 pid = waitpid(child_pid, &status, 0);
358 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
364 int nssocket(
int domain,
int type,
int protocol)
366 int cmd[] = {CMD_SOCKET, domain, type, protocol};
368 if (child_pid == 0 || kill(child_pid, 0) == -1) {
372 tx(PARENT_FD, cmd, 4, 0);
373 return rx_fd(PARENT_FD);
379 int debug_nfct_cb(
const struct nlmsghdr *nlh,
void *data)
381 struct nf_conntrack *ct;
382 uint32_t type = NFCT_T_UNKNOWN;
385 switch(nlh->nlmsg_type & 0xFF) {
386 case IPCTNL_MSG_CT_NEW:
387 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
390 type = NFCT_T_UPDATE;
392 case IPCTNL_MSG_CT_DELETE:
393 type = NFCT_T_DESTROY;
401 nfct_nlmsg_parse(nlh, ct);
402 nfct_snprintf(buf,
sizeof(buf), ct, type, NFCT_O_DEFAULT, 0);
409 struct mnl_socket *mnl_nssocket_open(
int bus)
412 struct mnl_socket *nl;
414 fd = nssocket(AF_NETLINK, SOCK_RAW, bus);
418 nl = mnl_socket_fdopen(fd);
429 struct nf_conntrack *author_new(
const struct nlmsghdr *nlh,
void *data)
431 struct nf_conntrack *ct;
433 assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW);
434 assert(nlh->nlmsg_flags == (NLM_F_CREATE | NLM_F_EXCL));
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);
446 struct nf_conntrack *author_update(
const struct nlmsghdr *nlh,
void *data)
448 struct nf_conntrack *ct;
450 assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW);
451 assert(nlh->nlmsg_flags == 0);
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);
463 struct nf_conntrack *author_destroy(
const struct nlmsghdr *nlh,
void *data)
465 struct nf_conntrack *ct;
467 assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_DELETE);
468 assert(nlh->nlmsg_flags == 0);
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);
479 void assert_proto(
const struct nf_conntrack *ct,
480 uint8_t l3proto, uint8_t l4proto)
488 void assert_inaddr(
const struct nf_conntrack *ct,
489 const char *src,
const char *dst)
492 assert(inet_aton((src), &addr) != 0);
495 assert(inet_aton((dst), &addr) != 0);
500 void assert_port(
const struct nf_conntrack *ct,
501 uint16_t src, uint16_t dst)
513 void assert_typecode(
const struct nf_conntrack *ct,
514 uint8_t type, uint8_t code)
520 int cb_icmp_new(
const struct nlmsghdr *nlh,
void *data)
522 struct nf_conntrack *ct = author_new(nlh, data);
523 assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
528 int cb_icmp_update(
const struct nlmsghdr *nlh,
void *data)
530 struct nf_conntrack *ct = author_update(nlh, data);
531 assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
536 int cb_icmp_destroy(
const struct nlmsghdr *nlh,
void *data)
538 struct nf_conntrack *ct = author_destroy(nlh, data);
539 assert_typecode(ct, ICMP_TYPE, ICMP_CODE);
544 int cb_udp_new(
const struct nlmsghdr *nlh,
void *data)
546 struct nf_conntrack *ct = author_new(nlh, data);
547 assert_port(ct, 0, DSTPORT);
552 int cb_udp_update(
const struct nlmsghdr *nlh,
void *data)
554 struct nf_conntrack *ct = author_update(nlh, data);
555 assert_port(ct, 0, DSTPORT);
560 int cb_udp_destroy(
const struct nlmsghdr *nlh,
void *data)
562 struct nf_conntrack *ct = author_destroy(nlh, data);
563 assert_port(ct, 0, DSTPORT);
568 int cb_tcp_new(
const struct nlmsghdr *nlh,
void *data)
570 struct nf_conntrack *ct = author_new(nlh, data);
571 assert_port(ct, 0, DSTPORT);
577 int cb_tcp_syn_recv(
const struct nlmsghdr *nlh,
void *data)
579 struct nf_conntrack *ct = author_update(nlh, data);
580 assert_port(ct, 0, DSTPORT);
586 int cb_tcp_established(
const struct nlmsghdr *nlh,
void *data)
588 struct nf_conntrack *ct = author_update(nlh, data);
589 assert_port(ct, 0, DSTPORT);
596 int cb_tcp_fin_wait(
const struct nlmsghdr *nlh,
void *data)
598 struct nf_conntrack *ct = author_update(nlh, data);
599 assert_port(ct, 0, DSTPORT);
606 int cb_tcp_close_wait(
const struct nlmsghdr *nlh,
void *data)
608 struct nf_conntrack *ct = author_update(nlh, data);
609 assert_port(ct, 0, DSTPORT);
616 int cb_tcp_close(
const struct nlmsghdr *nlh,
void *data)
618 struct nf_conntrack *ct = author_update(nlh, data);
619 assert_port(ct, 0, DSTPORT);
626 int cb_tcp_destroy(
const struct nlmsghdr *nlh,
void *data)
628 struct nf_conntrack *ct = author_destroy(nlh, data);
629 assert_port(ct, 0, DSTPORT);
636 void tcp_echo(
const struct mnl_socket *nl,
637 const char *pre,
const char *post)
639 uint8_t proto = IPPROTO_TCP;
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);
654 int handle_qacb(
const struct mnl_socket *nl,
bool should_receive,
655 int(*cb)(
const struct nlmsghdr *nlh,
void *data),
void *data)
657 char buf[MNL_SOCKET_BUFFER_SIZE];
659 int ret, fd = mnl_socket_get_fd(nl);
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);
670 assert(receive_nfnl ==
false);
674 ret = mnl_socket_recvfrom(nl, buf,
sizeof(buf));
676 child_exit(
"mnl_socket_recvfrom", EXIT_FAILURE);
677 mnl_cb_run(buf, ret, 0, 0, debug_nfct_cb, NULL);
679 ret = mnl_cb_run(buf, ret, 0, 0, cb, data);
681 child_exit(
"mnl_cb_run", EXIT_FAILURE);
688 static void sigabrt_handler(
int signum)
693 struct mnl_socket *mnl_event_nssocket(
const char *nsname)
695 struct mnl_socket *nl;
698 sigemptyset(&sa.sa_mask);
700 sa.sa_handler = sigabrt_handler;
701 if (sigaction(SIGABRT, &sa, NULL) == -1)
704 if (init_nssocket(nsname) == -1)
707 nl = mnl_nssocket_open(NETLINK_NETFILTER);
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);
722 void sync_fifo(
const char *name)
725 int fd = open(name, O_WRONLY);
727 parent_fail(
"open fifo");
730 if (fstat(fd, &statbuf) == -1) {
731 parent_fail(
"fstat fifo");
734 if (!S_ISFIFO(statbuf.st_mode)) {
735 parent_fail(
"S_ISFIFO");
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)
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)
int nfct_attr_is_set(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)