Resolve ip address in all of tha nat modes (mrash/fwknop#43).
authorFranck Joncourt <franck@debian.org>
Wed, 10 Apr 2013 14:06:06 +0000 (16:06 +0200)
committerFranck Joncourt <franck@debian.org>
Wed, 10 Apr 2013 14:06:06 +0000 (16:06 +0200)
client/fwknop.c
test/local_spa.key

index c845701..722e42d 100644 (file)
@@ -59,14 +59,117 @@ static void clean_exit(fko_ctx_t ctx, fko_cli_options_t *opts,
     unsigned int exit_status);
 static void *get_in_addr(struct sockaddr *sa);
 static int resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize);
+static int is_hostname_str_with_port(const char *str, char *hostname, size_t hostname_bufsize, int *port);
 
-#define MAX_CMDLINE_ARGS    50  /* should be way more than enough */
+#define MAX_CMDLINE_ARGS            50                  /*!< should be way more than enough */
+#define IPV4_STR_TEMPLATE           "%u.%u.%u.%u"       /*!< Template for a string as an ipv4 address with sscanf */
+#define NAT_ACCESS_STR_TEMPLATE     "%s,%d"             /*!< Template for a nat access string ip,port with sscanf*/
+#define HOSTNAME_BUFSIZE            64                  /*!< Maximum size of a hostname string */
 
 
 /**
+ * @brief Check whether a string is an ipv4 address or not
+ *
+ * @param str String to check for an ipv4 address.
+ *
+ * @return 1 if the string is an ipv4 address, 0 otherwise.
+ */
+static int
+is_ipv4_str(char *str)
+{
+    int o1, o2, o3, o4;
+    int valid_ipv4;
+
+    /* Check format and values.
+    */
+    if((sscanf(str, IPV4_STR_TEMPLATE, &o1, &o2, &o3, &o4)) == 4
+        && o1 >= 0 && o1 <= 255
+        && o2 >= 0 && o2 <= 255
+        && o3 >= 0 && o3 <= 255
+        && o4 >= 0 && o4 <= 255)
+    {
+        valid_ipv4 = 1;
+    }
+    else
+        valid_ipv4 = 0;
+
+    return valid_ipv4;
+}
+
+/**
+ * @brief Check whether a string is an ipv6 address or not
+ *
+ * @param str String to check for an ipv6 address.
+ *
+ * @return 1 if the string is an ipv6 address, 0 otherwise.
+ */
+static int
+is_ipv6_str(char *str)
+{
+    return 0;
+}
+
+/**
+ * @brief Check a string to find out if it is built as 'hostname,port'
+ *
+ * This function check if we can extract an hostname and a port from the string.
+ * If yes, we return 1, and both the hostname buffer and the port number are set
+ * accordingly.
+ *
+ * We could have used sscanf() here with a template "%[^,],%u", but this way we
+ * do not limit the size of the value copy in the hostname destination buffer.
+ * Limiting the string in the sscanf() can be done but would prevent any easy change
+ * for the hostname buffer size.
+ *
+ * @param str String to parse.
+ * @param hostname Buffer where to store the hostname value read from @str.
+ * @param hostname_bufsize Hostname buffer size.
+ * @param port Value of the port read from @str.
+ *
+ * @return 1 if the string is built as 'hostname,port', 0 otherwise.
+ */
+static int
+is_hostname_str_with_port(const char *str, char *hostname, size_t hostname_bufsize, int *port)
+{
+    int     valid = 0;              /* Result of the function */
+    char    buf[MAX_LINE_LEN];      /* Copy of the buffer eg. "hostname,port" */
+    char   *h;                      /* Pointer on the hostname string */
+    char   *p;                      /* Ponter on the port string */
+
+    memset(buf, 0, sizeof(buf));
+    memset(hostname, 0, hostname_bufsize);
+    *port = 0;
+
+    /* Replace the comma in the string with a NULL char to split the
+     * buffer in two strings (hostname and port) */
+    strlcpy(buf, str, sizeof(buf));
+    p = strchr(buf, ',');
+
+    if(p != NULL)
+    {
+        *p++ = 0;
+        h = buf;
+
+        *port = atoi(p);
+
+        /* If the string does not match an ipv4 or ipv6 address we assume this
+         * is an hostname. We make sure the port is in the good range too */
+        if (   (is_ipv4_str(buf) == 0)
+            && (is_ipv6_str(buf) == 0)
+            && ((*port > 0) && (*port < 65536)) )
+        {
+            strlcpy(hostname, h, hostname_bufsize);
+            valid = 1;
+        }
+    }
+
+    return valid;
+}
+
+/**
  * @brief Grab the sin address from the sockaddr structure.
  *
- * This functions returns the sin address as a sockaddr_in or sockaddr_in6
+ * This function returns the sin address as a sockaddr_in or sockaddr_in6
  * structure according to the family set (ipv4 or ipv6) in the sockaddr
  * structure.
  *
@@ -74,7 +177,8 @@ static int resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *i
  *
  * @return the sin addr if the sa family is AF_INET or the sin6_addr otherwise.
  */
