diff options
Diffstat (limited to 'netfilter/nl.c')
-rw-r--r-- | netfilter/nl.c | 193 |
1 files changed, 193 insertions, 0 deletions
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 <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <linux/netlink.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <getopt.h> +#include <ctype.h> +#include <fcntl.h> +#include <poll.h> +#include <errno.h> + +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; +} + |