From f9c1d809cd9b78e6edeb4b2832deeb09b0f101ce Mon Sep 17 00:00:00 2001 From: dmitry pervushin Date: Mon, 22 Apr 2013 20:58:38 +0200 Subject: netfilter: idletimer testing --- netfilter/Android.mk | 21 +++++ netfilter/ipt-idletimer.sh | 144 +++++++++++++++++++++++++++++++++ netfilter/nl.c | 193 +++++++++++++++++++++++++++++++++++++++++++++ product.mk | 4 +- 4 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 netfilter/Android.mk create mode 100644 netfilter/ipt-idletimer.sh create mode 100644 netfilter/nl.c diff --git a/netfilter/Android.mk b/netfilter/Android.mk new file mode 100644 index 0000000..1906e7b --- /dev/null +++ b/netfilter/Android.mk @@ -0,0 +1,21 @@ + +############################################################################# +# Copyright (c) 2013 Linaro +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Linaro +############################################################################# + + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := nl.c +LOCAL_MODULE := nl-listener +LOCAL_MODULE_TAGS := optional tests + +include $(BUILD_EXECUTABLE) diff --git a/netfilter/ipt-idletimer.sh b/netfilter/ipt-idletimer.sh new file mode 100644 index 0000000..fdc70bb --- /dev/null +++ b/netfilter/ipt-idletimer.sh @@ -0,0 +1,144 @@ +#!/system/bin/sh + +mount -o rw,remount / +mkdir -p /tmp + +IFACE=lo +T=5 +LABEL=sample +NLLOG=/tmp/nl.$$.log +NLEXE=/system/bin/nl-listener + +function init_modules() { + PWD=`pwd` + cd /system/modules + insmod x_tables.ko + insmod ip_tables.ko + insmod iptable_filter.ko + insmod iptable_raw.ko + insmod xt_IDLETIMER.ko + cd $PWD +} + +function init_iptables() { + iptables -F + iptables -t raw -F idletimer_PREROUTING + iptables -t raw -N idletimer_PREROUTING + iptables -t raw -D PREROUTING -j idletimer_PREROUTING + iptables -t raw -I PREROUTING -j idletimer_PREROUTING +} + +function fail() { + rc=$1 + shift + echo "FAIL: $*" + return $rc +} + +function pass() { + echo "PASS: $*" + return 0 +} + +function note() { + echo "NOTE: $*" + return 0 +} + +function iptables_set() { + iptables -t raw -F + iptables -t raw -N idletimer_PREROUTING + iptables -t raw -A idletimer_PREROUTING -i $1 -j IDLETIMER --timeout $2 --label $3 $4 + rc=$? + note "iptables_set: exit code $rc" + return $rc +} + +function test_5() { + + A="Xyz -1 17" # each value is incorrect + + for a in $A; do + iptables_set $IFACE $T $LABEL "--send_nl_msg $a" + rc=$? + if [ $rc -eq 0 ]; then + fail $rc "iptables should fail on --send_nl_msg $a" + return $? + fi + done + pass $1 +} + +function test_1_2() { + # + # The idea of test is: + # 1. flush iptables rules + # 2. set rule to fire IDLETIMER after T seconds (with additional parameter, probably) + # 3. start listener with timeout of T+2 seconds + # 3a. do nothing for T seconds... DONE! + # 4. verify that: + # a. listener caught the event + # b. listener printed it with "OK" -- event was correct + # c. time between end and start of listener is no greater than T + # 5. print the log, just for reference + # + + iptables_set $IFACE $T $LABEL "$2" + rc=$? + if [ $rc -ne 0 ]; then + fail $rc "iptables failed" + return $? + fi + + note "Waiting for event..." + + T1=`date +%s` + $NLEXE "$3" --timeout $(($T+2)) > $NLLOG + rc=$? + T2=`date +%s` + if [ $rc -ne 0 ]; then + # + # for example, timeout + # + fail $rc "nl-listener failed" + return $? + fi + if [ `grep "^OK" $NLLOG | wc -l` -ne "1" ]; then + # + # No OK in the log? Fail! + # + fail -1 "No 'OK' in nl-listener output" + return $? + fi + if [ $(($T2-$T1)) -lt $(($T-1)) ]; then + # + # nl-listener garantees us that it will wait no longer than T+2 + # now, check that delay was no shorter than T-1 + # + fail -1 "Too short delay! $(($T2-$T1)) instead of $T" + return $rc + fi + note "nl-listener log is below" + echo "---===== listener log =====---" + cat $NLLOG + echo "---=====++++++++++++++=====---" + pass "$1" + return 0 +} + +note "Starting tests" + +init_modules +init_iptables + +echo -e "\nTest 1: verify sysfs events" +test_1_2 "Test 1" "" "--sysfs=$LABEL" +echo -e "\nTest 2: verify netlink events" +test_1_2 "Test 2" "--send_nl_msg 1" "--netlink" +echo -e "\nTest 3: verify sysfs events even in case of --send-nl-msg 1" +test_1_2 "Test 3" "--send_nl_msg 1" "--sysfs=$LABEL" +echo -e "\nTest 4: verify sysfs events in case of --send_nl_msg 0" +test_1_2 "Test 4" "--send_nl_msg 0" "--sysfs=$LABEL" +echo -e "\nTest 5: verify parameters of send-nl-msg" +test_5 "Test 5" +exit 0 diff --git a/netfilter/nl.c b/netfilter/nl.c new file mode 100644 index 0000000..ca71ca0 --- /dev/null +++ b/netfilter/nl.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum type_t { + TYPE_SYSFS, + TYPE_NETLINK, +}; + +int dump(void *_a, size_t s) +{ + size_t i, j; + unsigned char *p = _a; + + for (i = 0; i < s; i += 16) { + for (j = 0; j < 16; j ++ ) { + if (j == 8) + printf(" - "); + if (i + j > s) { + printf(" "); + } else { + printf("%c", (isprint(p[i+j])) ? p[i+j] : '.'); + } + } + printf(" "); + for (j = 0; j < 16; j ++ ) { + if (j == 8) + printf(" - "); + printf("%02X ", p[i+j]); + } + printf("\n"); + } + return 0; +} + +int sysfs_handle_open(char *name) +{ + char sysfs[256] = "/sys/devices/virtual/xt_idletimer/timers/"; + char buffer[256]; + int r, rd; + + strcat(sysfs, name); + r = open(sysfs, O_RDONLY); + if (r < 0) + return r; + rd = read(r, buffer, sizeof(buffer)); + return r; +} + +#define sysfs_handle_close(h) close(h) + +int netlink_socket_open(struct sockaddr_nl *s_nladdr) +{ + int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + bind(fd, (struct sockaddr*)s_nladdr, sizeof(*s_nladdr)); + return fd; +} + +#define netlink_socket_close(h) close(h) + +int do_wait(char *nick, enum type_t type, int seconds) +{ + struct pollfd pfd; + int r; + short exp; + struct sockaddr_nl s_nladdr; + static char buffer[256]; + char *ptr; + + pfd.revents = 0; + + if (type == TYPE_SYSFS) { + + pfd.fd = sysfs_handle_open(nick); + pfd.events = POLLPRI | POLLERR; + exp = POLLPRI | POLLERR; + + } + + if (type == TYPE_NETLINK) { + + memset(&s_nladdr, 0 ,sizeof(s_nladdr)); + s_nladdr.nl_family = AF_NETLINK ; + s_nladdr.nl_pid = getpid(); + s_nladdr.nl_groups = 0xffffffff; + + pfd.fd = netlink_socket_open(&s_nladdr); + pfd.events = POLLIN; + exp = POLLIN; + } + + r = poll(&pfd, 1, seconds * 1000); + if (r <= 0) + return r; + + if (type == TYPE_NETLINK) { + struct msghdr msg; + struct iovec iov[2]; + struct nlmsghdr nlh; + + iov[0].iov_base = (void *)&nlh; + iov[0].iov_len = sizeof(nlh); + iov[1].iov_base = (void *)buffer; + iov[1].iov_len = sizeof(buffer); + msg.msg_name = &s_nladdr; + msg.msg_namelen = sizeof(s_nladdr); + msg.msg_iov = iov; + msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]); + memset(buffer, 0, sizeof(buffer)); + + r = recvmsg(pfd.fd, &msg, 0); + } else { + lseek(pfd.fd, 0, SEEK_SET); + r = read(pfd.fd, buffer, sizeof(buffer)); + } + if (r < 0) + return r; + + for (ptr = buffer; ptr - buffer < r; ptr = ptr + strlen(ptr) + 1) { + if (strlen(ptr) == 0) + continue; + printf("%s\n", ptr); + } + return 1; +} + + +int main(int argc, char *argv[]) +{ + int c, r, opti; + int timeout_sec = 10; + struct option lopt[] = { + { "timeout", required_argument, NULL, 't' }, + { "sysfs", required_argument, NULL, 's' }, + { "netlink", no_argument, NULL, 'n' }, + { NULL, 0, NULL, 0 }, + }; + char *shopt = "ts:n"; + char *nick = NULL; + enum type_t type; + + while ((c = getopt_long(argc, argv, shopt, lopt, &opti)) != -1 ) { + switch (c) { + case 't': + timeout_sec = atoi(optarg); + break; + case 's': + case 'n': + if (!nick) { + if (optarg) { + nick = strdup(optarg); + } else { + nick = (char*)0xffffffff; + } + type = (c == 's' ? TYPE_SYSFS : TYPE_NETLINK); + } else { + printf("sysfs and netlink could not be used at the same time\n"); + exit(1); + } + break; + default: + printf("Hmmm, c = 0x%x (%c)\n", c, isprint(c) ? c : '*'); + break; + } + } + if (!nick) { + printf("Sorry, you have to provide one of --sysfs=ARG or --netlink\n"); + return EINVAL; + } + + r = do_wait(nick, type, timeout_sec); + if (r < 0) { + perror("do_wait"); + return r; + } + else if (r == 0) { + printf("No data within %d seconds\n", timeout_sec); + return 1; + } + printf("OK\n"); + return 0; +} + diff --git a/product.mk b/product.mk index 35fcbf0..9867f2f 100644 --- a/product.mk +++ b/product.mk @@ -14,9 +14,11 @@ PRODUCT_PACKAGES += alarm-dev-test \ ashmemtest \ ashmemtest-expanded \ loggerdevtest \ - sync-basic + sync-basic \ + nl-listener PRODUCT_COPY_FILES += external/linaro-android-kernel-test/binder/bindertest.sh:system/bin/bindertest.sh PRODUCT_COPY_FILES += external/linaro-android-kernel-test/linaro-android-kernel-tests.sh:system/bin/linaro-android-kernel-tests.sh +PRODUCT_COPY_FILES += external/linaro-android-kernel-test/netfilter/ipt-idletimer.sh:system/bin/ipt-idletimer.sh # put expanded ashmemtest in/out files on the device filesystem PRODUCT_COPY_FILES += \ -- cgit v1.2.3