-static void *get_in_addr(struct sockaddr *sa)
+static void *
+get_in_addr(struct sockaddr *sa)
 {
   if (sa->sa_family == AF_INET)
   {
@@ -97,7 +201,8 @@ static void *get_in_addr(struct sockaddr *sa)
  *
  * @return 0 if successful, 1 if an error occured.
  */
-static int resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize)
+static int
+resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize)
 {
     int                 error;      /* Function error return code */
     struct addrinfo    *result;     /* Result of getaddrinfo() */
@@ -747,7 +852,9 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc
     char                nat_access_buf[MAX_LINE_LEN] = {0};
     char                tmp_access_port[MAX_PORT_STR_LEN+1], *ndx = NULL;
     int                 access_port = 0, i = 0, is_err = 0;
-    char                dst_ip_str[INET_ADDRSTRLEN];
+    char                dst_ip_str[INET_ADDRSTRLEN] = {0};
+    char                hostname[HOSTNAME_BUFSIZE] = {0};
+    int                 port = 0;
     struct addrinfo     hints;
 
     memset(nat_access_buf, 0x0, MAX_LINE_LEN);
@@ -781,22 +888,7 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc
 
     if (options->nat_local && options->nat_access_str[0] == 0x0)
     {
-        /* Speed up the name resolution by forcing ipv4 (AF_INET).
-         * A NULL pointer could be used instead if there is no constraint.
-         * Maybe when ipv6 support will be enable the structure could initialize the
-         * family to either AF_INET or AF_INET6 */
-        hints.ai_family = AF_INET;
-
-        if (resolve_dest_adr(options->spa_server_str, &hints, dst_ip_str, sizeof(dst_ip_str)) != 0)
-        {
-            fprintf(stderr, "[*] Unable to resolve %s as an ip address\n",
-                    options->spa_server_str);
-            clean_exit(ctx, options, EXIT_FAILURE);
-        }
-
-        strlcpy(options->spa_server_str, dst_ip_str, sizeof(options->spa_server_str));
-
-        snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
+        snprintf(nat_access_buf, MAX_LINE_LEN, NAT_ACCESS_STR_TEMPLATE,
             options->spa_server_str, access_port);
     }
 
@@ -809,11 +901,30 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc
         }
         else
         {
-            snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
+            snprintf(nat_access_buf, MAX_LINE_LEN, NAT_ACCESS_STR_TEMPLATE,
                 options->nat_access_str, access_port);
         }
     }
 
+    if (is_hostname_str_with_port(nat_access_buf, hostname, sizeof(hostname), &port))
+    {
+        /* Speed up the name resolution by forcing ipv4 (AF_INET).
+         * A NULL pointer could be used instead if there is no constraint.
+         * Maybe when ipv6 support will be enable the structure could initialize the
+         * family to either AF_INET or AF_INET6 */
+        hints.ai_family = AF_INET;
+
+        if (resolve_dest_adr(hostname, &hints, dst_ip_str, sizeof(dst_ip_str)) != 0)
+        {
+            fprintf(stderr, "[*] Unable to resolve %s as an ip address\n",
+                    hostname);
+            clean_exit(ctx, options, EXIT_FAILURE);
+        }
+
+        snprintf(nat_access_buf, MAX_LINE_LEN, NAT_ACCESS_STR_TEMPLATE,
+                dst_ip_str, port);
+    }
+
     if(options->nat_rand_port)
     {
         /* Must print to stdout what the random port is since
index f4dc516..d2eddbd 100644 (file)
@@ -1,4 +1,3 @@
 127.0.0.1: fwknoptest
 localhost: fwknoptest
 some.host.through.proxy.com: fwknoptest
-74.220.215.85: fwknoptest