diff --git a/configure.ac b/configure.ac index 319dd674..376c5bfe 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,16 @@ 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 server mode (no libpcap dependency) +dnl +want_udp_server=no +AC_ARG_ENABLE([udp-server], + [AS_HELP_STRING([--enable-udp-server], + [Enable UDP server mode for no libpcap dependency @<:@default is to disable@:>@])], + [want_udp_server=$enableval], + []) +AM_CONDITIONAL([UDP_SERVER], [test "$want_udp_server" = yes]) + dnl Decide whether or not to enable all warnings with -Wall dnl use_wall=yes @@ -443,12 +453,15 @@ 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], [ + + 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])] ) + ]) AS_IF([test "$want_digest_cache" = yes], [ use_ndbm=no @@ -687,6 +700,10 @@ if [test "$want_server" = "yes" ]; then firewall type: $FIREWALL_TYPE firewall program path: $FIREWALL_EXE " +if [test "$want_udp_server" = "yes" ]; then + echo " UDP server mode enabled, no libpcap dependency +" + fi if [test "$want_digest_cache" = "no" ]; then echo " *WARNING* 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/Makefile.am b/server/Makefile.am index c9ccdbc2..fbea5842 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 !UDP_SERVER + 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..f4cd7833 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -57,6 +57,9 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "ENABLE_SPA_OVER_HTTP", "ENABLE_TCP_SERVER", "TCPSERV_PORT", + "ENABLE_UDP_SERVER", + "UDPSERV_PORT", + "UDPSERV_SELECT_TIMEOUT", "LOCALE", "SYSLOG_IDENTITY", "SYSLOG_FACILITY", @@ -186,6 +189,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..6be26a90 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -151,6 +151,10 @@ 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); + 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], @@ -808,6 +812,30 @@ 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) + { + 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. + */ + 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) @@ -1113,6 +1141,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..a7870ce5 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -31,14 +31,17 @@ #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" #include "fw_util.h" #include "sig_handler.h" #include "replay_cache.h" #include "tcp_server.h" +#include "udp_server.h" + +#if USE_LIBPCAP + #include "pcap_capture.h" +#endif /* Prototypes */ @@ -178,7 +181,25 @@ 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(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 + * 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 +210,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 @@ -379,7 +403,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); @@ -388,12 +412,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 @@ -406,13 +430,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/fwknopd_common.h b/server/fwknopd_common.h index e7b2e932..2353728e 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,6 +101,13 @@ #define DEF_ENABLE_SPA_OVER_HTTP "N" #define DEF_ENABLE_TCP_SERVER "N" #define DEF_TCPSERV_PORT "62201" +#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 #define DEF_SYSLOG_FACILITY "LOG_DAEMON" @@ -112,6 +119,8 @@ #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_UDPSERV_SELECT_TIMEOUT (2 << 22) #define RCHK_MAX_PCAP_DISPATCH_COUNT (2 << 22) #define RCHK_MAX_FW_TIMEOUT (2 << 22) @@ -225,6 +234,9 @@ enum { CONF_ENABLE_SPA_OVER_HTTP, CONF_ENABLE_TCP_SERVER, CONF_TCPSERV_PORT, + CONF_ENABLE_UDP_SERVER, + CONF_UDPSERV_PORT, + CONF_UDPSERV_SELECT_TIMEOUT, CONF_LOCALE, CONF_SYSLOG_IDENTITY, CONF_SYSLOG_FACILITY, @@ -567,6 +579,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..43557597 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -28,12 +28,13 @@ * ***************************************************************************** */ + + #include #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" @@ -44,6 +45,8 @@ #include #endif +#if USE_LIBPCAP + /* The pcap capture routine. */ int @@ -247,24 +250,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, @@ -347,4 +336,6 @@ pcap_capture(fko_srv_options_t *opts) return(0); } +#endif /* USE_LIBPCAP */ + /***EOF***/ diff --git a/server/process_packet.h b/server/process_packet.h index d45cdd20..a5966290 100644 --- a/server/process_packet.h +++ b/server/process_packet.h @@ -46,6 +46,8 @@ /* Prototypes */ +#if USE_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/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/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); diff --git a/server/udp_server.c b/server/udp_server.c new file mode 100644 index 00000000..3dde17be --- /dev/null +++ b/server/udp_server.c @@ -0,0 +1,234 @@ +/* + ***************************************************************************** + * + * 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 "sig_handler.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 is_err, s_timeout; + fd_set sfd_set; + struct sockaddr_in saddr, caddr; + struct timeval tv; + char sipbuf[MAX_IPV4_STR_LEN] = {0}; + 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); + if(is_err != FKO_SUCCESS) + { + 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 + */ + if ((s_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + log_msg(LOG_ERR, "run_udp_server: socket() failed: %s", + strerror(errno)); + return -1; + } + + /* Make our main socket non-blocking so we don't have to be stuck on + * listening for incoming datagrams. + */ + 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, 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 */ + + /* 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; + } + + /* 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) + { + if(sig_do_stop()) + { + close(s_sock); + return 1; + } + + /* Check for any expired firewall rules and deal with them. + */ + if(!opts->test) + check_firewall_rules(opts); + + /* Initialize and setup the socket for select. + */ + FD_ZERO(&sfd_set); + FD_SET(s_sock, &sfd_set); + + /* Set our select timeout to (500ms by default). + */ + tv.tv_sec = 0; + tv.tv_usec = s_timeout; + + 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; + + /* If we make it here then there is a datagram to process + */ + clen = sizeof(caddr); + + pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN, + 0, (struct sockaddr *)&caddr, &clen); + + dgram_msg[pkt_len] = 0x0; + + 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 datagram (%d bytes) from: %s", + pkt_len, sipbuf); + } + + /* Expect the data to not be too large + */ + if(pkt_len <= MAX_SPA_PACKET_LEN) + { + /* Copy the packet for SPA processing + */ + 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; + 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); + } + + 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); + + /* 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. + */ + 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 */ + + close(s_sock); + 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***/ 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 069fef90..803318cf 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -126,6 +126,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/basic_operations.pl b/test/tests/basic_operations.pl index a96ca7e1..a30f9b8d 100644 --- a/test/tests/basic_operations.pl +++ b/test/tests/basic_operations.pl @@ -2494,6 +2494,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', @@ -2586,6 +2594,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', diff --git a/test/tests/rijndael.pl b/test/tests/rijndael.pl index 2397e40c..e1786c0a 100644 --- a/test/tests/rijndael.pl +++ b/test/tests/rijndael.pl @@ -621,6 +621,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', diff --git a/test/tests/rijndael_hmac.pl b/test/tests/rijndael_hmac.pl index de3b260c..212a75c9 100644 --- a/test/tests/rijndael_hmac.pl +++ b/test/tests/rijndael_hmac.pl @@ -970,6 +970,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_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, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + }, + + { 'category' => 'Rijndael+HMAC', 'subcategory' => 'client', 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/], + }, );