diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-10 10:15:09 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-26 15:29:19 +0200 |
commit | d2e942c76f87ea061d5e8643007f1d4c3ed39694 (patch) | |
tree | 0c607e76d0f6e025a2c4de9580eb927628676c88 /src | |
parent | 867b5b6496a3296078146ba3d06616eda3b0717e (diff) | |
download | conntrack-tools-d2e942c76f87ea061d5e8643007f1d4c3ed39694.tar.gz conntrack-tools-d2e942c76f87ea061d5e8643007f1d4c3ed39694.zip |
src: integrate nfct into the conntrack-tools tree
I'll need for the upcoming cthelper infrastructure. Moreover, we avoid
more fragmentation in the netfilter user-space utilities. And the plan
is that `nfct' will replace `conntrack' at some point.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/nfct-extensions/timeout.c | 486 | ||||
-rw-r--r-- | src/nfct.c | 116 |
3 files changed, 609 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7d7b2ac..5dbdef3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,11 +4,17 @@ AM_YFLAGS = -d CLEANFILES = read_config_yy.c read_config_lex.c -sbin_PROGRAMS = conntrack conntrackd +sbin_PROGRAMS = conntrack conntrackd nfct conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la ${LIBNETFILTER_CONNTRACK_LIBS} +nfct_SOURCES = nfct.c \ + nfct-extensions/timeout.c +nfct_LDADD = ${LIBMNL_LIBS} \ + ${LIBNETFILTER_CONNTRACK_LIBS} \ + ${LIBNETFILTER_CTTIMEOUT_LIBS} + conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ diff --git a/src/nfct-extensions/timeout.c b/src/nfct-extensions/timeout.c new file mode 100644 index 0000000..a69537d --- /dev/null +++ b/src/nfct-extensions/timeout.c @@ -0,0 +1,486 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <netinet/in.h> +#include <errno.h> + +#include <libmnl/libmnl.h> +#include <linux/netfilter/nfnetlink_cttimeout.h> +#include <libnetfilter_cttimeout/libnetfilter_cttimeout.h> + +#include "nfct.h" + +static void +nfct_cmd_timeout_usage(char *argv[]) +{ + fprintf(stderr, "nfct v%s: Missing command\n" + "%s timeout list|add|delete|get|flush " + "[parameters...]\n", VERSION, argv[0]); +} + +int nfct_cmd_timeout_parse_params(int argc, char *argv[]) +{ + int cmd = NFCT_CMD_NONE, ret = 0; + + if (argc < 3) { + nfct_cmd_timeout_usage(argv); + return -1; + } + if (strncmp(argv[2], "list", strlen(argv[2])) == 0) + cmd = NFCT_CMD_LIST; + else if (strncmp(argv[2], "add", strlen(argv[2])) == 0) + cmd = NFCT_CMD_ADD; + else if (strncmp(argv[2], "delete", strlen(argv[2])) == 0) + cmd = NFCT_CMD_DELETE; + else if (strncmp(argv[2], "get", strlen(argv[2])) == 0) + cmd = NFCT_CMD_GET; + else if (strncmp(argv[2], "flush", strlen(argv[2])) == 0) + cmd = NFCT_CMD_FLUSH; + else { + fprintf(stderr, "nfct v%s: Unknown command: %s\n", + VERSION, argv[2]); + nfct_cmd_timeout_usage(argv); + return -1; + } + switch(cmd) { + case NFCT_CMD_LIST: + ret = nfct_cmd_timeout_list(argc, argv); + break; + case NFCT_CMD_ADD: + ret = nfct_cmd_timeout_add(argc, argv); + break; + case NFCT_CMD_DELETE: + ret = nfct_cmd_timeout_delete(argc, argv); + break; + case NFCT_CMD_GET: + ret = nfct_cmd_timeout_get(argc, argv); + break; + case NFCT_CMD_FLUSH: + ret = nfct_cmd_timeout_flush(argc, argv); + break; + } + + return 0; +} + +static int nfct_timeout_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nfct_timeout *t; + char buf[4096]; + + t = nfct_timeout_alloc(); + if (t == NULL) { + nfct_perror("OOM"); + goto err; + } + + if (nfct_timeout_nlmsg_parse_payload(nlh, t) < 0) { + nfct_perror("nfct_timeout_nlmsg_parse_payload"); + goto err_free; + } + + nfct_timeout_snprintf(buf, sizeof(buf), t, 0); + printf("%s\n", buf); + +err_free: + nfct_timeout_free(t); +err: + return MNL_CB_OK; +} + +int nfct_cmd_timeout_list(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + unsigned int seq, portid; + int ret; + + if (argc > 3) { + nfct_perror("too many arguments"); + return -1; + } + + seq = time(NULL); + nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_GET, + NLM_F_DUMP, seq); + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + nfct_perror("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + nfct_perror("mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + nfct_perror("mnl_socket_send"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + nfct_perror("error"); + return -1; + } + mnl_socket_close(nl); + + return 0; +} + +static uint32_t nfct_timeout_attr_max[IPPROTO_MAX] = { + [IPPROTO_ICMP] = NFCT_TIMEOUT_ATTR_ICMP_MAX, + [IPPROTO_TCP] = NFCT_TIMEOUT_ATTR_TCP_MAX, + [IPPROTO_UDP] = NFCT_TIMEOUT_ATTR_UDP_MAX, + [IPPROTO_UDPLITE] = NFCT_TIMEOUT_ATTR_UDPLITE_MAX, + [IPPROTO_SCTP] = NFCT_TIMEOUT_ATTR_SCTP_MAX, + [IPPROTO_DCCP] = NFCT_TIMEOUT_ATTR_DCCP_MAX, + [IPPROTO_ICMPV6] = NFCT_TIMEOUT_ATTR_ICMPV6_MAX, + [IPPROTO_GRE] = NFCT_TIMEOUT_ATTR_GRE_MAX, + [IPPROTO_RAW] = NFCT_TIMEOUT_ATTR_GENERIC_MAX, +}; + +int nfct_cmd_timeout_add(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + uint32_t portid, seq; + struct nfct_timeout *t; + uint16_t l3proto; + uint8_t l4proto; + int ret, i; + unsigned int j; + + if (argc < 6) { + nfct_perror("missing parameters\n" + "syntax: nfct timeout add name " + "family protocol state1 " + "timeout1 state2 timeout2..."); + return -1; + } + + t = nfct_timeout_alloc(); + if (t == NULL) { + nfct_perror("OOM"); + return -1; + } + + nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); + + if (strcmp(argv[4], "inet") == 0) + l3proto = AF_INET; + else if (strcmp(argv[4], "inet6") == 0) + l3proto = AF_INET6; + else { + nfct_perror("unknown layer 3 protocol"); + return -1; + } + nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO, l3proto); + + if (strcmp(argv[5], "tcp") == 0) + l4proto = IPPROTO_TCP; + else if (strcmp(argv[5], "udp") == 0) + l4proto = IPPROTO_UDP; + else if (strcmp(argv[5], "udplite") == 0) + l4proto = IPPROTO_UDPLITE; + else if (strcmp(argv[5], "sctp") == 0) + l4proto = IPPROTO_SCTP; + else if (strcmp(argv[5], "dccp") == 0) + l4proto = IPPROTO_DCCP; + else if (strcmp(argv[5], "icmp") == 0) + l4proto = IPPROTO_ICMP; + else if (strcmp(argv[5], "icmpv6") == 0) + l4proto = IPPROTO_ICMPV6; + else if (strcmp(argv[5], "gre") == 0) + l4proto = IPPROTO_GRE; + else if (strcmp(argv[5], "generic") == 0) + l4proto = IPPROTO_RAW; + else { + nfct_perror("unknown layer 4 protocol"); + return -1; + } + nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO, l4proto); + + for (i=6; i<argc; i+=2) { + int matching = -1; + + for (j=0; j<nfct_timeout_attr_max[l4proto]; j++) { + const char *state_name; + + state_name = + nfct_timeout_policy_attr_to_name(l4proto, j); + if (state_name == NULL) { + nfct_perror("state name is NULL"); + return -1; + } + if (strcasecmp(argv[i], state_name) != 0) + continue; + + matching = j; + break; + } + if (matching != -1) { + if (i+1 >= argc) { + nfct_perror("missing value for this timeout"); + return -1; + } + nfct_timeout_policy_attr_set_u32(t, matching, + atoi(argv[i+1])); + matching = -1; + } else { + fprintf(stderr, "nfct v%s: Wrong state name: `%s' " + "for protocol `%s'\n", + VERSION, argv[i], argv[5]); + return -1; + } + } + + seq = time(NULL); + nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_NEW, + NLM_F_CREATE | NLM_F_ACK, seq); + nfct_timeout_nlmsg_build_payload(nlh, t); + + nfct_timeout_free(t); + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + nfct_perror("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + nfct_perror("mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + nfct_perror("mnl_socket_send"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + nfct_perror("error"); + return -1; + } + mnl_socket_close(nl); + + return 0; +} + +int nfct_cmd_timeout_delete(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + uint32_t portid, seq; + struct nfct_timeout *t; + int ret; + + if (argc < 4) { + nfct_perror("missing timeout policy name"); + return -1; + } else if (argc > 4) { + nfct_perror("too many arguments"); + return -1; + } + + t = nfct_timeout_alloc(); + if (t == NULL) { + nfct_perror("OOM"); + return -1; + } + + nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); + + seq = time(NULL); + nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, + NLM_F_ACK, seq); + nfct_timeout_nlmsg_build_payload(nlh, t); + + nfct_timeout_free(t); + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + nfct_perror("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + nfct_perror("mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + nfct_perror("mnl_socket_send"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + nfct_perror("error"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} + +int nfct_cmd_timeout_get(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + uint32_t portid, seq; + struct nfct_timeout *t; + int ret; + + if (argc < 4) { + nfct_perror("missing timeout policy name"); + return -1; + } else if (argc > 4) { + nfct_perror("too many arguments"); + return -1; + } + + t = nfct_timeout_alloc(); + if (t == NULL) { + nfct_perror("OOM"); + return -1; + } + nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); + + seq = time(NULL); + nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_GET, + NLM_F_ACK, seq); + + nfct_timeout_nlmsg_build_payload(nlh, t); + + nfct_timeout_free(t); + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + nfct_perror("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + nfct_perror("mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + nfct_perror("mnl_socket_send"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + nfct_perror("error"); + return -1; + } + mnl_socket_close(nl); + + return 0; +} + +int nfct_cmd_timeout_flush(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + uint32_t portid, seq; + int ret; + + if (argc > 3) { + nfct_perror("too many arguments"); + return -1; + } + + seq = time(NULL); + nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, + NLM_F_ACK, seq); + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + nfct_perror("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + nfct_perror("mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + nfct_perror("mnl_socket_send"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + nfct_perror("error"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/src/nfct.c b/src/nfct.c new file mode 100644 index 0000000..db629e7 --- /dev/null +++ b/src/nfct.c @@ -0,0 +1,116 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <netinet/in.h> +#include <errno.h> + +#include <libmnl/libmnl.h> +#include <linux/netfilter/nfnetlink_cttimeout.h> +#include <libnetfilter_cttimeout/libnetfilter_cttimeout.h> + +#include "nfct.h" + +static int nfct_cmd_version(int argc, char *argv[]); +static int nfct_cmd_help(int argc, char *argv[]); + +static void usage(char *argv[]) +{ + fprintf(stderr, "Usage: %s subsystem command [parameters]...\n", + argv[0]); +} + +void nfct_perror(const char *msg) +{ + if (errno == 0) { + fprintf(stderr, "nfct v%s: %s\n", VERSION, msg); + } else { + fprintf(stderr, "nfct v%s: %s: %s\n", + VERSION, msg, strerror(errno)); + } +} + +int main(int argc, char *argv[]) +{ + int subsys = NFCT_SUBSYS_NONE, ret = 0; + + if (argc < 2) { + usage(argv); + exit(EXIT_FAILURE); + } + if (strncmp(argv[1], "timeout", strlen(argv[1])) == 0) { + subsys = NFCT_SUBSYS_TIMEOUT; + } else if (strncmp(argv[1], "version", strlen(argv[1])) == 0) + subsys = NFCT_SUBSYS_VERSION; + else if (strncmp(argv[1], "help", strlen(argv[1])) == 0) + subsys = NFCT_SUBSYS_HELP; + else { + fprintf(stderr, "nfct v%s: Unknown subsystem: %s\n", + VERSION, argv[1]); + usage(argv); + exit(EXIT_FAILURE); + } + + switch(subsys) { + case NFCT_SUBSYS_TIMEOUT: + ret = nfct_cmd_timeout_parse_params(argc, argv); + break; + case NFCT_SUBSYS_VERSION: + ret = nfct_cmd_version(argc, argv); + break; + case NFCT_SUBSYS_HELP: + ret = nfct_cmd_help(argc, argv); + break; + } + return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} + +static const char version_msg[] = + "nfct v%s: utility for the Netfilter's Connection Tracking System\n" + "Copyright (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n" + "This program comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it under " + "certain \nconditions; see LICENSE file distributed in this package " + "for details.\n"; + +static int nfct_cmd_version(int argc, char *argv[]) +{ + printf(version_msg, VERSION); + return 0; +} + +static const char help_msg[] = + "nfct v%s: utility for the Netfilter's Connection Tracking System\n" + "Usage: %s command [parameters]...\n\n" + "Subsystem:\n" + " timeout\t\tAllows definition of fine-grain timeout policies\n" + " version\t\tDisplay version and disclaimer\n" + " help\t\t\tDisplay this help message\n" + "Commands:\n" + " list [reset]\t\tList the accounting object table (and reset)\n" + " add object-name\tAdd new accounting object to table\n" + " delete object-name\tDelete existing accounting object\n" + " get object-name\tGet existing accounting object\n" + " flush\t\t\tFlush accounting object table\n"; + +static int nfct_cmd_help(int argc, char *argv[]) +{ + printf(help_msg, VERSION, argv[0]); + return 0; +} |