MEDIUM: tools: make str2sa_range support all address syntaxes
Right now we have multiple methods for parsing IP addresses in the
configuration. This is quite painful. This patch aims at adapting
str2sa_range() to make it support all formats, so that the callers
perform the appropriate tests on the return values. str2sa() was
changed to simply return str2sa_range().
The output values are now the following ones (taken from the comment
on top of the function).
Converts <str> to a locally allocated struct sockaddr_storage *, and a port
range or offset consisting in two integers that the caller will have to
check to find the relevant input format. The following format are supported :
String format | address | port | low | high
addr | <addr> | 0 | 0 | 0
addr: | <addr> | 0 | 0 | 0
addr:port | <addr> | <port> | <port> | <port>
addr:pl-ph | <addr> | <pl> | <pl> | <ph>
addr:+port | <addr> | <port> | 0 | <port>
addr:-port | <addr> |-<port> | <port> | 0
The detection of a port range or increment by the caller is made by
comparing <low> and <high>. If both are equal, then port 0 means no port
was specified. The caller may pass NULL for <low> and <high> if it is not
interested in retrieving port ranges.
Note that <addr> above may also be :
- empty ("") => family will be AF_INET and address will be INADDR_ANY
- "*" => family will be AF_INET and address will be INADDR_ANY
- "::" => family will be AF_INET6 and address will be IN6ADDR_ANY
- a host name => family and address will depend on host name resolving.
diff --git a/src/standard.c b/src/standard.c
index 380f7be..db0e0e4 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -610,89 +610,85 @@
}
/*
- * converts <str> to a locally allocated struct sockaddr_storage *.
- * The format is "addr[:[port]]", where "addr" can be a dotted IPv4 address, an
- * IPv6 address, a host name, or empty or "*" to indicate INADDR_ANY. If an IPv6
- * address wants to ignore port, it must be terminated by a trailing colon (':').
- * The IPv6 '::' address is IN6ADDR_ANY, so in order to bind to a given port on
- * IPv6, use ":::port". NULL is returned if the host part cannot be resolved.
+ * Converts <str> to a locally allocated struct sockaddr_storage *, and a port
+ * range or offset consisting in two integers that the caller will have to
+ * check to find the relevant input format. The following format are supported :
+ *
+ * String format | address | port | low | high
+ * addr | <addr> | 0 | 0 | 0
+ * addr: | <addr> | 0 | 0 | 0
+ * addr:port | <addr> | <port> | <port> | <port>
+ * addr:pl-ph | <addr> | <pl> | <pl> | <ph>
+ * addr:+port | <addr> | <port> | 0 | <port>
+ * addr:-port | <addr> |-<port> | <port> | 0
+ *
+ * The detection of a port range or increment by the caller is made by
+ * comparing <low> and <high>. If both are equal, then port 0 means no port
+ * was specified. The caller may pass NULL for <low> and <high> if it is not
+ * interested in retrieving port ranges.
+ *
+ * Note that <addr> above may also be :
+ * - empty ("") => family will be AF_INET and address will be INADDR_ANY
+ * - "*" => family will be AF_INET and address will be INADDR_ANY
+ * - "::" => family will be AF_INET6 and address will be IN6ADDR_ANY
+ * - a host name => family and address will depend on host name resolving.
+ *
+ * Also note that in order to avoid any ambiguity with IPv6 addresses, the ':'
+ * is mandatory after the IP address even when no port is specified. NULL is
+ * returned if the address cannot be parsed. The <low> and <high> ports are
+ * always initialized if non-null.
*/
-struct sockaddr_storage *str2sa(const char *str)
+struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high)
{
struct sockaddr_storage *ret = NULL;
char *str2;
- char *c;
- int port;
+ char *port1, *port2;
+ int portl, porth, porta;
+
+ portl = porth = porta = 0;
str2 = strdup(str);
if (str2 == NULL)
goto out;
- if ((c = strrchr(str2, ':')) != NULL) { /* Port */
- *c++ = '\0';
- port = atol(c);
- }
+ port1 = strrchr(str2, ':');
+ if (port1)
+ *port1++ = '\0';
else
- port = 0;
+ port1 = "";
ret = str2ip(str2);
if (!ret)
goto out;
- set_host_port(ret, port);
- out:
- free(str2);
- return ret;
-}
-
-/*
- * converts <str> to a locally allocated struct sockaddr_storage *, and a
- * port range consisting in two integers. The low and high end are always set
- * even if the port is unspecified, in which case (0,0) is returned. The low
- * port is set in the sockaddr. Thus, it is enough to check the size of the
- * returned range to know if an array must be allocated or not. The format is
- * "addr[:[port[-port]]]", where "addr" can be a dotted IPv4 address, an IPv6
- * address, a host name, or empty or "*" to indicate INADDR_ANY. If an IPv6
- * address wants to ignore port, it must be terminated by a trailing colon (':').
- * The IPv6 '::' address is IN6ADDR_ANY, so in order to bind to a given port on
- * IPv6, use ":::port". NULL is returned if the host part cannot be resolved.
- */
-struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high)
-{
- struct sockaddr_storage *ret = NULL;
- char *str2;
- char *c;
- int portl, porth;
-
- str2 = strdup(str);
- if (str2 == NULL)
- goto out;
-
- if ((c = strrchr(str2,':')) != NULL) { /* Port */
- char *sep;
- *c++ = '\0';
- sep = strchr(c, '-');
- if (sep)
- *sep++ = '\0';
+ if (isdigit(*port1)) { /* single port or range */
+ port2 = strchr(port1, '-');
+ if (port2)
+ *port2++ = '\0';
else
- sep = c;
- portl = atol(c);
- porth = atol(sep);
+ port2 = port1;
+ portl = atoi(port1);
+ porth = atoi(port2);
+ porta = portl;
}
- else {
- portl = 0;
- porth = 0;
+ else if (*port1 == '-') { /* negative offset */
+ portl = atoi(port1 + 1);
+ porta = -portl;
}
-
- ret = str2ip(str2);
- if (!ret)
- goto out;
+ else if (*port1 == '+') { /* positive offset */
+ porth = atoi(port1 + 1);
+ porta = porth;
+ }
+ else if (*port1) /* other any unexpected char */
+ ret = NULL;
- set_host_port(ret, portl);
+ set_host_port(ret, porta);
- *low = portl;
- *high = porth;
out:
+ if (low)
+ *low = portl;
+ if (high)
+ *high = porth;
free(str2);
return ret;
}
@@ -889,7 +885,7 @@
/* HTTP url matching */
if (http_code == 0x68747470) {
/* We are looking for IP address. If you want to parse and
- * resolve hostname found in url, you can use str2sa(), but
+ * resolve hostname found in url, you can use str2sa_range(), but
* be warned this can slow down global daemon performances
* while handling lagging dns responses.
*/