From fdfa72276a16d0bd42b795aef3ac6c8969210469 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Tue, 23 Sep 2014 00:14:04 +0000 Subject: [PATCH] tests: add a test for -yy option * tests/net-yy.test: New test. * tests/inet-accept-connect-send-recv.c: New file. * tests/netlink_inet_diag.c: Likewise. * tests/net-yy-accept.awk: Likewise. * tests/net-yy-connect.awk: Likewise. * tests/.gitignore: Add inet-accept-connect-send-recv, netlink_inet_diag, *.tmp-*, and *.tmp.*. * tests/Makefile.am (check_PROGRAMS): Add inet-accept-connect-send-recv and netlink_inet_diag. (TESTS): Add net-yy.test. (EXTRA_DIST): Add net-yy-accept.awk and net-yy-connect.awk. --- tests/.gitignore | 6 +- tests/Makefile.am | 10 ++- tests/inet-accept-connect-send-recv.c | 53 +++++++++++++++ tests/net-yy-accept.awk | 76 +++++++++++++++++++++ tests/net-yy-connect.awk | 55 +++++++++++++++ tests/net-yy.test | 59 ++++++++++++++++ tests/netlink_inet_diag.c | 96 +++++++++++++++++++++++++++ 7 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 tests/inet-accept-connect-send-recv.c create mode 100644 tests/net-yy-accept.awk create mode 100644 tests/net-yy-connect.awk create mode 100755 tests/net-yy.test create mode 100644 tests/netlink_inet_diag.c diff --git a/tests/.gitignore b/tests/.gitignore index cf7aaf0d..dc408c9a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1,6 @@ +inet-accept-connect-send-recv net-accept-connect +netlink_inet_diag scm_rights set_ptracer_any sigaction @@ -8,5 +10,7 @@ uio *.log *.log.* *.o -*.trs *.tmp +*.tmp-* +*.tmp.* +*.trs diff --git a/tests/Makefile.am b/tests/Makefile.am index 3b97b2cd..541a0c46 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,7 +3,9 @@ AM_CFLAGS = $(WARN_CFLAGS) check_PROGRAMS = \ + inet-accept-connect-send-recv \ net-accept-connect \ + netlink_inet_diag \ scm_rights \ set_ptracer_any \ sigaction \ @@ -27,6 +29,7 @@ TESTS = \ statfs.test \ net.test \ net-fd.test \ + net-yy.test \ uio.test \ count.test \ detach-sleeping.test \ @@ -38,6 +41,11 @@ net-fd.log: net.log TEST_LOG_COMPILER = $(srcdir)/run.sh -EXTRA_DIST = init.sh run.sh getdents.awk sigaction.awk $(TESTS) +EXTRA_DIST = init.sh run.sh \ + getdents.awk \ + net-yy-accept.awk \ + net-yy-connect.awk \ + sigaction.awk \ + $(TESTS) CLEANFILES = $(TESTS:=.tmp) diff --git a/tests/inet-accept-connect-send-recv.c b/tests/inet-accept-connect-send-recv.c new file mode 100644 index 00000000..38376aed --- /dev/null +++ b/tests/inet-accept-connect-send-recv.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + static const char data[] = "data"; + const size_t size = sizeof(data) - 1; + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + pid_t pid; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + close(0); + close(1); + + assert(socket(PF_INET, SOCK_STREAM, 0) == 0); + assert(bind(0, (struct sockaddr *) &addr, len) == 0); + assert(listen(0, 5) == 0); + + memset(&addr, 0, sizeof(addr)); + assert(getsockname(0, (struct sockaddr *) &addr, &len) == 0); + + assert((pid = fork()) >= 0); + + if (pid) { + char buf[sizeof(data)]; + int status; + + assert(accept(0, (struct sockaddr *) &addr, &len) == 1); + assert(close(0) == 0); + assert(recv(1, buf, sizeof(buf), MSG_WAITALL) == (int) size); + assert(waitpid(pid, &status, 0) == pid); + assert(status == 0); + assert(close(1) == 0); + } else { + assert(close(0) == 0); + assert(socket(PF_INET, SOCK_STREAM, 0) == 0); + assert(connect(0, (struct sockaddr *) &addr, len) == 0); + assert(send(0, data, size, MSG_DONTROUTE) == (int) size); + assert(close(0) == 0); + } + + return 0; +} diff --git a/tests/net-yy-accept.awk b/tests/net-yy-accept.awk new file mode 100644 index 00000000..3ea4afe1 --- /dev/null +++ b/tests/net-yy-accept.awk @@ -0,0 +1,76 @@ +BEGIN { + lines = 9 + fail = 0 + + inode = "?" + port_l = "?" + port_r = "?" + + r_i = "[1-9][0-9]*" + r_port = "[1-9][0-9][0-9][0-9]+" + r_localhost = "127\\.0\\.0\\.1" + r_bind = "^bind\\(0, {sa_family=AF_INET, sin_port=htons\\(0\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i "\\) += 0$" + r_listen = "^/$" + r_getsockname = "^getsockname\\(0<" r_localhost ":(" r_port ")>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, \\[" r_i "\\]\\) += 0$" + r_accept = "^/$" + r_close0 = "^/$" + r_recv = "^/$" + r_recvfrom = "^/$" + r_close1 = "^/$" +} + +NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next} + +NR == 2 { + if (match($0, r_bind, a)) { + inode = a[1] + r_listen = "^listen\\(0, 5\\) += 0$" + next + } +} + +NR == 3 {if (match($0, r_listen)) next} + +NR == 4 { + if (match($0, r_getsockname, a) && a[1] == a[2]) { + port_l = a[1] + r_accept = "^accept\\(0<" r_localhost ":" port_l ">, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, \\[" r_i "\\]\\) += 1<" r_localhost ":" port_l "->" r_localhost ":(" r_port ")>$" + r_close0 = "^close\\(0<" r_localhost ":" port_l ">) += 0$" + next + } +} + +NR == 5 { + if (match($0, r_accept, a) && a[1] == a[2]) { + port_r = a[1] + r_recv = "^recv\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">, \"data\", 5, MSG_WAITALL\\) += 4$" + r_recvfrom = "^recvfrom\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">, \"data\", 5, MSG_WAITALL, NULL, NULL\\) += 4$" + r_close1 = "^close\\(1<" r_localhost ":" port_l "->" r_localhost ":" port_r ">) += 0$" + next + } +} + +NR == 6 {if (match($0, r_close0)) next} + +NR == 7 {if (match($0, r_recv) || match($0, r_recvfrom)) next} + +NR == 8 {if (match($0, r_close1)) next} + +NR == lines && /^\+\+\+ exited with 0 \+\+\+$/ {next} + +{ + print "Line " NR " does not match: " $0 + fail=1 +} + +END { + if (NR != lines) { + print "Expected " lines " lines, found " NR " line(s)." + print "" + exit 1 + } + if (fail) { + print "" + exit 1 + } +} diff --git a/tests/net-yy-connect.awk b/tests/net-yy-connect.awk new file mode 100644 index 00000000..18c1a28d --- /dev/null +++ b/tests/net-yy-connect.awk @@ -0,0 +1,55 @@ +BEGIN { + lines = 5 + fail = 0 + + port_l = "?" + port_r = "?" + + r_i = "[1-9][0-9]*" + r_port = "[1-9][0-9][0-9][0-9]+" + r_localhost = "127\\.0\\.0\\.1" + r_connect = "^connect\\(0, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i ") += 0$" + r_send = "^/$" + r_sendto = "^/$" + r_close = "^/$" +} + +NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next} + +NR == 2 { + if (match($0, r_connect, a)) { + port_r = a[1] + r_send = "^send\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE\\) += 4$" + r_sendto = "^sendto\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE, NULL, 0\\) += 4$" + next + } +} + +NR == 3 { + if (match($0, r_send, a) || match($0, r_sendto, a)) { + port_l = a[1] + r_close = "^close\\(0<" r_localhost ":" port_l "->" r_localhost ":" port_r ">\\) += 0$" + next + } +} + +NR == 4 {if (match($0, r_close)) next} + +NR == lines && /^\+\+\+ exited with 0 \+\+\+$/ {next} + +{ + print "Line " NR " does not match: " $0 + fail=1 +} + +END { + if (NR != lines) { + print "Expected " lines " lines, found " NR " line(s)." + print "" + exit 1 + } + if (fail) { + print "" + exit 1 + } +} diff --git a/tests/net-yy.test b/tests/net-yy.test new file mode 100755 index 00000000..8b6c0982 --- /dev/null +++ b/tests/net-yy.test @@ -0,0 +1,59 @@ +#!/bin/sh + +# Check decoding of ip:port pairs associated with socket descriptors + +. "${srcdir=.}/init.sh" + +# strace -yy is implemented using /proc/self/fd +[ -d /proc/self/fd/ ] || + framework_skip_ '/proc/self/fd/ is not available' + +check_prog sed +check_prog awk + +rm -f $LOG.* $LOG-* + +./inet-accept-connect-send-recv || + fail_ 'inet-accept-connect-send-recv failed' + +./netlink_inet_diag || { + if [ $? -eq 77 ]; then + framework_skip_ 'NETLINK_INET_DIAG is not available' + else + fail_ 'netlink_inet_diag failed' + fi +} + +args="-tt -ff -yy -o $LOG -eclose,network ./inet-accept-connect-send-recv" +$STRACE $args || + fail_ "strace $args failed" + +"$srcdir"/../strace-log-merge $LOG > $LOG || { + cat $LOG + fail_ 'strace-log-merge failed' +} +rm -f $LOG.* + +child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' $LOG)" +[ -n "$child" ] || { + cat $LOG + fail_ 'failed to find pid of child process' +} + +sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-connect && +sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-accept || { + cat $LOG + fail_ 'failed to separate logs' +} + +awk -f "$srcdir"/net-yy-connect.awk $LOG-connect || { + cat $LOG-connect + fail_ "strace $args failed to decode socket descriptors properly" +} + +awk -f "$srcdir"/net-yy-accept.awk $LOG-accept || { + cat $LOG-accept + fail_ "strace $args failed to decode socket descriptors properly" +} + +exit 0 diff --git a/tests/netlink_inet_diag.c b/tests/netlink_inet_diag.c new file mode 100644 index 00000000..ffd3591a --- /dev/null +++ b/tests/netlink_inet_diag.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include + +static int +send_query(const int fd, const int family, const int proto) +{ + struct sockaddr_nl nladdr; + struct { + struct nlmsghdr nlh; + struct inet_diag_req_v2 idr; + } req; + struct iovec iov = { + .iov_base = &req, + .iov_len = sizeof(req) + }; + struct msghdr msg = { + .msg_name = (void*)&nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1 + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; + req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + req.idr.sdiag_family = family; + req.idr.sdiag_protocol = proto; + req.idr.idiag_states = -1; + + return sendmsg(fd, &msg, 0) > 0; +} + +static int +check_responses(const int fd) +{ + static char buf[8192]; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf) + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + struct msghdr msg = { + .msg_name = (void*)&nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0 + }; + + ssize_t ret = recvmsg(fd, &msg, 0); + if (ret <= 0) + return 0; + + struct nlmsghdr *h = (struct nlmsghdr*)buf; + return (NLMSG_OK(h, ret) && + h->nlmsg_type != NLMSG_ERROR && + h->nlmsg_type != NLMSG_DONE) ? 1 : 0; +} + +int main(void) +{ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + close(0); + close(1); + + assert(socket(PF_INET, SOCK_STREAM, 0) == 0); + assert(bind(0, (struct sockaddr *) &addr, len) == 0); + assert(listen(0, 5) == 0); + + if (socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG) != 1) + return 77; + + return (send_query(1, AF_INET, IPPROTO_TCP) && + check_responses(1)) ? 0 : 77; +} -- 2.40.0