From 07693a9245fc4a16ed6a9b64366a3ae90af7e297 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 16:22:25 -0400 Subject: [PATCH 01/78] Let IPs resolve to IPv6 addresses The remote code seems to be independent from the fwknop project though. Until it will be capable to return IPv6 addresses, in itself this will remain irrelevant for the purpose of adding IPv6 support to fwknop. On another hand, it does help us introduce definitions and update headers to actually support IPv6. --- client/fwknop_common.h | 4 +-- client/http_resolve_host.c | 55 +++++++++++++++----------------------- lib/fko_limits.h | 6 +++++ 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/client/fwknop_common.h b/client/fwknop_common.h index 52134de7..45fc75bc 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -87,8 +87,8 @@ typedef struct fko_cli_options int no_save_args; int use_hmac; char spa_server_str[MAX_SERVER_STR_LEN]; /* may be a hostname */ - char allow_ip_str[MAX_IPV4_STR_LEN]; - char spoof_ip_src_str[MAX_IPV4_STR_LEN]; + char allow_ip_str[MAX_IPV46_STR_LEN]; + char spoof_ip_src_str[MAX_IPV46_STR_LEN]; char spoof_user[MAX_USERNAME_LEN]; int rand_port; char gpg_recipient_key[MAX_GPG_KEY_ID]; diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index 1ca124ea..f6f1286d 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -58,9 +58,8 @@ struct url static int try_url(struct url *url, fko_cli_options_t *options) { - int sock=-1, sock_success=0, res, error, http_buf_len, i; + int sock=-1, sock_success=0, res, error, http_buf_len; int bytes_read = 0, position = 0; - int o1, o2, o3, o4; struct addrinfo *result=NULL, *rp, hints; char http_buf[HTTP_MAX_REQUEST_LEN] = {0}; char http_response[HTTP_MAX_RESPONSE_LEN] = {0}; @@ -197,45 +196,35 @@ try_url(struct url *url, fko_cli_options_t *options) } ndx += 4; - /* Walk along the content to try to find the end of the IP address. - * Note: We are expecting the content to be just an IP address + /* Try to parse the content as an IP address. + * Note: We are expecting the content to be exactly that * (possibly followed by whitespace or other not-digit value). */ - for(i=0; i= 0 && o1 <= 255 - && o2 >= 0 && o2 <= 255 - && o3 >= 0 && o3 <= 255 - && o4 >= 0 && o4 <= 255) - { - strlcpy(options->allow_ip_str, ndx, sizeof(options->allow_ip_str)); - - log_msg(LOG_VERBOSITY_INFO, - "\n[+] Resolved external IP (via http://%s%s) as: %s", - url->host, - url->path, - options->allow_ip_str); - - return(1); - } - else + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME; + error = getaddrinfo(ndx, NULL, &hints, &result); + if (error != 0) { log_msg(LOG_VERBOSITY_ERROR, "[-] From http://%s%s\n Invalid IP (%s) in HTTP response:\n\n%s", url->host, url->path, ndx, http_response); return(-1); } + for (rp = result; rp != NULL; rp = rp->ai_next) { + strlcpy(options->allow_ip_str, + rp->ai_canonname, sizeof(options->allow_ip_str)); + break; + } + freeaddrinfo(result); + + log_msg(LOG_VERBOSITY_INFO, + "\n[+] Resolved external IP (via http://%s%s) as: %s", + url->host, + url->path, + options->allow_ip_str); + + return(1); } static int diff --git a/lib/fko_limits.h b/lib/fko_limits.h index 5f02cc18..2a326008 100644 --- a/lib/fko_limits.h +++ b/lib/fko_limits.h @@ -59,6 +59,12 @@ #define MAX_IPV4_STR_LEN 16 #define MIN_IPV4_STR_LEN 7 +#define MAX_IPV46_STR_LEN 40 +#define MIN_IPV46_STR_LEN 3 + +#define MAX_IPV6_STR_LEN 40 +#define MIN_IPV6_STR_LEN 3 + #define MAX_PROTO_STR_LEN 4 /* tcp, udp, icmp for now */ #define MAX_PORT_STR_LEN 5 #define MAX_PORT 65535 From b8252dbdb872e3dd82984c7c33950459046c4370 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 16:34:36 -0400 Subject: [PATCH 02/78] Let IPs resolve to IPv6 addresses over SSL Again, this depends on the remote host to be actually supporting IPv6. --- client/http_resolve_host.c | 55 +++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index f6f1286d..978af567 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -212,6 +212,7 @@ try_url(struct url *url, fko_cli_options_t *options) return(-1); } for (rp = result; rp != NULL; rp = rp->ai_next) { + /* the canonical value is in the first structure returned */ strlcpy(options->allow_ip_str, rp->ai_canonname, sizeof(options->allow_ip_str)); break; @@ -312,8 +313,9 @@ parse_url(char *res_url, struct url* url) int resolve_ip_https(fko_cli_options_t *options) { - int o1, o2, o3, o4, got_resp=0, i=0; - char *ndx, resp[MAX_IPV4_STR_LEN+1] = {0}; + int got_resp=0, error; + char resp[MAX_IPV4_STR_LEN+1] = {0}; + struct addrinfo *result=NULL, *rp, hints; struct url url; /* for validation only */ char wget_ssl_cmd[MAX_URL_PATH_LEN] = {0}; /* for verbose logging only */ @@ -482,32 +484,35 @@ resolve_ip_https(fko_cli_options_t *options) pclose(wget); #endif - if(got_resp) + if(! got_resp) { - ndx = resp; - for(i=0; i= 0 && o1 <= 255 - && o2 >= 0 && o2 <= 255 - && o3 >= 0 && o3 <= 255 - && o4 >= 0 && o4 <= 255) - { - strlcpy(options->allow_ip_str, ndx, sizeof(options->allow_ip_str)); + log_msg(LOG_VERBOSITY_ERROR, + "[-] Could not resolve IP via: '%s'", wget_ssl_cmd); + return -1; + } - log_msg(LOG_VERBOSITY_INFO, - "\n[+] Resolved external IP (via '%s') as: %s", - wget_ssl_cmd, options->allow_ip_str); - return 1; - } + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME; + error = getaddrinfo(resp, NULL, &hints, &result); + if (error != 0) + { + log_msg(LOG_VERBOSITY_ERROR, + "[-] Could not resolve IP via: '%s'", wget_ssl_cmd); + return(-1); + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + /* the canonical value is in the first structure returned */ + strlcpy(options->allow_ip_str, + rp->ai_canonname, sizeof(options->allow_ip_str)); + break; } - log_msg(LOG_VERBOSITY_ERROR, - "[-] Could not resolve IP via: '%s'", wget_ssl_cmd); - return -1; + freeaddrinfo(result); + + log_msg(LOG_VERBOSITY_INFO, + "\n[+] Resolved external IP (via '%s') as: %s", + wget_ssl_cmd, options->allow_ip_str); + return 1; } int From 460bd8c672ce8a0dc7df702b5ef6566e55647936 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 16:44:19 -0400 Subject: [PATCH 03/78] Be more consistent when creating ~/.fwknoprc --- client/config_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 90fd924a..14b757c1 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -867,9 +867,9 @@ create_fwknoprc(const char *rcfile) "#FW_TIMEOUT 30\n" "#SPA_SERVER_PORT 62201\n" "#SPA_SERVER_PROTO udp\n" - "#ALLOW_IP \n" + "#ALLOW_IP \n" "#SPOOF_USER \n" - "#SPOOF_SOURCE_IP \n" + "#SPOOF_SOURCE_IP \n" "#TIME_OFFSET 0\n" "#USE_GPG N\n" "#GPG_HOMEDIR /path/to/.gnupg\n" From a0dda67dfe795f1536d9ddeb8b3d5bf3c20cf2b8 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 16:53:14 -0400 Subject: [PATCH 04/78] Also catch the IPv6 version of INADDR_ANY --- client/config_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/config_init.c b/client/config_init.c index 14b757c1..44059a6f 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -1846,7 +1846,8 @@ validate_options(fko_cli_options_t *options) exit(EXIT_FAILURE); } else if(options->verbose - && strncmp(options->allow_ip_str, "0.0.0.0", strlen("0.0.0.0")) == 0) + && (strncmp(options->allow_ip_str, "0.0.0.0", strlen("0.0.0.0")) == 0 + || strncmp(options->allow_ip_str, "::", strlen("::")) == 0)) { log_msg(LOG_VERBOSITY_WARNING, "[-] WARNING: Should use -a or -R to harden SPA against potential MITM attacks"); From b3494dcfc125aacce2aa7cf8a353b6f23fae0447 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 17:07:49 -0400 Subject: [PATCH 05/78] Migrate is_valid_ipv4_addr() to a more generic function It is now called is_valid_ip_addr() and expects an additional parameter for the address family. --- client/config_init.c | 6 +++--- client/fwknop.c | 2 +- common/fko_util.c | 2 +- common/fko_util.h | 2 +- lib/fko_message.c | 2 +- server/incoming_spa.c | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 44059a6f..268ac64b 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -982,7 +982,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var_name, char * val) else /* Assume IP address and validate */ { strlcpy(options->allow_ip_str, val, sizeof(options->allow_ip_str)); - if(! is_valid_ipv4_addr(options->allow_ip_str, strlen(options->allow_ip_str))) + if(! is_valid_ip_addr(options->allow_ip_str, strlen(options->allow_ip_str), AF_INET)) parse_error = -1; } } @@ -1862,7 +1862,7 @@ validate_options(fko_cli_options_t *options) { options->resolve_ip_http_https = 0; - if(! is_valid_ipv4_addr(options->allow_ip_str, strlen(options->allow_ip_str))) + if(! is_valid_ip_addr(options->allow_ip_str, strlen(options->allow_ip_str), AF_UNSPEC)) { log_msg(LOG_VERBOSITY_ERROR, "Invalid allow IP specified for SPA access"); @@ -1872,7 +1872,7 @@ validate_options(fko_cli_options_t *options) if (options->spoof_ip_src_str[0] != 0x00) { - if(! is_valid_ipv4_addr(options->spoof_ip_src_str, strlen(options->spoof_ip_src_str))) + if(! is_valid_ip_addr(options->spoof_ip_src_str, strlen(options->spoof_ip_src_str), AF_UNSPEC)) { log_msg(LOG_VERBOSITY_ERROR, "Invalid spoof IP"); exit(EXIT_FAILURE); diff --git a/client/fwknop.c b/client/fwknop.c index 020c627f..b4f0592f 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -820,7 +820,7 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc } - if (is_valid_ipv4_addr(options->nat_access_str, hostlen) || is_valid_hostname(options->nat_access_str, hostlen)) + if (is_valid_ip_addr(options->nat_access_str, hostlen, AF_UNSPEC) || is_valid_hostname(options->nat_access_str, hostlen)) { snprintf(nat_access_buf, MAX_LINE_LEN, NAT_ACCESS_STR_TEMPLATE, options->nat_access_str, access_port); diff --git a/common/fko_util.c b/common/fko_util.c index ca9a58b7..53727eec 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -122,7 +122,7 @@ is_valid_encoded_msg_len(const int len) /* Validate an IPv4 address */ int -is_valid_ipv4_addr(const char * const ip_str, const int len) +is_valid_ip_addr(const char * const ip_str, const int len, const int family) { const char *ndx = ip_str; char tmp_ip_str[MAX_IPV4_STR_LEN + 1] = {0}; diff --git a/common/fko_util.h b/common/fko_util.h index c5ad8f56..3fa4115f 100644 --- a/common/fko_util.h +++ b/common/fko_util.h @@ -40,7 +40,7 @@ */ int is_valid_encoded_msg_len(const int len); int is_valid_pt_msg_len(const int len); -int is_valid_ipv4_addr(const char * const ip_str, const int len); +int is_valid_ip_addr(const char * const ip_str, const int len, const int family); int is_valid_hostname(const char * const hostname_str, const int len); int is_base64(const unsigned char * const buf, const unsigned short int len); void hex_dump(const unsigned char *data, const int size); diff --git a/lib/fko_message.c b/lib/fko_message.c index 2faa7052..c9e3defa 100644 --- a/lib/fko_message.c +++ b/lib/fko_message.c @@ -64,7 +64,7 @@ have_allow_ip(const char *msg) res = FKO_ERROR_INVALID_ALLOW_IP; if(res == FKO_SUCCESS) - if (! is_valid_ipv4_addr(ip_str, strlen(ip_str))) + if (! is_valid_ip_addr(ip_str, strlen(ip_str), AF_INET)) res = FKO_ERROR_INVALID_ALLOW_IP; return(res); diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 968162c9..00731c3a 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -119,7 +119,7 @@ preprocess_spa_data(const fko_srv_options_t *opts, spa_pkt_info_t *spa_pkt, spa_ xff -= i - 1; - if (!is_valid_ipv4_addr(xff, strlen(xff))) + if (!is_valid_ip_addr(xff, strlen(xff), AF_UNSPEC)) log_msg(LOG_WARNING, "Error parsing X-Forwarded-For header: value '%s' is not an IP address", xff); @@ -1088,8 +1088,8 @@ incoming_spa(fko_srv_options_t *opts) continue; } - if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1 - || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN) + if((spa_ip_demark-spadat.spa_message) < MIN_IPV46_STR_LEN-1 + || (spa_ip_demark-spadat.spa_message) > MAX_IPV46_STR_LEN) { log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet", @@ -1100,7 +1100,7 @@ incoming_spa(fko_srv_options_t *opts) strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1); - if(! is_valid_ipv4_addr(spadat.spa_message_src_ip, strlen(spadat.spa_message_src_ip))) + if(! is_valid_ip_addr(spadat.spa_message_src_ip, strlen(spadat.spa_message_src_ip), AF_UNSPEC)) { log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet", From aea56f54c45af2ba74e8681f4bd7f05e72eb56d5 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 17:44:27 -0400 Subject: [PATCH 06/78] Implement is_valid_ip_addr() with getaddrinfo() --- common/fko_util.c | 60 ++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index 53727eec..6e665b6e 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -124,52 +124,22 @@ is_valid_encoded_msg_len(const int len) int is_valid_ip_addr(const char * const ip_str, const int len, const int family) { - const char *ndx = ip_str; - char tmp_ip_str[MAX_IPV4_STR_LEN + 1] = {0}; - int dot_ctr = 0, char_ctr = 0; - int res = 1; -#if HAVE_SYS_SOCKET_H - struct in_addr in; -#endif - - if(ip_str == NULL) - return 0; - - if((len > MAX_IPV4_STR_LEN) || (len < MIN_IPV4_STR_LEN)) - return 0; - - while(char_ctr < len) - { - /* If we've hit a null within the given length, then not valid regardless */ - if(*ndx == '\0') - return 0; - - char_ctr++; - - if(*ndx == '.') - dot_ctr++; - else if(isdigit((int)(unsigned char)*ndx) == 0) - { - res = 0; - break; - } - ndx++; + struct addrinfo * result, hints; + int error; + char * p; + + if((p = strndup(ip_str, len)) == NULL) + return 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(p, NULL, &hints, &result); + free(p); + if (error) { + return 0; } - - if((res == 1) && (dot_ctr != 3)) - res = 0; - -#if HAVE_SYS_SOCKET_H - /* Stronger IP validation now that we have a candidate that looks - * close enough - */ - if(res == 1) { - strncpy(tmp_ip_str, ip_str, len); - if (inet_aton(tmp_ip_str, &in) == 0) - res = 0; - } -#endif - return(res); + freeaddrinfo(result); + return 1; } /* Validate a hostname From f7b18d64f3841be8ef4011d453f3655202395ee4 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 12 Jun 2018 17:45:19 -0400 Subject: [PATCH 07/78] Give have_allow_ip() a chance to allow IPv6 This greatly loosens the check for a valid IPv4/IPv6 there - but it is redundant anyway, since there is always a call to is_valid_ip_addr(). --- lib/fko_message.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/fko_message.c b/lib/fko_message.c index c9e3defa..02859bc2 100644 --- a/lib/fko_message.c +++ b/lib/fko_message.c @@ -35,7 +35,7 @@ static int have_allow_ip(const char *msg) { const char *ndx = msg; - char ip_str[MAX_IPV4_STR_LEN]; + char ip_str[MAX_IPV46_STR_LEN]; int dot_ctr = 0, char_ctr = 0; int res = FKO_SUCCESS; @@ -43,14 +43,14 @@ have_allow_ip(const char *msg) { ip_str[char_ctr] = *ndx; char_ctr++; - if(char_ctr >= MAX_IPV4_STR_LEN) + if(char_ctr >= sizeof(ip_str)) { res = FKO_ERROR_INVALID_ALLOW_IP; break; } - if(*ndx == '.') + if(*ndx == '.' || *ndx == ':') dot_ctr++; - else if(isdigit((int)(unsigned char)*ndx) == 0) + else if(isdigit((int)(unsigned char)*ndx) == 0 && !((*ndx >= 'a' && *ndx <= 'f') || (*ndx >= 'A' && *ndx <= 'F'))) { res = FKO_ERROR_INVALID_ALLOW_IP; break; @@ -58,13 +58,13 @@ have_allow_ip(const char *msg) ndx++; } - if(char_ctr < MAX_IPV4_STR_LEN) + if(char_ctr < sizeof(ip_str)) ip_str[char_ctr] = '\0'; else res = FKO_ERROR_INVALID_ALLOW_IP; if(res == FKO_SUCCESS) - if (! is_valid_ip_addr(ip_str, strlen(ip_str), AF_INET)) + if (! is_valid_ip_addr(ip_str, strlen(ip_str), AF_UNSPEC)) res = FKO_ERROR_INVALID_ALLOW_IP; return(res); From 2f6ea521ff54318fddda1c2bddd57fdde1d1193e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 14 Jun 2018 18:21:24 -0400 Subject: [PATCH 08/78] Allow connecting to remote IPv6 hosts for TCP or UDP This alone should allow interacting with IPv4 firewalling rules over IPv6, for these two protocols. --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index aae4a97e..a27650e5 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -98,7 +98,7 @@ send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len, memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; /* Allow IPv4 only */ + hints.ai_family = AF_UNSPEC; if (options->spa_proto == FKO_PROTO_UDP) { From 72a50b9c8e859cee8bc192b86d18aaeb06a530eb Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 14 Jun 2018 18:23:01 -0400 Subject: [PATCH 09/78] Use uppercase to log "IP" --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index a27650e5..67e7de9c 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -719,7 +719,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) if (resolve_dst_addr(options->spa_server_str, &hints, ip_str, sizeof(ip_str), options) != 0) { - log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address", + log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an IP address", options->spa_server_str); return -1; } From 2367bc23e86f27584e0633fbd9f0e6770cc3cab6 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 14 Jun 2018 19:18:06 -0400 Subject: [PATCH 10/78] Also check for and This will allow porting the raw ICMP code to IPv6. --- configure.ac | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 238e7128..9b8371b0 100644 --- a/configure.ac +++ b/configure.ac @@ -369,7 +369,15 @@ AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_RESOLV -AC_CHECK_HEADERS([arpa/inet.h ctype.h endian.h errno.h locale.h netdb.h net/ethernet.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/ethernet.h sys/socket.h sys/stat.h sys/time.h sys/wait.h termios.h time.h unistd.h]) +AC_CHECK_HEADERS([arpa/inet.h ctype.h endian.h errno.h locale.h netdb.h net/ethernet.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/ethernet.h sys/socket.h sys/stat.h sys/time.h sys/types.h sys/wait.h termios.h time.h unistd.h]) +AC_CHECK_HEADERS([netinet/ip6.h netinet/icmp6.h], [], [], +[#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +]) # Type checks. # From ce9b5fb36483581623a1ebe6d5c6fa8107ec918c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 16:38:11 -0400 Subject: [PATCH 11/78] Rework the network listening routine --- server/process_packet.c | 103 ++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/server/process_packet.c b/server/process_packet.c index 32e99cb2..c0c26784 100644 --- a/server/process_packet.c +++ b/server/process_packet.c @@ -41,49 +41,60 @@ #include "log_msg.h" +static void +process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen, int offset); +static void +process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, + int offset, unsigned char * fr_end); +static void +process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, + int offset, unsigned char * fr_end); +static void +process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet); + + void process_packet(PROCESS_PKT_ARGS_TYPE *args, PACKET_HEADER_META, const unsigned char *packet) { - struct ether_header *eth_p; - struct iphdr *iph_p; - struct tcphdr *tcph_p; - struct udphdr *udph_p; - struct icmphdr *icmph_p; - - unsigned char *pkt_data; - unsigned short pkt_data_len; - unsigned char *pkt_end; - unsigned char *fr_end; + fko_srv_options_t *opts = (fko_srv_options_t *)args; - unsigned int ip_hdr_words; + int offset = opts->data_link_offset; - unsigned char proto; - unsigned int src_ip; - unsigned int dst_ip; + if (offset != 0) +#if USE_LIBPCAP + process_packet_ethernet(opts, packet, packet_header->len, + packet_header->caplen, offset); +#else + process_packet_ethernet(opts, packet, pkt_len, pkt_len, offset); +#endif + else + process_packet_raw(opts, packet); +} - unsigned short src_port = 0; - unsigned short dst_port = 0; - unsigned short eth_type; +static void +process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen, int offset) +{ + struct ether_header *eth_p; - fko_srv_options_t *opts = (fko_srv_options_t *)args; + unsigned char *fr_end; - int offset = opts->data_link_offset; + unsigned short eth_type; #if USE_LIBPCAP - unsigned short pkt_len = packet_header->len; - /* Gotta have a complete ethernet header. */ - if (packet_header->caplen < ETHER_HDR_LEN) + if (caplen < ETHER_HDR_LEN) return; /* Determine packet end. */ - fr_end = (unsigned char *) packet + packet_header->caplen; + fr_end = (unsigned char *) packet + caplen; #else - /* This is coming from NFQ and we get the packet lentgh as an arg. + /* This is coming from NFQ and we get the packet length as an arg. */ if (pkt_len < ETHER_HDR_LEN) return; @@ -127,6 +138,35 @@ process_packet(PROCESS_PKT_ARGS_TYPE *args, PACKET_HEADER_META, if (! ETHER_IS_VALID_LEN(pkt_len) ) return; + if (eth_type == ETHERTYPE_IP) + process_packet_ipv4(opts, packet, offset, fr_end); + else if (eth_type == ETHERTYPE_IPV6) + process_packet_ipv6(opts, packet, offset, fr_end); +} + + +static void +process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, + int offset, unsigned char * fr_end) +{ + struct iphdr *iph_p; + struct tcphdr *tcph_p; + struct udphdr *udph_p; + struct icmphdr *icmph_p; + + unsigned char *pkt_data; + unsigned short pkt_data_len; + unsigned char *pkt_end; + + unsigned int ip_hdr_words; + + unsigned char proto; + unsigned int src_ip; + unsigned int dst_ip; + + unsigned short src_port = 0; + unsigned short dst_port = 0; + /* Pull the IP header. */ iph_p = (struct iphdr*)(packet + offset); @@ -236,4 +276,19 @@ process_packet(PROCESS_PKT_ARGS_TYPE *args, PACKET_HEADER_META, } +static void +process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, + int offset, unsigned char * fr_end) +{ + /* FIXME implement */ +} + + +static void +process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet) +{ + /* FIXME implement */ +} + + /***EOF***/ From 3dc61166a4a9df42794103d142efbf8c403e73bf Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 17:36:20 -0400 Subject: [PATCH 12/78] Rework the network listening routine some more --- server/process_packet.c | 84 +++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/server/process_packet.c b/server/process_packet.c index c0c26784..11b91d3e 100644 --- a/server/process_packet.c +++ b/server/process_packet.c @@ -46,12 +46,16 @@ process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, unsigned short pkt_len, int caplen, int offset); static void process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, - int offset, unsigned char * fr_end); + int offset, unsigned char const * fr_end); static void process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, - int offset, unsigned char * fr_end); + int offset, unsigned char const * fr_end); static void -process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet); +process_packet_loop(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen); +static void +process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen); void @@ -62,15 +66,19 @@ process_packet(PROCESS_PKT_ARGS_TYPE *args, PACKET_HEADER_META, int offset = opts->data_link_offset; - if (offset != 0) #if USE_LIBPCAP + if (offset == sizeof(struct ether_header)) process_packet_ethernet(opts, packet, packet_header->len, packet_header->caplen, offset); + else if (offset == 4) + process_packet_loop(opts, packet, packet_header->len, + packet_header->caplen); + else if (offset == 0) + process_packet_raw(opts, packet, packet_header->len, + packet_header->caplen); #else - process_packet_ethernet(opts, packet, pkt_len, pkt_len, offset); + process_packet_raw(opts, packet, pkt_len, pkt_len); #endif - else - process_packet_raw(opts, packet); } @@ -84,7 +92,6 @@ process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, unsigned short eth_type; -#if USE_LIBPCAP /* Gotta have a complete ethernet header. */ if (caplen < ETHER_HDR_LEN) @@ -93,13 +100,6 @@ process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, /* Determine packet end. */ fr_end = (unsigned char *) packet + caplen; -#else - /* This is coming from NFQ and we get the packet length as an arg. - */ - if (pkt_len < ETHER_HDR_LEN) - return; - fr_end = (unsigned char *) packet + pkt_len; -#endif /* This is a hack to determine if we are using the linux cooked * interface. We base it on the offset being 16 which is the @@ -147,7 +147,7 @@ process_packet_ethernet(fko_srv_options_t * opts, const unsigned char * packet, static void process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, - int offset, unsigned char * fr_end) + int offset, unsigned char const * fr_end) { struct iphdr *iph_p; struct tcphdr *tcph_p; @@ -278,16 +278,62 @@ process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, static void process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, - int offset, unsigned char * fr_end) + int offset, unsigned char const * fr_end) { /* FIXME implement */ } static void -process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet) +process_packet_loop(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen) { - /* FIXME implement */ + uint32_t family; + + if (caplen < sizeof(family)) + return; + + memcpy(&family, packet, sizeof(family)); + + if (family == AF_INET) + process_packet_ipv4(opts, packet, 4, packet + caplen); + else if (family == AF_INET6) + process_packet_ipv6(opts, packet, 4, packet + caplen); +} + + +static void +process_packet_raw(fko_srv_options_t * opts, const unsigned char * packet, + unsigned short pkt_len, int caplen) +{ + struct iphdr *iph_p; + + unsigned char const *fr_end; + + /* Gotta have a complete ethernet header. + */ + if (caplen < ETHER_HDR_LEN) + return; + + /* Determine packet end. + */ + fr_end = (unsigned char *) packet + caplen; + + /* Tentatively pull an IP header. + */ + iph_p = (struct iphdr*)packet; + + /* If IP header is past calculated packet end, bail. + */ + if ((unsigned char*)(iph_p + 1) > fr_end) + return; + + /* Obtain the IP version. + */ + if (iph_p->version == 6) + process_packet_ipv6(opts, packet, 0, fr_end); + else + process_packet_ipv4(opts, packet, 0, fr_end); } From 1a813bb2b8fcc15ae064de0e885df71cba44e8cd Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 18:16:15 -0400 Subject: [PATCH 13/78] Code cleanup --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index 67e7de9c..54f52cc5 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -427,7 +427,7 @@ send_spa_packet_icmp(const char *spa_data, const int sd_len, char pkt_data[2048] = {0}; struct iphdr *iph = (struct iphdr *) pkt_data; - struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (struct iphdr)); + struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (*iph)); int hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr); From a525734afca2d6b618b29675b684df90de46eccb Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 18:18:43 -0400 Subject: [PATCH 14/78] Also include where relevant --- common/netinet_common.h | 3 +++ server/fwknopd_common.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/common/netinet_common.h b/common/netinet_common.h index c761cb45..642557b6 100644 --- a/common/netinet_common.h +++ b/common/netinet_common.h @@ -45,6 +45,9 @@ #if HAVE_NETINET_IN_H #include #endif + #if HAVE_NETINET_IP6_H + #include + #endif #if PLATFORM_NETBSD || PLATFORM_OPENBSD /* for autoconf net/if.h difficulties */ #include #include diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 29959952..f7bfc48f 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -32,9 +32,12 @@ #include "common.h" -#if PLATFORM_OPENBSD +#if HAVE_NETINET_IN_H #include #endif +#if HAVE_NETINET_IP6_H + #include +#endif #if HAVE_SYS_STAT_H #include From 37a8000aa2ebf8ed6fce667950cff3d850691c18 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 18:23:13 -0400 Subject: [PATCH 15/78] Protect some more headers for inclusion --- common/fko_util.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index 6e665b6e..3a72cfb7 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -35,9 +35,15 @@ #ifndef WIN32 /* for inet_aton() IP validation */ - #include - #include - #include +# if HAVE_SYS_SOCKET_H +# include +#endif +# if HAVE_NETINET_IN_H +# include +# endif +# if HAVE_ARPA_INET_H +# include +# endif #endif /* Check for a FKO error returned by a function an return the error code */ From 6bcaf4f3e31667ad67ea4a2e278aa772a71f85d3 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 15 Jun 2018 18:24:50 -0400 Subject: [PATCH 16/78] Add support for receiving SPA messages over IPv6 --- server/fwknopd_common.h | 20 +++++++- server/process_packet.c | 105 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 5 deletions(-) diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index f7bfc48f..360e162a 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -603,12 +603,28 @@ typedef struct spa_pkt_info { unsigned int packet_data_len; unsigned int packet_proto; - unsigned int packet_src_ip; - unsigned int packet_dst_ip; + unsigned int packet_family; + union + { + struct + { + unsigned int src_ip; + unsigned int dst_ip; + } inet; +#if HAVE_NETINET_IP6_H + struct + { + struct in6_addr src_ip; + struct in6_addr dst_ip; + } inet6; +#endif + } packet_addr; unsigned short packet_src_port; unsigned short packet_dst_port; unsigned char packet_data[MAX_SPA_PACKET_LEN+1]; } spa_pkt_info_t; +#define packet_src_ip packet_addr.inet.src_ip +#define packet_dst_ip packet_addr.inet.dst_ip /* Struct for (processed and verified) SPA data used by the server. */ diff --git a/server/process_packet.c b/server/process_packet.c index 11b91d3e..9b3f786b 100644 --- a/server/process_packet.c +++ b/server/process_packet.c @@ -265,14 +265,13 @@ process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, opts->spa_pkt.packet_data_len = pkt_data_len; opts->spa_pkt.packet_proto = proto; + opts->spa_pkt.packet_family = AF_INET; opts->spa_pkt.packet_src_ip = src_ip; opts->spa_pkt.packet_dst_ip = dst_ip; opts->spa_pkt.packet_src_port = src_port; opts->spa_pkt.packet_dst_port = dst_port; incoming_spa(opts); - - return; } @@ -280,7 +279,107 @@ static void process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, int offset, unsigned char const * fr_end) { - /* FIXME implement */ + struct ip6_hdr *iph_p; + struct tcphdr *tcph_p; + struct udphdr *udph_p; + + unsigned char *pkt_data; + unsigned short pkt_data_len; + unsigned char *pkt_end; + + unsigned char proto; + struct in6_addr src_ip; + struct in6_addr dst_ip; + + unsigned short src_port = 0; + unsigned short dst_port = 0; + + /* Pull the IPv6 header. + */ + iph_p = (struct ip6_hdr*)(packet + offset); + + /* If IPv6 header is past calculated packet end, bail. + */ + if ((unsigned char*)(iph_p + 1) > fr_end) + return; + + /* Make sure to calculate the packet end based on the length in the + * IP header. This allows additional bytes that may be added to the + * frame (such as a 4-byte Ethernet Frame Check Sequence) to not + * interfere with SPA operations. + */ + pkt_end = ((unsigned char*)iph_p)+ntohs(iph_p->ip6_plen); + if(pkt_end > fr_end) + return; + + /* Now, find the packet data payload (depending on IPPROTO). + */ + src_ip = iph_p->ip6_src; + dst_ip = iph_p->ip6_dst; + + /* FIXME look for the last header */ + proto = iph_p->ip6_nxt; + + if (proto == IPPROTO_TCP) + { + /* Process TCP packet + */ + tcph_p = (struct tcphdr*)(iph_p + 1); + + src_port = ntohs(tcph_p->source); + dst_port = ntohs(tcph_p->dest); + + pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr); + + pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + } + else if (proto == IPPROTO_UDP) + { + /* Process UDP packet + */ + udph_p = (struct udphdr*)(iph_p + 1); + + src_port = ntohs(udph_p->source); + dst_port = ntohs(udph_p->dest); + + pkt_data = ((unsigned char*)(udph_p + 1)); + pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + } + + else + return; + + /* + * Now we have data. For now, we are not checking IP or port values. We + * are relying on the pcap filter. This may change so we do retain the IP + * addresses and ports just in case. We just go ahead and queue the + * data. + */ + + /* Expect the data to be at least the minimum required size. This check + * will weed out a lot of things like small TCP ACK's if the user has a + * permissive pcap filter + */ + if(pkt_data_len < MIN_SPA_DATA_SIZE) + return; + + /* Expect the data to not be too large + */ + if(pkt_data_len > MAX_SPA_PACKET_LEN) + return; + + /* Copy the packet for SPA processing + */ + strlcpy((char *)opts->spa_pkt.packet_data, (char *)pkt_data, pkt_data_len+1); + opts->spa_pkt.packet_data_len = pkt_data_len; + opts->spa_pkt.packet_proto = proto; + opts->spa_pkt.packet_family = AF_INET6; + opts->spa_pkt.packet_addr.inet6.src_ip = src_ip; + opts->spa_pkt.packet_addr.inet6.dst_ip = dst_ip; + opts->spa_pkt.packet_src_port = src_port; + opts->spa_pkt.packet_dst_port = dst_port; + + incoming_spa(opts); } From 8ecd10b4c0836b18cebf36e509c02a2a4ede0212 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 26 Jun 2018 02:20:12 +0200 Subject: [PATCH 17/78] Interpret incoming addresses according to their family --- server/fwknopd_common.h | 8 ++++---- server/incoming_spa.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 360e162a..f6bf5a6f 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -635,10 +635,10 @@ typedef struct spa_data char *version; short message_type; char *spa_message; - char spa_message_src_ip[MAX_IPV4_STR_LEN]; - char pkt_source_ip[MAX_IPV4_STR_LEN]; - char pkt_source_xff_ip[MAX_IPV4_STR_LEN]; - char pkt_destination_ip[MAX_IPV4_STR_LEN]; + char spa_message_src_ip[MAX_IPV46_STR_LEN]; + char pkt_source_ip[MAX_IPV46_STR_LEN]; + char pkt_source_xff_ip[MAX_IPV46_STR_LEN]; + char pkt_destination_ip[MAX_IPV46_STR_LEN]; char spa_message_remain[1024]; /* --DSS FIXME: arbitrary bounds */ char *nat_access; char *server_auth; diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 00731c3a..34984aa4 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -930,10 +930,10 @@ incoming_spa(fko_srv_options_t *opts) */ acc_stanza_t *acc = opts->acc_stanzas; - inet_ntop(AF_INET, &(spa_pkt->packet_src_ip), + inet_ntop(spa_pkt->packet_family, &(spa_pkt->packet_src_ip), spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); - inet_ntop(AF_INET, &(spa_pkt->packet_dst_ip), + inet_ntop(spa_pkt->packet_family, &(spa_pkt->packet_dst_ip), spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip)); /* At this point, we want to validate and (if needed) preprocess the From 89c7d6f8b9ae73d2b414d5ea2f412a84a1ab566d Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 26 Jun 2018 03:20:44 +0200 Subject: [PATCH 18/78] Let access list stanzas be defined in IPv6 --- server/access.c | 53 +++++++++++++++++++++++++++++++---------- server/access.h | 2 +- server/fwknopd_common.h | 16 +++++++++++-- server/incoming_spa.c | 30 ++++++++++++++++------- 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/server/access.c b/server/access.c index d2abee91..04a197bc 100644 --- a/server/access.c +++ b/server/access.c @@ -373,8 +373,9 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) */ if(strcasecmp(ip, "ANY") == 0) { - new_sle->maddr = 0x0; - new_sle->mask = 0x0; + new_sle->family = AF_INET; + new_sle->acc_int.inet.maddr = 0x0; + new_sle->acc_int.inet.mask = 0x0; } else { @@ -473,17 +474,18 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) /* Store our mask converted from CIDR to a 32-bit value. */ + new_sle->family = AF_INET; if(mask == 32) - new_sle->mask = 0xFFFFFFFF; + new_sle->acc_int.inet.mask = 0xFFFFFFFF; else if(need_shift && (mask > 0 && mask < 32)) - new_sle->mask = (0xFFFFFFFF << (32 - mask)); + new_sle->acc_int.inet.mask = (0xFFFFFFFF << (32 - mask)); else - new_sle->mask = mask; + new_sle->acc_int.inet.mask = mask; /* Store our masked address for comparisons with future incoming * packets. */ - new_sle->maddr = ntohl(in.s_addr) & new_sle->mask; + new_sle->acc_int.inet.maddr = ntohl(in.s_addr) & new_sle->acc_int.inet.mask; } /* If this is not the first entry, we walk our pointer to the @@ -2070,22 +2072,49 @@ int valid_access_stanzas(acc_stanza_t *acc) } int -compare_addr_list(acc_int_list_t *ip_list, const uint32_t ip) +compare_addr_list(acc_int_list_t *ip_list, int family, ...) { - int match = 0; + va_list ap; + uint32_t ip; + struct in6_addr * ip6; + va_start(ap, family); + switch(family) + { + case AF_INET: + ip = va_arg(ap, uint32_t); + break; + case AF_INET6: + ip6 = va_arg(ap, struct in6_addr *); + break; + default: + va_end(ap); + return 0; + } + va_end(ap); while(ip_list) { - if((ip & ip_list->mask) == (ip_list->maddr & ip_list->mask)) + if(ip_list->family != family) { - match = 1; - break; + ip_list = ip_list->next; + continue; + } + switch(family) + { + case AF_INET: + if((ip & ip_list->acc_int.inet.mask) == (ip_list->acc_int.inet.maddr & ip_list->acc_int.inet.mask)) + return 1; + break; + case AF_INET6: + if(memcmp(&ip_list->acc_int.inet6.maddr, ip6, sizeof(*ip6)) == 0) + return 1; + break; } ip_list = ip_list->next; } - return(match); + return 0; } /** diff --git a/server/access.h b/server/access.h index 02dc9b19..d4fb045e 100644 --- a/server/access.h +++ b/server/access.h @@ -114,7 +114,7 @@ int valid_access_stanzas(acc_stanza_t *acc); * \return Returns true on a match * */ -int compare_addr_list(acc_int_list_t *source_list, const uint32_t ip); +int compare_addr_list(acc_int_list_t *source_list, int family, ...); /** * \brief Check for a proto-port string diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index f6bf5a6f..e202938e 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -361,8 +361,20 @@ enum { */ typedef struct acc_int_list { - unsigned int maddr; - unsigned int mask; + int family; + union + { + struct + { + unsigned int maddr; + unsigned int mask; + } inet; + struct + { + struct in6_addr maddr; + unsigned int prefix; + } inet6; + } acc_int; struct acc_int_list *next; } acc_int_list_t; diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 34984aa4..8bca0e79 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -347,14 +347,28 @@ check_stanza_expiration(acc_stanza_t *acc, spa_data_t *spadat, * source IP */ static int -is_src_match(acc_stanza_t *acc, const uint32_t ip) +is_src_match(acc_stanza_t *acc, const spa_pkt_info_t *spa_pkt) { - while (acc) + switch (spa_pkt->packet_family) { - if(compare_addr_list(acc->source_list, ip)) - return 1; + case AF_INET: + while (acc) + { + if(compare_addr_list(acc->source_list, AF_INET, ntohl(spa_pkt->packet_addr.inet.src_ip))) + return 1; - acc = acc->next; + acc = acc->next; + } + break; + case AF_INET6: + while (acc) + { + if(compare_addr_list(acc->source_list, AF_INET6, &spa_pkt->packet_addr.inet6.src_ip)) + return 1; + + acc = acc->next; + } + break; } return 0; } @@ -363,7 +377,7 @@ static int src_check(fko_srv_options_t *opts, spa_pkt_info_t *spa_pkt, spa_data_t *spadat, char **raw_digest) { - if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip))) + if (is_src_match(opts->acc_stanzas, spa_pkt)) { if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0) { @@ -427,9 +441,9 @@ static int src_dst_check(acc_stanza_t *acc, spa_pkt_info_t *spa_pkt, spa_data_t *spadat, const int stanza_num) { - if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)) || + if(! compare_addr_list(acc->source_list, AF_INET, ntohl(spa_pkt->packet_src_ip)) || (acc->destination_list != NULL - && ! compare_addr_list(acc->destination_list, ntohl(spa_pkt->packet_dst_ip)))) + && ! compare_addr_list(acc->destination_list, AF_INET, ntohl(spa_pkt->packet_dst_ip)))) { log_msg(LOG_DEBUG, "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria", From bd1c488cbde2c4132fac90f4a54fb93a8ccda02a Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 26 Jun 2018 03:23:12 +0200 Subject: [PATCH 19/78] Typo --- server/incoming_spa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 8bca0e79..673bcae4 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -254,7 +254,7 @@ get_raw_digest(char **digest, char *pkt_data) return res; } -/* Popluate a spa_data struct from an initialized (and populated) FKO context. +/* Populate a spa_data struct from an initialized (and populated) FKO context. */ static int get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat) From a2462c6c3edc56d2d700af7244203aa80168f579 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 26 Jun 2018 03:23:53 +0200 Subject: [PATCH 20/78] Typo --- perl/FKO/lib/FKO.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perl/FKO/lib/FKO.pm b/perl/FKO/lib/FKO.pm index 6e79d71d..a1a2608c 100644 --- a/perl/FKO/lib/FKO.pm +++ b/perl/FKO/lib/FKO.pm @@ -614,7 +614,7 @@ can be found at http://www.cipherdyne.org/fwknop. =item B The C method creates the I object. With no arguments, it creates -creates and empty I object ready to be popluated with data (i.e. create +creates and empty I object ready to be populated with data (i.e. create a new SPA data packet to send). You can also pass existing encoded/encrypted I data, a decryption From 82a5eec5713554c431dd5b1e7a76d199aaba9375 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 13:52:45 +0200 Subject: [PATCH 21/78] Constify --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index 54f52cc5..249033d6 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -429,7 +429,7 @@ send_spa_packet_icmp(const char *spa_data, const int sd_len, struct iphdr *iph = (struct iphdr *) pkt_data; struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (*iph)); - int hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr); + const size_t hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr); /* Values for setsockopt. */ From 17549b93be54277f30c0462ad3d6b513f3ddfb29 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 15:28:14 +0200 Subject: [PATCH 22/78] Use a more appropriate type for sd_len --- client/spa_comm.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index 249033d6..34ac5e65 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -82,7 +82,7 @@ chksum(unsigned short *buf, int nbytes) /* Send the SPA data via UDP packet. */ static int -send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len, +send_spa_packet_tcp_or_udp(const char *spa_data, const size_t sd_len, const fko_cli_options_t *options) { int sock=-1, sock_success=0, res=0, error; @@ -201,7 +201,7 @@ send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len, /* Send the SPA data via raw TCP packet. */ static int -send_spa_packet_tcp_raw(const char *spa_data, const int sd_len, +send_spa_packet_tcp_raw(const char *spa_data, const size_t sd_len, const struct sockaddr_in *saddr, const struct sockaddr_in *daddr, const fko_cli_options_t *options) { @@ -300,7 +300,7 @@ send_spa_packet_tcp_raw(const char *spa_data, const int sd_len, else if(res != sd_len + hdrlen) /* account for the header ?*/ { log_msg(LOG_VERBOSITY_WARNING, - "[#] Warning: bytes sent (%i) not spa data length (%i).", + "[#] Warning: bytes sent (%i) not spa data length (%zi).", res, sd_len ); } @@ -315,7 +315,7 @@ send_spa_packet_tcp_raw(const char *spa_data, const int sd_len, /* Send the SPA data via raw UDP packet. */ static int -send_spa_packet_udp_raw(const char *spa_data, const int sd_len, +send_spa_packet_udp_raw(const char *spa_data, const size_t sd_len, const struct sockaddr_in *saddr, const struct sockaddr_in *daddr, const fko_cli_options_t *options) { @@ -400,7 +400,7 @@ send_spa_packet_udp_raw(const char *spa_data, const int sd_len, else if(res != sd_len + hdrlen) /* account for the header ?*/ { log_msg(LOG_VERBOSITY_WARNING, - "[#] Warning: bytes sent (%i) not spa data length (%i).", + "[#] Warning: bytes sent (%i) not spa data length (%zi).", res, sd_len ); } @@ -415,7 +415,7 @@ send_spa_packet_udp_raw(const char *spa_data, const int sd_len, /* Send the SPA data via ICMP packet. */ static int -send_spa_packet_icmp(const char *spa_data, const int sd_len, +send_spa_packet_icmp(const char *spa_data, const size_t sd_len, const struct sockaddr_in *saddr, const struct sockaddr_in *daddr, const fko_cli_options_t *options) { @@ -519,12 +519,13 @@ send_spa_packet_icmp(const char *spa_data, const int sd_len, /* Send the SPA data packet via an HTTP request */ static int -send_spa_packet_http(const char *spa_data, const int sd_len, +send_spa_packet_http(const char *spa_data, const size_t sd_len, fko_cli_options_t *options) { - char http_buf[HTTP_MAX_REQUEST_LEN] = {0}, *spa_data_copy = NULL; - char *ndx = options->http_proxy; - int i, proxy_port = 0, is_err; + char http_buf[HTTP_MAX_REQUEST_LEN] = {0}, *spa_data_copy = NULL; + char *ndx = options->http_proxy; + int proxy_port = 0, is_err; + size_t i; spa_data_copy = malloc(sd_len+1); if (spa_data_copy == NULL) @@ -622,11 +623,12 @@ send_spa_packet_http(const char *spa_data, const int sd_len, int send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) { - int res, sd_len; + int res; char *spa_data; struct sockaddr_in saddr, daddr; char ip_str[INET_ADDRSTRLEN] = {0}; /* String used to contain the ip address of an hostname */ struct addrinfo hints; /* Structure used to set hints to resolve hostname */ + size_t sd_len; #ifdef WIN32 WSADATA wsa_data; #endif From d1c1373980929cf108267b96a39e460c9aa0da3c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 15:57:28 +0200 Subject: [PATCH 23/78] Allow access control "ANY" with any protocol family --- server/access.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/access.c b/server/access.c index 04a197bc..1a6f167f 100644 --- a/server/access.c +++ b/server/access.c @@ -373,9 +373,8 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) */ if(strcasecmp(ip, "ANY") == 0) { - new_sle->family = AF_INET; - new_sle->acc_int.inet.maddr = 0x0; - new_sle->acc_int.inet.mask = 0x0; + new_sle->family = AF_UNSPEC; + memset(&new_sle->acc_int, 0, sizeof(new_sle->acc_int)); } else { @@ -2094,6 +2093,8 @@ compare_addr_list(acc_int_list_t *ip_list, int family, ...) va_end(ap); while(ip_list) { + if(ip_list->family == AF_UNSPEC) + return 1; if(ip_list->family != family) { ip_list = ip_list->next; From baed23c50c0fdcd3cd68c9ac4ee6822a9dd978da Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 17:24:59 +0200 Subject: [PATCH 24/78] Use AF_INET instead of PF_INET I believe it should be more portable this way, since AF_INET is required to be present in in POSIX. --- client/spa_comm.c | 6 +++--- server/tcp_server.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index 34ac5e65..c22fa7fe 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -230,7 +230,7 @@ send_spa_packet_tcp_raw(const char *spa_data, const size_t sd_len, return res; } - sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW); + sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (sock < 0) { log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_tcp_raw: create socket: ", strerror(errno)); @@ -344,7 +344,7 @@ send_spa_packet_udp_raw(const char *spa_data, const size_t sd_len, return res; } - sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW); + sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (sock < 0) { log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_udp_raw: create socket: ", strerror(errno)); @@ -443,7 +443,7 @@ send_spa_packet_icmp(const char *spa_data, const size_t sd_len, return res; } - sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW); + sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (sock < 0) { diff --git a/server/tcp_server.c b/server/tcp_server.c index 7ba55bf1..6ae1dbe6 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -94,7 +94,7 @@ run_tcp_server(fko_srv_options_t *opts) /* Now, let's make a TCP server */ - if ((s_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + if ((s_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { log_msg(LOG_ERR, "run_tcp_server: socket() failed: %s", strerror(errno)); From f61a3085f04476e6318523e3833536cdb5f5fa54 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 17:58:26 +0200 Subject: [PATCH 25/78] Use sizeof() instead of re-using hard-coded values This should help with portability for the protocol family eventually. --- 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 6ae1dbe6..65a72e1b 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -225,8 +225,8 @@ run_tcp_server(fko_srv_options_t *opts) if(opts->verbose) { - memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); + memset(sipbuf, 0x0, sizeof(sipbuf)); + inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); } From b070e80623baafa24b046627616f8b5d37b49885 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 18:22:03 +0200 Subject: [PATCH 26/78] Use sizeof() instead of re-using hard-coded values This should help with portability for the protocol family eventually. --- server/udp_server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/udp_server.c b/server/udp_server.c index d5e837fe..7c1f6fda 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -193,8 +193,8 @@ run_udp_server(fko_srv_options_t *opts) if(opts->verbose) { - memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); + memset(sipbuf, 0x0, sizeof(sipbuf)); + inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s", pkt_len, sipbuf); } From da1ab0563dae849539497600aa2f0ac166e8801e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 9 Jul 2018 18:34:57 +0200 Subject: [PATCH 27/78] Use a constant for AF_INET This should eventually help with portability to IPv6. --- server/tcp_server.c | 7 ++++--- server/udp_server.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/server/tcp_server.c b/server/tcp_server.c index 65a72e1b..6dc8a8af 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -53,6 +53,7 @@ int run_tcp_server(fko_srv_options_t *opts) { + const int family = AF_INET; #if !CODE_COVERAGE pid_t pid, ppid; #endif @@ -94,7 +95,7 @@ run_tcp_server(fko_srv_options_t *opts) /* Now, let's make a TCP server */ - if ((s_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + if ((s_sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) { log_msg(LOG_ERR, "run_tcp_server: socket() failed: %s", strerror(errno)); @@ -136,7 +137,7 @@ run_tcp_server(fko_srv_options_t *opts) /* Construct local address structure */ memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; /* Internet address family */ + saddr.sin_family = family; /* Internet address family */ saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ saddr.sin_port = htons(opts->tcpserv_port); /* Local port */ @@ -226,7 +227,7 @@ run_tcp_server(fko_srv_options_t *opts) if(opts->verbose) { memset(sipbuf, 0x0, sizeof(sipbuf)); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); + inet_ntop(family, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); } diff --git a/server/udp_server.c b/server/udp_server.c index 7c1f6fda..ca799991 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -52,6 +52,7 @@ int run_udp_server(fko_srv_options_t *opts) { + const int family = AF_INET; int s_sock, sfd_flags, selval, pkt_len; int rv=1, chk_rm_all=0; fd_set sfd_set; @@ -66,7 +67,7 @@ run_udp_server(fko_srv_options_t *opts) /* Now, let's make a UDP server */ - if ((s_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if ((s_sock = socket(family, SOCK_DGRAM, 0)) < 0) { log_msg(LOG_ERR, "run_udp_server: socket() failed: %s", strerror(errno)); @@ -96,7 +97,7 @@ run_udp_server(fko_srv_options_t *opts) /* Construct local address structure */ memset(&saddr, 0x0, sizeof(saddr)); - saddr.sin_family = AF_INET; /* Internet address family */ + saddr.sin_family = family; /* Internet address family */ saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ saddr.sin_port = htons(opts->udpserv_port); /* Local port */ @@ -194,7 +195,7 @@ run_udp_server(fko_srv_options_t *opts) if(opts->verbose) { memset(sipbuf, 0x0, sizeof(sipbuf)); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); + inet_ntop(family, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s", pkt_len, sipbuf); } From 76d609bac6c4752cf9543094ce59dcd8a2a5bc2c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 12:12:05 +0200 Subject: [PATCH 28/78] Use /usr/bin/env to locate perl --- test/test-fwknop.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 0f87987a..8b55c7b6 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl -w # # This is the main driver program for the fwknop test suite. Test definitions # are imported from the tests/ directory. From 587a4fbcb170740767e462b50ce4f9c4a84a7990 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 12:58:36 +0200 Subject: [PATCH 29/78] Rework IPv6 support when comparing addresses --- server/access.c | 63 ++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/server/access.c b/server/access.c index 1a6f167f..b069b606 100644 --- a/server/access.c +++ b/server/access.c @@ -2070,9 +2070,40 @@ int valid_access_stanzas(acc_stanza_t *acc) return 1; } +static int +compare_addr_list_ipv4(acc_int_list_t *ip_list, uint32_t ip) +{ + for(; ip_list; ip_list = ip_list->next) + { + if(ip_list->family == AF_UNSPEC) + return 1; + if(ip_list->family != AF_INET6) + continue; + if((ip & ip_list->acc_int.inet.mask) == (ip_list->acc_int.inet.maddr & ip_list->acc_int.inet.mask)) + return 1; + } + return 0; +} + +static int +compare_addr_list_ipv6(acc_int_list_t *ip_list, struct in6_addr *ip6) +{ + for(; ip_list; ip_list = ip_list->next) + { + if(ip_list->family == AF_UNSPEC) + return 1; + if(ip_list->family != AF_INET6) + continue; + if(memcmp(&ip_list->acc_int.inet6.maddr, ip6, sizeof(*ip6)) == 0) + return 1; + } + return 0; +} + int compare_addr_list(acc_int_list_t *ip_list, int family, ...) { + int res; va_list ap; uint32_t ip; struct in6_addr * ip6; @@ -2082,40 +2113,18 @@ compare_addr_list(acc_int_list_t *ip_list, int family, ...) { case AF_INET: ip = va_arg(ap, uint32_t); + res = compare_addr_list_ipv4(ip_list, ip); break; case AF_INET6: ip6 = va_arg(ap, struct in6_addr *); + res = compare_addr_list_ipv6(ip_list, ip6); break; default: - va_end(ap); - return 0; + res = 0; + break; } va_end(ap); - while(ip_list) - { - if(ip_list->family == AF_UNSPEC) - return 1; - if(ip_list->family != family) - { - ip_list = ip_list->next; - continue; - } - switch(family) - { - case AF_INET: - if((ip & ip_list->acc_int.inet.mask) == (ip_list->acc_int.inet.maddr & ip_list->acc_int.inet.mask)) - return 1; - break; - case AF_INET6: - if(memcmp(&ip_list->acc_int.inet6.maddr, ip6, sizeof(*ip6)) == 0) - return 1; - break; - } - - ip_list = ip_list->next; - } - - return 0; + return res; } /** From 11e9b29f244ef904d6f16ea063021cf4098fe5d8 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 13:01:53 +0200 Subject: [PATCH 30/78] Fix processing command-line arguments with whitespace --- test/run-test-suite.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-test-suite.sh b/test/run-test-suite.sh index 56a71abc..feb77e49 100755 --- a/test/run-test-suite.sh +++ b/test/run-test-suite.sh @@ -9,6 +9,6 @@ # to work properly. # -LD_LIBRARY_PATH=../lib/.libs DYLD_LIBRARY_PATH=../lib/.libs ./test-fwknop.pl $@ +LD_LIBRARY_PATH=../lib/.libs DYLD_LIBRARY_PATH=../lib/.libs ./test-fwknop.pl "$@" exit From d6ce22b989cdf27584ccfff7fdb529b6d199e979 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 15:29:20 +0200 Subject: [PATCH 31/78] Set the address family for incoming SPA over UDP --- server/udp_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server/udp_server.c b/server/udp_server.c index ca799991..620ba1c9 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -209,6 +209,7 @@ run_udp_server(fko_srv_options_t *opts) 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_family = family; 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); From 32cdd1183e79c81d69b4be3cfe8a94890bd189b5 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 15:43:10 +0200 Subject: [PATCH 32/78] Specify the family at run-time for TCP/UDP servers This is still using IPv4 by default for the moment. --- server/fwknopd.c | 4 ++-- server/pcap_capture.c | 2 +- server/tcp_server.c | 3 +-- server/tcp_server.h | 2 +- server/udp_server.c | 3 +-- server/udp_server.h | 2 +- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/server/fwknopd.c b/server/fwknopd.c index d7b1abff..4fbad5c0 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -259,7 +259,7 @@ main(int argc, char **argv) if(opts.enable_udp_server || strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) { - if(run_udp_server(&opts) < 0) + if(run_udp_server(&opts, AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_udp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); @@ -280,7 +280,7 @@ main(int argc, char **argv) */ if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0) { - if(run_tcp_server(&opts) < 0) + if(run_tcp_server(&opts, AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_tcp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); diff --git a/server/pcap_capture.c b/server/pcap_capture.c index e25904b5..73678feb 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -211,7 +211,7 @@ pcap_capture(fko_srv_options_t *opts) /* Attempt to restart tcp server ? */ usleep(1000000); - run_tcp_server(opts); + run_tcp_server(opts, AF_INET); } } diff --git a/server/tcp_server.c b/server/tcp_server.c index 6dc8a8af..5ea2cabe 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -51,9 +51,8 @@ * the child process or -1 if there is a fork error. */ int -run_tcp_server(fko_srv_options_t *opts) +run_tcp_server(fko_srv_options_t *opts, int family) { - const int family = AF_INET; #if !CODE_COVERAGE pid_t pid, ppid; #endif diff --git a/server/tcp_server.h b/server/tcp_server.h index 13db296e..9368efb9 100644 --- a/server/tcp_server.h +++ b/server/tcp_server.h @@ -32,7 +32,7 @@ /* Function prototypes */ -int run_tcp_server(fko_srv_options_t *opts); +int run_tcp_server(fko_srv_options_t *opts, int family); #endif /* TCP_SERVER_H */ diff --git a/server/udp_server.c b/server/udp_server.c index 620ba1c9..f56a9b27 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -50,9 +50,8 @@ #include int -run_udp_server(fko_srv_options_t *opts) +run_udp_server(fko_srv_options_t *opts, int family) { - const int family = AF_INET; int s_sock, sfd_flags, selval, pkt_len; int rv=1, chk_rm_all=0; fd_set sfd_set; diff --git a/server/udp_server.h b/server/udp_server.h index dcbdfec2..c601b66b 100644 --- a/server/udp_server.h +++ b/server/udp_server.h @@ -32,7 +32,7 @@ /* Function prototypes */ -int run_udp_server(fko_srv_options_t *opts); +int run_udp_server(fko_srv_options_t *opts, int family); #endif /* UDP_SERVER_H */ From f35c1d7cb7a625c909ca0933e41519c8ac91c78d Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jul 2018 16:25:20 +0200 Subject: [PATCH 33/78] Add IPv6 support to the plain UDP and TCP servers --- server/tcp_server.c | 38 ++++++++++++++++++------ server/udp_server.c | 71 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 83 insertions(+), 26 deletions(-) diff --git a/server/tcp_server.c b/server/tcp_server.c index 5ea2cabe..eeed1d7a 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -60,8 +60,9 @@ run_tcp_server(fko_srv_options_t *opts, int family) int reuse_addr = 1, rv=1; fd_set sfd_set; struct sockaddr_in saddr, caddr; + struct sockaddr_in6 saddr6, caddr6; struct timeval tv; - char sipbuf[MAX_IPV4_STR_LEN] = {0}; + char sipbuf[MAX_IPV46_STR_LEN] = {0}; log_msg(LOG_INFO, "Kicking off TCP server to listen on port %i.", opts->tcpserv_port); @@ -135,13 +136,29 @@ run_tcp_server(fko_srv_options_t *opts, int family) #endif /* Construct local address structure */ - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = family; /* Internet address family */ - saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ - saddr.sin_port = htons(opts->tcpserv_port); /* Local port */ + if(family == AF_INET) + { + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = family; /* Internet address family */ + saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + saddr.sin_port = htons(opts->tcpserv_port); /* Local port */ + } else if(family == AF_INET6) { + memset(&saddr6, 0, sizeof(saddr6)); + saddr6.sin6_family = family; /* Internet address family */ + saddr6.sin6_addr = in6addr_any; /* Any incoming interface */ + saddr6.sin6_port = htons(opts->tcpserv_port); /* Local port */ + } + else + { + log_msg(LOG_ERR, "run_tcp_server: unsupported protocol family (%d)", + family); + close(s_sock); + return -1; + } /* Bind to the local address */ - if (bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + if ((family == AF_INET && bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + || (family == AF_INET6 && bind(s_sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0)) { log_msg(LOG_ERR, "run_tcp_server: bind() failed: %s", strerror(errno)); @@ -172,7 +189,7 @@ run_tcp_server(fko_srv_options_t *opts, int family) */ while(1) { - clen = sizeof(caddr); + clen = (family == AF_INET) ? sizeof(caddr) : sizeof(caddr6); /* Initialize and setup the socket for select. */ @@ -225,8 +242,11 @@ run_tcp_server(fko_srv_options_t *opts, int family) if(opts->verbose) { - memset(sipbuf, 0x0, sizeof(sipbuf)); - inet_ntop(family, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); + memset(sipbuf, 0, sizeof(sipbuf)); + if(family == AF_INET) + inet_ntop(family, &caddr.sin_addr.s_addr, sipbuf, sizeof(sipbuf)); + else if(family == AF_INET6) + inet_ntop(family, &caddr6.sin6_addr, sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); } diff --git a/server/udp_server.c b/server/udp_server.c index f56a9b27..be95f4ea 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -56,8 +56,9 @@ run_udp_server(fko_srv_options_t *opts, int family) int rv=1, chk_rm_all=0; fd_set sfd_set; struct sockaddr_in saddr, caddr; + struct sockaddr_in6 saddr6, caddr6; struct timeval tv; - char sipbuf[MAX_IPV4_STR_LEN] = {0}; + char sipbuf[MAX_IPV46_STR_LEN] = {0}; char dgram_msg[MAX_SPA_PACKET_LEN+1] = {0}; socklen_t clen; @@ -95,13 +96,29 @@ run_udp_server(fko_srv_options_t *opts, int family) } /* Construct local address structure */ - memset(&saddr, 0x0, sizeof(saddr)); - saddr.sin_family = family; /* Internet address family */ - saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ - saddr.sin_port = htons(opts->udpserv_port); /* Local port */ + if(family == AF_INET) + { + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = family; /* Internet address family */ + saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + saddr.sin_port = htons(opts->udpserv_port); /* Local port */ + } else if(family == AF_INET6) { + memset(&saddr6, 0, sizeof(saddr6)); + saddr6.sin6_family = family; /* Internet address family */ + saddr6.sin6_addr = in6addr_any; /* Any incoming interface */ + saddr6.sin6_port = htons(opts->udpserv_port); /* Local port */ + } + else + { + log_msg(LOG_ERR, "run_udp_server: unsupported protocol family (%d)", + family); + close(s_sock); + return -1; + } /* Bind to the local address */ - if (bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + if ((family == AF_INET && bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + || (family == AF_INET6 && bind(s_sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0)) { log_msg(LOG_ERR, "run_udp_server: bind() failed: %s", strerror(errno)); @@ -184,17 +201,27 @@ run_udp_server(fko_srv_options_t *opts, int family) /* 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); + if(family == AF_INET) { + clen = sizeof(caddr); + pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN, + 0, (struct sockaddr *)&caddr, &clen); + } + else if(family == AF_INET6) + { + clen = sizeof(caddr6); + pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN, + 0, (struct sockaddr *)&caddr6, &clen); + } dgram_msg[pkt_len] = 0x0; if(opts->verbose) { - memset(sipbuf, 0x0, sizeof(sipbuf)); - inet_ntop(family, &(caddr.sin_addr.s_addr), sipbuf, sizeof(sipbuf)); + memset(sipbuf, 0, sizeof(sipbuf)); + if(family == AF_INET) + inet_ntop(family, &caddr.sin_addr.s_addr, sipbuf, sizeof(sipbuf)); + else if(family == AF_INET6) + inet_ntop(family, &caddr6.sin6_addr, sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s", pkt_len, sipbuf); } @@ -209,15 +236,25 @@ run_udp_server(fko_srv_options_t *opts, int family) opts->spa_pkt.packet_data_len = pkt_len; opts->spa_pkt.packet_proto = IPPROTO_UDP; opts->spa_pkt.packet_family = family; - 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); + if(family == AF_INET) + { + 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); + } + else if(family == AF_INET6) + { + opts->spa_pkt.packet_addr.inet6.src_ip = caddr6.sin6_addr; + opts->spa_pkt.packet_addr.inet6.dst_ip = saddr6.sin6_addr; + opts->spa_pkt.packet_src_port = ntohs(caddr6.sin6_port); + opts->spa_pkt.packet_dst_port = ntohs(saddr6.sin6_port); + } incoming_spa(opts); } - memset(dgram_msg, 0x0, sizeof(dgram_msg)); + memset(dgram_msg, 0, sizeof(dgram_msg)); opts->packet_ctr += 1; if(opts->foreground == 1 && opts->verbose > 2) From 74370395a719b75e20d9cd1bbbf5f7b69986a25d Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 17 Jul 2018 17:24:52 +0200 Subject: [PATCH 34/78] Constify --- server/tcp_server.c | 2 +- server/tcp_server.h | 2 +- server/udp_server.c | 2 +- server/udp_server.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/tcp_server.c b/server/tcp_server.c index eeed1d7a..fa85b6c7 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -51,7 +51,7 @@ * the child process or -1 if there is a fork error. */ int -run_tcp_server(fko_srv_options_t *opts, int family) +run_tcp_server(fko_srv_options_t *opts, const int family) { #if !CODE_COVERAGE pid_t pid, ppid; diff --git a/server/tcp_server.h b/server/tcp_server.h index 9368efb9..f4264ed7 100644 --- a/server/tcp_server.h +++ b/server/tcp_server.h @@ -32,7 +32,7 @@ /* Function prototypes */ -int run_tcp_server(fko_srv_options_t *opts, int family); +int run_tcp_server(fko_srv_options_t *opts, const int family); #endif /* TCP_SERVER_H */ diff --git a/server/udp_server.c b/server/udp_server.c index be95f4ea..fa77cbc7 100644 --- a/server/udp_server.c +++ b/server/udp_server.c @@ -50,7 +50,7 @@ #include int -run_udp_server(fko_srv_options_t *opts, int family) +run_udp_server(fko_srv_options_t *opts, const int family) { int s_sock, sfd_flags, selval, pkt_len; int rv=1, chk_rm_all=0; diff --git a/server/udp_server.h b/server/udp_server.h index c601b66b..29ffb685 100644 --- a/server/udp_server.h +++ b/server/udp_server.h @@ -32,7 +32,7 @@ /* Function prototypes */ -int run_udp_server(fko_srv_options_t *opts, int family); +int run_udp_server(fko_srv_options_t *opts, const int family); #endif /* UDP_SERVER_H */ From a2902cbc629dbf1e953b065866178c4dff35d1ed Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 17 Jul 2018 17:48:26 +0200 Subject: [PATCH 35/78] Terminate IPs resolved externally as expected --- client/http_resolve_host.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index 978af567..70f0b3df 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -58,12 +58,12 @@ struct url static int try_url(struct url *url, fko_cli_options_t *options) { - int sock=-1, sock_success=0, res, error, http_buf_len; + int sock=-1, sock_success=0, i, res, error, http_buf_len; int bytes_read = 0, position = 0; struct addrinfo *result=NULL, *rp, hints; char http_buf[HTTP_MAX_REQUEST_LEN] = {0}; char http_response[HTTP_MAX_RESPONSE_LEN] = {0}; - char *ndx; + char *ndx, c; #ifdef WIN32 WSADATA wsa_data; @@ -196,10 +196,21 @@ try_url(struct url *url, fko_cli_options_t *options) } ndx += 4; - /* Try to parse the content as an IP address. - * Note: We are expecting the content to be exactly that - * (possibly followed by whitespace or other not-digit value). + /* Walk along the content to try to find the end of the IP address. + * Note: We are expecting the content to be just an IP address + * (possibly followed by whitespace or other not-digit value). + */ + for(i=0; i= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) && c != '.' && c != ':') + break; + } + + /* Terminate at the first non-digit and non-dot. */ + *(ndx+i) = '\0'; + + /* Try to parse the content as an IP address. */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME; From c753215038c5a3aaab85881c9384c9d816c8c306 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 18 Jul 2018 04:38:12 +0200 Subject: [PATCH 36/78] Prepare access stanzas for more address families --- server/access.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/server/access.c b/server/access.c index b069b606..518b35fb 100644 --- a/server/access.c +++ b/server/access.c @@ -351,13 +351,15 @@ static int add_int_ent(acc_int_list_t **ilist, const char *ip) { char *ndx; - char ip_str[MAX_IPV4_STR_LEN] = {0}; - char ip_mask_str[MAX_IPV4_STR_LEN] = {0}; + char ip_str[MAX_IPV46_STR_LEN] = {0}; + char ip_mask_str[MAX_IPV46_STR_LEN] = {0}; uint32_t mask; int is_err, mask_len = 0, need_shift = 1; struct in_addr in; struct in_addr mask_in; + struct addrinfo *ai, hints; + struct sockaddr_in *sin; acc_int_list_t *last_sle, *new_sle, *tmp_sle; @@ -383,7 +385,7 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) */ if((ndx = strchr(ip, '/')) != NULL) { - if(((ndx-ip)) >= MAX_IPV4_STR_LEN) + if(((ndx-ip)) >= MAX_IPV46_STR_LEN) { log_msg(LOG_ERR, "[*] Error parsing string to IP"); free(new_sle); @@ -426,7 +428,7 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) { /* CIDR mask */ - mask = strtol_wrapper(ndx+1, 1, 32, NO_EXIT_UPON_ERR, &is_err); + mask = strtol_wrapper(ndx+1, 1, 128, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1); @@ -449,7 +451,7 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) else { mask = 32; - if(strnlen(ip, MAX_IPV4_STR_LEN+1) >= MAX_IPV4_STR_LEN) + if(strnlen(ip, MAX_IPV46_STR_LEN+1) >= MAX_IPV46_STR_LEN) { log_msg(LOG_ERR, "[*] Error parsing string to IP"); free(new_sle); @@ -459,21 +461,38 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) strlcpy(ip_str, ip, sizeof(ip_str)); } - if(inet_aton(ip_str, &in) == 0) + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME; + if(getaddrinfo(ip_str, NULL, &hints, &ai) != 0) { log_msg(LOG_ERR, "[*] Fatal error parsing IP to int for: %s", ip_str ); - free(new_sle); new_sle = NULL; - return 0; } + switch(ai->ai_family) + { + case AF_INET: + sin = (struct sockaddr_in *)ai->ai_addr; + in = sin->sin_addr; + break; + default: + log_msg(LOG_ERR, + "[*] Unsupported family parsing IP to int for: %s", ip_str + ); + free(new_sle); + new_sle = NULL; + freeaddrinfo(ai); + return 0; + } + new_sle->family = ai->ai_family; + freeaddrinfo(ai); /* Store our mask converted from CIDR to a 32-bit value. */ - new_sle->family = AF_INET; if(mask == 32) new_sle->acc_int.inet.mask = 0xFFFFFFFF; else if(need_shift && (mask > 0 && mask < 32)) From d260f502d97398e2b83989a1fe084195327574ee Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 18 Jul 2018 21:57:37 +0200 Subject: [PATCH 37/78] Use the correct offset for inet_ntop() --- server/incoming_spa.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 673bcae4..acc31f5f 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -944,11 +944,25 @@ incoming_spa(fko_srv_options_t *opts) */ acc_stanza_t *acc = opts->acc_stanzas; - inet_ntop(spa_pkt->packet_family, &(spa_pkt->packet_src_ip), - spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); + switch(spa_pkt->packet_family) + { + case AF_INET: + inet_ntop(AF_INET, &(spa_pkt->packet_addr.inet.src_ip), + spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); - inet_ntop(spa_pkt->packet_family, &(spa_pkt->packet_dst_ip), - spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip)); + inet_ntop(AF_INET, &(spa_pkt->packet_addr.inet.dst_ip), + spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip)); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(spa_pkt->packet_addr.inet6.src_ip), + spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); + + inet_ntop(AF_INET6, &(spa_pkt->packet_addr.inet6.dst_ip), + spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip)); + break; + default: + return; + } /* At this point, we want to validate and (if needed) preprocess the * SPA data and/or to be reasonably sure we have a SPA packet (i.e From c8670aa2d3102572cdb257cc5c92ba32b69c7426 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 18 Jul 2018 22:31:36 +0200 Subject: [PATCH 38/78] Simplify the calculation of pkt_data_len --- server/process_packet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/process_packet.c b/server/process_packet.c index 9b3f786b..0b1cf03d 100644 --- a/server/process_packet.c +++ b/server/process_packet.c @@ -212,7 +212,7 @@ process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr); - pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + pkt_data_len = pkt_end - pkt_data; } else if (proto == IPPROTO_UDP) { @@ -224,7 +224,7 @@ process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, dst_port = ntohs(udph_p->dest); pkt_data = ((unsigned char*)(udph_p + 1)); - pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + pkt_data_len = pkt_end - pkt_data; } else if (proto == IPPROTO_ICMP) { @@ -233,7 +233,7 @@ process_packet_ipv4(fko_srv_options_t * opts, const unsigned char * packet, icmph_p = (struct icmphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2)); pkt_data = ((unsigned char*)(icmph_p + 1)); - pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + pkt_data_len = pkt_end - pkt_data; } else @@ -331,7 +331,7 @@ process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr); - pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + pkt_data_len = pkt_end - pkt_data; } else if (proto == IPPROTO_UDP) { @@ -343,7 +343,7 @@ process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, dst_port = ntohs(udph_p->dest); pkt_data = ((unsigned char*)(udph_p + 1)); - pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); + pkt_data_len = pkt_end - pkt_data; } else From 3e329a537d271a6fef875609512e39c88a37dab6 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 18 Jul 2018 22:37:54 +0200 Subject: [PATCH 39/78] Correct the packet length calculation with IPv6 --- server/process_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/process_packet.c b/server/process_packet.c index 0b1cf03d..962766d3 100644 --- a/server/process_packet.c +++ b/server/process_packet.c @@ -308,7 +308,7 @@ process_packet_ipv6(fko_srv_options_t * opts, const unsigned char * packet, * frame (such as a 4-byte Ethernet Frame Check Sequence) to not * interfere with SPA operations. */ - pkt_end = ((unsigned char*)iph_p)+ntohs(iph_p->ip6_plen); + pkt_end = ((unsigned char*)(iph_p + 1))+ntohs(iph_p->ip6_plen); if(pkt_end > fr_end) return; From 987875616ac321fcd7146edc838dac88ba168748 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 19 Jul 2018 00:03:54 +0200 Subject: [PATCH 40/78] Fix some issues with TCP over IPv6 --- server/tcp_server.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/server/tcp_server.c b/server/tcp_server.c index fa85b6c7..6eaff064 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -56,11 +56,13 @@ run_tcp_server(fko_srv_options_t *opts, const int family) #if !CODE_COVERAGE pid_t pid, ppid; #endif - int s_sock, c_sock, sfd_flags, clen, selval; + int s_sock, c_sock, sfd_flags, selval; + socklen_t slen, clen; int reuse_addr = 1, rv=1; fd_set sfd_set; - struct sockaddr_in saddr, caddr; + struct sockaddr_in saddr4, caddr4; struct sockaddr_in6 saddr6, caddr6; + struct sockaddr *saddr, *caddr; struct timeval tv; char sipbuf[MAX_IPV46_STR_LEN] = {0}; @@ -138,15 +140,21 @@ run_tcp_server(fko_srv_options_t *opts, const int family) /* Construct local address structure */ if(family == AF_INET) { - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = family; /* Internet address family */ - saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ - saddr.sin_port = htons(opts->tcpserv_port); /* Local port */ + memset(&saddr4, 0, sizeof(saddr4)); + saddr4.sin_family = family; /* Internet address family */ + saddr4.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + saddr4.sin_port = htons(opts->tcpserv_port); /* Local port */ + saddr = (struct sockaddr *)&saddr4; + slen = sizeof(saddr4); + caddr = (struct sockaddr *)&caddr4; } else if(family == AF_INET6) { memset(&saddr6, 0, sizeof(saddr6)); saddr6.sin6_family = family; /* Internet address family */ saddr6.sin6_addr = in6addr_any; /* Any incoming interface */ saddr6.sin6_port = htons(opts->tcpserv_port); /* Local port */ + saddr = (struct sockaddr *)&saddr6; + slen = sizeof(saddr6); + caddr = (struct sockaddr *)&caddr6; } else { @@ -157,8 +165,7 @@ run_tcp_server(fko_srv_options_t *opts, const int family) } /* Bind to the local address */ - if ((family == AF_INET && bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) - || (family == AF_INET6 && bind(s_sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0)) + if (bind(s_sock, saddr, slen) < 0) { log_msg(LOG_ERR, "run_tcp_server: bind() failed: %s", strerror(errno)); @@ -189,8 +196,6 @@ run_tcp_server(fko_srv_options_t *opts, const int family) */ while(1) { - clen = (family == AF_INET) ? sizeof(caddr) : sizeof(caddr6); - /* Initialize and setup the socket for select. */ FD_SET(s_sock, &sfd_set); @@ -232,7 +237,8 @@ run_tcp_server(fko_srv_options_t *opts, const int family) /* Wait for a client to connect */ - if((c_sock = accept(s_sock, (struct sockaddr *) &caddr, (socklen_t *)&clen)) < 0) + clen = (family == AF_INET) ? sizeof(caddr) : sizeof(caddr6); + if((c_sock = accept(s_sock, caddr, &clen)) < 0) { log_msg(LOG_ERR, "run_tcp_server: accept() failed: %s", strerror(errno)); @@ -244,7 +250,7 @@ run_tcp_server(fko_srv_options_t *opts, const int family) { memset(sipbuf, 0, sizeof(sipbuf)); if(family == AF_INET) - inet_ntop(family, &caddr.sin_addr.s_addr, sipbuf, sizeof(sipbuf)); + inet_ntop(family, &caddr4.sin_addr.s_addr, sipbuf, sizeof(sipbuf)); else if(family == AF_INET6) inet_ntop(family, &caddr6.sin6_addr, sipbuf, sizeof(sipbuf)); log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); From 1fd5fe197daac6df24d5ac8c0e6be89b091073e2 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 24 Jul 2018 15:44:14 +0200 Subject: [PATCH 41/78] Begin to allow IPv6 addresses in source stanzas --- server/access.c | 98 +++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/server/access.c b/server/access.c index 518b35fb..8e1c4171 100644 --- a/server/access.c +++ b/server/access.c @@ -351,15 +351,16 @@ static int add_int_ent(acc_int_list_t **ilist, const char *ip) { char *ndx; - char ip_str[MAX_IPV46_STR_LEN] = {0}; - char ip_mask_str[MAX_IPV46_STR_LEN] = {0}; - uint32_t mask; - int is_err, mask_len = 0, need_shift = 1; + char ip_str[MAX_IPV46_STR_LEN] = {0}; + char ip_mask_str[MAX_IPV46_STR_LEN] = {0}; + uint32_t mask; + int is_err, mask_len = 0, need_shift = 1; - struct in_addr in; - struct in_addr mask_in; - struct addrinfo *ai, hints; - struct sockaddr_in *sin; + struct in_addr in; + struct in_addr mask_in; + struct addrinfo *ai, hints; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; acc_int_list_t *last_sle, *new_sle, *tmp_sle; @@ -395,7 +396,7 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) mask_len = strlen(ip) - (ndx-ip+1); - if(mask_len > 2) + if(mask_len > 3) { if(mask_len >= MIN_IPV4_STR_LEN && mask_len < MAX_IPV4_STR_LEN) { @@ -422,29 +423,25 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) return 0; } } - else - { - if(mask_len > 0) + else if(mask_len > 0) { + /* CIDR mask + */ + mask = strtol_wrapper(ndx+1, 1, 128, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) { - /* CIDR mask - */ - mask = strtol_wrapper(ndx+1, 1, 128, NO_EXIT_UPON_ERR, &is_err); - if(is_err != FKO_SUCCESS) - { - log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1); - free(new_sle); - new_sle = NULL; - return 0; - } - } - else - { - log_msg(LOG_ERR, "[*] Missing mask value."); + log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1); free(new_sle); new_sle = NULL; return 0; } } + else + { + log_msg(LOG_ERR, "[*] Missing mask value."); + free(new_sle); + new_sle = NULL; + return 0; + } strlcpy(ip_str, ip, (ndx-ip)+1); } @@ -478,6 +475,41 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) case AF_INET: sin = (struct sockaddr_in *)ai->ai_addr; in = sin->sin_addr; + + /* Store our mask converted from CIDR to a 32-bit value. + */ + if(mask > 32) + { + log_msg(LOG_ERR, "[*] Invalid IP mask '%u'.", mask); + freeaddrinfo(ai); + free(new_sle); + new_sle = NULL; + return 0; + } + else if(mask == 32) + new_sle->acc_int.inet.mask = 0xFFFFFFFF; + else if(need_shift && (mask > 0 && mask < 32)) + new_sle->acc_int.inet.mask = (0xFFFFFFFF << (32 - mask)); + else + new_sle->acc_int.inet.mask = mask; + + /* Store our masked address for comparisons with future incoming + * packets. + */ + new_sle->acc_int.inet.maddr = ntohl(in.s_addr) & new_sle->acc_int.inet.mask; + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + new_sle->acc_int.inet6.maddr = sin6->sin6_addr; + if(mask > 128) + { + log_msg(LOG_ERR, "[*] Invalid IPv6 prefix '%u'.", mask); + freeaddrinfo(ai); + free(new_sle); + new_sle = NULL; + return 0; + } + new_sle->acc_int.inet6.prefix = mask; break; default: log_msg(LOG_ERR, @@ -490,20 +522,6 @@ add_int_ent(acc_int_list_t **ilist, const char *ip) } new_sle->family = ai->ai_family; freeaddrinfo(ai); - - /* Store our mask converted from CIDR to a 32-bit value. - */ - if(mask == 32) - new_sle->acc_int.inet.mask = 0xFFFFFFFF; - else if(need_shift && (mask > 0 && mask < 32)) - new_sle->acc_int.inet.mask = (0xFFFFFFFF << (32 - mask)); - else - new_sle->acc_int.inet.mask = mask; - - /* Store our masked address for comparisons with future incoming - * packets. - */ - new_sle->acc_int.inet.maddr = ntohl(in.s_addr) & new_sle->acc_int.inet.mask; } /* If this is not the first entry, we walk our pointer to the From 64053988582f483637d220aa7393e5bb99eca75f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 27 Jul 2018 03:56:41 +0200 Subject: [PATCH 42/78] Add a command-line option to enable IPv6 (TCP/UDP) This is currently "--ipv6", or "-6" for short. --- server/cmd_opts.h | 5 +++-- server/config_init.c | 4 ++++ server/fwknopd.c | 4 ++-- server/fwknopd_common.h | 1 + server/pcap_capture.c | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/server/cmd_opts.h b/server/cmd_opts.h index a2feed5d..e51506df 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -181,9 +181,9 @@ enum { /* Our getopt_long options string. */ #if USE_LIBNETFILTER_QUEUE - #define GETOPTS_OPTION_STRING "Aa:c:C:d:Dfhi:Kl:nO:p:P:Rr:StUvV" + #define GETOPTS_OPTION_STRING "Aa:c:C:d:Dfhi:6Kl:nO:p:P:Rr:StUvV" #else - #define GETOPTS_OPTION_STRING "Aa:c:C:d:Dfhi:Kl:O:p:P:Rr:StUvV" + #define GETOPTS_OPTION_STRING "Aa:c:C:d:Dfhi:6Kl:O:p:P:Rr:StUvV" #endif /* Our program command-line options... @@ -206,6 +206,7 @@ static struct option cmd_opts[] = {"fault-injection-tag", 1, NULL, FAULT_INJECTION_TAG}, {"help", 0, NULL, 'h'}, {"interface", 1, NULL, 'i'}, + {"ipv6", 0, NULL, '6'}, {"key-gen", 0, NULL, 'k'}, {"key-gen-file", 1, NULL, KEY_GEN_FILE }, {"key-len", 1, NULL, KEY_LEN }, diff --git a/server/config_init.c b/server/config_init.c index 58519094..97e76534 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -1372,6 +1372,9 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) case 'i': set_config_entry(opts, CONF_PCAP_INTF, optarg); break; + case '6': + opts->ipv6 = 1; + break; case FIREWD_DISABLE_CHECK_SUPPORT: opts->firewd_disable_check_support = 1; break; @@ -1498,6 +1501,7 @@ usage(void) " a background daemon).\n" " -i, --interface - Specify interface to listen for incoming SPA\n" " packets.\n" + " -6, --ipv6 - Start the server in IPv6 mode (TCP/UDP).\n" " -C, --packet-limit - Limit the number of candidate SPA packets to\n" " process and exit when this limit is reached.\n" " -d, --digest-file - Specify an alternate digest.cache file.\n" diff --git a/server/fwknopd.c b/server/fwknopd.c index 4fbad5c0..aed5dc52 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -259,7 +259,7 @@ main(int argc, char **argv) if(opts.enable_udp_server || strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) { - if(run_udp_server(&opts, AF_INET) < 0) + if(run_udp_server(&opts, opts.ipv6 ? AF_INET6 : AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_udp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); @@ -280,7 +280,7 @@ main(int argc, char **argv) */ if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0) { - if(run_tcp_server(&opts, AF_INET) < 0) + if(run_tcp_server(&opts, opts.ipv6 ? AF_INET6 : AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_tcp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index e202938e..387d5290 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -688,6 +688,7 @@ typedef struct fko_srv_options unsigned char enable_nfq_capture; /* Enable Netfilter Queue capture mode */ unsigned char enable_fw; /* Command modes by themselves don't need firewall support. */ + unsigned char ipv6; /* Enable IPv6 mode (TCP/UDP) */ 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 73678feb..f32aeca8 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -211,7 +211,7 @@ pcap_capture(fko_srv_options_t *opts) /* Attempt to restart tcp server ? */ usleep(1000000); - run_tcp_server(opts, AF_INET); + run_tcp_server(opts, opts->ipv6 ? AF_INET6 : AF_INET); } } From 08e805da538547be9adb353952ae2058b0c8aaf9 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 27 Jul 2018 04:12:38 +0200 Subject: [PATCH 43/78] Optimize moot variable initialization away --- common/fko_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index 3a72cfb7..b8b13647 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -602,7 +602,7 @@ char { char* ns = NULL; if(s) { - ns = calloc(1, len + 1); + ns = malloc(len + 1); if(ns) { ns[len] = 0; // strncpy to be pedantic about modification in multithreaded @@ -724,7 +724,7 @@ add_argv(char **argv_new, int *argc_new, const char *new_arg) int buf_size = 0; buf_size = strlen(new_arg) + 1; - argv_new[*argc_new] = calloc(1, buf_size); + argv_new[*argc_new] = malloc(buf_size); if(argv_new[*argc_new] == NULL) return 0; From 15dfc94e9c90f45cce293934ea0079dc11923a44 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 27 Jul 2018 14:15:23 +0200 Subject: [PATCH 44/78] Fix the build on Linux (iptables) --- common/fko_util.c | 8 ++++---- server/access.c | 4 ++-- server/config_init.c | 4 ++-- server/fw_util_iptables.c | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index b8b13647..40a28398 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -1145,15 +1145,15 @@ DECLARE_UTEST(test_hostname_validator, "test the is_valid_hostname function") strcpy(test_hostname, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b"); CU_ASSERT(is_valid_hostname(test_hostname, strlen(test_hostname)) == 0); } -DECLARE_UTEST(test_ipv4_validator, "test the is_valid_ipv4_addr function") +DECLARE_UTEST(test_ipv4_validator, "test the is_valid_ip_addr function") { char test_str[32]; strcpy(test_str, "1.2.3.4"); - CU_ASSERT(is_valid_ipv4_addr(test_str, strlen(test_str))); + CU_ASSERT(is_valid_ip_addr(test_str, strlen(test_str), AF_INET)); strcpy(test_str, "127.0.0.2"); - CU_ASSERT(is_valid_ipv4_addr(test_str, 9)); + CU_ASSERT(is_valid_ip_addr(test_str, 9, AF_INET)); strcpy(test_str, "1.2.3.400"); - CU_ASSERT(is_valid_ipv4_addr(test_str, strlen(test_str)) == 0); + CU_ASSERT(is_valid_ip_addr(test_str, strlen(test_str), AF_INET) == 0); } DECLARE_UTEST(test_count_characters, "test the count_characters function") diff --git a/server/access.c b/server/access.c index 8e1c4171..551a1d24 100644 --- a/server/access.c +++ b/server/access.c @@ -297,7 +297,7 @@ add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } - if(! is_valid_ipv4_addr(ip_str, strlen(ip_str))) + if(! is_valid_ip_addr(ip_str, strlen(ip_str), AF_INET)) { log_msg(LOG_ERR, "[*] Fatal: invalid FORCE_NAT IP '%s'", ip_str); @@ -327,7 +327,7 @@ add_acc_force_snat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } - if(! is_valid_ipv4_addr(ip_str, strlen(ip_str))) + if(! is_valid_ip_addr(ip_str, strlen(ip_str), AF_INET)) { log_msg(LOG_ERR, "[*] Fatal: invalid FORCE_SNAT IP '%s'", ip_str); diff --git a/server/config_init.c b/server/config_init.c index 97e76534..78f1677c 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -554,7 +554,7 @@ validate_options(fko_srv_options_t *opts) */ if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) { - if(! is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + if(! is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { log_msg(LOG_ERR, "Invalid IPv4 addr for SNAT_TRANSLATE_IP" @@ -697,7 +697,7 @@ validate_options(fko_srv_options_t *opts) */ if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) { - if(! is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + if(! is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { log_msg(LOG_ERR, "Invalid IPv4 addr for SNAT_TRANSLATE_IP" diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 8d0c1848..696caa9c 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1385,7 +1385,7 @@ static void snat_rule(const fko_srv_options_t * const opts, /* Add SNAT or MASQUERADE rules. */ - if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ipv4_addr(acc->force_snat_ip, strlen(acc->force_snat_ip))) + if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ip_addr(acc->force_snat_ip, strlen(acc->force_snat_ip), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); @@ -1393,7 +1393,7 @@ static void snat_rule(const fko_srv_options_t * const opts, "--to-source %s", acc->force_snat_ip); } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) - && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + && is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); @@ -1419,7 +1419,7 @@ static void snat_rule(const fko_srv_options_t * const opts, { /* Add SNAT or MASQUERADE rules. */ - if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ipv4_addr(acc->force_snat_ip, strlen(acc->force_snat_ip))) + if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ip_addr(acc->force_snat_ip, strlen(acc->force_snat_ip), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); @@ -1434,7 +1434,7 @@ static void snat_rule(const fko_srv_options_t * const opts, "--to-ports %i", fst_port); } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) - && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + && is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); @@ -1545,7 +1545,7 @@ process_spa_request(const fko_srv_options_t * const opts, if((ndx != NULL) && (str_len <= MAX_HOSTNAME_LEN)) { strlcpy(nat_dst, spadat->nat_access, str_len+1); - if(! is_valid_ipv4_addr(nat_dst, str_len)) + if(! is_valid_ip_addr(nat_dst, str_len, AF_INET)) { if(strncasecmp(opts->config[CONF_ENABLE_NAT_DNS], "Y", 1) == 0) { From bbb341c0403faab4b6f0a4cc7c207d837dd412e7 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 27 Jul 2018 14:52:35 +0200 Subject: [PATCH 45/78] Fix the build with firewalld --- server/fw_util_firewalld.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index 2b872853..a6c875c5 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -1402,7 +1402,7 @@ static void snat_rule(const fko_srv_options_t * const opts, /* Add SNAT or MASQUERADE rules. */ - if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ipv4_addr(acc->force_snat_ip, strlen(acc->force_snat_ip))) + if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ip_addr(acc->force_snat_ip, strlen(acc->force_snat_ip), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); @@ -1410,7 +1410,7 @@ static void snat_rule(const fko_srv_options_t * const opts, "--to-source %s", acc->force_snat_ip); } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) - && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + && is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); @@ -1436,7 +1436,7 @@ static void snat_rule(const fko_srv_options_t * const opts, { /* Add SNAT or MASQUERADE rules. */ - if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ipv4_addr(acc->force_snat_ip, strlen(acc->force_snat_ip))) + if(acc->force_snat && acc->force_snat_ip != NULL && is_valid_ip_addr(acc->force_snat_ip, strlen(acc->force_snat_ip), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); @@ -1451,7 +1451,7 @@ static void snat_rule(const fko_srv_options_t * const opts, "--to-ports %i", fst_port); } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) - && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]))) + && is_valid_ip_addr(opts->config[CONF_SNAT_TRANSLATE_IP], strlen(opts->config[CONF_SNAT_TRANSLATE_IP]), AF_INET)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); @@ -1561,7 +1561,7 @@ process_spa_request(const fko_srv_options_t * const opts, if((ndx != NULL) && (str_len <= MAX_HOSTNAME_LEN)) { strlcpy(nat_dst, spadat->nat_access, str_len+1); - if(! is_valid_ipv4_addr(nat_dst, str_len)) + if(! is_valid_ip_addr(nat_dst, str_len, AF_INET)) { if(strncasecmp(opts->config[CONF_ENABLE_NAT_DNS], "Y", 1) == 0) { From 3a8e01adeabd33254e8fbfbbb6f27d309d905101 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 30 Jul 2018 16:17:46 +0200 Subject: [PATCH 46/78] Update the manual page for the -6 option (--ipv6) --- doc/fwknopd.man.asciidoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index 24669bff..440a4851 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -46,6 +46,10 @@ COMMAND-LINE OPTIONS option is not usually needed because the ``PCAP_INTF'' keyword in the 'fwknopd.conf' file defines the sniffing interface. +*-6, --ipv6*:: + Bind the UDP and TCP sockets on IPv6 addresses. This does not affect PCAP + mode. + *-f, --foreground*:: Run *fwknopd* in the foreground instead of becoming a daemon. When run in the foreground, message that would go to the log would instead be From 13dee2cdd8efb46d362ca6428321c75203656451 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 6 Aug 2018 17:29:04 +0200 Subject: [PATCH 47/78] Support further address families in the future --- server/config_init.c | 2 +- server/fwknopd.c | 4 ++-- server/fwknopd_common.h | 2 +- server/pcap_capture.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/config_init.c b/server/config_init.c index 78f1677c..225290aa 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -1373,7 +1373,7 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) set_config_entry(opts, CONF_PCAP_INTF, optarg); break; case '6': - opts->ipv6 = 1; + opts->family = AF_INET6; break; case FIREWD_DISABLE_CHECK_SUPPORT: opts->firewd_disable_check_support = 1; diff --git a/server/fwknopd.c b/server/fwknopd.c index aed5dc52..e475a5e8 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -259,7 +259,7 @@ main(int argc, char **argv) if(opts.enable_udp_server || strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0) { - if(run_udp_server(&opts, opts.ipv6 ? AF_INET6 : AF_INET) < 0) + if(run_udp_server(&opts, (opts.family != AF_UNSPEC) ? opts.family : AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_udp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); @@ -280,7 +280,7 @@ main(int argc, char **argv) */ if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0) { - if(run_tcp_server(&opts, opts.ipv6 ? AF_INET6 : AF_INET) < 0) + if(run_tcp_server(&opts, (opts.family != AF_UNSPEC) ? opts.family : AF_INET) < 0) { log_msg(LOG_ERR, "Fatal run_tcp_server() error"); clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE); diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 387d5290..85c85612 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -688,7 +688,7 @@ typedef struct fko_srv_options unsigned char enable_nfq_capture; /* Enable Netfilter Queue capture mode */ unsigned char enable_fw; /* Command modes by themselves don't need firewall support. */ - unsigned char ipv6; /* Enable IPv6 mode (TCP/UDP) */ + int family; /* Family restriction (TCP/UDP) */ 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 f32aeca8..6d616956 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -211,7 +211,7 @@ pcap_capture(fko_srv_options_t *opts) /* Attempt to restart tcp server ? */ usleep(1000000); - run_tcp_server(opts, opts->ipv6 ? AF_INET6 : AF_INET); + run_tcp_server(opts, (opts->family != AF_UNSPEC) ? opts->family : AF_INET); } } From 9923fc0a8824e5dc4d57cfc4e5c6c677c6e80158 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 6 Aug 2018 17:29:28 +0200 Subject: [PATCH 48/78] Verify if the protocol family matches incoming packets --- server/incoming_spa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/incoming_spa.c b/server/incoming_spa.c index acc31f5f..75cb041d 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -944,6 +944,10 @@ incoming_spa(fko_srv_options_t *opts) */ acc_stanza_t *acc = opts->acc_stanzas; + /* Verify the network family if relevant */ + if(opts->family != AF_UNSPEC && opts->family != spa_pkt->packet_family) + return; + switch(spa_pkt->packet_family) { case AF_INET: From c5994a34b78c59e3c7e79712ab2299991069bd8c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 6 Aug 2018 19:05:19 +0200 Subject: [PATCH 49/78] Do not use INADDR_ANY for default ports --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index c22fa7fe..2558763b 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -689,7 +689,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) if (options->spa_src_port) saddr.sin_port = htons(options->spa_src_port); else - saddr.sin_port = INADDR_ANY; + saddr.sin_port = 0; if (options->spoof_ip_src_str[0] != 0x00) { saddr.sin_addr.s_addr = inet_addr(options->spoof_ip_src_str); From e3aeb468b62e88e707b14c121d1eded1aaa2f5c5 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 6 Aug 2018 19:08:27 +0200 Subject: [PATCH 50/78] Check for errors from inet_addr() with INADDR_NONE --- client/spa_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/spa_comm.c b/client/spa_comm.c index 2558763b..b8aad8e0 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -696,7 +696,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) } else saddr.sin_addr.s_addr = INADDR_ANY; /* default */ - if (saddr.sin_addr.s_addr == -1) + if (saddr.sin_addr.s_addr == INADDR_NONE) { log_msg(LOG_VERBOSITY_ERROR, "Could not set source IP."); return -1; From e29d62ef102dd7c8db9889f849ead0ea0079098f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 7 Aug 2018 08:21:37 +0200 Subject: [PATCH 51/78] Fix build with NFQ enabled --- server/nfq_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/nfq_capture.c b/server/nfq_capture.c index 3b72e89a..e7c773f0 100644 --- a/server/nfq_capture.c +++ b/server/nfq_capture.c @@ -195,7 +195,7 @@ nfq_capture(fko_srv_options_t *opts) /* Attempt to restart tcp server ? */ usleep(1000000); - run_tcp_server(opts); + run_tcp_server(opts, (opts->family != AF_UNSPEC) ? opts->family : AF_INET); } } From 956e1df2281b8d54d6678581a8536a903d243034 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 7 Aug 2018 13:54:16 +0200 Subject: [PATCH 52/78] Allow the longest possible IPv6 address in sources --- server/access.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/access.h b/server/access.h index d4fb045e..8b37a4cf 100644 --- a/server/access.h +++ b/server/access.h @@ -36,9 +36,9 @@ /** * \def ACCESS_BUF_LEN * - * \brief Allow strings as large as 123.123.123.123/255.255.255.255 + * \brief Allow strings as large as 1234:5678:9abc:deff:ffff:ffff:ffff:ffff/128 */ -#define ACCESS_BUF_LEN 33 +#define ACCESS_BUF_LEN 45 /** * \def MAX_DEPTH From edeea235bc0e46a801a0302c832c7896c968c200 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 13:54:11 +0200 Subject: [PATCH 53/78] Add a configuration variable for IPv6 firewall binaries This is only relevant for iptables at the moment. --- android/project/jni/config.h | 3 +++ configure.ac | 21 +++++++++++++++++++ extras/openwrt/package/fwknop/Makefile | 4 +++- iphone/Classes/config.h | 3 +++ server/cmd_opts.h | 1 + server/fw_util_iptables.c | 1 + server/fwknopd.conf | 1 + server/fwknopd_common.h | 2 ++ .../server-conf/iptables/fwknopd.conf | 1 + 9 files changed, 36 insertions(+), 1 deletion(-) diff --git a/android/project/jni/config.h b/android/project/jni/config.h index a005368e..75d8a9db 100644 --- a/android/project/jni/config.h +++ b/android/project/jni/config.h @@ -32,6 +32,9 @@ /* Path to firewall command executable (it should match the firewall type). */ #define FIREWALL_EXE "/sbin/iptables" +/* Path to firewall command executable for IPv6 (it should match the firewall type). */ +#define FIREWALL_EXE_IPV6 "/sbin/ip6tables" + /* The firewall type: ipf. */ /* #undef FIREWALL_IPF */ diff --git a/configure.ac b/configure.ac index 9b8371b0..8d9efecd 100644 --- a/configure.ac +++ b/configure.ac @@ -685,6 +685,24 @@ dnl ] ) +dnl Check for ip6tables +dnl + AC_ARG_WITH([ip6tables], + [AS_HELP_STRING([--with-ip6tables=/path/to/ip6tables], + [Specify path to the ip6tables executable @<:@default=check path@:>@])], + [ + AS_IF([ test "x$withval" = xno ], [], + AS_IF([ test "x$withval" = x -o "x$withval" = xyes ], + [AC_MSG_ERROR([--with-ip6tables requires an argument specifying a path to ip6tables])], + [ FORCE_IP6TABLES_EXE=$withval ] + ) + ) + ], + [ + AC_PATH_PROG(IP6TABLES_EXE, [ip6tables], [], [$APP_PATH]) + ] + ) + dnl Check for ipfw dnl AC_ARG_WITH([ipfw], @@ -815,6 +833,9 @@ dnl AC_DEFINE_UNQUOTED([FIREWALL_EXE], ["$FIREWALL_EXE"], [Path to firewall command executable (it should match the firewall type).]) + AC_DEFINE_UNQUOTED([FIREWALL_EXE_IPV6], ["$FIREWALL_EXE_IPV6"], + [Path to firewall command executable for IPv6 (it should match the firewall type).]) + ], [test "$want_server" = no], [ use_ndbm=no diff --git a/extras/openwrt/package/fwknop/Makefile b/extras/openwrt/package/fwknop/Makefile index 22dc5a20..dbfd7a7c 100644 --- a/extras/openwrt/package/fwknop/Makefile +++ b/extras/openwrt/package/fwknop/Makefile @@ -40,7 +40,8 @@ endef CONFIGURE_ARGS += \ --disable-client \ --without-gpgme \ - --with-iptables=/usr/sbin/iptables + --with-iptables=/usr/sbin/iptables \ + --with-ip6tables=/usr/sbin/ip6tables @@ -108,6 +109,7 @@ define Build/Configure --with-gpgme \ --with-gpg=/usr/bin/gpg \ --with-iptables=/usr/sbin/iptables \ + --with-ip6tables=/usr/sbin/ip6tables \ --with-sh=/bin/sh \ ) endef diff --git a/iphone/Classes/config.h b/iphone/Classes/config.h index 61beea02..50a0945c 100644 --- a/iphone/Classes/config.h +++ b/iphone/Classes/config.h @@ -26,6 +26,9 @@ Copyright (C) Max Kastanas 2010 /* Path to firewall command executable (it should match the firewall type). */ #define FIREWALL_EXE "/sbin/iptables" +/* Path to firewall command executable for IPv6 (it should match the firewall type). */ +#define FIREWALL_EXE_IPV6 "/sbin/ip6tables" + /* The firewall type: ipf. */ /* #undef FIREWALL_IPF */ diff --git a/server/cmd_opts.h b/server/cmd_opts.h index e51506df..97aa6f9b 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -142,6 +142,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "GPG_EXE", "SUDO_EXE", "FIREWALL_EXE", + "FIREWALL_EXE_IPV6", "VERBOSE", #if AFL_FUZZING "AFL_PKT_FILE", diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 696caa9c..a86a989f 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1031,6 +1031,7 @@ fw_config_init(fko_srv_options_t * const opts) /* Set our firewall exe command path (iptables in most cases). */ strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command)); + strlcpy(fwc.fw_command6, opts->config[CONF_FIREWALL_EXE_IPV6], sizeof(fwc.fw_command6)); #if HAVE_LIBFIU fiu_return_on("fw_config_init", 0); diff --git a/server/fwknopd.conf b/server/fwknopd.conf index 647ecf05..6fd328bc 100644 --- a/server/fwknopd.conf +++ b/server/fwknopd.conf @@ -559,5 +559,6 @@ # #FIREWALL_EXE /bin/firewall-cmd; #FIREWALL_EXE /sbin/iptables; +#FIREWALL_EXE_IPV6 /sbin/ip6tables; ###EOF### diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 85c85612..88ef8f70 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -347,6 +347,7 @@ enum { CONF_GPG_EXE, CONF_SUDO_EXE, CONF_FIREWALL_EXE, + CONF_FIREWALL_EXE_IPV6, CONF_VERBOSE, #if AFL_FUZZING CONF_AFL_PKT_FILE, @@ -521,6 +522,7 @@ typedef struct cmd_cycle_list struct fw_config { struct fw_chain chain[NUM_FWKNOP_ACCESS_TYPES]; char fw_command[MAX_PATH_LEN]; + char fw_command6[MAX_PATH_LEN]; /* Flag for setting destination field in rule */ diff --git a/test/afl/test-cases/server-conf/iptables/fwknopd.conf b/test/afl/test-cases/server-conf/iptables/fwknopd.conf index 25af65a8..6adbda6b 100644 --- a/test/afl/test-cases/server-conf/iptables/fwknopd.conf +++ b/test/afl/test-cases/server-conf/iptables/fwknopd.conf @@ -43,5 +43,6 @@ DIGEST_FILE /var/run/fwknop/digest.cache GPG_HOME_DIR /root/.gnupg GPG_EXE /usr/bin/gpg FIREWALL_EXE /sbin/iptables +FIREWALL_EXE_IPV6 /sbin/ip6tables VERBOSE Y #FAULT_INJECTION_TAG From a7a9ecb991985d2b41f3dba1bc721b2b79ca6000 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 14:00:01 +0200 Subject: [PATCH 54/78] Add the fw_command6 member to the right struct fw_config --- server/fwknopd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 88ef8f70..4342c70b 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -522,7 +522,6 @@ typedef struct cmd_cycle_list struct fw_config { struct fw_chain chain[NUM_FWKNOP_ACCESS_TYPES]; char fw_command[MAX_PATH_LEN]; - char fw_command6[MAX_PATH_LEN]; /* Flag for setting destination field in rule */ @@ -570,6 +569,7 @@ typedef struct cmd_cycle_list struct fw_config { struct fw_chain chain[NUM_FWKNOP_ACCESS_TYPES]; char fw_command[MAX_PATH_LEN]; + char fw_command6[MAX_PATH_LEN]; /* Flag for setting destination field in rule */ From 7f9d09e8d3eeecc88a16ef5631f08039c3f35dfd Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 14:21:40 +0200 Subject: [PATCH 55/78] Initialize the configuration for ip6tables as well --- server/config_init.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/config_init.c b/server/config_init.c index 225290aa..36bf2511 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -1031,6 +1031,16 @@ validate_options(fko_srv_options_t *opts) clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } +#if FIREWALL_IPTABLES + if(opts->config[CONF_FIREWALL_EXE_IPV6] == NULL) + { + log_msg(LOG_ERR, + "[*] No firewall command executable is set for IPv6. Please check FIREWALL_EXE_IPV6 in fwknopd.conf." + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } +#endif + return; } @@ -1048,6 +1058,9 @@ set_preconfig_entries(fko_srv_options_t *opts) #ifdef FIREWALL_EXE set_config_entry(opts, CONF_FIREWALL_EXE, FIREWALL_EXE); #endif +#ifdef FIREWALL_EXE_IPV6 + set_config_entry(opts, CONF_FIREWALL_EXE_IPV6, FIREWALL_EXE_IPV6); +#endif } From 576eb111912ea3e8ff6ed9c37add65069adc6e4a Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 14:28:29 +0200 Subject: [PATCH 56/78] Add IPv6 support to --fw-list{,all} --- server/fw_util_iptables.c | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index a86a989f..a703e917 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -567,6 +567,36 @@ fw_dump_rules(const fko_srv_options_t * const opts) got_err++; } } + + /* the same with IPv6 */ + for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + zero_cmd_buffers(); + + /* Create the list command + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS, + opts->fw_config->fw_command6, + ch[i].table + ); + + res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR, + NO_TIMEOUT, &pid_status, opts); + + log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)", + cmd_buf, res); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "fw_dump_rules() Error %i from cmd:'%s': %s", + res, cmd_buf, err_buf); + got_err++; + } + } } else { @@ -605,6 +635,40 @@ fw_dump_rules(const fko_srv_options_t * const opts) got_err++; } } + + /* the same with IPv6 */ + for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + zero_cmd_buffers(); + + /* Create the list command + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command6, + ch[i].table, + ch[i].to_chain + ); + + fprintf(stdout, "\n"); + fflush(stdout); + + res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR, + NO_TIMEOUT, &pid_status, opts); + + log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)", + cmd_buf, res); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "fw_dump_rules() Error %i from cmd:'%s': %s", + res, cmd_buf, err_buf); + got_err++; + } + } } return(got_err); From 81e22559122d879f86088c8c3ced132121fbefac Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:03:05 +0200 Subject: [PATCH 57/78] Update a comment --- common/fko_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/fko_util.c b/common/fko_util.c index 40a28398..3571bd65 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -125,7 +125,7 @@ is_valid_encoded_msg_len(const int len) return(1); } -/* Validate an IPv4 address +/* Validate an IP address */ int is_valid_ip_addr(const char * const ip_str, const int len, const int family) From fa664db600ce5361b91d58c337d86f2a5a0005a5 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:07:03 +0200 Subject: [PATCH 58/78] Add preliminary support for IPv6 with iptables --- server/fw_util.h | 1 + server/fw_util_iptables.c | 159 +++++++++++++++++++++----------------- server/fw_util_iptables.h | 6 +- 3 files changed, 94 insertions(+), 72 deletions(-) diff --git a/server/fw_util.h b/server/fw_util.h index 01bc20dd..e3231e57 100644 --- a/server/fw_util.h +++ b/server/fw_util.h @@ -39,6 +39,7 @@ #define EXPIRE_COMMENT_PREFIX "_exp_" #define TMP_COMMENT "__TMPCOMMENT__" #define DUMMY_IP "127.0.0.2" +#define DUMMY_IPV6 "::2" #if FIREWALL_FIREWALLD #include "fw_util_firewalld.h" diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index a703e917..8cb0d595 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -67,7 +67,8 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, const unsigned int port, const char * const natip, const unsigned int nat_port, - const unsigned int exp_ts) + const unsigned int exp_ts, + int ipv6) { int rule_exists=0; char ipt_line_buf[CMD_BUFSIZE] = {0}; @@ -92,7 +93,7 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, #endif snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, fwc->table, fwc->to_chain ); @@ -175,18 +176,18 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, if(rule_exists) log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule already exists", - proto_search, port, srcip, exp_ts); + proto_search, port, srcip, exp_ts, ipv6); else log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist", - proto_search, port, srcip, exp_ts); + proto_search, port, srcip, exp_ts, ipv6); return(rule_exists); } static int rule_exists_chk_support(const fko_srv_options_t * const opts, - const char * const chain, const char * const rule) + const char * const chain, const char * const rule, int ipv6) { int rule_exists = 0; int res = 0; @@ -194,7 +195,8 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS, - opts->fw_config->fw_command, chain, rule); + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, + chain, rule); res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR, NO_TIMEOUT, &pid_status, opts); @@ -231,16 +233,17 @@ rule_exists(const fko_srv_options_t * const opts, const unsigned int port, const char * const nat_ip, const unsigned int nat_port, - const unsigned int exp_ts) + const unsigned int exp_ts, + int ipv6) { int rule_exists = 0; if(have_ipt_chk_support == 1) - rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); + rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule, ipv6); else rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, - nat_ip, nat_port, exp_ts); + nat_ip, nat_port, exp_ts, ipv6); if(rule_exists == 1) log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists", @@ -253,7 +256,7 @@ rule_exists(const fko_srv_options_t * const opts, } static void -ipt_chk_support(const fko_srv_options_t * const opts) +ipt_chk_support(const fko_srv_options_t * const opts, int ipv6) { int res = 1; struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); @@ -265,10 +268,11 @@ ipt_chk_support(const fko_srv_options_t * const opts) * delete the rule, and return. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_CHK_RULE_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, 1, /* first rule */ + ipv6 ? DUMMY_IPV6 : DUMMY_IP, in_chain->target ); @@ -284,9 +288,10 @@ ipt_chk_support(const fko_srv_options_t * const opts) /* Now see if '-C' works - any output indicates failure */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_VERIFY_CHK_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, + ipv6 ? DUMMY_IPV6 : DUMMY_IP, in_chain->target ); @@ -313,7 +318,7 @@ ipt_chk_support(const fko_srv_options_t * const opts) zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, 1 @@ -325,7 +330,7 @@ ipt_chk_support(const fko_srv_options_t * const opts) } static int -comment_match_exists(const fko_srv_options_t * const opts) +comment_match_exists(const fko_srv_options_t * const opts, int ipv6) { int res = 1; char *ndx = NULL; @@ -338,10 +343,11 @@ comment_match_exists(const fko_srv_options_t * const opts) * the rule and return true. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, 1, /* first rule */ + ipv6 ? DUMMY_IPV6 : DUMMY_IP, in_chain->target ); @@ -355,7 +361,7 @@ comment_match_exists(const fko_srv_options_t * const opts) zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain ); @@ -381,7 +387,7 @@ comment_match_exists(const fko_srv_options_t * const opts) zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, 1 @@ -394,14 +400,14 @@ comment_match_exists(const fko_srv_options_t * const opts) } static int -add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) +add_jump_rule(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0, rv = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain, fwc.chain[chain_num].jump_rule_pos, @@ -429,14 +435,14 @@ add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) } static int -chain_exists(const fko_srv_options_t * const opts, const int chain_num) +chain_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -460,7 +466,7 @@ chain_exists(const fko_srv_options_t * const opts, const int chain_num) } static int -jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num) +jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int exists = 0; char rule_buf[CMD_BUFSIZE] = {0}; @@ -470,7 +476,7 @@ jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int cha fwc.chain[chain_num].to_chain ); - if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf) == 1) + if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf, ipv6) == 1) { log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule found"); exists = 1; @@ -512,12 +518,12 @@ jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, } static int -jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num) +jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int exists = 0; if(have_ipt_chk_support == 1) - exists = jump_rule_exists_chk_support(opts, chain_num); + exists = jump_rule_exists_chk_support(opts, chain_num, ipv6); else exists = jump_rule_exists_no_chk_support(opts, chain_num); @@ -568,7 +574,7 @@ fw_dump_rules(const fko_srv_options_t * const opts) } } - /* the same with IPv6 */ + /* the same with IPv6 */ for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++) { if(fwc.chain[i].target[0] == '\0') @@ -636,7 +642,7 @@ fw_dump_rules(const fko_srv_options_t * const opts) } } - /* the same with IPv6 */ + /* the same with IPv6 */ for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++) { if(fwc.chain[i].target[0] == '\0') @@ -677,7 +683,7 @@ fw_dump_rules(const fko_srv_options_t * const opts) /* Quietly flush and delete all fwknop custom chains. */ static void -delete_all_chains(const fko_srv_options_t * const opts) +delete_all_chains(const fko_srv_options_t * const opts, int ipv6) { int i, res, cmd_ctr = 0; @@ -690,7 +696,7 @@ delete_all_chains(const fko_srv_options_t * const opts) * is there. */ cmd_ctr = 0; - while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1)) + while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i, ipv6) == 1)) { zero_cmd_buffers(); @@ -828,7 +834,7 @@ delete_all_chains(const fko_srv_options_t * const opts) } static int -create_chain(const fko_srv_options_t * const opts, const int chain_num) +create_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0, rv = 0; @@ -837,7 +843,7 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num) /* Create the custom chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -860,18 +866,18 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num) } static int -mk_chain(const fko_srv_options_t * const opts, const int chain_num) +mk_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int err = 0; /* Make sure the required chain and jump rule exist */ - if(! chain_exists(opts, chain_num)) - if(! create_chain(opts, chain_num)) + if(! chain_exists(opts, chain_num, ipv6)) + if(! create_chain(opts, chain_num, ipv6)) err++; - if (! jump_rule_exists(opts, chain_num)) - if(! add_jump_rule(opts, chain_num)) + if (! jump_rule_exists(opts, chain_num, ipv6)) + if(! add_jump_rule(opts, chain_num, ipv6)) err++; return err; @@ -880,7 +886,7 @@ mk_chain(const fko_srv_options_t * const opts, const int chain_num) /* Create the fwknop custom chains (at least those that are configured). */ static int -create_fw_chains(const fko_srv_options_t * const opts) +create_fw_chains(const fko_srv_options_t * const opts, int ipv6) { int i, got_err = 0; #if USE_LIBNETFILTER_QUEUE @@ -892,7 +898,7 @@ create_fw_chains(const fko_srv_options_t * const opts) if(fwc.chain[i].target[0] == '\0') continue; - got_err += mk_chain(opts, i); + got_err += mk_chain(opts, i, ipv6); } #if USE_LIBNETFILTER_QUEUE @@ -903,7 +909,7 @@ create_fw_chains(const fko_srv_options_t * const opts) /* Create the NF_QUEUE chains and rules */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], opts->config[CONF_NFQ_CHAIN] ); @@ -926,7 +932,7 @@ create_fw_chains(const fko_srv_options_t * const opts) /* Create the rule to direct traffic to the NFQ chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], "INPUT", 1, @@ -966,7 +972,7 @@ create_fw_chains(const fko_srv_options_t * const opts) else { snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NFQ_ADD_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], opts->config[CONF_NFQ_CHAIN], opts->config[CONF_NFQ_PORT], @@ -1166,16 +1172,22 @@ fw_initialize(const fko_srv_options_t * const opts) if(opts->ipt_disable_check_support) have_ipt_chk_support = 0; else - ipt_chk_support(opts); + { + ipt_chk_support(opts, 0); + ipt_chk_support(opts, 1); + } /* Flush the chains (just in case) so we can start fresh. */ if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_INIT], "Y", 1) == 0) - delete_all_chains(opts); + { + delete_all_chains(opts, 0); + delete_all_chains(opts, 1); + } /* Now create any configured chains. */ - if(create_fw_chains(opts) != 0) + if(create_fw_chains(opts, 0) != 0 || create_fw_chains(opts, 1) != 0) { log_msg(LOG_WARNING, "fw_initialize() Warning: Errors detected during fwknop custom chain creation"); @@ -1186,7 +1198,7 @@ fw_initialize(const fko_srv_options_t * const opts) */ if(strncasecmp(opts->config[CONF_ENABLE_IPT_COMMENT_CHECK], "Y", 1) == 0) { - if(comment_match_exists(opts) == 1) + if(comment_match_exists(opts, 0) == 1 && comment_match_exists(opts, 1) == 1) { log_msg(LOG_INFO, "iptables 'comment' match is available"); } @@ -1207,13 +1219,14 @@ fw_cleanup(const fko_srv_options_t * const opts) && opts->fw_flush == 0) return(0); - delete_all_chains(opts); + delete_all_chains(opts, 0); + delete_all_chains(opts, 1); return(0); } static int create_rule(const fko_srv_options_t * const opts, - const char * const fw_chain, const char * const fw_rule) + const char * const fw_chain, const char * const fw_rule, int ipv6) { int res = 0; @@ -1221,10 +1234,12 @@ create_rule(const fko_srv_options_t * const opts, if (strncasecmp(opts->config[CONF_ENABLE_RULE_PREPEND], "Y", 1) == 0) { snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -I %s %s", - opts->fw_config->fw_command, fw_chain, fw_rule); + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, + fw_chain, fw_rule); } else { snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -A %s %s", - opts->fw_config->fw_command, fw_chain, fw_rule); + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, + fw_chain, fw_rule); } res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR, NO_TIMEOUT, &pid_status, opts); @@ -1260,7 +1275,8 @@ ipt_rule(const fko_srv_options_t * const opts, const unsigned int exp_ts, const time_t now, const char * const msg, - const char * const access_msg) + const char * const access_msg, + int ipv6) { char rule_buf[CMD_BUFSIZE] = {0}; @@ -1285,12 +1301,12 @@ ipt_rule(const fko_srv_options_t * const opts, /* Check to make sure that the chain and jump rule exist */ - mk_chain(opts, chain->type); + mk_chain(opts, chain->type, ipv6); if(rule_exists(opts, chain, rule_buf, proto, srcip, - dstip, port, nat_ip, nat_port, exp_ts) == 0) + dstip, port, nat_ip, nat_port, exp_ts, ipv6) == 0) { - if(create_rule(opts, chain->to_chain, rule_buf)) + if(create_rule(opts, chain->to_chain, rule_buf, ipv6)) { log_msg(LOG_INFO, "Added %s rule to %s for %s -> %s %s, expires at %u", msg, chain->to_chain, srcip, (dstip == NULL) ? IPT_ANY_IP : dstip, @@ -1319,7 +1335,8 @@ static void forward_access_rule(const fko_srv_options_t * const opts, const unsigned int fst_port, spa_data_t * const spadat, const unsigned int exp_ts, - const time_t now) + const time_t now, + int ipv6) { char rule_buf[CMD_BUFSIZE] = {0}; @@ -1342,7 +1359,7 @@ static void forward_access_rule(const fko_srv_options_t * const opts, */ ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT, - fwd_chain, exp_ts, now, "FORWARD ALL", "*/*"); + fwd_chain, exp_ts, now, "FORWARD ALL", "*/*", ipv6); } else { @@ -1358,7 +1375,7 @@ static void forward_access_rule(const fko_srv_options_t * const opts, */ ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, NULL, fst_proto, nat_port, NULL, NAT_ANY_PORT, - fwd_chain, exp_ts, now, "FORWARD", spadat->spa_message_remain); + fwd_chain, exp_ts, now, "FORWARD", spadat->spa_message_remain, ipv6); } return; } @@ -1372,7 +1389,8 @@ static void dnat_rule(const fko_srv_options_t * const opts, const unsigned int fst_port, spa_data_t * const spadat, const unsigned int exp_ts, - const time_t now) + const time_t now, + int ipv6) { char rule_buf[CMD_BUFSIZE] = {0}; @@ -1396,7 +1414,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, */ ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT, - dnat_chain, exp_ts, now, "DNAT ALL", "*/*"); + dnat_chain, exp_ts, now, "DNAT ALL", "*/*", ipv6); } else { @@ -1417,7 +1435,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), fst_proto, fst_port, nat_ip, nat_port, dnat_chain, exp_ts, now, - "DNAT", spadat->spa_message_remain); + "DNAT", spadat->spa_message_remain, ipv6); } return; } @@ -1430,7 +1448,8 @@ static void snat_rule(const fko_srv_options_t * const opts, const unsigned int fst_port, spa_data_t * const spadat, const unsigned int exp_ts, - const time_t now) + const time_t now, + int ipv6) { char rule_buf[CMD_BUFSIZE] = {0}; char snat_target[SNAT_TARGET_BUFSIZE] = {0}; @@ -1478,7 +1497,7 @@ static void snat_rule(const fko_srv_options_t * const opts, ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT, - snat_chain, exp_ts, now, "SNAT ALL", "*/*"); + snat_chain, exp_ts, now, "SNAT ALL", "*/*", ipv6); } else { @@ -1529,7 +1548,7 @@ static void snat_rule(const fko_srv_options_t * const opts, ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, NULL, fst_proto, nat_port, nat_ip, nat_port, snat_chain, exp_ts, now, "SNAT", - spadat->spa_message_remain); + spadat->spa_message_remain, ipv6); } return; } @@ -1563,6 +1582,8 @@ process_spa_request(const fko_srv_options_t * const opts, time_t now; unsigned int exp_ts; + int ipv6 = 0; + /* Parse and expand our access message. */ if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1) @@ -1610,7 +1631,7 @@ process_spa_request(const fko_srv_options_t * const opts, if((ndx != NULL) && (str_len <= MAX_HOSTNAME_LEN)) { strlcpy(nat_dst, spadat->nat_access, str_len+1); - if(! is_valid_ip_addr(nat_dst, str_len, AF_INET)) + if(! is_valid_ip_addr(nat_dst, str_len, ipv6 ? AF_INET6 : AF_INET)) { if(strncasecmp(opts->config[CONF_ENABLE_NAT_DNS], "Y", 1) == 0) { @@ -1668,27 +1689,27 @@ process_spa_request(const fko_srv_options_t * const opts, ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), fst_proto, nat_port, nat_ip, nat_port, in_chain, exp_ts, - now, "local NAT", spadat->spa_message_remain); + now, "local NAT", spadat->spa_message_remain, ipv6); } else if(strlen(fwd_chain->to_chain)) { /* FORWARD access rule */ forward_access_rule(opts, acc, fwd_chain, nat_ip, - nat_port, fst_proto, fst_port, spadat, exp_ts, now); + nat_port, fst_proto, fst_port, spadat, exp_ts, now, ipv6); } /* DNAT rule */ if(strlen(dnat_chain->to_chain) && !acc->disable_dnat) dnat_rule(opts, acc, dnat_chain, nat_ip, - nat_port, fst_proto, fst_port, spadat, exp_ts, now); + nat_port, fst_proto, fst_port, spadat, exp_ts, now, ipv6); /* SNAT rule */ if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0) snat_rule(opts, acc, nat_ip, nat_port, - fst_proto, fst_port, spadat, exp_ts, now); + fst_proto, fst_port, spadat, exp_ts, now, ipv6); } else /* Non-NAT request - this is the typical case. */ { @@ -1699,7 +1720,7 @@ process_spa_request(const fko_srv_options_t * const opts, ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->proto, ple->port, NULL, NAT_ANY_PORT, - in_chain, exp_ts, now, "access", spadat->spa_message_remain); + in_chain, exp_ts, now, "access", spadat->spa_message_remain, ipv6); /* We need to make a corresponding OUTPUT rule if out_chain target * is not NULL. @@ -1709,7 +1730,7 @@ process_spa_request(const fko_srv_options_t * const opts, ipt_rule(opts, NULL, IPT_OUT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->proto, ple->port, NULL, NAT_ANY_PORT, - out_chain, exp_ts, now, "OUTPUT", spadat->spa_message_remain); + out_chain, exp_ts, now, "OUTPUT", spadat->spa_message_remain, ipv6); } ple = ple->next; } diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h index 9869f6e7..dc2680c0 100644 --- a/server/fw_util_iptables.h +++ b/server/fw_util_iptables.h @@ -49,9 +49,9 @@ #define IPT_DNAT_ALL_RULE_ARGS "-t %s -s %s -d %s -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s" SH_REDIR #define IPT_SNAT_RULE_ARGS "-t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR #define IPT_SNAT_ALL_RULE_ARGS "-t %s -s %s -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR -#define IPT_TMP_COMMENT_ARGS "-t %s -I %s %i -s " DUMMY_IP " -m comment --comment " TMP_COMMENT " -j %s" SH_REDIR -#define IPT_TMP_CHK_RULE_ARGS "-t %s -I %s %i -s " DUMMY_IP " -p udp -j %s" SH_REDIR -#define IPT_TMP_VERIFY_CHK_ARGS "-t %s -C %s -s " DUMMY_IP " -p udp -j %s" SH_REDIR +#define IPT_TMP_COMMENT_ARGS "-t %s -I %s %i -s %s -m comment --comment " TMP_COMMENT " -j %s" SH_REDIR +#define IPT_TMP_CHK_RULE_ARGS "-t %s -I %s %i -s %s -p udp -j %s" SH_REDIR +#define IPT_TMP_VERIFY_CHK_ARGS "-t %s -C %s -s %s -p udp -j %s" SH_REDIR #define IPT_DEL_RULE_ARGS "-t %s -D %s %i" SH_REDIR #define IPT_NEW_CHAIN_ARGS "-t %s -N %s" SH_REDIR #define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s" SH_REDIR From dd0597f7f82023dcd13c41b59e680c86ccb6ec4b Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:09:49 +0200 Subject: [PATCH 59/78] Code cleanup --- server/fw_util_iptables.c | 1 - 1 file changed, 1 deletion(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 8cb0d595..7ee9ae2a 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1550,7 +1550,6 @@ static void snat_rule(const fko_srv_options_t * const opts, snat_chain, exp_ts, now, "SNAT", spadat->spa_message_remain, ipv6); } - return; } /****************************************************************************/ From ba4d095daabb33b0424db415ee4b7dfad642bd83 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:10:02 +0200 Subject: [PATCH 60/78] Fix a couple more uses of ctype(3) --- server/fw_util_iptables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 7ee9ae2a..b30b5e74 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1038,7 +1038,7 @@ set_fw_chain_conf(const int type, const char * const conf_str) && *ndx != ' ' && *ndx != ',' && *ndx != '_' - && isalnum(*ndx) == 0) + && isalnum((int)(unsigned char)*ndx) == 0) { log_msg(LOG_ERR, "[*] Custom chain config parse error: " "invalid character '%c' for chain type %i, " @@ -1998,7 +1998,7 @@ validate_ipt_chain_conf(const char * const chain_str) && *ndx != ' ' && *ndx != ',' && *ndx != '_' - && isalnum(*ndx) == 0) + && isalnum((int)(unsigned char)*ndx) == 0) { rv = 0; break; From 282aa2dc09fddf92a2182b18841a7446b292194f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:10:49 +0200 Subject: [PATCH 61/78] Provide enough space to resolve IPv6 addresses --- server/fw_util_iptables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index b30b5e74..737609c4 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1560,7 +1560,7 @@ int process_spa_request(const fko_srv_options_t * const opts, const acc_stanza_t * const acc, spa_data_t * const spadat) { - char nat_ip[MAX_IPV4_STR_LEN] = {0}; + char nat_ip[MAX_IPV46_STR_LEN] = {0}; char nat_dst[MAX_HOSTNAME_LEN] = {0}; unsigned int nat_port = 0; @@ -1661,7 +1661,7 @@ process_spa_request(const fko_srv_options_t * const opts, } else { - strlcpy(nat_ip, nat_dst, MAX_IPV4_STR_LEN); + strlcpy(nat_ip, nat_dst, MAX_IPV46_STR_LEN); } nat_port = strtol_wrapper(ndx+1, 0, MAX_PORT, From 68cacee9f18e416a99dea0a572702bf32e2d4736 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 17:58:36 +0200 Subject: [PATCH 62/78] Remove support for IPv6 for rules shared with IPv4 --- server/fw_util_iptables.c | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 737609c4..706e2534 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -187,7 +187,7 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, static int rule_exists_chk_support(const fko_srv_options_t * const opts, - const char * const chain, const char * const rule, int ipv6) + const char * const chain, const char * const rule) { int rule_exists = 0; int res = 0; @@ -195,7 +195,7 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS, - ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, + opts->fw_config->fw_command, chain, rule); res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, @@ -239,7 +239,7 @@ rule_exists(const fko_srv_options_t * const opts, int rule_exists = 0; if(have_ipt_chk_support == 1) - rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule, ipv6); + rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); else rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, @@ -400,14 +400,14 @@ comment_match_exists(const fko_srv_options_t * const opts, int ipv6) } static int -add_jump_rule(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) { int res = 0, rv = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - ipv6 ? fwc.fw_command6 : fwc.fw_command, + fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain, fwc.chain[chain_num].jump_rule_pos, @@ -435,14 +435,14 @@ add_jump_rule(const fko_srv_options_t * const opts, const int chain_num, int ipv } static int -chain_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +chain_exists(const fko_srv_options_t * const opts, const int chain_num) { int res = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS, - ipv6 ? fwc.fw_command6 : fwc.fw_command, + fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -466,7 +466,7 @@ chain_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6 } static int -jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num) { int exists = 0; char rule_buf[CMD_BUFSIZE] = {0}; @@ -476,7 +476,7 @@ jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int cha fwc.chain[chain_num].to_chain ); - if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf, ipv6) == 1) + if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf) == 1) { log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule found"); exists = 1; @@ -518,12 +518,12 @@ jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, } static int -jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num) { int exists = 0; if(have_ipt_chk_support == 1) - exists = jump_rule_exists_chk_support(opts, chain_num, ipv6); + exists = jump_rule_exists_chk_support(opts, chain_num); else exists = jump_rule_exists_no_chk_support(opts, chain_num); @@ -696,7 +696,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) * is there. */ cmd_ctr = 0; - while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i, ipv6) == 1)) + while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1)) { zero_cmd_buffers(); @@ -834,7 +834,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) } static int -create_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +create_chain(const fko_srv_options_t * const opts, const int chain_num) { int res = 0, rv = 0; @@ -843,7 +843,7 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6 /* Create the custom chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, - ipv6 ? fwc.fw_command6 : fwc.fw_command, + fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -866,18 +866,18 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6 } static int -mk_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) +mk_chain(const fko_srv_options_t * const opts, const int chain_num) { int err = 0; /* Make sure the required chain and jump rule exist */ - if(! chain_exists(opts, chain_num, ipv6)) - if(! create_chain(opts, chain_num, ipv6)) + if(! chain_exists(opts, chain_num)) + if(! create_chain(opts, chain_num)) err++; - if (! jump_rule_exists(opts, chain_num, ipv6)) - if(! add_jump_rule(opts, chain_num, ipv6)) + if (! jump_rule_exists(opts, chain_num)) + if(! add_jump_rule(opts, chain_num)) err++; return err; @@ -898,7 +898,7 @@ create_fw_chains(const fko_srv_options_t * const opts, int ipv6) if(fwc.chain[i].target[0] == '\0') continue; - got_err += mk_chain(opts, i, ipv6); + got_err += mk_chain(opts, i); } #if USE_LIBNETFILTER_QUEUE @@ -932,7 +932,7 @@ create_fw_chains(const fko_srv_options_t * const opts, int ipv6) /* Create the rule to direct traffic to the NFQ chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - ipv6 ? fwc.fw_command6 : fwc.fw_command, + fwc.fw_command, opts->config[CONF_NFQ_TABLE], "INPUT", 1, @@ -1301,7 +1301,7 @@ ipt_rule(const fko_srv_options_t * const opts, /* Check to make sure that the chain and jump rule exist */ - mk_chain(opts, chain->type, ipv6); + mk_chain(opts, chain->type); if(rule_exists(opts, chain, rule_buf, proto, srcip, dstip, port, nat_ip, nat_port, exp_ts, ipv6) == 0) From d28d1cb12de6433facf00253f46f7ffa100759bd Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 18:16:39 +0200 Subject: [PATCH 63/78] Add support for rule expiration with IPv6 --- server/fw_util_iptables.c | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 706e2534..6ebc68de 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -701,7 +701,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_JUMP_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[i].table, fwc.chain[i].from_chain, fwc.chain[i].to_chain @@ -727,7 +727,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) /* Now flush and remove the chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_FLUSH_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[i].table, fwc.chain[i].to_chain ); @@ -747,7 +747,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[i].table, fwc.chain[i].to_chain ); @@ -773,7 +773,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) /* Delete the rule to direct traffic to the NFQ chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], "INPUT", 1 @@ -794,7 +794,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) /* Flush the NFQ chain */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_FLUSH_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], opts->config[CONF_NFQ_CHAIN] ); @@ -814,7 +814,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) /* Delete the NF_QUEUE chains and rules */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], opts->config[CONF_NFQ_CHAIN] ); @@ -932,7 +932,7 @@ create_fw_chains(const fko_srv_options_t * const opts, int ipv6) /* Create the rule to direct traffic to the NFQ chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], "INPUT", 1, @@ -961,7 +961,7 @@ create_fw_chains(const fko_srv_options_t * const opts, int ipv6) if(strlen(opts->config[CONF_NFQ_INTERFACE]) > 0) { snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NFQ_ADD_ARGS_WITH_IF, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, opts->config[CONF_NFQ_TABLE], opts->config[CONF_NFQ_CHAIN], opts->config[CONF_NFQ_INTERFACE], @@ -1745,7 +1745,7 @@ process_spa_request(const fko_srv_options_t * const opts, static void rm_expired_rules(const fko_srv_options_t * const opts, const char * const ipt_output_buf, - char *ndx, struct fw_chain *ch, int cpos, time_t now) + char *ndx, struct fw_chain *ch, int cpos, time_t now, int ipv6) { char exp_str[12] = {0}; char rule_num_str[6] = {0}; @@ -1843,7 +1843,7 @@ rm_expired_rules(const fko_srv_options_t * const opts, zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, ch[cpos].table, ch[cpos].to_chain, rule_num - rn_offset /* account for position of previously @@ -1893,16 +1893,14 @@ rm_expired_rules(const fko_srv_options_t * const opts, ch[cpos].next_expire = 0; else if(min_exp) ch[cpos].next_expire = min_exp; - - return; } /* Iterate over the configure firewall access chains and purge expired * firewall rules. */ -void -check_firewall_rules(const fko_srv_options_t * const opts, - const int chk_rm_all) +static void +check_firewall_rules_do(const fko_srv_options_t * const opts, + const int chk_rm_all, int ipv6) { char *ndx; char ipt_output_buf[STANDARD_CMD_OUT_BUFSIZE] = {0}; @@ -1938,7 +1936,7 @@ check_firewall_rules(const fko_srv_options_t * const opts, * mechanism. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, ch[i].table, ch[i].to_chain ); @@ -1976,10 +1974,16 @@ check_firewall_rules(const fko_srv_options_t * const opts, continue; } - rm_expired_rules(opts, ipt_output_buf, ndx, ch, i, now); + rm_expired_rules(opts, ipt_output_buf, ndx, ch, i, now, ipv6); } +} - return; +void +check_firewall_rules(const fko_srv_options_t * const opts, + const int chk_rm_all) +{ + check_firewall_rules_do(opts, chk_rm_all, 0); + check_firewall_rules_do(opts, chk_rm_all, 1); } int From f97214bcfc6b9e061e8e6ea1d0b8ba5b26a19894 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 8 Aug 2018 19:16:03 +0200 Subject: [PATCH 64/78] Revert "Remove support for IPv6 for rules shared with IPv4" This reverts commit d33c240070db98888bb960fe89fc5542f67f6fed. --- server/fw_util_iptables.c | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 6ebc68de..31cb3c27 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -187,7 +187,7 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, static int rule_exists_chk_support(const fko_srv_options_t * const opts, - const char * const chain, const char * const rule) + const char * const chain, const char * const rule, int ipv6) { int rule_exists = 0; int res = 0; @@ -195,7 +195,7 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS, - opts->fw_config->fw_command, + ipv6 ? opts->fw_config->fw_command6 : opts->fw_config->fw_command, chain, rule); res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, @@ -239,7 +239,7 @@ rule_exists(const fko_srv_options_t * const opts, int rule_exists = 0; if(have_ipt_chk_support == 1) - rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); + rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule, ipv6); else rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, @@ -400,14 +400,14 @@ comment_match_exists(const fko_srv_options_t * const opts, int ipv6) } static int -add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) +add_jump_rule(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0, rv = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain, fwc.chain[chain_num].jump_rule_pos, @@ -435,14 +435,14 @@ add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) } static int -chain_exists(const fko_srv_options_t * const opts, const int chain_num) +chain_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0; zero_cmd_buffers(); snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -466,7 +466,7 @@ chain_exists(const fko_srv_options_t * const opts, const int chain_num) } static int -jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num) +jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int exists = 0; char rule_buf[CMD_BUFSIZE] = {0}; @@ -476,7 +476,7 @@ jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int cha fwc.chain[chain_num].to_chain ); - if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf) == 1) + if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf, ipv6) == 1) { log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule found"); exists = 1; @@ -518,12 +518,12 @@ jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, } static int -jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num) +jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int exists = 0; if(have_ipt_chk_support == 1) - exists = jump_rule_exists_chk_support(opts, chain_num); + exists = jump_rule_exists_chk_support(opts, chain_num, ipv6); else exists = jump_rule_exists_no_chk_support(opts, chain_num); @@ -696,7 +696,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) * is there. */ cmd_ctr = 0; - while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1)) + while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i, ipv6) == 1)) { zero_cmd_buffers(); @@ -834,7 +834,7 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) } static int -create_chain(const fko_srv_options_t * const opts, const int chain_num) +create_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int res = 0, rv = 0; @@ -843,7 +843,7 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num) /* Create the custom chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, - fwc.fw_command, + ipv6 ? fwc.fw_command6 : fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -866,18 +866,18 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num) } static int -mk_chain(const fko_srv_options_t * const opts, const int chain_num) +mk_chain(const fko_srv_options_t * const opts, const int chain_num, int ipv6) { int err = 0; /* Make sure the required chain and jump rule exist */ - if(! chain_exists(opts, chain_num)) - if(! create_chain(opts, chain_num)) + if(! chain_exists(opts, chain_num, ipv6)) + if(! create_chain(opts, chain_num, ipv6)) err++; - if (! jump_rule_exists(opts, chain_num)) - if(! add_jump_rule(opts, chain_num)) + if (! jump_rule_exists(opts, chain_num, ipv6)) + if(! add_jump_rule(opts, chain_num, ipv6)) err++; return err; @@ -898,7 +898,7 @@ create_fw_chains(const fko_srv_options_t * const opts, int ipv6) if(fwc.chain[i].target[0] == '\0') continue; - got_err += mk_chain(opts, i); + got_err += mk_chain(opts, i, ipv6); } #if USE_LIBNETFILTER_QUEUE @@ -1301,7 +1301,7 @@ ipt_rule(const fko_srv_options_t * const opts, /* Check to make sure that the chain and jump rule exist */ - mk_chain(opts, chain->type); + mk_chain(opts, chain->type, ipv6); if(rule_exists(opts, chain, rule_buf, proto, srcip, dstip, port, nat_ip, nat_port, exp_ts, ipv6) == 0) From 0bbbd13d4568a26367619643f34cee1157b35e5c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 15:59:07 +0200 Subject: [PATCH 65/78] Code cleanup --- server/fw_util_iptables.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 31cb3c27..105f1a13 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -325,8 +325,6 @@ ipt_chk_support(const fko_srv_options_t * const opts, int ipv6) ); run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR, NO_TIMEOUT, &pid_status, opts); - - return; } static int @@ -830,7 +828,6 @@ delete_all_chains(const fko_srv_options_t * const opts, int ipv6) log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); } #endif - return; } static int @@ -1322,8 +1319,6 @@ ipt_rule(const fko_srv_options_t * const opts, chain->next_expire = exp_ts; } } - - return; } static void forward_access_rule(const fko_srv_options_t * const opts, @@ -1377,7 +1372,6 @@ static void forward_access_rule(const fko_srv_options_t * const opts, NULL, fst_proto, nat_port, NULL, NAT_ANY_PORT, fwd_chain, exp_ts, now, "FORWARD", spadat->spa_message_remain, ipv6); } - return; } static void dnat_rule(const fko_srv_options_t * const opts, @@ -1437,7 +1431,6 @@ static void dnat_rule(const fko_srv_options_t * const opts, fst_proto, fst_port, nat_ip, nat_port, dnat_chain, exp_ts, now, "DNAT", spadat->spa_message_remain, ipv6); } - return; } static void snat_rule(const fko_srv_options_t * const opts, From 2bdaeff67df1e2f20847d93261c4a9a3b8ac8e3e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:08:42 +0200 Subject: [PATCH 66/78] Default to IPv6 rules when listening on IPv6 --- server/fw_util_iptables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 105f1a13..fcf31cdf 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1574,7 +1574,8 @@ process_spa_request(const fko_srv_options_t * const opts, time_t now; unsigned int exp_ts; - int ipv6 = 0; + /* XXX set adequately per SPA message */ + int ipv6 = (opts->family == AF_INET6) ? 1 : 0; /* Parse and expand our access message. */ From fd6def040f9145fa6b3b7ad27317b817c77f8270 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:11:20 +0200 Subject: [PATCH 67/78] Remove useless code --- common/fko_util.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index 3571bd65..e672f97c 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -199,9 +199,6 @@ is_valid_hostname(const char * const hostname_str, const int len) if (*ndx == '-') return 0; - if (*ndx == '.') - total_size--; - if (label_size > 63) return 0; From 561ba964f3a9e75759ed34575935abac740915e4 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:27:21 +0200 Subject: [PATCH 68/78] Resolve hostnames to IPv6 addresses in IPv6 mode --- common/fko_util.c | 6 +++--- common/fko_util.h | 2 +- server/fw_util_firewalld.c | 4 ++-- server/fw_util_iptables.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index e672f97c..a1fa4dbd 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -1035,10 +1035,10 @@ get_in_addr(struct sockaddr *sa) * @return 0 if successful, 1 if an error occurred. */ int -ipv4_resolve(const char *dns_str, char *ip_str) +ip_resolve(const char *dns_str, char *ip_str, int family) { int error; /* Function error return code */ - size_t ip_bufsize = MAX_IPV4_STR_LEN; + size_t ip_bufsize = MAX_IPV46_STR_LEN; struct addrinfo hints; struct addrinfo *result; /* Result of getaddrinfo() */ struct addrinfo *rp; /* Element of the linked list returned by getaddrinfo() */ @@ -1061,7 +1061,7 @@ ipv4_resolve(const char *dns_str, char *ip_str) #endif memset(&hints, 0 , sizeof(hints)); - hints.ai_family = AF_INET; + hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; diff --git a/common/fko_util.h b/common/fko_util.h index 3fa4115f..83f2486b 100644 --- a/common/fko_util.h +++ b/common/fko_util.h @@ -74,7 +74,7 @@ int count_characters(const char *str, const char match, int len); int strtoargv(const char * const args_str, char **argv_new, int *argc_new); void free_argv(char **argv_new, int *argc_new); -int ipv4_resolve(const char *dns_str, char *ip_str); +int ip_resolve(const char *dns_str, char *ip_str, int family); #if !HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); #endif diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index a6c875c5..1c3f4c3a 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -1494,7 +1494,7 @@ int process_spa_request(const fko_srv_options_t * const opts, const acc_stanza_t * const acc, spa_data_t * const spadat) { - char nat_ip[MAX_IPV4_STR_LEN] = {0}; + char nat_ip[MAX_IPV46_STR_LEN] = {0}; char nat_dst[MAX_HOSTNAME_LEN] = {0}; unsigned int nat_port = 0; unsigned int fst_proto; @@ -1571,7 +1571,7 @@ process_spa_request(const fko_srv_options_t * const opts, free_acc_port_list(port_list); return res; } - if (ipv4_resolve(nat_dst, nat_ip) == 0) + if (ip_resolve(nat_dst, nat_ip, AF_INET) == 0) { log_msg(LOG_INFO, "Resolved NAT IP in SPA message"); } diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index fcf31cdf..7bb4bcf9 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1634,7 +1634,7 @@ process_spa_request(const fko_srv_options_t * const opts, free_acc_port_list(port_list); return res; } - if (ipv4_resolve(nat_dst, nat_ip) == 0) + if (ip_resolve(nat_dst, nat_ip, ipv6 ? AF_INET6 : AF_INET) == 0) { log_msg(LOG_INFO, "Resolved NAT IP in SPA message"); } From 159c62c8ef30e0629d6d7eb00304e44d845b1c34 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:28:52 +0200 Subject: [PATCH 69/78] Re-indent --- common/fko_util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index a1fa4dbd..61fbfebc 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -1080,13 +1080,13 @@ ip_resolve(const char *dns_str, char *ip_str, int family) memset(ip_str, 0, ip_bufsize); #if WIN32 && WINVER <= 0x0600 - /* On older Windows systems (anything before Vista?), - * we use inet_ntoa for now. - */ - in = (struct sockaddr_in*)(rp->ai_addr); - win_ip = inet_ntoa(in->sin_addr); + /* On older Windows systems (anything before Vista?), + * we use inet_ntoa for now. + */ + in = (struct sockaddr_in*)(rp->ai_addr); + win_ip = inet_ntoa(in->sin_addr); - if (win_ip != NULL && (strlcpy(ip_str, win_ip, ip_bufsize) > 0)) + if (win_ip != NULL && (strlcpy(ip_str, win_ip, ip_bufsize) > 0)) #else sai_remote = (struct sockaddr_in *)get_in_addr((struct sockaddr *)(rp->ai_addr)); if (inet_ntop(rp->ai_family, sai_remote, ip_str, ip_bufsize) != NULL) From 70df56f73cb3ae9693d12c7936b22f835d411f45 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:31:56 +0200 Subject: [PATCH 70/78] Only support IPv4 on Windows --- common/fko_util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/fko_util.c b/common/fko_util.c index 61fbfebc..e0b165e5 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -1080,6 +1080,8 @@ ip_resolve(const char *dns_str, char *ip_str, int family) memset(ip_str, 0, ip_bufsize); #if WIN32 && WINVER <= 0x0600 + if(rp->ai_family != AF_INET) + continue; /* On older Windows systems (anything before Vista?), * we use inet_ntoa for now. */ From c1d3656f0be6b40615c75d2e36f1070f8b0f1a2a Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sun, 12 Aug 2018 16:38:00 +0200 Subject: [PATCH 71/78] Code cleanup --- common/fko_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/fko_util.c b/common/fko_util.c index e0b165e5..ddd6898b 100644 --- a/common/fko_util.c +++ b/common/fko_util.c @@ -1047,7 +1047,7 @@ ip_resolve(const char *dns_str, char *ip_str, int family) struct sockaddr_in *in; char *win_ip; #else - struct sockaddr_in *sai_remote; /* Remote host information as a sockaddr_in structure */ + char *sai_remote; /* Remote host information */ #endif #if WIN32 @@ -1090,7 +1090,7 @@ ip_resolve(const char *dns_str, char *ip_str, int family) if (win_ip != NULL && (strlcpy(ip_str, win_ip, ip_bufsize) > 0)) #else - sai_remote = (struct sockaddr_in *)get_in_addr((struct sockaddr *)(rp->ai_addr)); + sai_remote = get_in_addr((struct sockaddr *)(rp->ai_addr)); if (inet_ntop(rp->ai_family, sai_remote, ip_str, ip_bufsize) != NULL) #endif { From 73d7b7904bbf8c5a93f10520393ee5f15089b8ae Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 15 Aug 2018 17:14:51 +0200 Subject: [PATCH 72/78] Use "::" for matching any address for IPv6 rules --- server/fw_util_iptables.c | 23 ++++++++++++++++------- server/fw_util_iptables.h | 1 + 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 7bb4bcf9..79e99087 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -56,6 +56,15 @@ zero_cmd_buffers(void) memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE); } +static char const * +any_ip(int ipv6) +{ + if(ipv6) + return IPT_ANY_IPV6; + else + return IPT_ANY_IP; +} + static int pid_status = 0; static int @@ -1306,7 +1315,7 @@ ipt_rule(const fko_srv_options_t * const opts, if(create_rule(opts, chain->to_chain, rule_buf, ipv6)) { log_msg(LOG_INFO, "Added %s rule to %s for %s -> %s %s, expires at %u", - msg, chain->to_chain, srcip, (dstip == NULL) ? IPT_ANY_IP : dstip, + msg, chain->to_chain, srcip, (dstip == NULL) ? any_ip(ipv6) : dstip, access_msg, exp_ts ); @@ -1398,7 +1407,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, snprintf(rule_buf, CMD_BUFSIZE-1, IPT_DNAT_ALL_RULE_ARGS, dnat_chain->table, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), exp_ts, dnat_chain->target, nat_ip @@ -1418,7 +1427,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, dnat_chain->table, fst_proto, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), fst_port, exp_ts, dnat_chain->target, @@ -1427,7 +1436,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, ); ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), fst_proto, fst_port, nat_ip, nat_port, dnat_chain, exp_ts, now, "DNAT", spadat->spa_message_remain, ipv6); } @@ -1680,7 +1689,7 @@ process_spa_request(const fko_srv_options_t * const opts, || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG) { ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), fst_proto, nat_port, nat_ip, nat_port, in_chain, exp_ts, now, "local NAT", spadat->spa_message_remain, ipv6); } @@ -1711,7 +1720,7 @@ process_spa_request(const fko_srv_options_t * const opts, while(ple != NULL) { ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), ple->proto, ple->port, NULL, NAT_ANY_PORT, in_chain, exp_ts, now, "access", spadat->spa_message_remain, ipv6); @@ -1721,7 +1730,7 @@ process_spa_request(const fko_srv_options_t * const opts, if(strlen(out_chain->to_chain)) { ipt_rule(opts, NULL, IPT_OUT_RULE_ARGS, spadat->use_src_ip, - (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), + (fwc.use_destination ? spadat->pkt_destination_ip : any_ip(ipv6)), ple->proto, ple->port, NULL, NAT_ANY_PORT, out_chain, exp_ts, now, "OUTPUT", spadat->spa_message_remain, ipv6); } diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h index dc2680c0..92299e9e 100644 --- a/server/fw_util_iptables.h +++ b/server/fw_util_iptables.h @@ -63,6 +63,7 @@ #define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n" SH_REDIR #define IPT_LIST_ALL_RULES_ARGS "-t %s -v -n -L --line-numbers" SH_REDIR #define IPT_ANY_IP "0.0.0.0/0" +#define IPT_ANY_IPV6 "::" #if USE_LIBNETFILTER_QUEUE #define IPT_NFQ_ADD_ARGS "-t %s -A %s -p udp -m udp --dport %s -j NFQUEUE --queue-num %s" From 460774cafdc710adfe20f00824b1e624d45131ba Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 15 Aug 2018 17:39:33 +0200 Subject: [PATCH 73/78] No longer accept colon (":") as port separator The correct syntax is the comma (",") instead. --- client/fwknop.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/client/fwknop.c b/client/fwknop.c index b4f0592f..011a9087 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -774,12 +774,6 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc if (nat_access_buf[0] == 0x0 && options->nat_access_str[0] != 0x0) { - /* Force the ':' (if any) to a ',' - */ - ndx = strchr(options->nat_access_str, ':'); - if (ndx != NULL) - *ndx = ','; - ndx = strchr(options->nat_access_str, ','); if (ndx != NULL) { From f3895bb721b1276dafcadcd2ce910b306a8c8d4c Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 15 Aug 2018 18:52:20 +0200 Subject: [PATCH 74/78] Fix DNAT with IPv6 --- server/fw_util_iptables.c | 2 +- server/fw_util_iptables.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 79e99087..341bb2bf 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -1423,7 +1423,7 @@ static void dnat_rule(const fko_srv_options_t * const opts, { memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_DNAT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, ipv6 ? IPT_DNAT_RULE_ARGS_IPV6 : IPT_DNAT_RULE_ARGS, dnat_chain->table, fst_proto, spadat->use_src_ip, diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h index 92299e9e..09b45a50 100644 --- a/server/fw_util_iptables.h +++ b/server/fw_util_iptables.h @@ -46,6 +46,7 @@ #define IPT_FWD_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR #define IPT_FWD_ALL_RULE_ARGS "-t %s -s %s -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR #define IPT_DNAT_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i" SH_REDIR +#define IPT_DNAT_RULE_ARGS_IPV6 "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination [%s]:%i" SH_REDIR #define IPT_DNAT_ALL_RULE_ARGS "-t %s -s %s -d %s -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s" SH_REDIR #define IPT_SNAT_RULE_ARGS "-t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR #define IPT_SNAT_ALL_RULE_ARGS "-t %s -s %s -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR From 46d4d77a66bb4ebec5a1061fa38b409866a71f8f Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 17 Aug 2018 00:42:04 +0200 Subject: [PATCH 75/78] Use "::/0" for IPT_ANY_IPV6 --- server/fw_util_iptables.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h index 09b45a50..7903b73e 100644 --- a/server/fw_util_iptables.h +++ b/server/fw_util_iptables.h @@ -64,7 +64,7 @@ #define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n" SH_REDIR #define IPT_LIST_ALL_RULES_ARGS "-t %s -v -n -L --line-numbers" SH_REDIR #define IPT_ANY_IP "0.0.0.0/0" -#define IPT_ANY_IPV6 "::" +#define IPT_ANY_IPV6 "::/0" #if USE_LIBNETFILTER_QUEUE #define IPT_NFQ_ADD_ARGS "-t %s -A %s -p udp -m udp --dport %s -j NFQUEUE --queue-num %s" From 3f3b304cf40d9dd6725a4f0639a03d5adec4cf15 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 17 Aug 2018 01:55:03 +0200 Subject: [PATCH 76/78] Port src_dst_check() to IPv6 The problem looks real, fix looks good to me, but have not been able to reproduce the actual issue so far :( --- server/incoming_spa.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 75cb041d..fedfb097 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -441,16 +441,32 @@ static int src_dst_check(acc_stanza_t *acc, spa_pkt_info_t *spa_pkt, spa_data_t *spadat, const int stanza_num) { - if(! compare_addr_list(acc->source_list, AF_INET, ntohl(spa_pkt->packet_src_ip)) || - (acc->destination_list != NULL - && ! compare_addr_list(acc->destination_list, AF_INET, ntohl(spa_pkt->packet_dst_ip)))) + switch (spa_pkt->packet_family) { - log_msg(LOG_DEBUG, - "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria", - stanza_num, spadat->pkt_source_ip, spadat->pkt_destination_ip); - return 0; + case AF_INET: + if(! compare_addr_list(acc->source_list, AF_INET, ntohl(spa_pkt->packet_src_ip)) || + (acc->destination_list != NULL + && ! compare_addr_list(acc->destination_list, AF_INET, ntohl(spa_pkt->packet_dst_ip)))) + { + log_msg(LOG_DEBUG, + "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria", + stanza_num, spadat->pkt_source_ip, spadat->pkt_destination_ip); + return 0; + } + return 1; + case AF_INET6: + if(! compare_addr_list(acc->source_list, AF_INET6, &spa_pkt->packet_addr.inet6.src_ip) || + (acc->destination_list != NULL + && ! compare_addr_list(acc->destination_list, AF_INET6, &spa_pkt->packet_addr.inet6.dst_ip))) + { + log_msg(LOG_DEBUG, + "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria", + stanza_num, spadat->pkt_source_ip, spadat->pkt_destination_ip); + return 0; + } + return 1; } - return 1; + return 0; } /* Process command messages From a2edaecad3f2dd9149ce5f5106ab5063512926cd Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 22 Aug 2018 16:41:27 +0200 Subject: [PATCH 77/78] Also output the value obtained for ip6tables This should address #1. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 8d9efecd..f331bdfe 100644 --- a/configure.ac +++ b/configure.ac @@ -871,6 +871,7 @@ if [test "$want_server" = "yes" ]; then echo " Server support: firewall type: $FIREWALL_TYPE firewall program path: $FIREWALL_EXE + firewall program path: $FIREWALL_EXE_IPV6 (for IPv6) " if [test "$want_udp_server" = "yes" ]; then echo " UDP server mode enabled, no libpcap dependency From 91f38424756bf060154ff29264b203d3122de7e3 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 25 Aug 2018 01:01:50 +0200 Subject: [PATCH 78/78] Complete the check and search for ip6tables Fixes #1. --- configure.ac | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index f331bdfe..4b1858fe 100644 --- a/configure.ac +++ b/configure.ac @@ -762,19 +762,24 @@ dnl AS_IF([test "x$FORCE_FIREWALLD_EXE" != x], [ FIREWALLD_EXE="$FORCE_FIREWALLD_EXE" ],[ - AS_IF([test "x$FORCE_IPTABLES_EXE" != x], [ - IPTABLES_EXE="$FORCE_IPTABLES_EXE" + AS_IF([test "x$FORCE_IPTABLES_EXE" != x -o "x$FORCE_IP6TABLES_EXE" != x], [ + AS_IF([test "x$FORCE_IPTABLES_EXE" != x], [ + IPTABLES_EXE="$FORCE_IPTABLES_EXE"]) + AS_IF([test "x$FORCE_IP6TABLES_EXE" != x], [ + IP6TABLES_EXE="$FORCE_IP6TABLES_EXE"]) FIREWALLD_EXE="" ],[ AS_IF([test "x$FORCE_IPFW_EXE" != x], [ IPFW_EXE="$FORCE_IPFW_EXE" IPTABLES_EXE="" + IP6TABLES_EXE="" FIREWALLD_EXE="" ],[ AS_IF([test "x$FORCE_PF_EXE" != x], [ PF_EXE="$FORCE_PF_EXE" IPFW_EXE="" IPTABLES_EXE="" + IP6TABLES_EXE="" FIREWALLD_EXE="" ],[ AS_IF([test "x$FORCE_IPF_EXE" != x], [ @@ -782,6 +787,7 @@ dnl PF_EXE="" IPFW_EXE="" IPTABLES_EXE="" + IP6TABLES_EXE="" FIREWALLD_EXE="" ] ] @@ -800,10 +806,11 @@ dnl FIREWALL_EXE=$FIREWALLD_EXE AC_DEFINE_UNQUOTED([FIREWALL_FIREWALLD], [1], [The firewall type: firewalld.]) ],[ - AS_IF([test "x$IPTABLES_EXE" != x], [ + AS_IF([test "x$IPTABLES_EXE" != x -o "x$IP6TABLES_EXE" != x], [ FW_DEF="FW_IPTABLES" FIREWALL_TYPE="iptables" FIREWALL_EXE=$IPTABLES_EXE + FIREWALL_EXE_IPV6=$IP6TABLES_EXE AC_DEFINE_UNQUOTED([FIREWALL_IPTABLES], [1], [The firewall type: iptables.]) ],[ AS_IF([test "x$IPFW_EXE" != x], [ @@ -870,9 +877,11 @@ echo " if [test "$want_server" = "yes" ]; then echo " Server support: firewall type: $FIREWALL_TYPE - firewall program path: $FIREWALL_EXE - firewall program path: $FIREWALL_EXE_IPV6 (for IPv6) -" + firewall program path: $FIREWALL_EXE" +if [test "$FIREWALL_TYPE" = "iptables" ]; then + echo " firewall program path: $FIREWALL_EXE_IPV6 (for IPv6)" + fi +echo if [test "$want_udp_server" = "yes" ]; then echo " UDP server mode enabled, no libpcap dependency "