diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-04-27 15:04:07 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-05-02 18:31:13 +0200 |
commit | c179ee88d91a84fc75dc4602cca500e8fa72ed66 (patch) | |
tree | b6b149622e02c81265a673145d6b9a260776f799 /src/client.c |
initial commit
This patch bootstrap the new nft-sync software. Basically, this
software aims to support two different setups:
1) Rule-set repository server. The software serves the nft rule-set to
clients that request the ruleset.
Basically from the system that acts as repository, you have to run:
# nft-sync -c ../contrib/nft-sync.conf.server
Then, from the client:
# nft-sync -c ../contrib/nft-sync.conf.client --fetch
Which displays the nft rule-set in the standard output, so you
can inspect the nft rule-set.
Alternatively, the client can also retrieve and apply the nft
rule-set using the pull command instead:
# nft-sync -c ../contrib/nft-sync.conf.client --pull
[ Note that this command above does not work in this bootstrap yet ]
2) Rule-set synchronization: In case of primary-backup and multiprimary
firewall configurations, the software makes sure that the firewall
cluster is deploying the same filtering policy. In this case, you have
to launch the process:
# nft-sync -c ../contrib/nft-sync.conf --sync
[ Note that this command above does not work in this bootstrap yet ]
This bootstrap provides the basic infrastructure as a proof-of-concept.
Many of the necessary features are still lacking:
* Implement --sync and --pull commands.
* Interaction with nft through libnftnl, which allows the software to
retrieve the local nft rule-set, as well as to parse it and apply it.
* SSL support, specifically the repository mode needs it to make sure
nobody can steal your filtering policy from the network.
* IPv6 support.
* Allow to serve different rule-sets in the repository mode.
And many others that will be added progressively.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/client.c')
-rw-r--r-- | src/client.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..d509a52 --- /dev/null +++ b/src/client.c @@ -0,0 +1,176 @@ +/* + * (C) 2014 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 Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fd.h> +#include <tcp.h> +#include <unistd.h> +#include <config.h> +#include <string.h> +#include <errno.h> + +#include "init.h" +#include "logging.h" +#include "msg_buff.h" +#include "proto.h" +#include "config.h" + +static void print_payload(struct msg_buff *msgb) +{ + write(1, msgb_data(msgb) + sizeof(struct nft_sync_hdr), + msgb_len(msgb) - sizeof(struct nft_sync_hdr)); + write(1, "\n", 1); +} + +static int process_response(struct msg_buff *msgb, int len) +{ + switch (nfts_inst.cmd) { + case NFTS_CMD_NONE: + break; + case NFTS_CMD_FETCH: + print_payload(msgb); + /* We're done, stop running this process */ + nfts_inst.stop = true; + return 0; + /* TODO: We'll have a pull command at some point, the code to parse + * the xml/json ruleset should go here. + */ + default: + break; + } + return -1; +} + +static void tcp_client_established_cb(struct nft_fd *nfd, uint32_t mask) +{ + struct tcp_client *c = nfd->data; + struct nft_sync_hdr *hdr; + char buf[sizeof(struct nft_sync_hdr)]; + struct msg_buff *msgb = tcp_client_get_data(c); + int ret, len; + + if (msgb == NULL) { + /* Retrieve the header first to know the response length */ + ret = tcp_client_recv(c, buf, sizeof(buf)); + if (ret < 0) { + nfts_log(NFTS_LOG_ERROR, "cannot received from socket"); + goto err1; + } else if (ret == 0) { + nfts_log(NFTS_LOG_ERROR, + "connection from server has been closed\n"); + /* FIXME retry every N seconds using a timer, + * otherwise this sucks up the CPU by retrying to + * connect very hard. + */ + goto err1; + } + + hdr = (struct nft_sync_hdr *)buf; + len = ntohl(hdr->len); + + /* Allocate a message for the entire response */ + msgb = msgb_alloc(len); + if (msgb == NULL) { + nfts_log(NFTS_LOG_ERROR, "OOM"); + goto err1; + } + memcpy(msgb_data(msgb), buf, sizeof(buf)); + msgb_put(msgb, sizeof(buf)); + + /* Attach this message to the client */ + tcp_client_set_data(c, msgb); + } + + /* Retrieve as much data as we can in this round */ + ret = tcp_client_recv(c, msgb_tail(msgb), + msgb_size(msgb) - msgb_len(msgb)); + if (ret < 0) { + nfts_log(NFTS_LOG_ERROR, "cannot received from socket"); + goto err1; + } else if (ret == 0) { + nfts_log(NFTS_LOG_ERROR, + "connection from server has been closed\n"); + goto err1; + } + msgb_put(msgb, ret); + + /* Not enough data to process the response yet */ + if (msgb_len(msgb) < msgb_size(msgb)) + return; + + if (process_response(msgb, len) < 0) { + nfts_log(NFTS_LOG_ERROR, "discarding malformed response"); + goto err1; + } + /* Detach this message from the client */ + tcp_client_set_data(c, NULL); +err1: + msgb_free(msgb); + close(tcp_client_get_fd(c)); + nft_fd_unregister(nfd); + tcp_client_destroy(c); +} + +static void tcp_client_connect_cb(struct nft_fd *nfd, uint32_t mask) +{ + struct nft_sync_hdr *hdr; + struct tcp_client *c = nfd->data; + struct msg_buff *msgb; + int len; + + msgb = msgb_alloc(NFTS_MAX_REQUEST); + if (msgb == NULL) { + nfts_log(NFTS_LOG_ERROR, "OOM"); + return; + } + + switch (nfts_inst.cmd) { + case NFTS_CMD_FETCH: + len = strlen("fetch") + sizeof(struct nft_sync_hdr); + hdr = msgb_put(msgb, sizeof(struct nft_sync_hdr)); + hdr->len = htonl(len); + memcpy(hdr->data, "fetch", strlen("fetch")); + msgb_put(msgb, strlen("fetch")); + break; + default: + nfts_log(NFTS_LOG_ERROR, "Unknown command"); + return; + } + + if (tcp_client_send(c, msgb_data(msgb), msgb_len(msgb)) < 0) { + nfts_log(NFTS_LOG_ERROR, "cannot send to socket: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Now that we got connected, register the descriptor again to + * permanently listen for incoming data. + */ + nft_fd_setup(&nfts_inst.tcp_client_nfd, tcp_client_get_fd(c), + tcp_client_established_cb, c); + nft_fd_register(nfd, EV_READ | EV_PERSIST); +} + +int tcp_client_start(struct nft_sync_inst *inst) +{ + struct tcp_client *c; + + c = tcp_client_create(&inst->tcp); + if (c == NULL) { + fprintf(stderr, "cannot initialize TCP client\n"); + return -1; + } + + nft_fd_setup(&inst->tcp_client_nfd, tcp_client_get_fd(c), + tcp_client_connect_cb, c); + nft_fd_register(&inst->tcp_client_nfd, EV_WRITE); + + return 0; +} |