diff options
Diffstat (limited to 'src/nfct.c')
-rw-r--r-- | src/nfct.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/nfct.c b/src/nfct.c new file mode 100644 index 0000000..3331e5b --- /dev/null +++ b/src/nfct.c @@ -0,0 +1,252 @@ +/* + * (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_list.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 command subsystem [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)); + } +} + +static LIST_HEAD(nfct_extension_list); + +void nfct_extension_register(struct nfct_extension *ext) +{ + list_add(&ext->head, &nfct_extension_list); +} + +static struct nfct_extension *nfct_extension_lookup(int type) +{ + struct nfct_extension *ext; + + list_for_each_entry(ext, &nfct_extension_list, head) { + if (ext->type == type) + return ext; + } + return NULL; +} + +static const char *nfct_cmd_array[NFCT_CMD_MAX] = { + [NFCT_CMD_LIST] = "list", + [NFCT_CMD_ADD] = "add", + [NFCT_CMD_DELETE] = "delete", + [NFCT_CMD_GET] = "get", + [NFCT_CMD_FLUSH] = "flush", + [NFCT_CMD_DISABLE] = "disable", + [NFCT_CMD_DEFAULT_SET] = "default-set", + [NFCT_CMD_DEFAULT_GET] = "default-get", +}; + +static int nfct_cmd_parse(const char *cmdstr) +{ + int i; + + for (i = 1; i < NFCT_CMD_MAX; i++) { + if (strncmp(nfct_cmd_array[i], cmdstr, strlen(cmdstr)) == 0) + return i; + } + return -1; +} + +static int nfct_cmd_error(char *argv[]) +{ + fprintf(stderr, "nfct v%s: Unknown command: %s\n", VERSION, argv[1]); + usage(argv); + + return EXIT_FAILURE; +} + +static const char *nfct_subsys_array[NFCT_SUBSYS_MAX] = { + [NFCT_SUBSYS_TIMEOUT] = "timeout", + [NFCT_SUBSYS_HELPER] = "helper", + [NFCT_SUBSYS_VERSION] = "version", + [NFCT_SUBSYS_HELP] = "help", +}; + +static int nfct_subsys_parse(const char *cmdstr) +{ + int i; + + for (i = 1; i < NFCT_SUBSYS_MAX; i++) { + if (strncmp(nfct_subsys_array[i], cmdstr, strlen(cmdstr)) == 0) + return i; + } + return -1; +} + +static int nfct_subsys_error(char *argv[]) +{ + fprintf(stderr, "nfct v%s: Unknown subsystem: %s\n", VERSION, argv[1]); + usage(argv); + + return EXIT_FAILURE; +} + +int main(int argc, char *argv[]) +{ + int subsys, cmd, ret = 0; + struct nfct_extension *ext; + struct mnl_socket *nl; + + if (argc < 3) { + usage(argv); + exit(EXIT_FAILURE); + } + + cmd = nfct_cmd_parse(argv[1]); + if (cmd < 0) { + /* Workaround not to break backward compatibility and to get + * the syntax in sync with nft. Old nfct versions allow to + * specify the subsystem before the command. + */ + subsys = nfct_subsys_parse(argv[1]); + if (subsys < 0) + return nfct_subsys_error(argv); + + cmd = nfct_cmd_parse(argv[2]); + if (cmd < 0) + return nfct_cmd_error(argv); + } else { + subsys = nfct_subsys_parse(argv[2]); + if (subsys < 0) + return nfct_subsys_error(argv); + } + + switch (subsys) { + case NFCT_SUBSYS_VERSION: + ret = nfct_cmd_version(argc, argv); + break; + case NFCT_SUBSYS_HELP: + ret = nfct_cmd_help(argc, argv); + break; + default: + ext = nfct_extension_lookup(subsys); + if (ext == NULL) { + fprintf(stderr, "nfct v%s: subsystem %s not supported\n", + VERSION, argv[1]); + return EXIT_FAILURE; + } + + nl = nfct_mnl_open(); + if (nl == NULL) { + nfct_perror("cannot open netlink"); + return -1; + } + + ret = ext->parse_params(nl, argc, argv, cmd); + mnl_socket_close(nl); + 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" + " helper\t\tAllows to configure user-space helper\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; +} + +int nfct_mnl_talk(struct mnl_socket *nl, struct nlmsghdr *nlh, + uint32_t seq, uint32_t portid, + int (*cb)(const struct nlmsghdr *nlh, void *data), + void *data) +{ + int ret; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + return -1; + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, cb, data); + if (ret <= 0) + break; + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) + return -1; + + return 0; +} + +struct mnl_socket *nfct_mnl_open(void) +{ + struct mnl_socket *nl; + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) + return NULL; + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + return NULL; + + return nl; +} |