From c07afac8833e0c46048a1ae34a8a96f19fa6a59e Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 09:29:30 -0400 Subject: [PATCH 01/15] calculate sizeof caddr for each client connection --- server/tcp_server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/tcp_server.c b/server/tcp_server.c index 682fddf1..41f23f41 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -169,13 +169,13 @@ run_tcp_server(fko_srv_options_t *opts) return -1; } - clen = sizeof(caddr); - /* Now loop and accept and drop connections after the first packet or a * short timeout. */ while(1) { + clen = sizeof(caddr); + /* Initialize and setup the socket for select. */ FD_ZERO(&sfd_set); From 1fd0e7e96012d9bdce0a2a3912bff3498fff3637 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 11:49:04 -0400 Subject: [PATCH 02/15] first cut at UDP server mode --- configure.ac | 24 +++++ server/Makefile.am | 13 ++- server/cmd_opts.h | 3 + server/config_init.c | 15 +++ server/fwknopd.c | 22 +++- server/fwknopd_common.h | 6 ++ server/pcap_capture.c | 5 + server/process_packet.h | 2 + server/udp_server.c | 211 +++++++++++++++++++++++++++++++++++++++ server/udp_server.c.orig | 117 ++++++++++++++++++++++ server/udp_server.h | 40 ++++++++ 11 files changed, 451 insertions(+), 7 deletions(-) create mode 100644 server/udp_server.c create mode 100644 server/udp_server.c.orig create mode 100644 server/udp_server.h diff --git a/configure.ac b/configure.ac index 5084e23f..20cb80dc 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,20 @@ if test "x$want_fuzzing_interfaces" = "xyes"; then AC_DEFINE([FUZZING_INTERFACES], [1], [Define for fuzzing interfaces support]) fi +dnl Decide whether or not to enable UDP listener mode (no libpcap dependency) +dnl +want_udp_listener=no +AC_ARG_ENABLE([udp-listener], + [AS_HELP_STRING([--enable-udp-listener], + [Enable UDP listener mode (no libpcap dependency) @<:@default is to disable@:>@])], + [want_udp_listener=$enableval], + []) +AM_CONDITIONAL([UDP_LISTENER], [test "$want_udp_listener" = yes]) + +#if test "$want_udp_listener" = yes; then +# AC_DEFINE([UDP_LISTENER], [1], [Define for UDP listener mode]) +#fi + dnl Decide whether or not to enable all warnings with -Wall dnl use_wall=yes @@ -430,12 +444,18 @@ AS_IF([test "x$WGET_EXE" != x], dnl Check for libpcap, gdbm (or ndbm) if we are building the server component dnl AS_IF([test "$want_server" = yes], [ + + use_libpcap=no + AS_IF([test "$want_udp_listener" = no], [ # Looking for libpcap # AC_CHECK_LIB([pcap],[pcap_open_live], [ AC_DEFINE([HAVE_LIBPCAP], [1], [Define if you have libpcap]) ], [ AC_MSG_ERROR([fwknopd needs libpcap])] ) + use_libpcap=yes + ]) + AM_CONDITIONAL([USE_LIBPCAP], [test x$use_libpcap = xyes]) AS_IF([test "$want_digest_cache" = yes], [ use_ndbm=no @@ -674,6 +694,10 @@ if [test "$want_server" = "yes" ]; then firewall type: $FIREWALL_TYPE firewall program path: $FIREWALL_EXE " +if [test "$want_udp_listener" = "yes" ]; then + echo " UDP listener mode enabled, no libpcap dependency +" + fi if [test "$want_digest_cache" = "no" ]; then echo " *WARNING* diff --git a/server/Makefile.am b/server/Makefile.am index c9ccdbc2..f5c51a7c 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -6,16 +6,21 @@ fwknopd_SOURCES = fwknopd.c fwknopd.h config_init.c config_init.h \ process_packet.h log_msg.c log_msg.h utils.c utils.h \ sig_handler.c sig_handler.h replay_cache.c replay_cache.h \ access.c access.h fwknopd_errors.c fwknopd_errors.h \ - tcp_server.c tcp_server.h extcmd.c extcmd.h \ + tcp_server.c tcp_server.h udp_server.c udp_server.h \ fw_util.c fw_util.h fw_util_ipf.c fw_util_ipf.h \ fw_util_firewalld.c fw_util_firewalld.h \ fw_util_iptables.c fw_util_iptables.h \ fw_util_ipfw.c fw_util_ipfw.h \ - fw_util_pf.c fw_util_pf.h cmd_opts.h + fw_util_pf.c fw_util_pf.h cmd_opts.h \ + extcmd.c extcmd.h -fwknopd_LDADD = $(top_builddir)/lib/libfko.la $(top_builddir)/common/libfko_util.a -lpcap +fwknopd_LDADD = $(top_builddir)/lib/libfko.la $(top_builddir)/common/libfko_util.a -if ! CONFIG_FILE_CACHE +if USE_LIBPCAP + fwknopd_LDADD += -lpcap +endif + +if !CONFIG_FILE_CACHE if USE_NDBM fwknopd_LDADD += -lndbm else diff --git a/server/cmd_opts.h b/server/cmd_opts.h index db2d4885..b432d50e 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -57,6 +57,8 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "ENABLE_SPA_OVER_HTTP", "ENABLE_TCP_SERVER", "TCPSERV_PORT", + "ENABLE_UDP_SERVER", + "UDPSERV_PORT", "LOCALE", "SYSLOG_IDENTITY", "SYSLOG_FACILITY", @@ -186,6 +188,7 @@ static struct option cmd_opts[] = {"restart", 0, NULL, 'R'}, {"status", 0, NULL, 'S'}, {"test", 0, NULL, 't'}, + {"udp-server", 0, NULL, 'U'}, {"verbose", 0, NULL, 'v'}, {"version", 0, NULL, 'V'}, {0, 0, 0, 0} diff --git a/server/config_init.c b/server/config_init.c index 55ca9d37..7ee64c4a 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -151,6 +151,8 @@ validate_int_var_ranges(fko_srv_options_t *opts) 1, RCHK_MAX_SNIFF_BYTES); range_check(opts, "TCPSERV_PORT", opts->config[CONF_TCPSERV_PORT], 1, RCHK_MAX_TCPSERV_PORT); + range_check(opts, "UDPSERV_PORT", opts->config[CONF_UDPSERV_PORT], + 1, RCHK_MAX_UDPSERV_PORT); #if FIREWALL_IPFW range_check(opts, "IPFW_START_RULE_NUM", opts->config[CONF_IPFW_START_RULE_NUM], @@ -808,6 +810,16 @@ validate_options(fko_srv_options_t *opts) if(opts->config[CONF_TCPSERV_PORT] == NULL) set_config_entry(opts, CONF_TCPSERV_PORT, DEF_TCPSERV_PORT); + /* Enable UDP server. + */ + if(opts->config[CONF_ENABLE_UDP_SERVER] == NULL) + set_config_entry(opts, CONF_ENABLE_UDP_SERVER, DEF_ENABLE_UDP_SERVER); + + /* UDP Server port. + */ + if(opts->config[CONF_UDPSERV_PORT] == NULL) + set_config_entry(opts, CONF_UDPSERV_PORT, DEF_UDPSERV_PORT); + /* Syslog identity. */ if(opts->config[CONF_SYSLOG_IDENTITY] == NULL) @@ -1113,6 +1125,9 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) case 't': opts->test = 1; break; + case 'U': + opts->enable_udp_server = 1; + break; /* Verbosity level */ case 'v': opts->verbose++; diff --git a/server/fwknopd.c b/server/fwknopd.c index 357a0bbd..6528accb 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -31,7 +31,6 @@ #include "fwknopd.h" #include "access.h" #include "config_init.h" -#include "process_packet.h" #include "pcap_capture.h" #include "log_msg.h" #include "utils.h" @@ -39,6 +38,7 @@ #include "sig_handler.h" #include "replay_cache.h" #include "tcp_server.h" +#include "udp_server.h" /* Prototypes */ @@ -178,7 +178,20 @@ main(int argc, char **argv) if(!opts.test && (fw_initialize(&opts) != 1)) clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); - /* If the TCP server option was set, fire it up here. + /* If we are to acquire SPA data via a UDP socket, start it up here. + */ + if(1 || strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) + { + if(run_udp_server(&opts) < 0) + { + log_msg(LOG_ERR, "Fatal run_udp_server() error"); + clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); + } + } + + /* If the TCP server option was set, fire it up here. Note that in + * this mode, fwknopd still acquires SPA packets via libpcap. If you + * want to use UDP only without the libpcap dependency, see the FIXME... */ if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0) { @@ -189,9 +202,12 @@ main(int argc, char **argv) } } +#if USE_LIBPCAP /* Intiate pcap capture mode... */ - pcap_capture(&opts); + if(strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "N", 1) == 0) + pcap_capture(&opts); +#endif /* Deal with any signals that we've received and break out * of the loop for any terminating signals diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 5622d36d..c3d11602 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -101,6 +101,8 @@ #define DEF_ENABLE_SPA_OVER_HTTP "N" #define DEF_ENABLE_TCP_SERVER "N" #define DEF_TCPSERV_PORT "62201" +#define DEF_ENABLE_UDP_SERVER "N" +#define DEF_UDPSERV_PORT "62201" #define DEF_SYSLOG_IDENTITY MY_NAME #define DEF_SYSLOG_FACILITY "LOG_DAEMON" @@ -112,6 +114,7 @@ #define RCHK_MAX_SPA_PACKET_AGE 100000 /* seconds, can disable */ #define RCHK_MAX_SNIFF_BYTES (2 << 14) #define RCHK_MAX_TCPSERV_PORT ((2 << 16) - 1) +#define RCHK_MAX_UDPSERV_PORT ((2 << 16) - 1) #define RCHK_MAX_PCAP_DISPATCH_COUNT (2 << 22) #define RCHK_MAX_FW_TIMEOUT (2 << 22) @@ -225,6 +228,8 @@ enum { CONF_ENABLE_SPA_OVER_HTTP, CONF_ENABLE_TCP_SERVER, CONF_TCPSERV_PORT, + CONF_ENABLE_UDP_SERVER, + CONF_UDPSERV_PORT, CONF_LOCALE, CONF_SYSLOG_IDENTITY, CONF_SYSLOG_FACILITY, @@ -565,6 +570,7 @@ typedef struct fko_srv_options unsigned char test; /* Test mode flag */ unsigned char verbose; /* Verbose mode flag */ unsigned char exit_after_parse_config; /* Parse config and exit */ + unsigned char enable_udp_server; /* Enable UDP server mode */ unsigned char firewd_disable_check_support; /* Don't use firewall-cmd ... -C */ unsigned char ipt_disable_check_support; /* Don't use iptables -C */ diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 35018ff1..537974ca 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -28,6 +28,9 @@ * ***************************************************************************** */ + +#if HAVE_LIBPCAP + #include #include "fwknopd_common.h" @@ -347,4 +350,6 @@ pcap_capture(fko_srv_options_t *opts) return(0); } +#endif /* HAVE_LIBPCAP */ + /***EOF***/ diff --git a/server/process_packet.h b/server/process_packet.h index d45cdd20..f914f405 100644 --- a/server/process_packet.h +++ b/server/process_packet.h @@ -46,6 +46,8 @@ /* Prototypes */ +#if HAVE_LIBPCAP void process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header, const unsigned char *packet); +#endif #endif /* PROCESS_PACKET_H */ diff --git a/server/udp_server.c b/server/udp_server.c new file mode 100644 index 00000000..fded9615 --- /dev/null +++ b/server/udp_server.c @@ -0,0 +1,211 @@ +/* + ***************************************************************************** + * + * File: udp_server.c + * + * Purpose: Collect SPA packets via a UDP server. + * + * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. + * Copyright (C) 2009-2014 fwknop developers and contributors. For a full + * list of contributors, see the file 'CREDITS'. + * + * License (GNU General Public License): + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#include "fwknopd_common.h" +#include "incoming_spa.h" +#include "log_msg.h" +#include "fw_util.h" +#include "utils.h" +#include + +#if HAVE_SYS_SOCKET_H + #include +#endif +#if HAVE_ARPA_INET_H + #include +#endif +#if HAVE_NETDB + #include +#endif + +#include +#include + +int +run_udp_server(fko_srv_options_t *opts) +{ + int s_sock, sfd_flags, selval, pkt_len; + //int reuse_addr = 1, is_err; + int is_err; + fd_set sfd_set; + struct sockaddr_in saddr, caddr; + struct timeval tv; + char sipbuf[MAX_IPV4_STR_LEN] = {0}; + char msg[5000]; + socklen_t clen; + + unsigned short port; + + port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT], + 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value."); + return -1; + } + log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port); + + /* Now, let's make a UDP server + */ + if ((s_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + log_msg(LOG_ERR, "run_udp_server: socket() failed: %s", + strerror(errno)); + return -1; + } + + /* So that we can re-bind to it without TIME_WAIT problems + if(setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) == -1) + { + log_msg(LOG_ERR, "run_udp_server: setsockopt error: %s", + strerror(errno)); + close(s_sock); + return -1; + } + */ + + /* Make our main socket non-blocking so we don't have to be stuck on + * listening for incoming connections. + */ + if((sfd_flags = fcntl(s_sock, F_GETFL, 0)) < 0) + { + log_msg(LOG_ERR, "run_udp_server: fcntl F_GETFL error: %s", + strerror(errno)); + close(s_sock); + return -1; + } + + sfd_flags |= O_NONBLOCK; + + if(fcntl(s_sock, F_SETFL, sfd_flags) < 0) + { + log_msg(LOG_ERR, "run_udp_server: fcntl F_SETFL error setting O_NONBLOCK: %s", + strerror(errno)); + close(s_sock); + return -1; + } + + /* Construct local address structure */ + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; /* Internet address family */ + saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + saddr.sin_port = htons(port); /* Local port */ + + /* Bind to the local address */ + if (bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + { + log_msg(LOG_ERR, "run_udp_server: bind() failed: %s", + strerror(errno)); + close(s_sock); + return -1; + } + + /* Mark the socket so it will listen for incoming connections + * (but only one at a time) + if (listen(s_sock, 1) < 0) + { + log_msg(LOG_ERR, "run_udp_server: listen() failed: %s", + strerror(errno)); + close(s_sock); + return -1; + } + */ + + /* Now loop and receive SPA packets + */ + while(1) + { + + /* Check for any expired firewall rules and deal with them. + */ + if(!opts->test) + check_firewall_rules(opts); + + clen = sizeof(caddr); + + /* Initialize and setup the socket for select. + */ + FD_ZERO(&sfd_set); + FD_SET(s_sock, &sfd_set); + + /* Set our select timeout to 500 ms. + */ + tv.tv_sec = 0; + tv.tv_usec = 500000; + + selval = select(s_sock+1, &sfd_set, NULL, NULL, &tv); + + if(selval == -1) + { + /* Select error so bail + */ + log_msg(LOG_ERR, "run_udp_server: select error socket: %s", + strerror(errno)); + close(s_sock); + return -1; + } + + if(selval == 0) + continue; + + pkt_len = recvfrom(s_sock, msg, 5000, 0, (struct sockaddr *)&caddr, &clen); + + printf("-------------------------------------------------------\n"); + msg[pkt_len] = 0; + printf("Received %d bytes:\n", pkt_len); + printf("%s",msg); + printf("\n-------------------------------------------------------\n"); + + if(opts->verbose) + { + memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); + inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); + log_msg(LOG_INFO, "udp_server: Got UDP connection from %s.", sipbuf); + } + + /* Copy the packet for SPA processing + */ + strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); + opts->spa_pkt.packet_data_len = pkt_len; + opts->spa_pkt.packet_proto = IPPROTO_UDP; + opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; + opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; + opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); + opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); + + incoming_spa(opts); + + usleep(1000000); + + } /* infinite while loop */ + return 1; +} + +/***EOF***/ diff --git a/server/udp_server.c.orig b/server/udp_server.c.orig new file mode 100644 index 00000000..12a77c0a --- /dev/null +++ b/server/udp_server.c.orig @@ -0,0 +1,117 @@ +/* + ***************************************************************************** + * + * File: udp_server.c + * + * Purpose: Collect SPA packets via a UDP server. + * + * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. + * Copyright (C) 2009-2014 fwknop developers and contributors. For a full + * list of contributors, see the file 'CREDITS'. + * + * License (GNU General Public License): + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#include "fwknopd_common.h" +#include "incoming_spa.h" +#include "log_msg.h" +#include "fw_util.h" +#include "utils.h" +#include + +#if HAVE_SYS_SOCKET_H + #include +#endif +#if HAVE_ARPA_INET_H + #include +#endif +#if HAVE_NETDB + #include +#endif + +#include +#include + +int +run_udp_server(fko_srv_options_t *opts) +{ + int is_err, pkt_len, sock_fd = 0; + char msg[5000]; + struct sockaddr_in saddr, caddr; + char sipbuf[MAX_IPV4_STR_LEN] = {0}; + + unsigned short port; + socklen_t len; + + port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT], + 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value."); + return -1; + } + log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port); + + /* Now, let's make a UDP server + */ + sock_fd = socket(AF_INET,SOCK_DGRAM,0); + + bzero(&saddr,sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr=htonl(INADDR_ANY); + saddr.sin_port=htons(port); + bind(sock_fd,(struct sockaddr *)&saddr,sizeof(saddr)); + + while(1) + { + len = sizeof(caddr); + pkt_len = recvfrom(sock_fd,msg,5000,0,(struct sockaddr *)&caddr,&len); + //sendto(sock_fd,msg,pkt_len,0,(struct sockaddr *)&caddr,sizeof(caddr)); + printf("-------------------------------------------------------\n"); + msg[pkt_len] = 0; + printf("Received %d bytes:\n", pkt_len); + printf("%s",msg); + printf("\n-------------------------------------------------------\n"); + + memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); + inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); + log_msg(LOG_INFO, "udp_server: Got UDP datagram from %s.", sipbuf); + + /* Copy the packet for SPA processing + */ + strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); + opts->spa_pkt.packet_data_len = pkt_len; + opts->spa_pkt.packet_proto = IPPROTO_UDP; + opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; + opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; + opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); + opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); + + incoming_spa(opts); + + /* Check for any expired firewall rules and deal with them. + */ + if(!opts->test) + check_firewall_rules(opts); + } + + return 1; +} + +/***EOF***/ diff --git a/server/udp_server.h b/server/udp_server.h new file mode 100644 index 00000000..75898b02 --- /dev/null +++ b/server/udp_server.h @@ -0,0 +1,40 @@ +/* + ***************************************************************************** + * + * File: udp_server.h + * + * Purpose: Header file for udp_server.c. + * + * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. + * Copyright (C) 2009-2014 fwknop developers and contributors. For a full + * list of contributors, see the file 'CREDITS'. + * + * License (GNU General Public License): + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef UDP_SERVER_H +#define UDP_SERVER_H + +/* Function prototypes +*/ +int run_udp_server(fko_srv_options_t *opts); + +#endif /* UDP_SERVER_H */ + +/***EOF***/ From f2a3562f712d511825967b5d3633cbf92abd9fad Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 11:49:24 -0400 Subject: [PATCH 03/15] removed --- server/udp_server.c.orig | 117 --------------------------------------- 1 file changed, 117 deletions(-) delete mode 100644 server/udp_server.c.orig diff --git a/server/udp_server.c.orig b/server/udp_server.c.orig deleted file mode 100644 index 12a77c0a..00000000 --- a/server/udp_server.c.orig +++ /dev/null @@ -1,117 +0,0 @@ -/* - ***************************************************************************** - * - * File: udp_server.c - * - * Purpose: Collect SPA packets via a UDP server. - * - * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. - * Copyright (C) 2009-2014 fwknop developers and contributors. For a full - * list of contributors, see the file 'CREDITS'. - * - * License (GNU General Public License): - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - ***************************************************************************** -*/ -#include "fwknopd_common.h" -#include "incoming_spa.h" -#include "log_msg.h" -#include "fw_util.h" -#include "utils.h" -#include - -#if HAVE_SYS_SOCKET_H - #include -#endif -#if HAVE_ARPA_INET_H - #include -#endif -#if HAVE_NETDB - #include -#endif - -#include -#include - -int -run_udp_server(fko_srv_options_t *opts) -{ - int is_err, pkt_len, sock_fd = 0; - char msg[5000]; - struct sockaddr_in saddr, caddr; - char sipbuf[MAX_IPV4_STR_LEN] = {0}; - - unsigned short port; - socklen_t len; - - port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT], - 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); - if(is_err != FKO_SUCCESS) - { - log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value."); - return -1; - } - log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port); - - /* Now, let's make a UDP server - */ - sock_fd = socket(AF_INET,SOCK_DGRAM,0); - - bzero(&saddr,sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr=htonl(INADDR_ANY); - saddr.sin_port=htons(port); - bind(sock_fd,(struct sockaddr *)&saddr,sizeof(saddr)); - - while(1) - { - len = sizeof(caddr); - pkt_len = recvfrom(sock_fd,msg,5000,0,(struct sockaddr *)&caddr,&len); - //sendto(sock_fd,msg,pkt_len,0,(struct sockaddr *)&caddr,sizeof(caddr)); - printf("-------------------------------------------------------\n"); - msg[pkt_len] = 0; - printf("Received %d bytes:\n", pkt_len); - printf("%s",msg); - printf("\n-------------------------------------------------------\n"); - - memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); - log_msg(LOG_INFO, "udp_server: Got UDP datagram from %s.", sipbuf); - - /* Copy the packet for SPA processing - */ - strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); - opts->spa_pkt.packet_data_len = pkt_len; - opts->spa_pkt.packet_proto = IPPROTO_UDP; - opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; - opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; - opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); - opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); - - incoming_spa(opts); - - /* Check for any expired firewall rules and deal with them. - */ - if(!opts->test) - check_firewall_rules(opts); - } - - return 1; -} - -/***EOF***/ From dc9e8da702c61c36f04072f2dd6cb5d8f99f8f5d Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 14:54:40 -0400 Subject: [PATCH 04/15] started on UDP server tests for Rijndael mode --- test/conf/udp_server_fwknopd.conf | 2 ++ test/test-fwknop.pl | 1 + test/tests/rijndael.pl | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 test/conf/udp_server_fwknopd.conf diff --git a/test/conf/udp_server_fwknopd.conf b/test/conf/udp_server_fwknopd.conf new file mode 100644 index 00000000..078b4114 --- /dev/null +++ b/test/conf/udp_server_fwknopd.conf @@ -0,0 +1,2 @@ +ENABLE_UDP_SERVER Y; +UDPSERV_PORT 62201; diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index a532839a..d66954cc 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -122,6 +122,7 @@ our %cf = ( 'gpg_no_sig_verify_access' => "$conf_dir/gpg_no_sig_verify_access.conf", 'gpg_invalid_sig_id_access' => "$conf_dir/gpg_invalid_sig_id_access.conf", 'tcp_server' => "$conf_dir/tcp_server_fwknopd.conf", + 'udp_server' => "$conf_dir/udp_server_fwknopd.conf", 'spa_over_http' => "$conf_dir/spa_over_http_fwknopd.conf", 'tcp_pcap_filter' => "$conf_dir/tcp_pcap_filter_fwknopd.conf", 'icmp_pcap_filter' => "$conf_dir/icmp_pcap_filter_fwknopd.conf", diff --git a/test/tests/rijndael.pl b/test/tests/rijndael.pl index 896caba1..66e982e5 100644 --- a/test/tests/rijndael.pl +++ b/test/tests/rijndael.pl @@ -622,6 +622,27 @@ 'fw_rule_created' => $NEW_RULE_REQUIRED, 'fw_rule_removed' => $NEW_RULE_REMOVED, }, + { + 'category' => 'Rijndael', + 'subcategory' => 'client+server', + 'detail' => "UDP server --udp-server / tcp/22", + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args $intf_str --udp-server", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + }, + { + 'category' => 'Rijndael', + 'subcategory' => 'client+server', + 'detail' => "UDP server conf / tcp/22", + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'udp_server'} -a $cf{'def_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + }, { 'category' => 'Rijndael', From 0af7f72500c6bb404af3fefa5b572403ec2593e5 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 16:49:12 -0400 Subject: [PATCH 05/15] enforce MAX_SPA_PACKET_LEN restriction for incoming datagrams for UDP listener mode --- server/udp_server.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/server/udp_server.c b/server/udp_server.c index fded9615..adbc49a3 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -52,7 +52,6 @@ int run_udp_server(fko_srv_options_t *opts) { int s_sock, sfd_flags, selval, pkt_len; - //int reuse_addr = 1, is_err; int is_err; fd_set sfd_set; struct sockaddr_in saddr, caddr; @@ -81,18 +80,8 @@ run_udp_server(fko_srv_options_t *opts) return -1; } - /* So that we can re-bind to it without TIME_WAIT problems - if(setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) == -1) - { - log_msg(LOG_ERR, "run_udp_server: setsockopt error: %s", - strerror(errno)); - close(s_sock); - return -1; - } - */ - /* Make our main socket non-blocking so we don't have to be stuck on - * listening for incoming connections. + * listening for incoming datagrams. */ if((sfd_flags = fcntl(s_sock, F_GETFL, 0)) < 0) { @@ -127,17 +116,6 @@ run_udp_server(fko_srv_options_t *opts) return -1; } - /* Mark the socket so it will listen for incoming connections - * (but only one at a time) - if (listen(s_sock, 1) < 0) - { - log_msg(LOG_ERR, "run_udp_server: listen() failed: %s", - strerror(errno)); - close(s_sock); - return -1; - } - */ - /* Now loop and receive SPA packets */ while(1) @@ -190,6 +168,11 @@ run_udp_server(fko_srv_options_t *opts) log_msg(LOG_INFO, "udp_server: Got UDP connection from %s.", sipbuf); } + /* Expect the data to not be too large + */ + if(pkt_len > MAX_SPA_PACKET_LEN) + continue; + /* Copy the packet for SPA processing */ strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); @@ -202,9 +185,8 @@ run_udp_server(fko_srv_options_t *opts) incoming_spa(opts); - usleep(1000000); - } /* infinite while loop */ + return 1; } From aa2492bba237529e6a2b7dc3a4530e2995750a69 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 16:51:38 -0400 Subject: [PATCH 06/15] Added UDP server HMAC cycle tests --- test/tests/rijndael_hmac.pl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/tests/rijndael_hmac.pl b/test/tests/rijndael_hmac.pl index 7ed9b041..f405741a 100644 --- a/test/tests/rijndael_hmac.pl +++ b/test/tests/rijndael_hmac.pl @@ -958,6 +958,30 @@ 'key_file' => $cf{'rc_hmac_sha512_short_key'}, }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "UDP server --udp-server / tcp/22", + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $cf{'hmac_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str --udp-server", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "UDP server conf / tcp/22", + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'udp_server'} -a $cf{'hmac_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + }, + + { 'category' => 'Rijndael+HMAC', 'subcategory' => 'client', From 5db3a12763b1322cc466379e14a362f67ff4d15c Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 20:30:09 -0400 Subject: [PATCH 07/15] add signal handling code to UDP server mode --- server/fwknopd.c | 17 +++++++++++------ server/pcap_capture.c | 1 - server/udp_server.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/server/fwknopd.c b/server/fwknopd.c index 6528accb..15b60fd4 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -180,13 +180,18 @@ main(int argc, char **argv) /* If we are to acquire SPA data via a UDP socket, start it up here. */ - if(1 || strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) + if(opts.enable_udp_server || + strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) { if(run_udp_server(&opts) < 0) { log_msg(LOG_ERR, "Fatal run_udp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); } + else + { + break; + } } /* If the TCP server option was set, fire it up here. Note that in @@ -395,7 +400,7 @@ static int handle_signals(fko_srv_options_t *opts) if(got_sighup) { - log_msg(LOG_WARNING, "Got SIGHUP. Re-reading configs."); + log_msg(LOG_WARNING, "Got SIGHUP. Re-reading configs."); free_configs(opts); kill(opts->tcp_server_pid, SIGTERM); usleep(1000000); @@ -404,12 +409,12 @@ static int handle_signals(fko_srv_options_t *opts) } else if(got_sigint) { - log_msg(LOG_WARNING, "Got SIGINT. Exiting..."); + log_msg(LOG_WARNING, "Got SIGINT. Exiting..."); got_sigint = 0; } else if(got_sigterm) { - log_msg(LOG_WARNING, "Got SIGTERM. Exiting..."); + log_msg(LOG_WARNING, "Got SIGTERM. Exiting..."); got_sigterm = 0; } else @@ -422,13 +427,13 @@ static int handle_signals(fko_srv_options_t *opts) && opts->packet_ctr >= opts->packet_ctr_limit) { log_msg(LOG_INFO, - "Packet count limit (%d) reached. Exiting...", + "Packet count limit (%d) reached. Exiting...", opts->packet_ctr_limit); } else /* got_signal was not set (should be if we are here) */ { log_msg(LOG_WARNING, - "Capture ended without signal. Exiting..."); + "Capture ended without signal. Exiting..."); } return rv; } diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 537974ca..92e26c7b 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -36,7 +36,6 @@ #include "fwknopd_common.h" #include "pcap_capture.h" #include "process_packet.h" -#include "sig_handler.h" #include "fw_util.h" #include "log_msg.h" #include "fwknopd_errors.h" diff --git a/server/udp_server.c b/server/udp_server.c index adbc49a3..21d1e5e7 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -29,6 +29,7 @@ ***************************************************************************** */ #include "fwknopd_common.h" +#include "sig_handler.h" #include "incoming_spa.h" #include "log_msg.h" #include "fw_util.h" @@ -116,10 +117,36 @@ run_udp_server(fko_srv_options_t *opts) return -1; } + /* Initialize our signal handlers. You can check the return value for + * the number of signals that were *not* set. Those that were not set + * will be listed in the log/stderr output. + */ + if(set_sig_handlers() > 0) + log_msg(LOG_ERR, "Errors encountered when setting signal handlers."); + /* Now loop and receive SPA packets */ while(1) { + /* Any signal except USR1, USR2, and SIGCHLD mean break the loop. + */ + if(got_signal != 0) + { + if(got_sigint || got_sigterm || got_sighup) + { + close(s_sock); + return 1; + } + else if(got_sigusr1 || got_sigusr2) + { + /* Not doing anything with these yet. + */ + got_sigusr1 = got_sigusr2 = 0; + got_signal = 0; + } + else + got_signal = 0; + } /* Check for any expired firewall rules and deal with them. */ @@ -165,7 +192,8 @@ run_udp_server(fko_srv_options_t *opts) { memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); - log_msg(LOG_INFO, "udp_server: Got UDP connection from %s.", sipbuf); + log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s", + pkt_len, sipbuf); } /* Expect the data to not be too large @@ -187,6 +215,7 @@ run_udp_server(fko_srv_options_t *opts) } /* infinite while loop */ + close(s_sock); return 1; } From a5dd273189a89071f25cae9954ae11a840e2e488 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 20:48:57 -0400 Subject: [PATCH 08/15] replay attack detection test for UDP server mode --- test/tests/rijndael_replay_attacks.pl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/tests/rijndael_replay_attacks.pl b/test/tests/rijndael_replay_attacks.pl index ad156f6b..33d3f25c 100644 --- a/test/tests/rijndael_replay_attacks.pl +++ b/test/tests/rijndael_replay_attacks.pl @@ -29,4 +29,13 @@ 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args $intf_str", 'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/], }, + { + 'category' => 'Rijndael', + 'subcategory' => 'client+server', + 'detail' => 'UDP server replay detection', + 'function' => \&replay_detection, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args $intf_str --udp-server", + 'server_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/], + }, ); From 360905ec5624edb927f708561acfb9f76e6c9423 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 21:19:19 -0400 Subject: [PATCH 09/15] implement --packet-limit for UDP server mode --- server/udp_server.c | 43 ++++++++++++++++++++++++---------- test/tests/basic_operations.pl | 8 +++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/server/udp_server.c b/server/udp_server.c index 21d1e5e7..fb76d9c1 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -180,6 +180,8 @@ run_udp_server(fko_srv_options_t *opts) if(selval == 0) continue; + /* If we make it here then there is a datagram to process + */ pkt_len = recvfrom(s_sock, msg, 5000, 0, (struct sockaddr *)&caddr, &clen); printf("-------------------------------------------------------\n"); @@ -198,20 +200,37 @@ run_udp_server(fko_srv_options_t *opts) /* Expect the data to not be too large */ - if(pkt_len > MAX_SPA_PACKET_LEN) - continue; + if(pkt_len <= MAX_SPA_PACKET_LEN) + { + /* Copy the packet for SPA processing + */ + strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); + opts->spa_pkt.packet_data_len = pkt_len; + opts->spa_pkt.packet_proto = IPPROTO_UDP; + opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; + opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; + opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); + opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); - /* Copy the packet for SPA processing + incoming_spa(opts); + } + + opts->packet_ctr += 1; + if(opts->foreground == 1 && opts->verbose > 2) + log_msg(LOG_DEBUG, "run_udp_server() processed: %d packets", opts->packet_ctr); + + /* Count the set of processed packets (pcap_dispatch() return + * value) - we use this as a comparison for --packet-limit regardless + * of SPA packet validity at this point. */ - strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); - opts->spa_pkt.packet_data_len = pkt_len; - opts->spa_pkt.packet_proto = IPPROTO_UDP; - opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; - opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; - opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); - opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); - - incoming_spa(opts); + if (opts->packet_ctr_limit && opts->packet_ctr >= opts->packet_ctr_limit) + { + log_msg(LOG_WARNING, + "* Incoming packet count limit of %i reached", + opts->packet_ctr_limit + ); + return 1; + } } /* infinite while loop */ diff --git a/test/tests/basic_operations.pl b/test/tests/basic_operations.pl index f6ba4c0e..91051edc 100644 --- a/test/tests/basic_operations.pl +++ b/test/tests/basic_operations.pl @@ -2482,6 +2482,14 @@ 'function' => \&server_packet_limit, 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str", }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'UDP server --packet-limit 1 exit', + 'function' => \&server_packet_limit, + 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args --udp-server --packet-limit 1 $intf_str", + }, + { 'category' => 'basic operations', 'subcategory' => 'server', From ad3b23091720be83c9f8ccb742cf10ea07fe7cf6 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 21:21:25 -0400 Subject: [PATCH 10/15] minor client cmd line bug fix for UDP server HMAC test --- test/tests/rijndael_hmac.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/rijndael_hmac.pl b/test/tests/rijndael_hmac.pl index f405741a..aaa08c4a 100644 --- a/test/tests/rijndael_hmac.pl +++ b/test/tests/rijndael_hmac.pl @@ -974,7 +974,7 @@ 'subcategory' => 'client+server', 'detail' => "UDP server conf / tcp/22", 'function' => \&spa_cycle, - 'cmdline' => $default_client_args, + 'cmdline' => $default_client_hmac_args, 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'udp_server'} -a $cf{'hmac_access'} " . "-d $default_digest_file -p $default_pid_file $intf_str", 'fw_rule_created' => $NEW_RULE_REQUIRED, From e2c2ad141e87b6b799525c3f91b80a294bc117f2 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 22:06:06 -0400 Subject: [PATCH 11/15] TCP/UDP server port validation tests --- test/tests/basic_operations.pl | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/tests/basic_operations.pl b/test/tests/basic_operations.pl index 91051edc..41e1cdb3 100644 --- a/test/tests/basic_operations.pl +++ b/test/tests/basic_operations.pl @@ -2582,6 +2582,38 @@ ], 'positive_output_matches' => [qr/invalid\sPCAP_DISPATCH_COUNT/], }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'invalid tcp server port', + 'function' => \&server_conf_files, + 'fwknopd_cmdline' => $server_rewrite_conf_files, + 'exec_err' => $YES, + 'server_access_file' => [ + 'SOURCE any', + 'KEY testtest', + ], + 'server_conf_file' => [ + 'TCPSERV_PORT 9999999999' + ], + 'positive_output_matches' => [qr/not in the range/], + }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'invalid udp server port', + 'function' => \&server_conf_files, + 'fwknopd_cmdline' => $server_rewrite_conf_files, + 'exec_err' => $YES, + 'server_access_file' => [ + 'SOURCE any', + 'KEY testtest', + ], + 'server_conf_file' => [ + 'UDPSERV_PORT 9999999999' + ], + 'positive_output_matches' => [qr/not in the range/], + }, { 'category' => 'basic operations', From 52c9d51d7d02e1caa0e02ea992fffcc435ae5845 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 22:06:34 -0400 Subject: [PATCH 12/15] consolidate signal handling a bit, UDP server msg size updates --- server/pcap_capture.c | 20 +++--------------- server/sig_handler.c | 24 +++++++++++++++++++++ server/sig_handler.h | 1 + server/udp_server.c | 49 +++++++++++++++---------------------------- 4 files changed, 45 insertions(+), 49 deletions(-) diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 92e26c7b..6cee596e 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -249,24 +249,10 @@ pcap_capture(fko_srv_options_t *opts) got_sigchld = 0; } - /* Any signal except USR1, USR2, and SIGCHLD mean break the loop. - */ - if(got_signal != 0) + if(sig_do_stop()) { - if(got_sigint || got_sigterm || got_sighup) - { - pcap_breakloop(pcap); - pending_break = 1; - } - else if(got_sigusr1 || got_sigusr2) - { - /* Not doing anything with these yet. - */ - got_sigusr1 = got_sigusr2 = 0; - got_signal = 0; - } - else - got_signal = 0; + pcap_breakloop(pcap); + pending_break = 1; } res = pcap_dispatch(pcap, pcap_dispatch_count, diff --git a/server/sig_handler.c b/server/sig_handler.c index 8054ca81..b642a9d8 100644 --- a/server/sig_handler.c +++ b/server/sig_handler.c @@ -148,4 +148,28 @@ set_sig_handlers(void) return(err); } +int +sig_do_stop(void) +{ + /* Any signal except USR1, USR2, and SIGCHLD mean break the loop. + */ + if(got_signal != 0) + { + if(got_sigint || got_sigterm || got_sighup) + { + return 1; + } + else if(got_sigusr1 || got_sigusr2) + { + /* Not doing anything with these yet. + */ + got_sigusr1 = got_sigusr2 = 0; + got_signal = 0; + } + else + got_signal = 0; + } + return 0; +} + /***EOF***/ diff --git a/server/sig_handler.h b/server/sig_handler.h index 9a433ffc..2adce6b8 100644 --- a/server/sig_handler.h +++ b/server/sig_handler.h @@ -44,6 +44,7 @@ extern sig_atomic_t got_sigchld; void sig_handler(int sig); int set_sig_handlers(void); +int sig_do_stop(void); #endif /* SIG_HANDLER_H */ diff --git a/server/udp_server.c b/server/udp_server.c index fb76d9c1..89af5308 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -58,10 +58,9 @@ run_udp_server(fko_srv_options_t *opts) struct sockaddr_in saddr, caddr; struct timeval tv; char sipbuf[MAX_IPV4_STR_LEN] = {0}; - char msg[5000]; - socklen_t clen; - + char dgram_msg[MAX_SPA_PACKET_LEN+1] = {0}; unsigned short port; + socklen_t clen; port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT], 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); @@ -103,7 +102,7 @@ run_udp_server(fko_srv_options_t *opts) } /* Construct local address structure */ - memset(&saddr, 0, sizeof(saddr)); + memset(&saddr, 0x0, sizeof(saddr)); saddr.sin_family = AF_INET; /* Internet address family */ saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ saddr.sin_port = htons(port); /* Local port */ @@ -128,24 +127,10 @@ run_udp_server(fko_srv_options_t *opts) */ while(1) { - /* Any signal except USR1, USR2, and SIGCHLD mean break the loop. - */ - if(got_signal != 0) + if(sig_do_stop()) { - if(got_sigint || got_sigterm || got_sighup) - { - close(s_sock); - return 1; - } - else if(got_sigusr1 || got_sigusr2) - { - /* Not doing anything with these yet. - */ - got_sigusr1 = got_sigusr2 = 0; - got_signal = 0; - } - else - got_signal = 0; + close(s_sock); + return 1; } /* Check for any expired firewall rules and deal with them. @@ -153,14 +138,12 @@ run_udp_server(fko_srv_options_t *opts) if(!opts->test) check_firewall_rules(opts); - clen = sizeof(caddr); - /* Initialize and setup the socket for select. */ FD_ZERO(&sfd_set); FD_SET(s_sock, &sfd_set); - /* Set our select timeout to 500 ms. + /* Set our select timeout to (500ms by default). */ tv.tv_sec = 0; tv.tv_usec = 500000; @@ -182,13 +165,12 @@ run_udp_server(fko_srv_options_t *opts) /* If we make it here then there is a datagram to process */ - pkt_len = recvfrom(s_sock, msg, 5000, 0, (struct sockaddr *)&caddr, &clen); + clen = sizeof(caddr); - printf("-------------------------------------------------------\n"); - msg[pkt_len] = 0; - printf("Received %d bytes:\n", pkt_len); - printf("%s",msg); - printf("\n-------------------------------------------------------\n"); + pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN, + 0, (struct sockaddr *)&caddr, &clen); + + dgram_msg[pkt_len] = 0x0; if(opts->verbose) { @@ -204,7 +186,7 @@ run_udp_server(fko_srv_options_t *opts) { /* Copy the packet for SPA processing */ - strlcpy((char *)opts->spa_pkt.packet_data, msg, pkt_len+1); + strlcpy((char *)opts->spa_pkt.packet_data, dgram_msg, pkt_len+1); opts->spa_pkt.packet_data_len = pkt_len; opts->spa_pkt.packet_proto = IPPROTO_UDP; opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; @@ -215,9 +197,12 @@ run_udp_server(fko_srv_options_t *opts) incoming_spa(opts); } + memset(dgram_msg, 0x0, sizeof(dgram_msg)); + opts->packet_ctr += 1; if(opts->foreground == 1 && opts->verbose > 2) - log_msg(LOG_DEBUG, "run_udp_server() processed: %d packets", opts->packet_ctr); + log_msg(LOG_DEBUG, "run_udp_server() processed: %d packets", + opts->packet_ctr); /* Count the set of processed packets (pcap_dispatch() return * value) - we use this as a comparison for --packet-limit regardless From 52d34a70a21d4e6d019d3a94bb84448051f87c29 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 22:32:20 -0400 Subject: [PATCH 13/15] fwknopd man page updates, added UDPSERV_SELECT_TIMEOUT config option --- configure.ac | 4 ++-- doc/fwknopd.man.asciidoc | 29 +++++++++++++++++++++-------- server/cmd_opts.h | 1 + server/config_init.c | 8 ++++++++ server/fwknopd_common.h | 3 +++ server/udp_server.c | 12 ++++++++++-- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 20cb80dc..055316dd 100644 --- a/configure.ac +++ b/configure.ac @@ -169,8 +169,8 @@ fi dnl Decide whether or not to enable UDP listener mode (no libpcap dependency) dnl want_udp_listener=no -AC_ARG_ENABLE([udp-listener], - [AS_HELP_STRING([--enable-udp-listener], +AC_ARG_ENABLE([udp-server], + [AS_HELP_STRING([--enable-udp-server], [Enable UDP listener mode (no libpcap dependency) @<:@default is to disable@:>@])], [want_udp_listener=$enableval], []) diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index f9d57010..07f00d1f 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -308,14 +308,14 @@ See the '@sysconfdir@/fwknop/fwknopd.conf'' file for the full list and correspon *ENABLE_TCP_SERVER* '':: Enable the fwknopd TCP server. This is a "dummy" TCP server that will - accept TCP connection requests on the specified TCPSERV_PORT. - If set to "Y", fwknopd will fork off a child process to listen for, and - accept incoming TCP request. This server only accepts the - request. It does not otherwise communicate. This is only to allow the - incoming SPA over TCP packet which is detected via PCAP. The connection - is closed after 1 second regardless. - Note that fwknopd still only gets its data via pcap, so the filter - defined by PCAP_FILTER needs to be updated to include this TCP port. + accept TCP connection requests on the specified TCPSERV_PORT. + If set to "Y", fwknopd will fork off a child process to listen for, and + accept incoming TCP request. This server only accepts the + request. It does not otherwise communicate. This is only to allow the + incoming SPA over TCP packet which is detected via PCAP. The connection + is closed after 1 second regardless. + Note that fwknopd still only gets its data via pcap, so the filter + defined by PCAP_FILTER needs to be updated to include this TCP port. *PCAP_DISPATCH_COUNT* '':: Sets the number of packets that are processed when the *pcap_dispatch()* @@ -346,6 +346,19 @@ See the '@sysconfdir@/fwknop/fwknopd.conf'' file for the full list and correspon Set the port number that the ``dummy'' TCP server listens on. This server is only spawned when ``ENABLE_TCP_SERVER'' is set to ``Y''. +*ENABLE_UDP_SERVER* '':: + Enable the *fwknopd* UDP server. This enables *fwknopd* to acquire SPA + packets via a UDP socket directly without having to use libpcap. When this + mode is enabled, *fwknop* should be compiled with *--enable-udp-server* + (passed to the *configure* script) so that libpcap can be removed as a + dependency. As one would expect, when the UDP server is used, no incoming + packets are ever acknowledged by *fwknopd* and therefore collecting SPA + packets in this mode is a good alternative to sniffing the wire directly. + +*UDPSERV_PORT* '':: + Set the port number that the UDP server listens on. This server + is only spawned when ``ENABLE_UDP_SERVER'' is set to ``Y''. + *SYSLOG_IDENTITY* '':: Override syslog identity on message logged by *fwknopd*. The defaults are usually ok. diff --git a/server/cmd_opts.h b/server/cmd_opts.h index b432d50e..f4cd7833 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -59,6 +59,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "TCPSERV_PORT", "ENABLE_UDP_SERVER", "UDPSERV_PORT", + "UDPSERV_SELECT_TIMEOUT", "LOCALE", "SYSLOG_IDENTITY", "SYSLOG_FACILITY", diff --git a/server/config_init.c b/server/config_init.c index 7ee64c4a..9fc0e446 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -153,6 +153,8 @@ validate_int_var_ranges(fko_srv_options_t *opts) 1, RCHK_MAX_TCPSERV_PORT); range_check(opts, "UDPSERV_PORT", opts->config[CONF_UDPSERV_PORT], 1, RCHK_MAX_UDPSERV_PORT); + range_check(opts, "UDPSERV_PORT", opts->config[CONF_UDPSERV_SELECT_TIMEOUT], + 1, RCHK_MAX_UDPSERV_SELECT_TIMEOUT); #if FIREWALL_IPFW range_check(opts, "IPFW_START_RULE_NUM", opts->config[CONF_IPFW_START_RULE_NUM], @@ -820,6 +822,12 @@ validate_options(fko_srv_options_t *opts) if(opts->config[CONF_UDPSERV_PORT] == NULL) set_config_entry(opts, CONF_UDPSERV_PORT, DEF_UDPSERV_PORT); + /* UDP server select() timeout in microseconds + */ + if(opts->config[CONF_UDPSERV_SELECT_TIMEOUT] == NULL) + set_config_entry(opts, CONF_UDPSERV_SELECT_TIMEOUT, + DEF_UDPSERV_SELECT_TIMEOUT); + /* Syslog identity. */ if(opts->config[CONF_SYSLOG_IDENTITY] == NULL) diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index c3d11602..fd0636c0 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -103,6 +103,7 @@ #define DEF_TCPSERV_PORT "62201" #define DEF_ENABLE_UDP_SERVER "N" #define DEF_UDPSERV_PORT "62201" +#define DEF_UDPSERV_SELECT_TIMEOUT "500000" /* half a second (in microseconds) */ #define DEF_SYSLOG_IDENTITY MY_NAME #define DEF_SYSLOG_FACILITY "LOG_DAEMON" @@ -115,6 +116,7 @@ #define RCHK_MAX_SNIFF_BYTES (2 << 14) #define RCHK_MAX_TCPSERV_PORT ((2 << 16) - 1) #define RCHK_MAX_UDPSERV_PORT ((2 << 16) - 1) +#define RCHK_MAX_UDPSERV_SELECT_TIMEOUT (2 << 22) #define RCHK_MAX_PCAP_DISPATCH_COUNT (2 << 22) #define RCHK_MAX_FW_TIMEOUT (2 << 22) @@ -230,6 +232,7 @@ enum { CONF_TCPSERV_PORT, CONF_ENABLE_UDP_SERVER, CONF_UDPSERV_PORT, + CONF_UDPSERV_SELECT_TIMEOUT, CONF_LOCALE, CONF_SYSLOG_IDENTITY, CONF_SYSLOG_FACILITY, diff --git a/server/udp_server.c b/server/udp_server.c index 89af5308..3dde17be 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -53,7 +53,7 @@ int run_udp_server(fko_srv_options_t *opts) { int s_sock, sfd_flags, selval, pkt_len; - int is_err; + int is_err, s_timeout; fd_set sfd_set; struct sockaddr_in saddr, caddr; struct timeval tv; @@ -69,6 +69,14 @@ run_udp_server(fko_srv_options_t *opts) log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value."); return -1; } + s_timeout = strtol_wrapper(opts->config[CONF_UDPSERV_SELECT_TIMEOUT], + 1, RCHK_MAX_UDPSERV_SELECT_TIMEOUT, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, "[*] Invalid max UDPSERV_SELECT_TIMEOUT value."); + return -1; + } + log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port); /* Now, let's make a UDP server @@ -146,7 +154,7 @@ run_udp_server(fko_srv_options_t *opts) /* Set our select timeout to (500ms by default). */ tv.tv_sec = 0; - tv.tv_usec = 500000; + tv.tv_usec = s_timeout; selval = select(s_sock+1, &sfd_set, NULL, NULL, &tv); From ddbba5bc90f105269a18d353e1e1b14bdff69299 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 22:40:50 -0400 Subject: [PATCH 14/15] autoconf update to ensure libpcap is not linked against in --enable-udp-server mode --- configure.ac | 27 +++++++++++---------------- server/Makefile.am | 2 +- server/config_init.c | 8 ++++++++ server/fwknopd.c | 5 ++++- server/fwknopd_common.h | 8 ++++++-- server/pcap_capture.c | 5 +++-- server/process_packet.h | 2 +- 7 files changed, 34 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 055316dd..96a80f8e 100644 --- a/configure.ac +++ b/configure.ac @@ -166,19 +166,15 @@ if test "x$want_fuzzing_interfaces" = "xyes"; then AC_DEFINE([FUZZING_INTERFACES], [1], [Define for fuzzing interfaces support]) fi -dnl Decide whether or not to enable UDP listener mode (no libpcap dependency) +dnl Decide whether or not to enable UDP server mode (no libpcap dependency) dnl -want_udp_listener=no +want_udp_server=no AC_ARG_ENABLE([udp-server], [AS_HELP_STRING([--enable-udp-server], - [Enable UDP listener mode (no libpcap dependency) @<:@default is to disable@:>@])], - [want_udp_listener=$enableval], + [Enable UDP server mode for no libpcap dependency @<:@default is to disable@:>@])], + [want_udp_server=$enableval], []) -AM_CONDITIONAL([UDP_LISTENER], [test "$want_udp_listener" = yes]) - -#if test "$want_udp_listener" = yes; then -# AC_DEFINE([UDP_LISTENER], [1], [Define for UDP listener mode]) -#fi +AM_CONDITIONAL([UDP_SERVER], [test "$want_udp_server" = yes]) dnl Decide whether or not to enable all warnings with -Wall dnl @@ -445,17 +441,16 @@ dnl Check for libpcap, gdbm (or ndbm) if we are building the server component dnl AS_IF([test "$want_server" = yes], [ - use_libpcap=no - AS_IF([test "$want_udp_listener" = no], [ + have_libpcap=no + AS_IF([test "$want_udp_server" = no], [ # Looking for libpcap # AC_CHECK_LIB([pcap],[pcap_open_live], - [ AC_DEFINE([HAVE_LIBPCAP], [1], [Define if you have libpcap]) ], + [ AC_DEFINE([USE_LIBPCAP], [1], [Define if you have libpcap]) ], [ AC_MSG_ERROR([fwknopd needs libpcap])] ) - use_libpcap=yes + have_libpcap=yes ]) - AM_CONDITIONAL([USE_LIBPCAP], [test x$use_libpcap = xyes]) AS_IF([test "$want_digest_cache" = yes], [ use_ndbm=no @@ -694,8 +689,8 @@ if [test "$want_server" = "yes" ]; then firewall type: $FIREWALL_TYPE firewall program path: $FIREWALL_EXE " -if [test "$want_udp_listener" = "yes" ]; then - echo " UDP listener mode enabled, no libpcap dependency +if [test "$want_udp_server" = "yes" ]; then + echo " UDP server mode enabled, no libpcap dependency " fi diff --git a/server/Makefile.am b/server/Makefile.am index f5c51a7c..fbea5842 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -16,7 +16,7 @@ fwknopd_SOURCES = fwknopd.c fwknopd.h config_init.c config_init.h \ fwknopd_LDADD = $(top_builddir)/lib/libfko.la $(top_builddir)/common/libfko_util.a -if USE_LIBPCAP +if !UDP_SERVER fwknopd_LDADD += -lpcap endif diff --git a/server/config_init.c b/server/config_init.c index 9fc0e446..6be26a90 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -815,7 +815,15 @@ validate_options(fko_srv_options_t *opts) /* Enable UDP server. */ if(opts->config[CONF_ENABLE_UDP_SERVER] == NULL) + { + if((strncasecmp(DEF_ENABLE_UDP_SERVER, "Y", 1) == 0) && + !opts->enable_udp_server) + { + log_msg(LOG_ERR, "pcap capture not enabled, forcing UDP server mode"); + opts->enable_udp_server = 1; + } set_config_entry(opts, CONF_ENABLE_UDP_SERVER, DEF_ENABLE_UDP_SERVER); + } /* UDP Server port. */ diff --git a/server/fwknopd.c b/server/fwknopd.c index 15b60fd4..a7870ce5 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -31,7 +31,6 @@ #include "fwknopd.h" #include "access.h" #include "config_init.h" -#include "pcap_capture.h" #include "log_msg.h" #include "utils.h" #include "fw_util.h" @@ -40,6 +39,10 @@ #include "tcp_server.h" #include "udp_server.h" +#if USE_LIBPCAP + #include "pcap_capture.h" +#endif + /* Prototypes */ static int check_dir_path(const char * const path, diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index fd0636c0..dff3032c 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -41,7 +41,7 @@ #include #endif -#if HAVE_LIBPCAP +#if USE_LIBPCAP #include #endif @@ -101,7 +101,11 @@ #define DEF_ENABLE_SPA_OVER_HTTP "N" #define DEF_ENABLE_TCP_SERVER "N" #define DEF_TCPSERV_PORT "62201" -#define DEF_ENABLE_UDP_SERVER "N" +#if USE_LIBPCAP + #define DEF_ENABLE_UDP_SERVER "N" +#else + #define DEF_ENABLE_UDP_SERVER "Y" +#endif #define DEF_UDPSERV_PORT "62201" #define DEF_UDPSERV_SELECT_TIMEOUT "500000" /* half a second (in microseconds) */ #define DEF_SYSLOG_IDENTITY MY_NAME diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 6cee596e..43557597 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -29,7 +29,6 @@ ***************************************************************************** */ -#if HAVE_LIBPCAP #include @@ -46,6 +45,8 @@ #include #endif +#if USE_LIBPCAP + /* The pcap capture routine. */ int @@ -335,6 +336,6 @@ pcap_capture(fko_srv_options_t *opts) return(0); } -#endif /* HAVE_LIBPCAP */ +#endif /* USE_LIBPCAP */ /***EOF***/ diff --git a/server/process_packet.h b/server/process_packet.h index f914f405..a5966290 100644 --- a/server/process_packet.h +++ b/server/process_packet.h @@ -46,7 +46,7 @@ /* Prototypes */ -#if HAVE_LIBPCAP +#if USE_LIBPCAP void process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header, const unsigned char *packet); #endif From 2b046392b7e05ac20387bbcf539530a6559da50b Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 28 Sep 2014 22:44:12 -0400 Subject: [PATCH 15/15] minor unused var removal --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index 96a80f8e..418c0061 100644 --- a/configure.ac +++ b/configure.ac @@ -441,7 +441,6 @@ dnl Check for libpcap, gdbm (or ndbm) if we are building the server component dnl AS_IF([test "$want_server" = yes], [ - have_libpcap=no AS_IF([test "$want_udp_server" = no], [ # Looking for libpcap # @@ -449,7 +448,6 @@ AS_IF([test "$want_server" = yes], [ [ AC_DEFINE([USE_LIBPCAP], [1], [Define if you have libpcap]) ], [ AC_MSG_ERROR([fwknopd needs libpcap])] ) - have_libpcap=yes ]) AS_IF([test "$want_digest_cache" = yes], [