Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IPv6 support to fwknop #285

Open
wants to merge 78 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
07693a9
Let IPs resolve to IPv6 addresses
khorben Jun 12, 2018
b8252db
Let IPs resolve to IPv6 addresses over SSL
khorben Jun 12, 2018
460bd8c
Be more consistent when creating ~/.fwknoprc
khorben Jun 12, 2018
a0dda67
Also catch the IPv6 version of INADDR_ANY
khorben Jun 12, 2018
b3494dc
Migrate is_valid_ipv4_addr() to a more generic function
khorben Jun 12, 2018
aea56f5
Implement is_valid_ip_addr() with getaddrinfo()
khorben Jun 12, 2018
f7b18d6
Give have_allow_ip() a chance to allow IPv6
khorben Jun 12, 2018
2f6ea52
Allow connecting to remote IPv6 hosts for TCP or UDP
khorben Jun 14, 2018
72a50b9
Use uppercase to log "IP"
khorben Jun 14, 2018
2367bc2
Also check for <netinet/ip6.h> and <netinet/icmp6.h>
khorben Jun 14, 2018
ce9b5fb
Rework the network listening routine
khorben Jun 15, 2018
3dc6116
Rework the network listening routine some more
khorben Jun 15, 2018
1a813bb
Code cleanup
khorben Jun 15, 2018
a525734
Also include <netinet/ip6.h> where relevant
khorben Jun 15, 2018
37a8000
Protect some more headers for inclusion
khorben Jun 15, 2018
6bcaf4f
Add support for receiving SPA messages over IPv6
khorben Jun 15, 2018
8ecd10b
Interpret incoming addresses according to their family
khorben Jun 26, 2018
89c7d6f
Let access list stanzas be defined in IPv6
khorben Jun 26, 2018
bd1c488
Typo
khorben Jun 26, 2018
a2462c6
Typo
khorben Jun 26, 2018
82a5eec
Constify
khorben Jul 9, 2018
17549b9
Use a more appropriate type for sd_len
khorben Jul 9, 2018
d1c1373
Allow access control "ANY" with any protocol family
khorben Jul 9, 2018
baed23c
Use AF_INET instead of PF_INET
khorben Jul 9, 2018
f61a308
Use sizeof() instead of re-using hard-coded values
khorben Jul 9, 2018
b070e80
Use sizeof() instead of re-using hard-coded values
khorben Jul 9, 2018
da1ab05
Use a constant for AF_INET
khorben Jul 9, 2018
76d609b
Use /usr/bin/env to locate perl
khorben Jul 10, 2018
587a4fb
Rework IPv6 support when comparing addresses
khorben Jul 10, 2018
11e9b29
Fix processing command-line arguments with whitespace
khorben Jul 10, 2018
d6ce22b
Set the address family for incoming SPA over UDP
khorben Jul 10, 2018
32cdd11
Specify the family at run-time for TCP/UDP servers
khorben Jul 10, 2018
f35c1d7
Add IPv6 support to the plain UDP and TCP servers
khorben Jul 10, 2018
7437039
Constify
khorben Jul 17, 2018
a2902cb
Terminate IPs resolved externally as expected
khorben Jul 17, 2018
c753215
Prepare access stanzas for more address families
khorben Jul 18, 2018
d260f50
Use the correct offset for inet_ntop()
khorben Jul 18, 2018
c8670aa
Simplify the calculation of pkt_data_len
khorben Jul 18, 2018
3e329a5
Correct the packet length calculation with IPv6
khorben Jul 18, 2018
9878756
Fix some issues with TCP over IPv6
khorben Jul 18, 2018
1fd5fe1
Begin to allow IPv6 addresses in source stanzas
khorben Jul 24, 2018
6405398
Add a command-line option to enable IPv6 (TCP/UDP)
khorben Jul 27, 2018
08e805d
Optimize moot variable initialization away
khorben Jul 27, 2018
15dfc94
Fix the build on Linux (iptables)
khorben Jul 27, 2018
bbb341c
Fix the build with firewalld
khorben Jul 27, 2018
3a8e01a
Update the manual page for the -6 option (--ipv6)
khorben Jul 30, 2018
13dee2c
Support further address families in the future
khorben Aug 6, 2018
9923fc0
Verify if the protocol family matches incoming packets
khorben Aug 6, 2018
c5994a3
Do not use INADDR_ANY for default ports
khorben Aug 6, 2018
e3aeb46
Check for errors from inet_addr() with INADDR_NONE
khorben Aug 6, 2018
e29d62e
Fix build with NFQ enabled
khorben Aug 7, 2018
956e1df
Allow the longest possible IPv6 address in sources
khorben Aug 7, 2018
edeea23
Add a configuration variable for IPv6 firewall binaries
khorben Aug 8, 2018
a7a9ecb
Add the fw_command6 member to the right struct fw_config
khorben Aug 8, 2018
7f9d09e
Initialize the configuration for ip6tables as well
khorben Aug 8, 2018
576eb11
Add IPv6 support to --fw-list{,all}
khorben Aug 8, 2018
81e2255
Update a comment
khorben Aug 8, 2018
fa664db
Add preliminary support for IPv6 with iptables
khorben Aug 8, 2018
dd0597f
Code cleanup
khorben Aug 8, 2018
ba4d095
Fix a couple more uses of ctype(3)
khorben Aug 8, 2018
282aa2d
Provide enough space to resolve IPv6 addresses
khorben Aug 8, 2018
68cacee
Remove support for IPv6 for rules shared with IPv4
khorben Aug 8, 2018
d28d1cb
Add support for rule expiration with IPv6
khorben Aug 8, 2018
f97214b
Revert "Remove support for IPv6 for rules shared with IPv4"
khorben Aug 8, 2018
0bbbd13
Code cleanup
khorben Aug 12, 2018
2bdaeff
Default to IPv6 rules when listening on IPv6
khorben Aug 12, 2018
fd6def0
Remove useless code
khorben Aug 12, 2018
561ba96
Resolve hostnames to IPv6 addresses in IPv6 mode
khorben Aug 12, 2018
159c62c
Re-indent
khorben Aug 12, 2018
70df56f
Only support IPv4 on Windows
khorben Aug 12, 2018
c1d3656
Code cleanup
khorben Aug 12, 2018
73d7b79
Use "::" for matching any address for IPv6 rules
khorben Aug 15, 2018
460774c
No longer accept colon (":") as port separator
khorben Aug 15, 2018
f3895bb
Fix DNAT with IPv6
khorben Aug 15, 2018
46d4d77
Use "::/0" for IPT_ANY_IPV6
khorben Aug 16, 2018
3f3b304
Port src_dst_check() to IPv6
khorben Aug 16, 2018
a2edaec
Also output the value obtained for ip6tables
khorben Aug 22, 2018
91f3842
Complete the check and search for ip6tables
khorben Aug 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions android/project/jni/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
13 changes: 7 additions & 6 deletions client/config_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <ip addr>\n"
"#ALLOW_IP <IP address>\n"
"#SPOOF_USER <username>\n"
"#SPOOF_SOURCE_IP <IPaddr>\n"
"#SPOOF_SOURCE_IP <IP address>\n"
"#TIME_OFFSET 0\n"
"#USE_GPG N\n"
"#GPG_HOMEDIR /path/to/.gnupg\n"
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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");
Expand All @@ -1861,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");
Expand All @@ -1871,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);
Expand Down
8 changes: 1 addition & 7 deletions client/fwknop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -820,7 +814,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);
Expand Down
4 changes: 2 additions & 2 deletions client/fwknop_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use INET6_ADDRSTRLEN
While you are right that longtest IPv6 address takes 39 bytes, with IPv4 tunneling, the longest form can be 45 bytes:

