From 9c0ed46f68cada9f3455be91adb553d020012596 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Mar 2019 11:56:05 +0100 Subject: Rename 'qa' directory to 'tests' When searching for library tests, 'qa' is easily overlooked. Use a more common name instead. Suggested-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- Makefile.am | 2 +- configure.ac | 4 +- qa/.gitignore | 4 - qa/Makefile.am | 19 -- qa/ct_echo_event.c | 62 ---- qa/ct_echo_event.sh | 20 -- qa/ct_events_reliable.c | 71 ----- qa/ct_mark_filter.c | 149 --------- qa/ct_mark_filter.sh | 36 --- qa/ct_stress.c | 75 ----- qa/inetd.conf | 7 - qa/nssocket.c | 739 -------------------------------------------- qa/nssocket.h | 102 ------ qa/nssocket_env.sh | 87 ------ qa/qa-connlabel.conf | 11 - qa/test_api.c | 751 --------------------------------------------- qa/test_connlabel.c | 70 ----- qa/test_filter.c | 79 ----- tests/.gitignore | 4 + tests/Makefile.am | 19 ++ tests/ct_echo_event.c | 62 ++++ tests/ct_echo_event.sh | 20 ++ tests/ct_events_reliable.c | 71 +++++ tests/ct_mark_filter.c | 149 +++++++++ tests/ct_mark_filter.sh | 36 +++ tests/ct_stress.c | 75 +++++ tests/inetd.conf | 7 + tests/nssocket.c | 739 ++++++++++++++++++++++++++++++++++++++++++++ tests/nssocket.h | 102 ++++++ tests/nssocket_env.sh | 87 ++++++ tests/qa-connlabel.conf | 11 + tests/test_api.c | 751 +++++++++++++++++++++++++++++++++++++++++++++ tests/test_connlabel.c | 70 +++++ tests/test_filter.c | 79 +++++ 34 files changed, 2285 insertions(+), 2285 deletions(-) delete mode 100644 qa/.gitignore delete mode 100644 qa/Makefile.am delete mode 100644 qa/ct_echo_event.c delete mode 100755 qa/ct_echo_event.sh delete mode 100644 qa/ct_events_reliable.c delete mode 100644 qa/ct_mark_filter.c delete mode 100755 qa/ct_mark_filter.sh delete mode 100644 qa/ct_stress.c delete mode 100644 qa/inetd.conf delete mode 100644 qa/nssocket.c delete mode 100644 qa/nssocket.h delete mode 100644 qa/nssocket_env.sh delete mode 100644 qa/qa-connlabel.conf delete mode 100644 qa/test_api.c delete mode 100644 qa/test_connlabel.c delete mode 100644 qa/test_filter.c create mode 100644 tests/.gitignore create mode 100644 tests/Makefile.am create mode 100644 tests/ct_echo_event.c create mode 100755 tests/ct_echo_event.sh create mode 100644 tests/ct_events_reliable.c create mode 100644 tests/ct_mark_filter.c create mode 100755 tests/ct_mark_filter.sh create mode 100644 tests/ct_stress.c create mode 100644 tests/inetd.conf create mode 100644 tests/nssocket.c create mode 100644 tests/nssocket.h create mode 100644 tests/nssocket_env.sh create mode 100644 tests/qa-connlabel.conf create mode 100644 tests/test_api.c create mode 100644 tests/test_connlabel.c create mode 100644 tests/test_filter.c diff --git a/Makefile.am b/Makefile.am index baa98ad..1a53c10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Make_global.am ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = include src utils examples qa +SUBDIRS = include src utils examples tests man_MANS = #nfnetlink_conntrack.3 nfnetlink_conntrack.7 diff --git a/configure.ac b/configure.ac index 6304543..6940c38 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3]) AC_CHECK_HEADERS(arpa/inet.h) dnl Check for inet_ntop AC_CHECK_FUNCS(inet_ntop) -dnl Check for setns used in qa +dnl Check for setns used in tests AC_CHECK_FUNCS(setns) dnl Again, some systems have it, but not IPv6 if test "$ac_cv_func_inet_ntop" = "yes" ; then @@ -66,7 +66,7 @@ fi dnl Output the makefile AC_CONFIG_FILES([Makefile src/Makefile include/Makefile utils/Makefile - examples/Makefile qa/Makefile include/libnetfilter_conntrack/Makefile + examples/Makefile tests/Makefile include/libnetfilter_conntrack/Makefile include/internal/Makefile src/conntrack/Makefile src/expect/Makefile libnetfilter_conntrack.pc doxygen.cfg]) AC_OUTPUT diff --git a/qa/.gitignore b/qa/.gitignore deleted file mode 100644 index 5e22175..0000000 --- a/qa/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/ct_events_reliable -/ct_stress -/test_api -/test_filter diff --git a/qa/Makefile.am b/qa/Makefile.am deleted file mode 100644 index 20ebaf2..0000000 --- a/qa/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -include $(top_srcdir)/Make_global.am - -check_PROGRAMS = test_api test_filter test_connlabel ct_stress \ - ct_events_reliable - -test_api_SOURCES = test_api.c -test_api_LDADD = ../src/libnetfilter_conntrack.la - -test_connlabel_SOURCES = test_connlabel.c -test_connlabel_LDADD = ../src/libnetfilter_conntrack.la - -test_filter_SOURCES = test_filter.c -test_filter_LDADD = ../src/libnetfilter_conntrack.la - -ct_stress_SOURCES = ct_stress.c -ct_stress_LDADD = ../src/libnetfilter_conntrack.la - -ct_events_reliable_SOURCES = ct_events_reliable.c -ct_events_reliable_LDADD = ../src/libnetfilter_conntrack.la diff --git a/qa/ct_echo_event.c b/qa/ct_echo_event.c deleted file mode 100644 index eb9c82f..0000000 --- a/qa/ct_echo_event.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "nssocket.h" - -static void udp_echo(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - uint8_t proto = IPPROTO_UDP; - - sync_fifo(pre); - timeout.tv_sec = INIT_TIMEOUT; - handle_qacb(nl, true, cb_udp_new, &proto); - handle_qacb(nl, true, cb_udp_update, &proto); - handle_qacb(nl, true, cb_udp_destroy, &proto); - handle_qacb(nl, false, NULL, NULL); - sync_fifo(post); -} - -static void icmp_echo(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - uint8_t proto = IPPROTO_ICMP; - - sync_fifo(pre); - timeout.tv_sec = INIT_TIMEOUT; - handle_qacb(nl, true, cb_icmp_new, &proto); - handle_qacb(nl, true, cb_icmp_update, &proto); - handle_qacb(nl, true, cb_icmp_destroy, &proto); - handle_qacb(nl, false, NULL, NULL); - sync_fifo(post); -} - -int main(int argc, char *argv[]) -{ - struct mnl_socket *nl; - char *pre, *post; - - if (argc != 4) { - fprintf(stderr, "usage: %s \n", argv[0]); - exit(EXIT_FAILURE); - } - pre = argv[2]; - post = argv[3]; - - nl = mnl_event_nssocket(argv[1]); - if (nl == NULL) { - perror("init_mnl_socket"); - exit(EXIT_FAILURE); - } - - tcp_echo(nl, pre, post); - udp_echo(nl, pre, post); - icmp_echo(nl, pre, post); - - return fini_nssocket(); -} diff --git a/qa/ct_echo_event.sh b/qa/ct_echo_event.sh deleted file mode 100755 index b4d7409..0000000 --- a/qa/ct_echo_event.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -. `dirname $0`/nssocket_env.sh - -echo "---- TCP echo" -pre_sync -echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT -post_sync - -echo "---- UDP echo" -pre_sync -echo | nc -q 0 -u $VETH_CHILD_ADDR $DSTPORT -post_sync - -echo "---- ICMP echo" -pre_sync -ping -c 1 $VETH_CHILD_ADDR > /dev/null 2>&1 -post_sync - -fin diff --git a/qa/ct_events_reliable.c b/qa/ct_events_reliable.c deleted file mode 100644 index b51d0e5..0000000 --- a/qa/ct_events_reliable.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -static int events = 0; -static int new, update, destroy; - -static int event_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - if (type == NFCT_T_NEW) - new++; - else if (type == NFCT_T_UPDATE) - update++; - else if (type == NFCT_T_DESTROY) - destroy++; - - if ((++events % 10000) == 0) - printf("%d events received (%d new, %d update, %d destroy)\n", - events, new, update, destroy); - - return NFCT_CB_CONTINUE; -} - -static void sighandler(int foo) -{ - printf("%d events received (%d new, %d update, %d destroy)\n", - events, new, update, destroy); - exit(EXIT_SUCCESS); -} - -int main(void) -{ - int ret; - struct nfct_handle *h; - int on = 1; - - signal(SIGINT, sighandler); - - h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); - if (!h) { - perror("nfct_open"); - return 0; - } - - setsockopt(nfct_fd(h), SOL_NETLINK, - NETLINK_BROADCAST_SEND_ERROR, &on, sizeof(int)); - setsockopt(nfct_fd(h), SOL_NETLINK, - NETLINK_NO_ENOBUFS, &on, sizeof(int)); - - nfct_callback_register(h, NFCT_T_ALL, event_cb, NULL); - - printf("TEST: waiting for events...\n"); - - ret = nfct_catch(h); - - printf("TEST: conntrack events "); - if (ret == -1) - printf("(%d)(%s)\n", ret, strerror(errno)); - else - printf("(OK)\n"); - - nfct_close(h); - - ret == -1 ? exit(EXIT_FAILURE) : exit(EXIT_SUCCESS); -} diff --git a/qa/ct_mark_filter.c b/qa/ct_mark_filter.c deleted file mode 100644 index cd6dd27..0000000 --- a/qa/ct_mark_filter.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -#include "nssocket.h" - -static void tcp_echo_before_fin(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - uint8_t proto = IPPROTO_TCP; - - sync_fifo(pre); - timeout.tv_sec = INIT_TIMEOUT; - handle_qacb(nl, true, cb_tcp_new, &proto); - handle_qacb(nl, true, cb_tcp_syn_recv, &proto); - handle_qacb(nl, true, cb_tcp_established, &proto); - handle_qacb(nl, false, NULL, NULL); - sync_fifo(post); -} - -static void tcp_echo_after_fin(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - uint8_t proto = IPPROTO_TCP; - - sync_fifo(pre); - timeout.tv_sec = INIT_TIMEOUT; - handle_qacb(nl, true, cb_tcp_fin_wait, &proto); - handle_qacb(nl, true, cb_tcp_close_wait, &proto); - handle_qacb(nl, true, cb_tcp_close, &proto); - handle_qacb(nl, true, cb_tcp_destroy, &proto); - handle_qacb(nl, false, NULL, NULL); - sync_fifo(post); -} - -static void filter_mark_zero(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - struct nfct_filter *filter = nfct_filter_create(); - struct nfct_filter_dump_mark mark = {val: 0, mask: 0}; - - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); - nfct_filter_destroy(filter); - tcp_echo(nl, pre, post); - assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); -} - -static void filter_mark_1_1(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - struct nfct_filter *filter = nfct_filter_create(); - struct nfct_filter_dump_mark mark = {val: 1, mask: 1}; - - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); - nfct_filter_destroy(filter); - tcp_echo_after_fin(nl, pre, post); - assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); -} - -static void filter_mark_neg_1_1(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - struct nfct_filter *filter = nfct_filter_create(); - struct nfct_filter_dump_mark mark = {val: 1, mask: 1}; - - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK, - NFCT_FILTER_LOGIC_NEGATIVE) != -1); - assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); - nfct_filter_destroy(filter); - tcp_echo_before_fin(nl, pre, post); - assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); -} - -static void filter_mark_neg_0_fffffffd(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - struct nfct_filter *filter = nfct_filter_create(); - struct nfct_filter_dump_mark mark = {val: 0, mask: 0xfffffffd}; - - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK, - NFCT_FILTER_LOGIC_NEGATIVE) != -1); - assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); - nfct_filter_destroy(filter); - tcp_echo_after_fin(nl, pre, post); - assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); -} - -static void filter_mark_max(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - struct nfct_filter *filter = nfct_filter_create(); - struct nfct_filter_dump_mark mark; - int i; - - for (i = 0; i < 126; i++) { - /* does not match to mark value 3 */ - mark = (struct nfct_filter_dump_mark){val: 0, mask: 3}; - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - } - - /* __FILTER_MARK_MAX 127, should be added */ - mark = (struct nfct_filter_dump_mark){val: 1, mask: 1}; - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - - /* over __FILTER_MARK_MAX, should be ignored */ - mark = (struct nfct_filter_dump_mark){val: 0, mask: 0}; - nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); - - assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); - nfct_filter_destroy(filter); - tcp_echo_after_fin(nl, pre, post); - assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); -} - -int main(int argc, char *argv[]) -{ - struct mnl_socket *nl; - char *pre, *post; - - if (argc != 4) { - fprintf(stderr, "usage: %s \n", argv[0]); - exit(EXIT_FAILURE); - } - pre = argv[2]; - post = argv[3]; - - nl = mnl_event_nssocket(argv[1]); - if (nl == NULL) { - perror("init_mnl_socket"); - exit(EXIT_FAILURE); - } - - filter_mark_zero(nl, pre, post); - filter_mark_1_1(nl, pre, post); - filter_mark_neg_1_1(nl, pre, post); - filter_mark_neg_0_fffffffd(nl, pre, post); - filter_mark_max(nl, pre, post); - - return fini_nssocket(); -} diff --git a/qa/ct_mark_filter.sh b/qa/ct_mark_filter.sh deleted file mode 100755 index a2c7fed..0000000 --- a/qa/ct_mark_filter.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -. `dirname $0`/nssocket_env.sh - -echo "---- TCP echo with ctmark 0/0 [filter_mark_zero]" -pre_sync -echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT -post_sync - -echo "---- iptables CONNMARK settings - ctmark tcp 2/2, tcp fin 1/1" -ip netns exec $NETNS sh < -#include -#include -#include -#include -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - time_t t; - int ret, i, j, r; - struct nfct_handle *h; - struct nf_conntrack *ct; - - if (argc < 2) { - fprintf(stderr, "Usage: %s [ct_table_size]\n", argv[0]); - exit(EXIT_FAILURE); - } - - time(&t); - srandom(t); - r = random(); - - ct = nfct_new(); - if (!ct) { - perror("nfct_new"); - return 0; - } - - h = nfct_open(CONNTRACK, 0); - if (!h) { - perror("nfct_open"); - nfct_destroy(ct); - return -1; - } - - for (i = r, j = 0;i < (r + atoi(argv[1]) * 2); i++, j++) { - nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET); - nfct_set_attr_u32(ct, ATTR_IPV4_SRC, inet_addr("1.1.1.1") + i); - nfct_set_attr_u32(ct, ATTR_IPV4_DST, inet_addr("2.2.2.2") + i); - - nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP); - nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(10)); - nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(20)); - - nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - - nfct_set_attr_u8(ct, ATTR_TCP_STATE, TCP_CONNTRACK_ESTABLISHED); - nfct_set_attr_u32(ct, ATTR_TIMEOUT, 1000); - nfct_set_attr_u32(ct, ATTR_STATUS, IPS_ASSURED); - - if (i % 10000 == 0) - printf("added %d flow entries\n", j); - - ret = nfct_query(h, NFCT_Q_CREATE, ct); - if (ret == -1) - perror("nfct_query: "); - } - nfct_close(h); - - nfct_destroy(ct); - - exit(EXIT_SUCCESS); -} diff --git a/qa/inetd.conf b/qa/inetd.conf deleted file mode 100644 index 0216b7d..0000000 --- a/qa/inetd.conf +++ /dev/null @@ -1,7 +0,0 @@ -#:INTERNAL: Internal services -echo stream tcp nowait root internal -echo dgram udp wait root internal -#discard stream tcp nowait root internal -#discard dgram udp wait root internal -#daytime stream tcp nowait root internal -#time stream tcp nowait root internal diff --git a/qa/nssocket.c b/qa/nssocket.c deleted file mode 100644 index 114938c..0000000 --- a/qa/nssocket.c +++ /dev/null @@ -1,739 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "config.h" -#include "nssocket.h" - -int fdpair[2]; -#define PARENT_FD (fdpair[0]) -#define CHILD_FD (fdpair[1]) - -pid_t child_pid; - -void add_child(pid_t pid) -{ - /* XXX: check excess MAX_CHILD */ - children[nchild++] = pid; -} - -static int get_unaligned_int(const void *s) -{ - int x; - memcpy(&x, s, sizeof(x)); - return x; -} - -static void put_unaligned_int(void *d, int x) -{ - memcpy(d, &x, sizeof(x)); -} - -/* - * message exchange via socketpair using send/recv msg() - * - * - use cdata: - * cdata represents a file descriptor - * cmd[0] means -errno - * - * - without cdata: - * cmd[0] means: - * > 0: command - * == 0: sync, echo - * < 0: -errno - * - * it's an given fact that tx() and rx() never fail. - */ -ssize_t tx(int fd, int *cmd, uint8_t cmdlen, int cdata) -{ - struct msghdr msg; - struct iovec iov[cmdlen]; - size_t cmsglen = CMSG_SPACE(sizeof(int)); - char control[CMSG_SPACE(sizeof(int))]; - struct cmsghdr *cmsg; - int i; - - memset(&msg, 0, sizeof(struct msghdr)); - memset(iov, 0, sizeof(struct iovec) * cmdlen); - - msg.msg_iov = iov; - msg.msg_iovlen = cmdlen; - for (i = 0; i < cmdlen; i++) { - iov[i].iov_len = sizeof(int); - iov[i].iov_base = &cmd[i]; - } - if (cdata) { - msg.msg_control = control; - msg.msg_controllen = cmsglen; - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - put_unaligned_int(CMSG_DATA(cmsg), cdata); - } - - return sendmsg(fd, &msg, 0); -} - -ssize_t rx(int fd, int *cmd, uint8_t cmdlen, int *cdata) -{ - struct msghdr msg; - struct iovec iov[cmdlen]; - size_t cmsglen = CMSG_SPACE(sizeof(int)); - char control[CMSG_SPACE(sizeof(int))]; - struct cmsghdr *cmsg; - ssize_t ret; - int i; - - memset(&msg, 0, sizeof(struct msghdr)); - memset(iov, 0, sizeof(struct iovec)); - - msg.msg_iov = iov; - msg.msg_iovlen = cmdlen; - for (i = 0; i < cmdlen; i++) { - iov[i].iov_len = sizeof(int); - iov[i].iov_base = &cmd[i]; - } - if (cdata != NULL) { - msg.msg_control = control; - msg.msg_controllen = cmsglen; - } - - ret = recvmsg(fd, &msg, 0); - if (ret == -1) { - perror("recvmsg"); - return ret; - } - - if (cdata == NULL) - return ret; - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) - || cmsg->cmsg_level != SOL_SOCKET - || cmsg->cmsg_type != SCM_RIGHTS) { - errno = EBADMSG; - return -1; - } - *cdata = get_unaligned_int(CMSG_DATA(cmsg)); - - return ret; -} - -int tx_cmd(int fd, int cmd) -{ - return tx(fd, &cmd, 1, 0); -} - -int rx_cmd(int fd) -{ - int cmd; - if (rx((fd), &cmd, 1, NULL) == -1) - return -1; - return cmd; -} - -int tx_fd(int fd1, int fd2, int e) -{ - return tx(fd1, &e, 1, fd2); -} - -int rx_fd(int fd1) -{ - int e, fd2; - - if (rx(fd1, &e, 1, &fd2) == -1) - return -1; - - errno = -e; - return fd2; -} - -/* - * copy from ip/ipnetns.c::iproute2 - */ -#ifndef HAVE_SETNS -#include -static int setns(int fd, int nstype) -{ -#ifdef __NR_setns - return syscall(__NR_setns, fd, nstype); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif /* HAVE_SETNS */ - -#define NETNS_RUN_DIR "/var/run/netns" -static int netns_setup(const char *name) -{ - /* Setup the proper environment for apps that are not netns - * aware, and execute a program in that environment. - */ - char net_path[MAXPATHLEN]; - int netns; - - snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name); - netns = open(net_path, O_RDONLY | O_CLOEXEC); - if (netns < 0) { - fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", - name, strerror(errno)); - return -1; - } - - if (setns(netns, CLONE_NEWNET) < 0) { - fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", - name, strerror(errno)); - return -1; - } - - if (unshare(CLONE_NEWNS) < 0) { - fprintf(stderr, "unshare failed: %s\n", strerror(errno)); - return -1; - } - /* Don't let any mounts propagate back to the parent */ - if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { - fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", - strerror(errno)); - return -1; - } - /* Mount a version of /sys that describes the network namespace */ - if (umount2("/sys", MNT_DETACH) < 0) { - fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); - return -1; - } - if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { - fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); - return -1; - } - - return 0; -} - -static void child(const char *nsname) -{ - int cmd = CMD_SYNC; - int params[3]; /* XXX: magic number, see enum CALL_ */ - int sockfd; - - if (netns_setup(nsname) == -1) - child_exit("netns_setup", EXIT_FAILURE); - - /* sync with parent */ - if (tx_cmd(CHILD_FD, CMD_SYNC) == -1) - child_exit("tx_cmd", EXIT_FAILURE); - - /* waiting cmd */ - while (1) { - debug_ns("child waiting for cmd...\n"); - cmd = rx_cmd(CHILD_FD); - switch (cmd) { - case CMD_DONE: - debug_ns("child received CMD_DONE - exiting\n"); - close(CHILD_FD); - child_exit("receive CMD_DONE", EXIT_SUCCESS); - break; - case CMD_SOCKET: - if (rx(CHILD_FD, params, 3, NULL) == -1) - child_exit("rx", EXIT_FAILURE); - debug_ns("child received CMD_SOCKET -" - " domain: %d, type: %d, protocol: %d\n", - params[0], params[1], params[2]); - sockfd = socket(params[0], params[1], params[2]); - if (tx_fd(CHILD_FD, sockfd, -errno) == -1) - child_exit("tx_fd", EXIT_FAILURE); - break; - default: - debug_ns("child received unknown cmd: %d\n", cmd); - child_exit("receive unknown cmd", EXIT_FAILURE); - break; - } - } -} - -/* - * kill all the other registered child by SIGKILL - * - * SIGCHLD will not be raised if child has killed in SIGABRT handler - */ -static void sigchld_handler(int signum) -{ - pid_t pid; - int status, i, fail = 0; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - debug_ns("receive SIGCHLD - pid: %d\n", pid); - if (WIFEXITED(status)) - fail |= WEXITSTATUS(status); - else if (WIFSIGNALED(status) || WCOREDUMP(status)) - fail |= status; - if (pid == child_pid) - child_pid = 0; - for (i = 0; i < nchild; i++) - if (children[i] == pid) - children[i] = 0; - else - kill(children[i], SIGKILL); - } - if (pid == -1 && errno != ECHILD) - fail |= errno; - - /* overdoing? kill myself - * if (fail) kill(0, SIGKILL); - */ -} - -/* - * core public API - */ -int init_nssocket(const char *nsname) -{ - pid_t pid; - struct sigaction sa; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) - return -1; - - sigemptyset(&sa.sa_mask); - sa.sa_handler = sigchld_handler; - sa.sa_flags = SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa, NULL) == -1) - return -1; - - fflush(stdout); - pid = fork(); - switch (pid) { - case -1: - return -1; - break; - case 0: - child(nsname); /* not return */ - break; - default: - child_pid = pid; - add_child(pid); - if (rx_cmd(PARENT_FD) < 0) { - parent_fail("rx_cmd"); - return -1; - } - break; - } - - return 0; -} - -int fini_nssocket(void) -{ - int status; - sigset_t block_mask; - pid_t pid; - - sigemptyset(&block_mask); - sigaddset(&block_mask, SIGCHLD); - if (sigprocmask(SIG_SETMASK, &block_mask, NULL) == -1) - return -1; - tx_cmd(PARENT_FD, CMD_DONE); - close(PARENT_FD); - pid = waitpid(child_pid, &status, 0); - child_pid = 0; - if (pid < 0) - return -1; - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - - return status; -} - -int nssocket(int domain, int type, int protocol) -{ - int cmd[] = {CMD_SOCKET, domain, type, protocol}; - - if (child_pid == 0 || kill(child_pid, 0) == -1) { - errno = ECHILD; - return -1; - } - tx(PARENT_FD, cmd, 4, 0); - return rx_fd(PARENT_FD); -} - -/* - * utils API - */ -int debug_nfct_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct; - uint32_t type = NFCT_T_UNKNOWN; - char buf[4096]; - - switch(nlh->nlmsg_type & 0xFF) { - case IPCTNL_MSG_CT_NEW: - if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL)) - type = NFCT_T_NEW; - else - type = NFCT_T_UPDATE; - break; - case IPCTNL_MSG_CT_DELETE: - type = NFCT_T_DESTROY; - break; - } - - ct = nfct_new(); - if (ct == NULL) - return MNL_CB_OK; - - nfct_nlmsg_parse(nlh, ct); - nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_DEFAULT, 0); - debug("%s\n", buf); - nfct_destroy(ct); - - return MNL_CB_OK; -} - -struct mnl_socket *mnl_nssocket_open(int bus) -{ - int fd; - struct mnl_socket *nl; - - fd = nssocket(AF_NETLINK, SOCK_RAW, bus); - if (fd == -1) - return NULL; - - nl = mnl_socket_fdopen(fd); - if (nl == NULL) { - close(fd); - return NULL; - } - return nl; -} - -/* - * assert utilities - */ -struct nf_conntrack *author_new(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct; - - assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW); - assert(nlh->nlmsg_flags == (NLM_F_CREATE | NLM_F_EXCL)); - ct = nfct_new(); - assert(ct != NULL); - assert(nfct_nlmsg_parse((nlh), ct) == 0); - assert_proto(ct, AF_INET, *(uint8_t *) data); - assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY) == 0); - timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1; - - return ct; -} - -struct nf_conntrack *author_update(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct; - - assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW); - assert(nlh->nlmsg_flags == 0); - ct = nfct_new(); - assert(ct != NULL); - assert(nfct_nlmsg_parse((nlh), ct) == 0); - assert_proto(ct, AF_INET, *(uint8_t *) data); - assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY)); - timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1; - - return ct; -} - -struct nf_conntrack *author_destroy(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct; - - assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_DELETE); - assert(nlh->nlmsg_flags == 0); - ct = nfct_new(); - assert(ct != NULL); - assert(nfct_nlmsg_parse((nlh), ct) == 0); - assert_proto(ct, AF_INET, *(uint8_t *) data); - assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY)); - - return ct; -} - -void assert_proto(const struct nf_conntrack *ct, - uint8_t l3proto, uint8_t l4proto) -{ - assert(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) == l3proto); - assert(nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO) == l3proto); - assert(nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO) == l4proto); - assert(nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO) == l4proto); -} - -void assert_inaddr(const struct nf_conntrack *ct, - const char *src, const char *dst) -{ - struct in_addr addr; - assert(inet_aton((src), &addr) != 0); - assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_SRC) == addr.s_addr); - assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_DST) == addr.s_addr); - assert(inet_aton((dst), &addr) != 0); - assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_DST) == addr.s_addr); - assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_SRC) == addr.s_addr); -} - -void assert_port(const struct nf_conntrack *ct, - uint16_t src, uint16_t dst) -{ - if ((src)) { - assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_SRC) == htons((src))); - assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_DST) == htons((src))); - } - if ((dst)) { - assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_DST) == htons((dst))); - assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_SRC) == htons((dst))); - } -} - -void assert_typecode(const struct nf_conntrack *ct, - uint8_t type, uint8_t code) -{ - assert(nfct_get_attr_u8((ct), ATTR_ICMP_TYPE) == type); - assert(nfct_get_attr_u8((ct), ATTR_ICMP_CODE) == code); -} - -int cb_icmp_new(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_new(nlh, data); - assert_typecode(ct, ICMP_TYPE, ICMP_CODE); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_icmp_update(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_typecode(ct, ICMP_TYPE, ICMP_CODE); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_icmp_destroy(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_destroy(nlh, data); - assert_typecode(ct, ICMP_TYPE, ICMP_CODE); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_udp_new(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_new(nlh, data); - assert_port(ct, 0, DSTPORT); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_udp_update(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_udp_destroy(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_destroy(nlh, data); - assert_port(ct, 0, DSTPORT); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_new(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_new(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_SENT); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_syn_recv(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_RECV); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_established(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_fin_wait(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_close_wait(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE_WAIT); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_close(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_update(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); - nfct_destroy(ct); - return MNL_CB_OK; -} - -int cb_tcp_destroy(const struct nlmsghdr *nlh, void *data) -{ - struct nf_conntrack *ct = author_destroy(nlh, data); - assert_port(ct, 0, DSTPORT); - assert(nfct_attr_is_set(ct, ATTR_TCP_STATE) == 0); - assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); - nfct_destroy(ct); - return MNL_CB_OK; -} - -void tcp_echo(const struct mnl_socket *nl, - const char *pre, const char *post) -{ - uint8_t proto = IPPROTO_TCP; - - sync_fifo(pre); - timeout.tv_sec = INIT_TIMEOUT; - handle_qacb(nl, true, cb_tcp_new, &proto); - handle_qacb(nl, true, cb_tcp_syn_recv, &proto); - handle_qacb(nl, true, cb_tcp_established, &proto); - handle_qacb(nl, true, cb_tcp_fin_wait, &proto); - handle_qacb(nl, true, cb_tcp_close_wait, &proto); - handle_qacb(nl, true, cb_tcp_close, &proto); - handle_qacb(nl, true, cb_tcp_destroy, &proto); - handle_qacb(nl, false, NULL, NULL); - sync_fifo(post); -} - -int handle_qacb(const struct mnl_socket *nl, bool should_receive, - int(*cb)(const struct nlmsghdr *nlh, void *data), void *data) -{ - char buf[MNL_SOCKET_BUFFER_SIZE]; - fd_set rfds; - int ret, fd = mnl_socket_get_fd(nl); - bool receive_nfnl; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - if (select(fd + 1, &rfds, NULL, NULL, &timeout) < 0) - child_exit("select", EXIT_FAILURE); - receive_nfnl = FD_ISSET(fd, &rfds); - if (should_receive) { - assert(receive_nfnl == true); - } else { - assert(receive_nfnl == false); - return MNL_CB_ERROR; - } - - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) - child_exit("mnl_socket_recvfrom", EXIT_FAILURE); - mnl_cb_run(buf, ret, 0, 0, debug_nfct_cb, NULL); - if (cb != NULL) { - ret = mnl_cb_run(buf, ret, 0, 0, cb, data); - if (ret == -1) - child_exit("mnl_cb_run", EXIT_FAILURE); - return ret; - } - - return MNL_CB_OK; -} - -static void sigabrt_handler(int signum) -{ - fini_nssocket(); -} - -struct mnl_socket *mnl_event_nssocket(const char *nsname) -{ - struct mnl_socket *nl; - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = sigabrt_handler; - if (sigaction(SIGABRT, &sa, NULL) == -1) - return NULL; - - if (init_nssocket(nsname) == -1) - return NULL; - - nl = mnl_nssocket_open(NETLINK_NETFILTER); - if (nl == NULL) - return NULL; - if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_NEW | - NF_NETLINK_CONNTRACK_UPDATE | - NF_NETLINK_CONNTRACK_DESTROY, - MNL_SOCKET_AUTOPID) < 0) { - parent_fail("mnl_socket_bind"); - mnl_socket_close(nl); - return NULL; - } - - return nl; -} - -void sync_fifo(const char *name) -{ - struct stat statbuf; - int fd = open(name, O_WRONLY); - if (fd == -1) { - parent_fail("open fifo"); - exit(EXIT_FAILURE); - } - if (fstat(fd, &statbuf) == -1) { - parent_fail("fstat fifo"); - exit(EXIT_FAILURE); - } - if (!S_ISFIFO(statbuf.st_mode)) { - parent_fail("S_ISFIFO"); - exit(EXIT_FAILURE); - } - close(fd); -} diff --git a/qa/nssocket.h b/qa/nssocket.h deleted file mode 100644 index 338ed2f..0000000 --- a/qa/nssocket.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _QA_NSSOCKET_H_ -#define _QA_NSSOCKET_H_ - -#include - -/* ipc command */ -enum { - CMD_SYNC, - CMD_SOCKET, /* int domain, int type, int protocol */ - CMD_DONE, - CMD_ERREXIT, -}; - -int init_nssocket(const char *nsname); -int fini_nssocket(void); -int nssocket(int domain, int type, int protocol); -struct mnl_socket *mnl_nssocket_open(int bus); - -ssize_t tx(int fd, int *cmd, uint8_t cmdlen, int cdata); -ssize_t rx(int fd, int *cmd, uint8_t cmdlen, int *cdata); -int tx_cmd(int fd, int cmd); -int rx_cmd(int fd); -int tx_fd(int fd1, int fd2, int e); -int rx_fd(int fd1); -int debug_nfct_cb(const struct nlmsghdr *nlh, void *data); - -/* assert utilities */ -struct nf_conntrack *author_new(const struct nlmsghdr *nlh, void *data); -struct nf_conntrack *author_update(const struct nlmsghdr *nlh, void *data); -struct nf_conntrack *author_destroy(const struct nlmsghdr *nlh, void *data); -void assert_proto(const struct nf_conntrack *ct, - uint8_t l3proto, uint8_t l4proto); -void assert_inaddr(const struct nf_conntrack *ct, - const char *src, const char *dst); -void assert_port(const struct nf_conntrack *ct, - uint16_t src, uint16_t dst); -void assert_typecode(const struct nf_conntrack *ct, - uint8_t type, uint8_t code); -int cb_icmp_new(const struct nlmsghdr *nlh, void *data); -int cb_icmp_update(const struct nlmsghdr *nlh, void *data); -int cb_icmp_destroy(const struct nlmsghdr *nlh, void *data); -int cb_udp_new(const struct nlmsghdr *nlh, void *data); -int cb_udp_update(const struct nlmsghdr *nlh, void *data); -int cb_udp_destroy(const struct nlmsghdr *nlh, void *data); -int cb_tcp_new(const struct nlmsghdr *nlh, void *data); -int cb_tcp_syn_recv(const struct nlmsghdr *nlh, void *data); -int cb_tcp_established(const struct nlmsghdr *nlh, void *data); -int cb_tcp_fin_wait(const struct nlmsghdr *nlh, void *data); -int cb_tcp_close_wait(const struct nlmsghdr *nlh, void *data); -int cb_tcp_close(const struct nlmsghdr *nlh, void *data); -int cb_tcp_destroy(const struct nlmsghdr *nlh, void *data); -void tcp_echo(const struct mnl_socket *nl, - const char *pre, const char *post); -int handle_qacb(const struct mnl_socket *nl, bool should_receive, - int(*cb)(const struct nlmsghdr *nlh, void *data), void *data); -struct mnl_socket *mnl_event_nssocket(const char *nsname); -void sync_fifo(const char *name); - - -#define MAX_CHILD 64 -pid_t children[MAX_CHILD]; /* kill if not 0 */ -int nchild; -void add_child(pid_t pid); - -/* tv_sec will update every cb */ -struct timeval timeout; - -#define parent_fail(msg) do { \ - int i; \ - fprintf(stderr, "parent fail - %s:%d %s() %s: %s\n", \ - __FILE__, __LINE__, __func__, (msg), strerror(errno)); \ - for (i = 0; i < nchild; i++) \ - if (children[i]) \ - kill(children[i], SIGKILL); \ - } while (0) - -#define child_exit(msg, code) \ - do { \ - if (code) \ - fprintf(stderr, "child exiting - %s:%d %s() %s: %s\n", \ - __FILE__, __LINE__, __func__, (msg), strerror(errno)); \ - _exit((code)); \ - } while (0) - -/* #define DEBUG_NS */ -#define DEBUG - -#ifdef DEBUG -#include -#define debug(...) do { fprintf(stderr, ##__VA_ARGS__); } while (0) -#else -#define debug(...) -#endif - -#ifdef DEBUG_NS -#include -#define debug_ns(...) do { fprintf(stderr, ##__VA_ARGS__); } while (0) -#else -#define debug_ns(...) -#endif - -#endif /* _QA_NSSOCKET_H_ */ diff --git a/qa/nssocket_env.sh b/qa/nssocket_env.sh deleted file mode 100644 index 1732eb1..0000000 --- a/qa/nssocket_env.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/sh - -NETNS="lnfct_qa" -VETH_NAME="veth_qa0" -VETH_PEER="veth_qa1" -DUMMY_DEV="dummy_qa0" -VETH_PARENT_ADDR="10.255.255.249" -VETH_CHILD_ADDR="10.255.255.250" -VETH_MASK="30" -DSTPORT="7" -ICMP_TYPE="8" -ICMP_CODE="0" -NF_TIMEOUT=2 -INIT_TIMEOUT=8 - -dname=`dirname $0` -bname=`basename $0` -qname=${bname%.sh} - -PRE_FIFO="$dname/qa_pre_fifo" -POST_FIFO="$dname/qa_post_fifo" - -[ -z `which ip` ] && echo "ip(8) required" >&2 && exit 1 -[ -z `which inetd` ] && echo "inetd required" >&2 && exit 1 -[ -z `which nc` ] && echo "nc required" >&2 && exit 1 -[ -z `which iptables` ] && echo "iptables required" >&2 && exit 1 -modprobe nf_conntrack_ipv4 || exit 1 -modprobe nfnetlink_cttimeout || exit 1 - -make -C $dname \ - CFLAGS="-DVETH_PARENT_ADDR=\\\"$VETH_PARENT_ADDR\\\" \ - -DVETH_CHILD_ADDR=\\\"$VETH_CHILD_ADDR\\\" \ - -DDSTPORT=$DSTPORT -DICMP_TYPE=$ICMP_TYPE -DICMP_CODE=$ICMP_CODE \ - -DINIT_TIMEOUT=$INIT_TIMEOUT" \ - $qname || exit 1 - -# parent / client -ip netns add $NETNS -trap "ip netns del $NETNS; exit 1" 1 2 15 -ip link ls $VETH_NAME > /dev/null 2>&1 && ip link del $VETH_NAME -ip link add $VETH_NAME type veth peer name $VETH_PEER -ip link set $VETH_PEER netns $NETNS -ip link set $VETH_NAME up -ip addr add ${VETH_PARENT_ADDR}/${VETH_MASK} dev $VETH_NAME - -# child / server -ip netns exec $NETNS sh < /proc/sys/net/ipv4/ip_forward -for f in /proc/sys/net/netfilter/*timeout*; do echo $NF_TIMEOUT > "\$f"; done -ip link set lo up -ip link set $VETH_PEER up -ip addr add ${VETH_CHILD_ADDR}/${VETH_MASK} dev $VETH_PEER -ip link add ${DUMMY_DEV} up type dummy -ip route add default dev ${DUMMY_DEV} -EOF -ip netns exec $NETNS inetd -d $dname/inetd.conf > /dev/null 2>&1 & -server_pid=$! - -rm -f $PRE_FIFO $POST_FIFO -mkfifo $PRE_FIFO || exit 1 -mkfifo $POST_FIFO || exit 1 - -${dname}/${qname} $NETNS $PRE_FIFO $POST_FIFO & -qa_pid=$! - -trap_handle() { - rm -f $PRE_FIFO $POST_FIFO - kill $server_pid > /dev/null 2>&1 - kill -6 $qa_pid > /dev/null 2>&1 - ip netns del $NETNS > /dev/null 2>&1 -} -trap "trap_handle; exit 1" 1 2 15 - -fin() { - wait $qa_pid - trap_handle -} - -pre_sync() { - 8< $PRE_FIFO || kill $$ - 8>&- -} - -post_sync() { - 8< $POST_FIFO || kill $$ - 8>&- -} diff --git a/qa/qa-connlabel.conf b/qa/qa-connlabel.conf deleted file mode 100644 index 38c3115..0000000 --- a/qa/qa-connlabel.conf +++ /dev/null @@ -1,11 +0,0 @@ -0 zero -# duplicate names should be skipped -1 zero -1 test label 1 -1 zero -# .. so this should have added bit 1 as "test label 1" -2 test label 2 -# duplicate bit, should be skipped, too -2 duplicate -5 unused label -42 T diff --git a/qa/test_api.c b/qa/test_api.c deleted file mode 100644 index 57fdb90..0000000 --- a/qa/test_api.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Run this after adding a new attribute to the nf_conntrack object - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * this file contains a test to check the set/get/copy/cmp APIs. - */ - -static void eval_sigterm(int status) -{ - switch(WTERMSIG(status)) { - case SIGSEGV: - printf("received SIGSEV\n"); - break; - case 0: - printf("OK\n"); - break; - default: - printf("exited with signal: %d\n", WTERMSIG(status)); - break; - } -} - -static void test_nfct_bitmask(void) -{ - struct nfct_bitmask *a, *b; - unsigned short int maxb, i; - struct nf_conntrack *ct1, *ct2; - - printf("== test nfct_bitmask_* API ==\n"); - - maxb = rand() & 0xffff; - - a = nfct_bitmask_new(maxb); - - assert(!nfct_bitmask_test_bit(a, maxb + 32)); - nfct_bitmask_set_bit(a, maxb + 32); - assert(!nfct_bitmask_test_bit(a, maxb + 32)); - - for (i = 0; i <= maxb; i++) - assert(!nfct_bitmask_test_bit(a, i)); - - for (i = 0; i <= maxb; i++) { - if (rand() & 1) { - assert(!nfct_bitmask_test_bit(a, i)); - continue; - } - nfct_bitmask_set_bit(a, i); - assert(nfct_bitmask_test_bit(a, i)); - } - - b = nfct_bitmask_clone(a); - assert(b); - - for (i = 0; i <= maxb; i++) { - if (nfct_bitmask_test_bit(a, i)) - assert(nfct_bitmask_test_bit(b, i)); - else - assert(!nfct_bitmask_test_bit(b, i)); - } - - nfct_bitmask_destroy(a); - - for (i = 0; i <= maxb; i++) { - if (rand() & 1) - continue; - nfct_bitmask_unset_bit(b, i); - assert(!nfct_bitmask_test_bit(b, i)); - } - - /* nfct_bitmask_clear() */ - for (i = 0; i < maxb; i++) { - nfct_bitmask_set_bit(b, i); - assert(nfct_bitmask_test_bit(b, i)); - nfct_bitmask_clear(b); - assert(!nfct_bitmask_test_bit(b, i)); - } - - for (i = 0; i < maxb; i++) - nfct_bitmask_set_bit(b, i); - nfct_bitmask_clear(b); - for (i = 0; i < maxb; i++) - assert(!nfct_bitmask_test_bit(b, i)); - - /* nfct_bitmask_equal() */ - for (i = 0; i < maxb / 32 * 32; i += 32) { - a = nfct_bitmask_new(i); - assert(!nfct_bitmask_equal(a, b)); - nfct_bitmask_destroy(a); - } - - a = nfct_bitmask_clone(b); - assert(nfct_bitmask_equal(a, b)); - for (i = 0; i < maxb; i++) { - if (nfct_bitmask_test_bit(a, i)) { - nfct_bitmask_unset_bit(a, i); - assert(!nfct_bitmask_equal(a, b)); - nfct_bitmask_set_bit(a, i); - } else { - nfct_bitmask_set_bit(a, i); - assert(!nfct_bitmask_equal(a, b)); - nfct_bitmask_unset_bit(a, i); - } - assert(nfct_bitmask_equal(a, b)); - } - - nfct_bitmask_destroy(a); - nfct_bitmask_destroy(b); - - ct1 = nfct_new(); - ct2 = nfct_new(); - - maxb = rand() & 0xff; - maxb += 128; - maxb /= 2; - a = nfct_bitmask_new(maxb * 2); - b = nfct_bitmask_new(maxb); - nfct_set_attr(ct1, ATTR_CONNLABELS, a); - nfct_set_attr(ct2, ATTR_CONNLABELS, b); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - - nfct_bitmask_set_bit(a, maxb); - nfct_bitmask_set_bit(b, maxb); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - - nfct_bitmask_set_bit(a, maxb * 2); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 0); - nfct_destroy(ct1); - nfct_destroy(ct2); - printf("OK\n"); -} - -/* These attributes cannot be set, ignore them. */ -static int attr_is_readonly(int attr) -{ - switch (attr) { - case ATTR_ORIG_COUNTER_PACKETS: - case ATTR_REPL_COUNTER_PACKETS: - case ATTR_ORIG_COUNTER_BYTES: - case ATTR_REPL_COUNTER_BYTES: - case ATTR_USE: - case ATTR_SECCTX: - case ATTR_TIMESTAMP_START: - case ATTR_TIMESTAMP_STOP: - return 1; - } - return 0; -} - - -static int test_nfct_cmp_api_single(struct nf_conntrack *ct1, - struct nf_conntrack *ct2, int attr) -{ - char data[256]; - struct nfct_bitmask *b; - int bit; - - if (attr_is_readonly(attr)) - return 0; - - switch (attr) { - case ATTR_SECMARK: /* obsolete */ - return 0; - - /* FIXME: not implemented comparators: */ - case ATTR_SNAT_IPV4: - case ATTR_DNAT_IPV4: - case ATTR_SNAT_IPV6: - case ATTR_DNAT_IPV6: - case ATTR_SNAT_PORT: - case ATTR_DNAT_PORT: - - case ATTR_TCP_FLAGS_ORIG: - case ATTR_TCP_FLAGS_REPL: - case ATTR_TCP_MASK_ORIG: - case ATTR_TCP_MASK_REPL: - - case ATTR_MASTER_IPV4_SRC: - case ATTR_MASTER_IPV4_DST: - case ATTR_MASTER_IPV6_SRC: - case ATTR_MASTER_IPV6_DST: - case ATTR_MASTER_PORT_SRC: - case ATTR_MASTER_PORT_DST: - case ATTR_MASTER_L3PROTO: - case ATTR_MASTER_L4PROTO: - - case ATTR_ORIG_NAT_SEQ_CORRECTION_POS: - case ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE: - case ATTR_ORIG_NAT_SEQ_OFFSET_AFTER: - case ATTR_REPL_NAT_SEQ_CORRECTION_POS: - case ATTR_REPL_NAT_SEQ_OFFSET_BEFORE: - case ATTR_REPL_NAT_SEQ_OFFSET_AFTER: - - case ATTR_SCTP_VTAG_ORIG: - case ATTR_SCTP_VTAG_REPL: - - case ATTR_HELPER_NAME: - - case ATTR_DCCP_ROLE: - case ATTR_DCCP_HANDSHAKE_SEQ: - - case ATTR_TCP_WSCALE_ORIG: - case ATTR_TCP_WSCALE_REPL: - - case ATTR_SYNPROXY_ISN: - case ATTR_SYNPROXY_ITS: - case ATTR_SYNPROXY_TSOFF: - - case ATTR_HELPER_INFO: - return 0; /* XXX */ - - default: - break; - } - - if (attr >= ATTR_SCTP_STATE) { - nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_SCTP); - nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_SCTP); - } else if (attr >= ATTR_TCP_FLAGS_ORIG) { - nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); - nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); - } else if (attr >= ATTR_ICMP_CODE) { - nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_ICMP); - nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_ICMP); - } else if (attr >= ATTR_ORIG_PORT_SRC) { - nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); - nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); - } - - nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); - memset(data, 42, sizeof(data)); - - assert(nfct_attr_is_set(ct1, attr)); - assert(nfct_attr_is_set(ct2, attr)); - - switch (attr) { - case ATTR_CONNLABELS: - case ATTR_CONNLABELS_MASK: - b = (void *) nfct_get_attr(ct1, attr); - assert(b); - b = nfct_bitmask_clone(b); - assert(b); - bit = nfct_bitmask_maxbit(b); - if (nfct_bitmask_test_bit(b, bit)) { - nfct_bitmask_unset_bit(b, bit); - assert(!nfct_bitmask_test_bit(b, bit)); - } else { - nfct_bitmask_set_bit(b, bit); - assert(nfct_bitmask_test_bit(b, bit)); - } - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - nfct_set_attr(ct2, attr, b); - break; - case ATTR_HELPER_INFO: - nfct_set_attr_l(ct2, attr, "test", 4); - break; - default: - nfct_set_attr(ct2, attr, data); - break; - } - - if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL) != 0) { - fprintf(stderr, "nfct_cmp assert failure for attr %d\n", attr); - fprintf(stderr, "%p, %p, %x, %x\n", nfct_get_attr(ct1, attr), - nfct_get_attr(ct2, attr), - nfct_get_attr_u32(ct1, attr), nfct_get_attr_u32(ct2, attr)); - return -1; - } - if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) != 0) { - fprintf(stderr, "nfct_cmp strict assert failure for attr %d\n", attr); - return -1; - } - return 0; -} - -static int test_cmp_attr32(int attr, bool at1, bool at2, - uint32_t v1, uint32_t v2, unsigned int flags) -{ - struct nf_conntrack *ct1 = nfct_new(); - struct nf_conntrack *ct2 = nfct_new(); - int ret; - - if (at1) - nfct_set_attr_u32(ct1, attr, v1); - if (at2) - nfct_set_attr_u32(ct2, attr, v2); - - ret = nfct_cmp(ct1, ct2, NFCT_CMP_ALL | flags); - - nfct_destroy(ct1); - nfct_destroy(ct2); - - return ret; -} - -static void test_nfct_cmp_attr(int attr) -{ - unsigned int flags = 0; - - /* 0000, 1000, 1100, 0010, 1010... */ - /* attr at1 at2 v1 v2 */ - assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); - - flags = NFCT_CMP_STRICT; - assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); - - flags = NFCT_CMP_MASK; - assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); - - flags = NFCT_CMP_STRICT|NFCT_CMP_MASK; - assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); - assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); - assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ - assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ - assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ - assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); -} - -static void test_nfct_cmp_api(struct nf_conntrack *ct1, struct nf_conntrack *ct2) -{ - int i; - - printf("== test cmp API ==\n"); - - test_nfct_cmp_attr(ATTR_ZONE); - test_nfct_cmp_attr(ATTR_ORIG_ZONE); - test_nfct_cmp_attr(ATTR_REPL_ZONE); - test_nfct_cmp_attr(ATTR_MARK); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); - - nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); - - for (i=0; i < ATTR_MAX ; i++) { - nfct_attr_unset(ct1, i); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); - } - nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); - for (i=0; i < ATTR_MAX ; i++) { - nfct_attr_unset(ct2, i); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 0); - } - - for (i=0; i < ATTR_MAX ; i++) - assert(test_nfct_cmp_api_single(ct1, ct2, i) == 0); - - nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); - for (i=0; i < ATTR_MAX ; i++) { - nfct_attr_unset(ct1, i); - nfct_attr_unset(ct2, i); - - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); - assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); - } - nfct_destroy(ct1); - nfct_destroy(ct2); -} - -static void test_nfexp_cmp_api(struct nf_expect *ex1, struct nf_expect *ex2) -{ - int i; - - printf("== test expect cmp API ==\n"); - - /* XXX: missing nfexp_copy API. */ - memcpy(ex1, ex2, nfexp_maxsize()); - - assert(nfexp_cmp(ex1, ex2, 0) == 1); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); - - assert(nfexp_attr_is_set(ex1, 0) == 1); - nfexp_attr_unset(ex1, 0); - assert(nfexp_attr_is_set(ex1, 0) == 0); - - memcpy(ex1, ex2, nfexp_maxsize()); - for (i=0; i < ATTR_EXP_MAX; i++) { - nfexp_attr_unset(ex1, i); - - assert(nfexp_cmp(ex1, ex2, 0) == 1); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 0); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); - } - memcpy(ex1, ex2, nfexp_maxsize()); - for (i=0; i < ATTR_EXP_MAX; i++) { - nfexp_attr_unset(ex2, i); - - assert(nfexp_cmp(ex1, ex2, 0) == 1); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 0); - } - memcpy(ex1, ex2, nfexp_maxsize()); - for (i=0; i < ATTR_EXP_MAX; i++) { - nfexp_attr_unset(ex1, i); - nfexp_attr_unset(ex2, i); - - assert(nfexp_cmp(ex1, ex2, 0) == 1); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); - assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); - } - nfexp_destroy(ex1); - nfexp_destroy(ex2); -} - -int main(void) -{ - int ret, i; - struct nf_conntrack *ct, *ct2, *tmp; - struct nf_expect *exp, *tmp_exp; - char data[256]; - const char *val; - int status; - struct nfct_bitmask *b, *b2; - - srand(time(NULL)); - - /* initialize fake data for testing purposes */ - for (i=0; i -#include -#include -#include - -#include -#include - -static void print_label(struct nfct_labelmap *map) -{ - int b = nfct_labelmap_get_bit(map, "test label 1"); - assert(b == 1); - - b = nfct_labelmap_get_bit(map, "zero"); - assert(b == 0); - - b = nfct_labelmap_get_bit(map, "test label 2"); - assert(b == 2); - - b = nfct_labelmap_get_bit(map, "duplicate"); - assert(b < 0); - - b = nfct_labelmap_get_bit(map, "invalid label"); - assert(b < 0); - - b = nfct_labelmap_get_bit(map, "T"); - assert(b == 42); -} - -static void dump_map(struct nfct_labelmap *map) -{ - unsigned int i = 0; - - for (;;) { - const char *name = nfct_labelmap_get_name(map, i); - if (!name) - break; - if (name[0]) - printf("\t\"%s\", bit %d\n", name, i); - i++; - } -} - -int main(void) -{ - struct nfct_labelmap *l; - - l = nfct_labelmap_new("/"); - assert(l == NULL); - - l = nfct_labelmap_new(NULL); - if (l) { - puts("default connlabel.conf:"); - dump_map(l); - nfct_labelmap_destroy(l); - } else { - puts("no default config found"); - } - - l = nfct_labelmap_new("qa-connlabel.conf"); - if (!l) - l = nfct_labelmap_new("qa/qa-connlabel.conf"); - assert(l); - puts("qa-connlabel.conf:"); - dump_map(l); - print_label(l); - nfct_labelmap_destroy(l); - - return 0; -} diff --git a/qa/test_filter.c b/qa/test_filter.c deleted file mode 100644 index 7877819..0000000 --- a/qa/test_filter.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Test for the filter API - */ - -#include -#include -#include -#include -#include - -#include - -static int event_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - static int n = 0; - char buf[1024]; - - nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_PLAIN, NFCT_OF_TIME); - printf("%s\n", buf); - - if (++n == 10) - return NFCT_CB_STOP; - - return NFCT_CB_CONTINUE; -} - -int main(void) -{ - int i, ret; - struct nfct_handle *h; - struct nfct_filter *filter; - - h = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW | - NF_NETLINK_CONNTRACK_UPDATE); - if (!h) { - perror("nfct_open"); - return 0; - } - - filter = nfct_filter_create(); - if (!filter) { - perror("nfct_create_filter"); - return 0; - } - - if (nfct_filter_attach(nfct_fd(h), filter) == -1) { - perror("nfct_filter_attach"); - return 0; - } - - /* protocol 255 is skipped since we support up to 255 protocols max */ - for (i=0; i +#include +#include +#include +#include + +#include + +#include "nssocket.h" + +static void udp_echo(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + uint8_t proto = IPPROTO_UDP; + + sync_fifo(pre); + timeout.tv_sec = INIT_TIMEOUT; + handle_qacb(nl, true, cb_udp_new, &proto); + handle_qacb(nl, true, cb_udp_update, &proto); + handle_qacb(nl, true, cb_udp_destroy, &proto); + handle_qacb(nl, false, NULL, NULL); + sync_fifo(post); +} + +static void icmp_echo(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + uint8_t proto = IPPROTO_ICMP; + + sync_fifo(pre); + timeout.tv_sec = INIT_TIMEOUT; + handle_qacb(nl, true, cb_icmp_new, &proto); + handle_qacb(nl, true, cb_icmp_update, &proto); + handle_qacb(nl, true, cb_icmp_destroy, &proto); + handle_qacb(nl, false, NULL, NULL); + sync_fifo(post); +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char *pre, *post; + + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + pre = argv[2]; + post = argv[3]; + + nl = mnl_event_nssocket(argv[1]); + if (nl == NULL) { + perror("init_mnl_socket"); + exit(EXIT_FAILURE); + } + + tcp_echo(nl, pre, post); + udp_echo(nl, pre, post); + icmp_echo(nl, pre, post); + + return fini_nssocket(); +} diff --git a/tests/ct_echo_event.sh b/tests/ct_echo_event.sh new file mode 100755 index 0000000..b4d7409 --- /dev/null +++ b/tests/ct_echo_event.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +. `dirname $0`/nssocket_env.sh + +echo "---- TCP echo" +pre_sync +echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT +post_sync + +echo "---- UDP echo" +pre_sync +echo | nc -q 0 -u $VETH_CHILD_ADDR $DSTPORT +post_sync + +echo "---- ICMP echo" +pre_sync +ping -c 1 $VETH_CHILD_ADDR > /dev/null 2>&1 +post_sync + +fin diff --git a/tests/ct_events_reliable.c b/tests/ct_events_reliable.c new file mode 100644 index 0000000..b51d0e5 --- /dev/null +++ b/tests/ct_events_reliable.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#include + +static int events = 0; +static int new, update, destroy; + +static int event_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + if (type == NFCT_T_NEW) + new++; + else if (type == NFCT_T_UPDATE) + update++; + else if (type == NFCT_T_DESTROY) + destroy++; + + if ((++events % 10000) == 0) + printf("%d events received (%d new, %d update, %d destroy)\n", + events, new, update, destroy); + + return NFCT_CB_CONTINUE; +} + +static void sighandler(int foo) +{ + printf("%d events received (%d new, %d update, %d destroy)\n", + events, new, update, destroy); + exit(EXIT_SUCCESS); +} + +int main(void) +{ + int ret; + struct nfct_handle *h; + int on = 1; + + signal(SIGINT, sighandler); + + h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + if (!h) { + perror("nfct_open"); + return 0; + } + + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_BROADCAST_SEND_ERROR, &on, sizeof(int)); + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_NO_ENOBUFS, &on, sizeof(int)); + + nfct_callback_register(h, NFCT_T_ALL, event_cb, NULL); + + printf("TEST: waiting for events...\n"); + + ret = nfct_catch(h); + + printf("TEST: conntrack events "); + if (ret == -1) + printf("(%d)(%s)\n", ret, strerror(errno)); + else + printf("(OK)\n"); + + nfct_close(h); + + ret == -1 ? exit(EXIT_FAILURE) : exit(EXIT_SUCCESS); +} diff --git a/tests/ct_mark_filter.c b/tests/ct_mark_filter.c new file mode 100644 index 0000000..cd6dd27 --- /dev/null +++ b/tests/ct_mark_filter.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "nssocket.h" + +static void tcp_echo_before_fin(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + uint8_t proto = IPPROTO_TCP; + + sync_fifo(pre); + timeout.tv_sec = INIT_TIMEOUT; + handle_qacb(nl, true, cb_tcp_new, &proto); + handle_qacb(nl, true, cb_tcp_syn_recv, &proto); + handle_qacb(nl, true, cb_tcp_established, &proto); + handle_qacb(nl, false, NULL, NULL); + sync_fifo(post); +} + +static void tcp_echo_after_fin(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + uint8_t proto = IPPROTO_TCP; + + sync_fifo(pre); + timeout.tv_sec = INIT_TIMEOUT; + handle_qacb(nl, true, cb_tcp_fin_wait, &proto); + handle_qacb(nl, true, cb_tcp_close_wait, &proto); + handle_qacb(nl, true, cb_tcp_close, &proto); + handle_qacb(nl, true, cb_tcp_destroy, &proto); + handle_qacb(nl, false, NULL, NULL); + sync_fifo(post); +} + +static void filter_mark_zero(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + struct nfct_filter *filter = nfct_filter_create(); + struct nfct_filter_dump_mark mark = {val: 0, mask: 0}; + + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); + nfct_filter_destroy(filter); + tcp_echo(nl, pre, post); + assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); +} + +static void filter_mark_1_1(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + struct nfct_filter *filter = nfct_filter_create(); + struct nfct_filter_dump_mark mark = {val: 1, mask: 1}; + + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); + nfct_filter_destroy(filter); + tcp_echo_after_fin(nl, pre, post); + assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); +} + +static void filter_mark_neg_1_1(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + struct nfct_filter *filter = nfct_filter_create(); + struct nfct_filter_dump_mark mark = {val: 1, mask: 1}; + + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK, + NFCT_FILTER_LOGIC_NEGATIVE) != -1); + assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); + nfct_filter_destroy(filter); + tcp_echo_before_fin(nl, pre, post); + assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); +} + +static void filter_mark_neg_0_fffffffd(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + struct nfct_filter *filter = nfct_filter_create(); + struct nfct_filter_dump_mark mark = {val: 0, mask: 0xfffffffd}; + + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK, + NFCT_FILTER_LOGIC_NEGATIVE) != -1); + assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); + nfct_filter_destroy(filter); + tcp_echo_after_fin(nl, pre, post); + assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); +} + +static void filter_mark_max(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + struct nfct_filter *filter = nfct_filter_create(); + struct nfct_filter_dump_mark mark; + int i; + + for (i = 0; i < 126; i++) { + /* does not match to mark value 3 */ + mark = (struct nfct_filter_dump_mark){val: 0, mask: 3}; + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + } + + /* __FILTER_MARK_MAX 127, should be added */ + mark = (struct nfct_filter_dump_mark){val: 1, mask: 1}; + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + + /* over __FILTER_MARK_MAX, should be ignored */ + mark = (struct nfct_filter_dump_mark){val: 0, mask: 0}; + nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark); + + assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1); + nfct_filter_destroy(filter); + tcp_echo_after_fin(nl, pre, post); + assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1); +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char *pre, *post; + + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + pre = argv[2]; + post = argv[3]; + + nl = mnl_event_nssocket(argv[1]); + if (nl == NULL) { + perror("init_mnl_socket"); + exit(EXIT_FAILURE); + } + + filter_mark_zero(nl, pre, post); + filter_mark_1_1(nl, pre, post); + filter_mark_neg_1_1(nl, pre, post); + filter_mark_neg_0_fffffffd(nl, pre, post); + filter_mark_max(nl, pre, post); + + return fini_nssocket(); +} diff --git a/tests/ct_mark_filter.sh b/tests/ct_mark_filter.sh new file mode 100755 index 0000000..a2c7fed --- /dev/null +++ b/tests/ct_mark_filter.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +. `dirname $0`/nssocket_env.sh + +echo "---- TCP echo with ctmark 0/0 [filter_mark_zero]" +pre_sync +echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT +post_sync + +echo "---- iptables CONNMARK settings - ctmark tcp 2/2, tcp fin 1/1" +ip netns exec $NETNS sh < +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + time_t t; + int ret, i, j, r; + struct nfct_handle *h; + struct nf_conntrack *ct; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [ct_table_size]\n", argv[0]); + exit(EXIT_FAILURE); + } + + time(&t); + srandom(t); + r = random(); + + ct = nfct_new(); + if (!ct) { + perror("nfct_new"); + return 0; + } + + h = nfct_open(CONNTRACK, 0); + if (!h) { + perror("nfct_open"); + nfct_destroy(ct); + return -1; + } + + for (i = r, j = 0;i < (r + atoi(argv[1]) * 2); i++, j++) { + nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET); + nfct_set_attr_u32(ct, ATTR_IPV4_SRC, inet_addr("1.1.1.1") + i); + nfct_set_attr_u32(ct, ATTR_IPV4_DST, inet_addr("2.2.2.2") + i); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(10)); + nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(20)); + + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); + + nfct_set_attr_u8(ct, ATTR_TCP_STATE, TCP_CONNTRACK_ESTABLISHED); + nfct_set_attr_u32(ct, ATTR_TIMEOUT, 1000); + nfct_set_attr_u32(ct, ATTR_STATUS, IPS_ASSURED); + + if (i % 10000 == 0) + printf("added %d flow entries\n", j); + + ret = nfct_query(h, NFCT_Q_CREATE, ct); + if (ret == -1) + perror("nfct_query: "); + } + nfct_close(h); + + nfct_destroy(ct); + + exit(EXIT_SUCCESS); +} diff --git a/tests/inetd.conf b/tests/inetd.conf new file mode 100644 index 0000000..0216b7d --- /dev/null +++ b/tests/inetd.conf @@ -0,0 +1,7 @@ +#:INTERNAL: Internal services +echo stream tcp nowait root internal +echo dgram udp wait root internal +#discard stream tcp nowait root internal +#discard dgram udp wait root internal +#daytime stream tcp nowait root internal +#time stream tcp nowait root internal diff --git a/tests/nssocket.c b/tests/nssocket.c new file mode 100644 index 0000000..114938c --- /dev/null +++ b/tests/nssocket.c @@ -0,0 +1,739 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "config.h" +#include "nssocket.h" + +int fdpair[2]; +#define PARENT_FD (fdpair[0]) +#define CHILD_FD (fdpair[1]) + +pid_t child_pid; + +void add_child(pid_t pid) +{ + /* XXX: check excess MAX_CHILD */ + children[nchild++] = pid; +} + +static int get_unaligned_int(const void *s) +{ + int x; + memcpy(&x, s, sizeof(x)); + return x; +} + +static void put_unaligned_int(void *d, int x) +{ + memcpy(d, &x, sizeof(x)); +} + +/* + * message exchange via socketpair using send/recv msg() + * + * - use cdata: + * cdata represents a file descriptor + * cmd[0] means -errno + * + * - without cdata: + * cmd[0] means: + * > 0: command + * == 0: sync, echo + * < 0: -errno + * + * it's an given fact that tx() and rx() never fail. + */ +ssize_t tx(int fd, int *cmd, uint8_t cmdlen, int cdata) +{ + struct msghdr msg; + struct iovec iov[cmdlen]; + size_t cmsglen = CMSG_SPACE(sizeof(int)); + char control[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + int i; + + memset(&msg, 0, sizeof(struct msghdr)); + memset(iov, 0, sizeof(struct iovec) * cmdlen); + + msg.msg_iov = iov; + msg.msg_iovlen = cmdlen; + for (i = 0; i < cmdlen; i++) { + iov[i].iov_len = sizeof(int); + iov[i].iov_base = &cmd[i]; + } + if (cdata) { + msg.msg_control = control; + msg.msg_controllen = cmsglen; + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + put_unaligned_int(CMSG_DATA(cmsg), cdata); + } + + return sendmsg(fd, &msg, 0); +} + +ssize_t rx(int fd, int *cmd, uint8_t cmdlen, int *cdata) +{ + struct msghdr msg; + struct iovec iov[cmdlen]; + size_t cmsglen = CMSG_SPACE(sizeof(int)); + char control[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + ssize_t ret; + int i; + + memset(&msg, 0, sizeof(struct msghdr)); + memset(iov, 0, sizeof(struct iovec)); + + msg.msg_iov = iov; + msg.msg_iovlen = cmdlen; + for (i = 0; i < cmdlen; i++) { + iov[i].iov_len = sizeof(int); + iov[i].iov_base = &cmd[i]; + } + if (cdata != NULL) { + msg.msg_control = control; + msg.msg_controllen = cmsglen; + } + + ret = recvmsg(fd, &msg, 0); + if (ret == -1) { + perror("recvmsg"); + return ret; + } + + if (cdata == NULL) + return ret; + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) + || cmsg->cmsg_level != SOL_SOCKET + || cmsg->cmsg_type != SCM_RIGHTS) { + errno = EBADMSG; + return -1; + } + *cdata = get_unaligned_int(CMSG_DATA(cmsg)); + + return ret; +} + +int tx_cmd(int fd, int cmd) +{ + return tx(fd, &cmd, 1, 0); +} + +int rx_cmd(int fd) +{ + int cmd; + if (rx((fd), &cmd, 1, NULL) == -1) + return -1; + return cmd; +} + +int tx_fd(int fd1, int fd2, int e) +{ + return tx(fd1, &e, 1, fd2); +} + +int rx_fd(int fd1) +{ + int e, fd2; + + if (rx(fd1, &e, 1, &fd2) == -1) + return -1; + + errno = -e; + return fd2; +} + +/* + * copy from ip/ipnetns.c::iproute2 + */ +#ifndef HAVE_SETNS +#include +static int setns(int fd, int nstype) +{ +#ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif /* HAVE_SETNS */ + +#define NETNS_RUN_DIR "/var/run/netns" +static int netns_setup(const char *name) +{ + /* Setup the proper environment for apps that are not netns + * aware, and execute a program in that environment. + */ + char net_path[MAXPATHLEN]; + int netns; + + snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name); + netns = open(net_path, O_RDONLY | O_CLOEXEC); + if (netns < 0) { + fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", + name, strerror(errno)); + return -1; + } + + if (setns(netns, CLONE_NEWNET) < 0) { + fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", + name, strerror(errno)); + return -1; + } + + if (unshare(CLONE_NEWNS) < 0) { + fprintf(stderr, "unshare failed: %s\n", strerror(errno)); + return -1; + } + /* Don't let any mounts propagate back to the parent */ + if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { + fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", + strerror(errno)); + return -1; + } + /* Mount a version of /sys that describes the network namespace */ + if (umount2("/sys", MNT_DETACH) < 0) { + fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); + return -1; + } + if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { + fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); + return -1; + } + + return 0; +} + +static void child(const char *nsname) +{ + int cmd = CMD_SYNC; + int params[3]; /* XXX: magic number, see enum CALL_ */ + int sockfd; + + if (netns_setup(nsname) == -1) + child_exit("netns_setup", EXIT_FAILURE); + + /* sync with parent */ + if (tx_cmd(CHILD_FD, CMD_SYNC) == -1) + child_exit("tx_cmd", EXIT_FAILURE); + + /* waiting cmd */ + while (1) { + debug_ns("child waiting for cmd...\n"); + cmd = rx_cmd(CHILD_FD); + switch (cmd) { + case CMD_DONE: + debug_ns("child received CMD_DONE - exiting\n"); + close(CHILD_FD); + child_exit("receive CMD_DONE", EXIT_SUCCESS); + break; + case CMD_SOCKET: + if (rx(CHILD_FD, params, 3, NULL) == -1) + child_exit("rx", EXIT_FAILURE); + debug_ns("child received CMD_SOCKET -" + " domain: %d, type: %d, protocol: %d\n", + params[0], params[1], params[2]); + sockfd = socket(params[0], params[1], params[2]); + if (tx_fd(CHILD_FD, sockfd, -errno) == -1) + child_exit("tx_fd", EXIT_FAILURE); + break; + default: + debug_ns("child received unknown cmd: %d\n", cmd); + child_exit("receive unknown cmd", EXIT_FAILURE); + break; + } + } +} + +/* + * kill all the other registered child by SIGKILL + * + * SIGCHLD will not be raised if child has killed in SIGABRT handler + */ +static void sigchld_handler(int signum) +{ + pid_t pid; + int status, i, fail = 0; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + debug_ns("receive SIGCHLD - pid: %d\n", pid); + if (WIFEXITED(status)) + fail |= WEXITSTATUS(status); + else if (WIFSIGNALED(status) || WCOREDUMP(status)) + fail |= status; + if (pid == child_pid) + child_pid = 0; + for (i = 0; i < nchild; i++) + if (children[i] == pid) + children[i] = 0; + else + kill(children[i], SIGKILL); + } + if (pid == -1 && errno != ECHILD) + fail |= errno; + + /* overdoing? kill myself + * if (fail) kill(0, SIGKILL); + */ +} + +/* + * core public API + */ +int init_nssocket(const char *nsname) +{ + pid_t pid; + struct sigaction sa; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) + return -1; + + sigemptyset(&sa.sa_mask); + sa.sa_handler = sigchld_handler; + sa.sa_flags = SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa, NULL) == -1) + return -1; + + fflush(stdout); + pid = fork(); + switch (pid) { + case -1: + return -1; + break; + case 0: + child(nsname); /* not return */ + break; + default: + child_pid = pid; + add_child(pid); + if (rx_cmd(PARENT_FD) < 0) { + parent_fail("rx_cmd"); + return -1; + } + break; + } + + return 0; +} + +int fini_nssocket(void) +{ + int status; + sigset_t block_mask; + pid_t pid; + + sigemptyset(&block_mask); + sigaddset(&block_mask, SIGCHLD); + if (sigprocmask(SIG_SETMASK, &block_mask, NULL) == -1) + return -1; + tx_cmd(PARENT_FD, CMD_DONE); + close(PARENT_FD); + pid = waitpid(child_pid, &status, 0); + child_pid = 0; + if (pid < 0) + return -1; + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + return 0; + + return status; +} + +int nssocket(int domain, int type, int protocol) +{ + int cmd[] = {CMD_SOCKET, domain, type, protocol}; + + if (child_pid == 0 || kill(child_pid, 0) == -1) { + errno = ECHILD; + return -1; + } + tx(PARENT_FD, cmd, 4, 0); + return rx_fd(PARENT_FD); +} + +/* + * utils API + */ +int debug_nfct_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct; + uint32_t type = NFCT_T_UNKNOWN; + char buf[4096]; + + switch(nlh->nlmsg_type & 0xFF) { + case IPCTNL_MSG_CT_NEW: + if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL)) + type = NFCT_T_NEW; + else + type = NFCT_T_UPDATE; + break; + case IPCTNL_MSG_CT_DELETE: + type = NFCT_T_DESTROY; + break; + } + + ct = nfct_new(); + if (ct == NULL) + return MNL_CB_OK; + + nfct_nlmsg_parse(nlh, ct); + nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_DEFAULT, 0); + debug("%s\n", buf); + nfct_destroy(ct); + + return MNL_CB_OK; +} + +struct mnl_socket *mnl_nssocket_open(int bus) +{ + int fd; + struct mnl_socket *nl; + + fd = nssocket(AF_NETLINK, SOCK_RAW, bus); + if (fd == -1) + return NULL; + + nl = mnl_socket_fdopen(fd); + if (nl == NULL) { + close(fd); + return NULL; + } + return nl; +} + +/* + * assert utilities + */ +struct nf_conntrack *author_new(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct; + + assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW); + assert(nlh->nlmsg_flags == (NLM_F_CREATE | NLM_F_EXCL)); + ct = nfct_new(); + assert(ct != NULL); + assert(nfct_nlmsg_parse((nlh), ct) == 0); + assert_proto(ct, AF_INET, *(uint8_t *) data); + assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY) == 0); + timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1; + + return ct; +} + +struct nf_conntrack *author_update(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct; + + assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_NEW); + assert(nlh->nlmsg_flags == 0); + ct = nfct_new(); + assert(ct != NULL); + assert(nfct_nlmsg_parse((nlh), ct) == 0); + assert_proto(ct, AF_INET, *(uint8_t *) data); + assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY)); + timeout.tv_sec = nfct_get_attr_u32(ct, ATTR_TIMEOUT) + 1; + + return ct; +} + +struct nf_conntrack *author_destroy(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct; + + assert((nlh->nlmsg_type & 0xFF) == IPCTNL_MSG_CT_DELETE); + assert(nlh->nlmsg_flags == 0); + ct = nfct_new(); + assert(ct != NULL); + assert(nfct_nlmsg_parse((nlh), ct) == 0); + assert_proto(ct, AF_INET, *(uint8_t *) data); + assert_inaddr(ct, VETH_PARENT_ADDR, VETH_CHILD_ADDR); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_SEEN_REPLY)); + + return ct; +} + +void assert_proto(const struct nf_conntrack *ct, + uint8_t l3proto, uint8_t l4proto) +{ + assert(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) == l3proto); + assert(nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO) == l3proto); + assert(nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO) == l4proto); + assert(nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO) == l4proto); +} + +void assert_inaddr(const struct nf_conntrack *ct, + const char *src, const char *dst) +{ + struct in_addr addr; + assert(inet_aton((src), &addr) != 0); + assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_SRC) == addr.s_addr); + assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_DST) == addr.s_addr); + assert(inet_aton((dst), &addr) != 0); + assert(nfct_get_attr_u32((ct), ATTR_ORIG_IPV4_DST) == addr.s_addr); + assert(nfct_get_attr_u32((ct), ATTR_REPL_IPV4_SRC) == addr.s_addr); +} + +void assert_port(const struct nf_conntrack *ct, + uint16_t src, uint16_t dst) +{ + if ((src)) { + assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_SRC) == htons((src))); + assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_DST) == htons((src))); + } + if ((dst)) { + assert(nfct_get_attr_u16((ct), ATTR_ORIG_PORT_DST) == htons((dst))); + assert(nfct_get_attr_u16((ct), ATTR_REPL_PORT_SRC) == htons((dst))); + } +} + +void assert_typecode(const struct nf_conntrack *ct, + uint8_t type, uint8_t code) +{ + assert(nfct_get_attr_u8((ct), ATTR_ICMP_TYPE) == type); + assert(nfct_get_attr_u8((ct), ATTR_ICMP_CODE) == code); +} + +int cb_icmp_new(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_new(nlh, data); + assert_typecode(ct, ICMP_TYPE, ICMP_CODE); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_icmp_update(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_typecode(ct, ICMP_TYPE, ICMP_CODE); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_icmp_destroy(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_destroy(nlh, data); + assert_typecode(ct, ICMP_TYPE, ICMP_CODE); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_udp_new(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_new(nlh, data); + assert_port(ct, 0, DSTPORT); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_udp_update(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_udp_destroy(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_destroy(nlh, data); + assert_port(ct, 0, DSTPORT); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_new(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_new(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_SENT); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_syn_recv(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_SYN_RECV); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_established(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_fin_wait(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_close_wait(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE_WAIT); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_close(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_update(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_CLOSE); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); + nfct_destroy(ct); + return MNL_CB_OK; +} + +int cb_tcp_destroy(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct = author_destroy(nlh, data); + assert_port(ct, 0, DSTPORT); + assert(nfct_attr_is_set(ct, ATTR_TCP_STATE) == 0); + assert((nfct_get_attr_u32(ct, ATTR_STATUS) & IPS_ASSURED)); + nfct_destroy(ct); + return MNL_CB_OK; +} + +void tcp_echo(const struct mnl_socket *nl, + const char *pre, const char *post) +{ + uint8_t proto = IPPROTO_TCP; + + sync_fifo(pre); + timeout.tv_sec = INIT_TIMEOUT; + handle_qacb(nl, true, cb_tcp_new, &proto); + handle_qacb(nl, true, cb_tcp_syn_recv, &proto); + handle_qacb(nl, true, cb_tcp_established, &proto); + handle_qacb(nl, true, cb_tcp_fin_wait, &proto); + handle_qacb(nl, true, cb_tcp_close_wait, &proto); + handle_qacb(nl, true, cb_tcp_close, &proto); + handle_qacb(nl, true, cb_tcp_destroy, &proto); + handle_qacb(nl, false, NULL, NULL); + sync_fifo(post); +} + +int handle_qacb(const struct mnl_socket *nl, bool should_receive, + int(*cb)(const struct nlmsghdr *nlh, void *data), void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + fd_set rfds; + int ret, fd = mnl_socket_get_fd(nl); + bool receive_nfnl; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + if (select(fd + 1, &rfds, NULL, NULL, &timeout) < 0) + child_exit("select", EXIT_FAILURE); + receive_nfnl = FD_ISSET(fd, &rfds); + if (should_receive) { + assert(receive_nfnl == true); + } else { + assert(receive_nfnl == false); + return MNL_CB_ERROR; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) + child_exit("mnl_socket_recvfrom", EXIT_FAILURE); + mnl_cb_run(buf, ret, 0, 0, debug_nfct_cb, NULL); + if (cb != NULL) { + ret = mnl_cb_run(buf, ret, 0, 0, cb, data); + if (ret == -1) + child_exit("mnl_cb_run", EXIT_FAILURE); + return ret; + } + + return MNL_CB_OK; +} + +static void sigabrt_handler(int signum) +{ + fini_nssocket(); +} + +struct mnl_socket *mnl_event_nssocket(const char *nsname) +{ + struct mnl_socket *nl; + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = sigabrt_handler; + if (sigaction(SIGABRT, &sa, NULL) == -1) + return NULL; + + if (init_nssocket(nsname) == -1) + return NULL; + + nl = mnl_nssocket_open(NETLINK_NETFILTER); + if (nl == NULL) + return NULL; + if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY, + MNL_SOCKET_AUTOPID) < 0) { + parent_fail("mnl_socket_bind"); + mnl_socket_close(nl); + return NULL; + } + + return nl; +} + +void sync_fifo(const char *name) +{ + struct stat statbuf; + int fd = open(name, O_WRONLY); + if (fd == -1) { + parent_fail("open fifo"); + exit(EXIT_FAILURE); + } + if (fstat(fd, &statbuf) == -1) { + parent_fail("fstat fifo"); + exit(EXIT_FAILURE); + } + if (!S_ISFIFO(statbuf.st_mode)) { + parent_fail("S_ISFIFO"); + exit(EXIT_FAILURE); + } + close(fd); +} diff --git a/tests/nssocket.h b/tests/nssocket.h new file mode 100644 index 0000000..338ed2f --- /dev/null +++ b/tests/nssocket.h @@ -0,0 +1,102 @@ +#ifndef _QA_NSSOCKET_H_ +#define _QA_NSSOCKET_H_ + +#include + +/* ipc command */ +enum { + CMD_SYNC, + CMD_SOCKET, /* int domain, int type, int protocol */ + CMD_DONE, + CMD_ERREXIT, +}; + +int init_nssocket(const char *nsname); +int fini_nssocket(void); +int nssocket(int domain, int type, int protocol); +struct mnl_socket *mnl_nssocket_open(int bus); + +ssize_t tx(int fd, int *cmd, uint8_t cmdlen, int cdata); +ssize_t rx(int fd, int *cmd, uint8_t cmdlen, int *cdata); +int tx_cmd(int fd, int cmd); +int rx_cmd(int fd); +int tx_fd(int fd1, int fd2, int e); +int rx_fd(int fd1); +int debug_nfct_cb(const struct nlmsghdr *nlh, void *data); + +/* assert utilities */ +struct nf_conntrack *author_new(const struct nlmsghdr *nlh, void *data); +struct nf_conntrack *author_update(const struct nlmsghdr *nlh, void *data); +struct nf_conntrack *author_destroy(const struct nlmsghdr *nlh, void *data); +void assert_proto(const struct nf_conntrack *ct, + uint8_t l3proto, uint8_t l4proto); +void assert_inaddr(const struct nf_conntrack *ct, + const char *src, const char *dst); +void assert_port(const struct nf_conntrack *ct, + uint16_t src, uint16_t dst); +void assert_typecode(const struct nf_conntrack *ct, + uint8_t type, uint8_t code); +int cb_icmp_new(const struct nlmsghdr *nlh, void *data); +int cb_icmp_update(const struct nlmsghdr *nlh, void *data); +int cb_icmp_destroy(const struct nlmsghdr *nlh, void *data); +int cb_udp_new(const struct nlmsghdr *nlh, void *data); +int cb_udp_update(const struct nlmsghdr *nlh, void *data); +int cb_udp_destroy(const struct nlmsghdr *nlh, void *data); +int cb_tcp_new(const struct nlmsghdr *nlh, void *data); +int cb_tcp_syn_recv(const struct nlmsghdr *nlh, void *data); +int cb_tcp_established(const struct nlmsghdr *nlh, void *data); +int cb_tcp_fin_wait(const struct nlmsghdr *nlh, void *data); +int cb_tcp_close_wait(const struct nlmsghdr *nlh, void *data); +int cb_tcp_close(const struct nlmsghdr *nlh, void *data); +int cb_tcp_destroy(const struct nlmsghdr *nlh, void *data); +void tcp_echo(const struct mnl_socket *nl, + const char *pre, const char *post); +int handle_qacb(const struct mnl_socket *nl, bool should_receive, + int(*cb)(const struct nlmsghdr *nlh, void *data), void *data); +struct mnl_socket *mnl_event_nssocket(const char *nsname); +void sync_fifo(const char *name); + + +#define MAX_CHILD 64 +pid_t children[MAX_CHILD]; /* kill if not 0 */ +int nchild; +void add_child(pid_t pid); + +/* tv_sec will update every cb */ +struct timeval timeout; + +#define parent_fail(msg) do { \ + int i; \ + fprintf(stderr, "parent fail - %s:%d %s() %s: %s\n", \ + __FILE__, __LINE__, __func__, (msg), strerror(errno)); \ + for (i = 0; i < nchild; i++) \ + if (children[i]) \ + kill(children[i], SIGKILL); \ + } while (0) + +#define child_exit(msg, code) \ + do { \ + if (code) \ + fprintf(stderr, "child exiting - %s:%d %s() %s: %s\n", \ + __FILE__, __LINE__, __func__, (msg), strerror(errno)); \ + _exit((code)); \ + } while (0) + +/* #define DEBUG_NS */ +#define DEBUG + +#ifdef DEBUG +#include +#define debug(...) do { fprintf(stderr, ##__VA_ARGS__); } while (0) +#else +#define debug(...) +#endif + +#ifdef DEBUG_NS +#include +#define debug_ns(...) do { fprintf(stderr, ##__VA_ARGS__); } while (0) +#else +#define debug_ns(...) +#endif + +#endif /* _QA_NSSOCKET_H_ */ diff --git a/tests/nssocket_env.sh b/tests/nssocket_env.sh new file mode 100644 index 0000000..1732eb1 --- /dev/null +++ b/tests/nssocket_env.sh @@ -0,0 +1,87 @@ +#!/bin/sh + +NETNS="lnfct_qa" +VETH_NAME="veth_qa0" +VETH_PEER="veth_qa1" +DUMMY_DEV="dummy_qa0" +VETH_PARENT_ADDR="10.255.255.249" +VETH_CHILD_ADDR="10.255.255.250" +VETH_MASK="30" +DSTPORT="7" +ICMP_TYPE="8" +ICMP_CODE="0" +NF_TIMEOUT=2 +INIT_TIMEOUT=8 + +dname=`dirname $0` +bname=`basename $0` +qname=${bname%.sh} + +PRE_FIFO="$dname/qa_pre_fifo" +POST_FIFO="$dname/qa_post_fifo" + +[ -z `which ip` ] && echo "ip(8) required" >&2 && exit 1 +[ -z `which inetd` ] && echo "inetd required" >&2 && exit 1 +[ -z `which nc` ] && echo "nc required" >&2 && exit 1 +[ -z `which iptables` ] && echo "iptables required" >&2 && exit 1 +modprobe nf_conntrack_ipv4 || exit 1 +modprobe nfnetlink_cttimeout || exit 1 + +make -C $dname \ + CFLAGS="-DVETH_PARENT_ADDR=\\\"$VETH_PARENT_ADDR\\\" \ + -DVETH_CHILD_ADDR=\\\"$VETH_CHILD_ADDR\\\" \ + -DDSTPORT=$DSTPORT -DICMP_TYPE=$ICMP_TYPE -DICMP_CODE=$ICMP_CODE \ + -DINIT_TIMEOUT=$INIT_TIMEOUT" \ + $qname || exit 1 + +# parent / client +ip netns add $NETNS +trap "ip netns del $NETNS; exit 1" 1 2 15 +ip link ls $VETH_NAME > /dev/null 2>&1 && ip link del $VETH_NAME +ip link add $VETH_NAME type veth peer name $VETH_PEER +ip link set $VETH_PEER netns $NETNS +ip link set $VETH_NAME up +ip addr add ${VETH_PARENT_ADDR}/${VETH_MASK} dev $VETH_NAME + +# child / server +ip netns exec $NETNS sh < /proc/sys/net/ipv4/ip_forward +for f in /proc/sys/net/netfilter/*timeout*; do echo $NF_TIMEOUT > "\$f"; done +ip link set lo up +ip link set $VETH_PEER up +ip addr add ${VETH_CHILD_ADDR}/${VETH_MASK} dev $VETH_PEER +ip link add ${DUMMY_DEV} up type dummy +ip route add default dev ${DUMMY_DEV} +EOF +ip netns exec $NETNS inetd -d $dname/inetd.conf > /dev/null 2>&1 & +server_pid=$! + +rm -f $PRE_FIFO $POST_FIFO +mkfifo $PRE_FIFO || exit 1 +mkfifo $POST_FIFO || exit 1 + +${dname}/${qname} $NETNS $PRE_FIFO $POST_FIFO & +qa_pid=$! + +trap_handle() { + rm -f $PRE_FIFO $POST_FIFO + kill $server_pid > /dev/null 2>&1 + kill -6 $qa_pid > /dev/null 2>&1 + ip netns del $NETNS > /dev/null 2>&1 +} +trap "trap_handle; exit 1" 1 2 15 + +fin() { + wait $qa_pid + trap_handle +} + +pre_sync() { + 8< $PRE_FIFO || kill $$ + 8>&- +} + +post_sync() { + 8< $POST_FIFO || kill $$ + 8>&- +} diff --git a/tests/qa-connlabel.conf b/tests/qa-connlabel.conf new file mode 100644 index 0000000..38c3115 --- /dev/null +++ b/tests/qa-connlabel.conf @@ -0,0 +1,11 @@ +0 zero +# duplicate names should be skipped +1 zero +1 test label 1 +1 zero +# .. so this should have added bit 1 as "test label 1" +2 test label 2 +# duplicate bit, should be skipped, too +2 duplicate +5 unused label +42 T diff --git a/tests/test_api.c b/tests/test_api.c new file mode 100644 index 0000000..57fdb90 --- /dev/null +++ b/tests/test_api.c @@ -0,0 +1,751 @@ +/* + * Run this after adding a new attribute to the nf_conntrack object + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * this file contains a test to check the set/get/copy/cmp APIs. + */ + +static void eval_sigterm(int status) +{ + switch(WTERMSIG(status)) { + case SIGSEGV: + printf("received SIGSEV\n"); + break; + case 0: + printf("OK\n"); + break; + default: + printf("exited with signal: %d\n", WTERMSIG(status)); + break; + } +} + +static void test_nfct_bitmask(void) +{ + struct nfct_bitmask *a, *b; + unsigned short int maxb, i; + struct nf_conntrack *ct1, *ct2; + + printf("== test nfct_bitmask_* API ==\n"); + + maxb = rand() & 0xffff; + + a = nfct_bitmask_new(maxb); + + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + nfct_bitmask_set_bit(a, maxb + 32); + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + + for (i = 0; i <= maxb; i++) + assert(!nfct_bitmask_test_bit(a, i)); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) { + assert(!nfct_bitmask_test_bit(a, i)); + continue; + } + nfct_bitmask_set_bit(a, i); + assert(nfct_bitmask_test_bit(a, i)); + } + + b = nfct_bitmask_clone(a); + assert(b); + + for (i = 0; i <= maxb; i++) { + if (nfct_bitmask_test_bit(a, i)) + assert(nfct_bitmask_test_bit(b, i)); + else + assert(!nfct_bitmask_test_bit(b, i)); + } + + nfct_bitmask_destroy(a); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) + continue; + nfct_bitmask_unset_bit(b, i); + assert(!nfct_bitmask_test_bit(b, i)); + } + + /* nfct_bitmask_clear() */ + for (i = 0; i < maxb; i++) { + nfct_bitmask_set_bit(b, i); + assert(nfct_bitmask_test_bit(b, i)); + nfct_bitmask_clear(b); + assert(!nfct_bitmask_test_bit(b, i)); + } + + for (i = 0; i < maxb; i++) + nfct_bitmask_set_bit(b, i); + nfct_bitmask_clear(b); + for (i = 0; i < maxb; i++) + assert(!nfct_bitmask_test_bit(b, i)); + + /* nfct_bitmask_equal() */ + for (i = 0; i < maxb / 32 * 32; i += 32) { + a = nfct_bitmask_new(i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_destroy(a); + } + + a = nfct_bitmask_clone(b); + assert(nfct_bitmask_equal(a, b)); + for (i = 0; i < maxb; i++) { + if (nfct_bitmask_test_bit(a, i)) { + nfct_bitmask_unset_bit(a, i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_set_bit(a, i); + } else { + nfct_bitmask_set_bit(a, i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_unset_bit(a, i); + } + assert(nfct_bitmask_equal(a, b)); + } + + nfct_bitmask_destroy(a); + nfct_bitmask_destroy(b); + + ct1 = nfct_new(); + ct2 = nfct_new(); + + maxb = rand() & 0xff; + maxb += 128; + maxb /= 2; + a = nfct_bitmask_new(maxb * 2); + b = nfct_bitmask_new(maxb); + nfct_set_attr(ct1, ATTR_CONNLABELS, a); + nfct_set_attr(ct2, ATTR_CONNLABELS, b); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + + nfct_bitmask_set_bit(a, maxb); + nfct_bitmask_set_bit(b, maxb); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + + nfct_bitmask_set_bit(a, maxb * 2); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 0); + nfct_destroy(ct1); + nfct_destroy(ct2); + printf("OK\n"); +} + +/* These attributes cannot be set, ignore them. */ +static int attr_is_readonly(int attr) +{ + switch (attr) { + case ATTR_ORIG_COUNTER_PACKETS: + case ATTR_REPL_COUNTER_PACKETS: + case ATTR_ORIG_COUNTER_BYTES: + case ATTR_REPL_COUNTER_BYTES: + case ATTR_USE: + case ATTR_SECCTX: + case ATTR_TIMESTAMP_START: + case ATTR_TIMESTAMP_STOP: + return 1; + } + return 0; +} + + +static int test_nfct_cmp_api_single(struct nf_conntrack *ct1, + struct nf_conntrack *ct2, int attr) +{ + char data[256]; + struct nfct_bitmask *b; + int bit; + + if (attr_is_readonly(attr)) + return 0; + + switch (attr) { + case ATTR_SECMARK: /* obsolete */ + return 0; + + /* FIXME: not implemented comparators: */ + case ATTR_SNAT_IPV4: + case ATTR_DNAT_IPV4: + case ATTR_SNAT_IPV6: + case ATTR_DNAT_IPV6: + case ATTR_SNAT_PORT: + case ATTR_DNAT_PORT: + + case ATTR_TCP_FLAGS_ORIG: + case ATTR_TCP_FLAGS_REPL: + case ATTR_TCP_MASK_ORIG: + case ATTR_TCP_MASK_REPL: + + case ATTR_MASTER_IPV4_SRC: + case ATTR_MASTER_IPV4_DST: + case ATTR_MASTER_IPV6_SRC: + case ATTR_MASTER_IPV6_DST: + case ATTR_MASTER_PORT_SRC: + case ATTR_MASTER_PORT_DST: + case ATTR_MASTER_L3PROTO: + case ATTR_MASTER_L4PROTO: + + case ATTR_ORIG_NAT_SEQ_CORRECTION_POS: + case ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE: + case ATTR_ORIG_NAT_SEQ_OFFSET_AFTER: + case ATTR_REPL_NAT_SEQ_CORRECTION_POS: + case ATTR_REPL_NAT_SEQ_OFFSET_BEFORE: + case ATTR_REPL_NAT_SEQ_OFFSET_AFTER: + + case ATTR_SCTP_VTAG_ORIG: + case ATTR_SCTP_VTAG_REPL: + + case ATTR_HELPER_NAME: + + case ATTR_DCCP_ROLE: + case ATTR_DCCP_HANDSHAKE_SEQ: + + case ATTR_TCP_WSCALE_ORIG: + case ATTR_TCP_WSCALE_REPL: + + case ATTR_SYNPROXY_ISN: + case ATTR_SYNPROXY_ITS: + case ATTR_SYNPROXY_TSOFF: + + case ATTR_HELPER_INFO: + return 0; /* XXX */ + + default: + break; + } + + if (attr >= ATTR_SCTP_STATE) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_SCTP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_SCTP); + } else if (attr >= ATTR_TCP_FLAGS_ORIG) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); + } else if (attr >= ATTR_ICMP_CODE) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_ICMP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_ICMP); + } else if (attr >= ATTR_ORIG_PORT_SRC) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); + } + + nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); + memset(data, 42, sizeof(data)); + + assert(nfct_attr_is_set(ct1, attr)); + assert(nfct_attr_is_set(ct2, attr)); + + switch (attr) { + case ATTR_CONNLABELS: + case ATTR_CONNLABELS_MASK: + b = (void *) nfct_get_attr(ct1, attr); + assert(b); + b = nfct_bitmask_clone(b); + assert(b); + bit = nfct_bitmask_maxbit(b); + if (nfct_bitmask_test_bit(b, bit)) { + nfct_bitmask_unset_bit(b, bit); + assert(!nfct_bitmask_test_bit(b, bit)); + } else { + nfct_bitmask_set_bit(b, bit); + assert(nfct_bitmask_test_bit(b, bit)); + } + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + nfct_set_attr(ct2, attr, b); + break; + case ATTR_HELPER_INFO: + nfct_set_attr_l(ct2, attr, "test", 4); + break; + default: + nfct_set_attr(ct2, attr, data); + break; + } + + if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL) != 0) { + fprintf(stderr, "nfct_cmp assert failure for attr %d\n", attr); + fprintf(stderr, "%p, %p, %x, %x\n", nfct_get_attr(ct1, attr), + nfct_get_attr(ct2, attr), + nfct_get_attr_u32(ct1, attr), nfct_get_attr_u32(ct2, attr)); + return -1; + } + if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) != 0) { + fprintf(stderr, "nfct_cmp strict assert failure for attr %d\n", attr); + return -1; + } + return 0; +} + +static int test_cmp_attr32(int attr, bool at1, bool at2, + uint32_t v1, uint32_t v2, unsigned int flags) +{ + struct nf_conntrack *ct1 = nfct_new(); + struct nf_conntrack *ct2 = nfct_new(); + int ret; + + if (at1) + nfct_set_attr_u32(ct1, attr, v1); + if (at2) + nfct_set_attr_u32(ct2, attr, v2); + + ret = nfct_cmp(ct1, ct2, NFCT_CMP_ALL | flags); + + nfct_destroy(ct1); + nfct_destroy(ct2); + + return ret; +} + +static void test_nfct_cmp_attr(int attr) +{ + unsigned int flags = 0; + + /* 0000, 1000, 1100, 0010, 1010... */ + /* attr at1 at2 v1 v2 */ + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_STRICT; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_MASK; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_STRICT|NFCT_CMP_MASK; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); +} + +static void test_nfct_cmp_api(struct nf_conntrack *ct1, struct nf_conntrack *ct2) +{ + int i; + + printf("== test cmp API ==\n"); + + test_nfct_cmp_attr(ATTR_ZONE); + test_nfct_cmp_attr(ATTR_ORIG_ZONE); + test_nfct_cmp_attr(ATTR_REPL_ZONE); + test_nfct_cmp_attr(ATTR_MARK); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + + nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); + + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct1, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); + } + nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct2, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 0); + } + + for (i=0; i < ATTR_MAX ; i++) + assert(test_nfct_cmp_api_single(ct1, ct2, i) == 0); + + nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct1, i); + nfct_attr_unset(ct2, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); + } + nfct_destroy(ct1); + nfct_destroy(ct2); +} + +static void test_nfexp_cmp_api(struct nf_expect *ex1, struct nf_expect *ex2) +{ + int i; + + printf("== test expect cmp API ==\n"); + + /* XXX: missing nfexp_copy API. */ + memcpy(ex1, ex2, nfexp_maxsize()); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); + + assert(nfexp_attr_is_set(ex1, 0) == 1); + nfexp_attr_unset(ex1, 0); + assert(nfexp_attr_is_set(ex1, 0) == 0); + + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex1, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 0); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); + } + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex2, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 0); + } + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex1, i); + nfexp_attr_unset(ex2, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); + } + nfexp_destroy(ex1); + nfexp_destroy(ex2); +} + +int main(void) +{ + int ret, i; + struct nf_conntrack *ct, *ct2, *tmp; + struct nf_expect *exp, *tmp_exp; + char data[256]; + const char *val; + int status; + struct nfct_bitmask *b, *b2; + + srand(time(NULL)); + + /* initialize fake data for testing purposes */ + for (i=0; i +#include +#include +#include + +#include +#include + +static void print_label(struct nfct_labelmap *map) +{ + int b = nfct_labelmap_get_bit(map, "test label 1"); + assert(b == 1); + + b = nfct_labelmap_get_bit(map, "zero"); + assert(b == 0); + + b = nfct_labelmap_get_bit(map, "test label 2"); + assert(b == 2); + + b = nfct_labelmap_get_bit(map, "duplicate"); + assert(b < 0); + + b = nfct_labelmap_get_bit(map, "invalid label"); + assert(b < 0); + + b = nfct_labelmap_get_bit(map, "T"); + assert(b == 42); +} + +static void dump_map(struct nfct_labelmap *map) +{ + unsigned int i = 0; + + for (;;) { + const char *name = nfct_labelmap_get_name(map, i); + if (!name) + break; + if (name[0]) + printf("\t\"%s\", bit %d\n", name, i); + i++; + } +} + +int main(void) +{ + struct nfct_labelmap *l; + + l = nfct_labelmap_new("/"); + assert(l == NULL); + + l = nfct_labelmap_new(NULL); + if (l) { + puts("default connlabel.conf:"); + dump_map(l); + nfct_labelmap_destroy(l); + } else { + puts("no default config found"); + } + + l = nfct_labelmap_new("qa-connlabel.conf"); + if (!l) + l = nfct_labelmap_new("tests/qa-connlabel.conf"); + assert(l); + puts("qa-connlabel.conf:"); + dump_map(l); + print_label(l); + nfct_labelmap_destroy(l); + + return 0; +} diff --git a/tests/test_filter.c b/tests/test_filter.c new file mode 100644 index 0000000..7877819 --- /dev/null +++ b/tests/test_filter.c @@ -0,0 +1,79 @@ +/* + * Test for the filter API + */ + +#include +#include +#include +#include +#include + +#include + +static int event_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + static int n = 0; + char buf[1024]; + + nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_PLAIN, NFCT_OF_TIME); + printf("%s\n", buf); + + if (++n == 10) + return NFCT_CB_STOP; + + return NFCT_CB_CONTINUE; +} + +int main(void) +{ + int i, ret; + struct nfct_handle *h; + struct nfct_filter *filter; + + h = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE); + if (!h) { + perror("nfct_open"); + return 0; + } + + filter = nfct_filter_create(); + if (!filter) { + perror("nfct_create_filter"); + return 0; + } + + if (nfct_filter_attach(nfct_fd(h), filter) == -1) { + perror("nfct_filter_attach"); + return 0; + } + + /* protocol 255 is skipped since we support up to 255 protocols max */ + for (i=0; i