From 3af8e4c51769495a702a28bd630abf37162ada6c Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Wed, 15 Aug 2012 22:49:29 -0400 Subject: [PATCH] [client] Added cipherdyne.com backup check in -R mode. Added backup check against a cipherdyne.com 'myip' cgi instance in -R mode if the normal check against cipherdyne.org fails. --- ChangeLog | 2 + client/fwknop.c | 2 + client/fwknop_common.h | 3 +- client/http_resolve_host.c | 225 ++++++++++++++++++++----------------- 4 files changed, 131 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6bcdbd02..49e0f7be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,8 @@ fwknop-2.0.2 (08//2012): remote webserver IP resolution mode (-R). Previously IP resolution could fail if HTTP headers were transferred separately from the data (for whatever reason). Jonathan Schulz submitted a patch for this. + - [client] Added backup check against a cipherdyne.com 'myip' cgi instance + in -R mode if the normal check against cipherdyne.org fails. - [server] Bug fix to implement FLUSH_IPT_AT_INIT and FLUSH_IPT_AT_EXIT functionality. These are enabled by default, and now iptables rules added by fwknopd can be made persistant by setting these variables to diff --git a/client/fwknop.c b/client/fwknop.c index 1d1f7336..97192b6c 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -152,11 +152,13 @@ main(int argc, char **argv) * if this fails, consider it fatal. */ if (options.resolve_ip_http) + { if(resolve_ip_http(&options) < 0) { fko_destroy(ctx); return(EXIT_FAILURE); } + } /* Set a message string by combining the allow IP and the * port/protocol. The fwknopd server allows no port/protocol diff --git a/client/fwknop_common.h b/client/fwknop_common.h index 5d7e8ef3..bdbe5b90 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -63,10 +63,11 @@ * for now. */ #define HTTP_RESOLVE_HOST "www.cipherdyne.org" +#define HTTP_BACKUP_RESOLVE_HOST "www.cipherdyne.com" #define HTTP_RESOLVE_URL "/cgi-bin/myip" #define HTTP_MAX_REQUEST_LEN 2000 #define HTTP_MAX_RESPONSE_LEN 2000 -#define HTTP_MAX_USER_AGENT_LEN 50 +#define HTTP_MAX_USER_AGENT_LEN 100 #define MAX_HOSTNAME_LEN 70 #define MAX_URL_HOST_LEN 256 #define MAX_URL_PATH_LEN 1024 diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index a9b7be1d..8312fbce 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -52,90 +52,12 @@ struct url }; static int -parse_url(char *res_url, struct url* url) -{ - char *s_ndx, *e_ndx; - int tlen, tlen_offset, port; - - /* https is not supported. - */ - if(strncasecmp(res_url, "https", 5) == 0) - { - fprintf(stderr, "https is not yet supported for http-resolve-ip.\n"); - return(-1); - } - - /* Strip off http:// portion if necessary - */ - if(strncasecmp(res_url, "http://", 7) == 0) - s_ndx = res_url + 7; - else - s_ndx = res_url; - - /* Look for a colon in case an alternate port was specified. - */ - e_ndx = strchr(s_ndx, ':'); - if(e_ndx != NULL) - { - port = atoi(e_ndx+1); - if(port < 1 || port > MAX_PORT) - { - fprintf(stderr, "resolve-url port value is invalid.\n"); - return(-1); - } - - sprintf(url->port, "%u", port); - - /* Get the offset we need to skip the port portion when we - * extract the hostname part. - */ - tlen_offset = strlen(url->port)+1; - } - else - { - strlcpy(url->port, "80", 3); - tlen_offset = 0; - } - - e_ndx = strchr(s_ndx, '/'); - if(e_ndx == NULL) - tlen = strlen(s_ndx)+1; - else - tlen = (e_ndx-s_ndx)+1; - - tlen -= tlen_offset; - - if(tlen > MAX_URL_HOST_LEN) - { - fprintf(stderr, "resolve-url hostname portion is too large.\n"); - return(-1); - } - strlcpy(url->host, s_ndx, tlen); - - if(e_ndx != NULL) - { - if(strlen(e_ndx) > MAX_URL_PATH_LEN) - { - fprintf(stderr, "resolve-url path portion is too large.\n"); - return(-1); - } - - strlcpy(url->path, e_ndx, MAX_URL_PATH_LEN); - } - else - *(url->path) = '\0'; - - return(0); -} - -int -resolve_ip_http(fko_cli_options_t *options) +try_url(struct url *url, fko_cli_options_t *options) { int sock, res, error, http_buf_len, i; int bytes_read = 0, position = 0; int o1, o2, o3, o4; struct addrinfo *result, *rp, hints; - struct url url; char http_buf[HTTP_MAX_REQUEST_LEN]; char http_response[HTTP_MAX_RESPONSE_LEN] = {0}; char *ndx; @@ -153,28 +75,15 @@ resolve_ip_http(fko_cli_options_t *options) } #endif - if(options->resolve_url != NULL) - { - if(parse_url(options->resolve_url, &url) < 0) - { - fprintf(stderr, "Error parsing resolve-url\n"); - return(-1); - } - } else { - strlcpy(url.port, "80", 3); - strlcpy(url.host, HTTP_RESOLVE_HOST, MAX_URL_HOST_LEN); - strlcpy(url.path, HTTP_RESOLVE_URL, MAX_URL_PATH_LEN); - } - /* Build our HTTP request to resolve the external IP (this is similar to * to contacting whatismyip.org, but using a different URL). */ snprintf(http_buf, HTTP_MAX_REQUEST_LEN, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n" "Host: %s\r\nConnection: close\r\n\r\n", - url.path, + url->path, options->http_user_agent, - url.host + url->host ); http_buf_len = strlen(http_buf); @@ -185,7 +94,7 @@ resolve_ip_http(fko_cli_options_t *options) hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - error = getaddrinfo(url.host, url.port, &hints, &result); + error = getaddrinfo(url->host, url->port, &hints, &result); if (error != 0) { fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); @@ -282,19 +191,135 @@ resolve_ip_http(fko_cli_options_t *options) { strlcpy(options->allow_ip_str, ndx, MAX_IPV4_STR_LEN); + if(options->verbose > 1) + printf("\nHTTP response: %s\n", http_response); + if(options->verbose) - printf("Resolved external IP (via http://%s%s) as: %s\n", - url.host, - url.path, + printf("\n[+] Resolved external IP (via http://%s%s) as: %s\n", + url->host, + url->path, options->allow_ip_str); - return(0); + return(1); } else { - fprintf(stderr, "Invalid IP (%s) in HTTP response.\n", ndx); + fprintf(stderr, "Invalid IP (%s) in HTTP response:\n\n%s\n", + ndx, http_response); return(-1); } } +static int +parse_url(char *res_url, struct url* url) +{ + char *s_ndx, *e_ndx; + int tlen, tlen_offset, port; + + /* https is not supported. + */ + if(strncasecmp(res_url, "https", 5) == 0) + { + fprintf(stderr, "https is not yet supported for http-resolve-ip.\n"); + return(-1); + } + + /* Strip off http:// portion if necessary + */ + if(strncasecmp(res_url, "http://", 7) == 0) + s_ndx = res_url + 7; + else + s_ndx = res_url; + + /* Look for a colon in case an alternate port was specified. + */ + e_ndx = strchr(s_ndx, ':'); + if(e_ndx != NULL) + { + port = atoi(e_ndx+1); + if(port < 1 || port > MAX_PORT) + { + fprintf(stderr, "resolve-url port value is invalid.\n"); + return(-1); + } + + sprintf(url->port, "%u", port); + + /* Get the offset we need to skip the port portion when we + * extract the hostname part. + */ + tlen_offset = strlen(url->port)+1; + } + else + { + strlcpy(url->port, "80", 3); + tlen_offset = 0; + } + + e_ndx = strchr(s_ndx, '/'); + if(e_ndx == NULL) + tlen = strlen(s_ndx)+1; + else + tlen = (e_ndx-s_ndx)+1; + + tlen -= tlen_offset; + + if(tlen > MAX_URL_HOST_LEN) + { + fprintf(stderr, "resolve-url hostname portion is too large.\n"); + return(-1); + } + strlcpy(url->host, s_ndx, tlen); + + if(e_ndx != NULL) + { + if(strlen(e_ndx) > MAX_URL_PATH_LEN) + { + fprintf(stderr, "resolve-url path portion is too large.\n"); + return(-1); + } + + strlcpy(url->path, e_ndx, MAX_URL_PATH_LEN); + } + else + *(url->path) = '\0'; + + return(0); +} + +int +resolve_ip_http(fko_cli_options_t *options) +{ + int res; + struct url url; + + if(options->resolve_url != NULL) + { + if(parse_url(options->resolve_url, &url) < 0) + { + fprintf(stderr, "Error parsing resolve-url\n"); + return(-1); + } + + res = try_url(&url, options); + + } else { + strlcpy(url.port, "80", 3); + strlcpy(url.host, HTTP_RESOLVE_HOST, MAX_URL_HOST_LEN); + strlcpy(url.path, HTTP_RESOLVE_URL, MAX_URL_PATH_LEN); + + res = try_url(&url, options); + if(res != 1) + { + /* try the backup url (just switches the host to cipherdyne.com) + */ + strlcpy(url.host, HTTP_BACKUP_RESOLVE_HOST, MAX_URL_HOST_LEN); + + sleep(2); + res = try_url(&url, options); + } + } + return(res); +} + /***EOF***/