char spoof_ip_src_str[MAX_IPV46_STR_LEN];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use INET6_ADDRSTRLEN

char spoof_user[MAX_USERNAME_LEN];
int rand_port;
char gpg_recipient_key[MAX_GPG_KEY_ID];
Expand Down
123 changes: 64 additions & 59 deletions client/http_resolve_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +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, i;
int sock=-1, sock_success=0, i, 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};
char *ndx;
char *ndx, c;

#ifdef WIN32
WSADATA wsa_data;
Expand Down Expand Up @@ -197,45 +196,47 @@ 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
* (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<MAX_IPV46_STR_LEN; i++) {
c = *(ndx+i);
if(! isdigit((int)(unsigned char)c) && ! ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) && c != '.' && c != ':')
break;
}

/* Terminate at the first non-digit and non-dot.
*/
for(i=0; i<MAX_IPV4_STR_LEN; i++) {
if(! isdigit((int)(unsigned char)*(ndx+i)) && *(ndx+i) != '.')
break;
}

/* Terminate at the first non-digit and non-dot.
*/
*(ndx+i) = '\0';

/* Now that we have what we think is an IP address string. We make
* sure the format and values are sane.
*/
if((sscanf(ndx, "%u.%u.%u.%u", &o1, &o2, &o3, &o4)) == 4
&& o1 >= 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);
*(ndx+i) = '\0';

return(1);
}
else
/* 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;
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) {
/* the canonical value is in the first structure returned */
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
Expand Down Expand Up @@ -323,8 +324,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};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAX_IPV46_STR_LEN ?

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 */

Expand Down Expand Up @@ -493,32 +495,35 @@ resolve_ip_https(fko_cli_options_t *options)
pclose(wget);
#endif

if(got_resp)
if(! got_resp)
{
ndx = resp;
for(i=0; i<MAX_IPV4_STR_LEN; i++) {
if(! isdigit((int)(unsigned char)*(ndx+i)) && *(ndx+i) != '.')
break;
}
*(ndx+i) = '\0';

if((sscanf(ndx, "%u.%u.%u.%u", &o1, &o2, &o3, &o4)) == 4
&& o1 >= 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);
}
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));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why getting last entry ?

break;
}
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
Expand Down
Loading