diff options
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..cd4ac0a --- /dev/null +++ b/src/server.c @@ -0,0 +1,164 @@ +/* + * (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" +#include "proto.h" + +static int send_ruleset(struct nft_fd *nfd) +{ + struct msg_buff *msgb; + struct nft_sync_hdr *hdr; + /* TODO: send real ruleset in json/xml format here, replace this + * code with the real libnftnl code. + */ + const char *ruleset = "this is the ruleset in XML/JSON format"; + int ret, ruleset_len = strlen(ruleset); + + msgb = msgb_alloc(sizeof(struct nft_sync_hdr) + ruleset_len); + if (msgb == NULL) + return -1; + + hdr = msgb_put(msgb, sizeof(struct nft_sync_hdr) + ruleset_len); + hdr->len = htonl(sizeof(struct nft_sync_hdr) + ruleset_len); + memcpy(hdr->data, ruleset, ruleset_len); + + ret = send(nfd->fd, msgb_data(msgb), msgb_len(msgb), 0); + msgb_free(msgb); + + return ret; +} + +static int nfts_parse_request(struct nft_fd *nfd, const char *req) +{ + int ret = -1; + + if (strncmp(req, "fetch", strlen("fetch")) == 0) + ret = send_ruleset(nfd); + + return ret; +} + +static void tcp_server_established_cb(struct nft_fd *nfd, uint32_t mask) +{ + struct msg_buff *msgb = nfd->data; + struct nft_sync_hdr *hdr; + uint32_t len; + int ret; + + ret = recv(nfd->fd, msgb_tail(msgb), + msgb_size(msgb) - msgb_len(msgb), 0); + if (ret == 0) + goto err1; + else if (ret < 0) { + nfts_log(NFTS_LOG_ERROR, "cannot receive from client"); + goto err1; + } + msgb_put(msgb, ret); + + /* Not enough room for header yet, grab more bytes later */ + if (msgb_len(msgb) < sizeof(struct nft_sync_hdr)) + return; + + hdr = (struct nft_sync_hdr *) msgb_data(msgb); + + len = ntohl(hdr->len); + + if (len >= NFTS_MAX_REQUEST) { + nfts_log(NFTS_LOG_ERROR, "discarding message too large %d", + len, NFTS_MAX_REQUEST); + goto err1; + } + + /* Not enough data to process this request yet */ + if (len < (uint32_t)ret) + return; + + hdr = msgb_pull(msgb, len); + if (hdr == NULL) { + nfts_log(NFTS_LOG_FATAL, "cannot pull out header"); + goto err1; + } + + if (nfts_parse_request(nfd, hdr->data) < 0) { + nfts_log(NFTS_LOG_ERROR, "discarding malformed request"); + goto err1; + } + + /* There's still some pending bytes from the stream in the message, + * move them at the head of the message buffer. + */ + if (msgb_len(msgb) > 0) + msgb_burp(msgb); + + return; +err1: + nfts_log(NFTS_LOG_NOTICE, "closing connection"); + msgb_free(msgb); + close(nfd->fd); + nft_fd_unregister(nfd); + nft_fd_free(nfd); +} + +static void tcp_server_cb(struct nft_fd *nfd, uint32_t mask) +{ + struct nft_fd *accept_nfd; + struct msg_buff *msgb; + struct sockaddr_in addr; + int fd; + + msgb = msgb_alloc(NFTS_MAX_REQUEST); + if (msgb == NULL) { + nfts_log(NFTS_LOG_ERROR, "OOM"); + return; + } + + fd = tcp_server_accept(nfd->data, &addr); + if (fd < 0) { + msgb_free(msgb); + nfts_log(NFTS_LOG_ERROR, "failed to accept socket"); + return; + } + nfts_log(NFTS_LOG_NOTICE, "accepted new connection from %s", + inet_ntoa(addr.sin_addr)); + + accept_nfd = nft_fd_alloc(); + nft_fd_setup(accept_nfd, fd, tcp_server_established_cb, msgb); + nft_fd_register(accept_nfd, EV_READ | EV_PERSIST); +} + +int tcp_server_start(struct nft_sync_inst *inst) +{ + struct tcp_server *s; + + nfts_inst.tcp.ipproto = AF_INET; + nfts_inst.tcp.port = 1234; + + s = tcp_server_create(&inst->tcp); + if (s == NULL) + return -1; + + nft_fd_setup(&inst->tcp_server_fd, tcp_server_get_fd(s), + tcp_server_cb, s); + nft_fd_register(&inst->tcp_server_fd, EV_READ | EV_PERSIST); + + return 0; +} |