mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 23:56:57 +02:00
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.
This commit is contained in:
parent
7cf479cc09
commit
d4448bc836
@ -228,16 +228,6 @@ struct sockaddr_un *str2sun(const char *str);
|
|||||||
*/
|
*/
|
||||||
struct sockaddr_storage *str2ip(const char *str);
|
struct sockaddr_storage *str2ip(const char *str);
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
struct sockaddr_storage *str2sa(const char *str);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* converts <str> to a locally allocated struct sockaddr_storage *, and a
|
* 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
|
* port range consisting in two integers. The low and high end are always set
|
||||||
|
128
src/standard.c
128
src/standard.c
@ -610,89 +610,85 @@ struct sockaddr_storage *str2ip(const char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* converts <str> to a locally allocated struct sockaddr_storage *.
|
* Converts <str> to a locally allocated struct sockaddr_storage *, and a port
|
||||||
* The format is "addr[:[port]]", where "addr" can be a dotted IPv4 address, an
|
* range or offset consisting in two integers that the caller will have to
|
||||||
* IPv6 address, a host name, or empty or "*" to indicate INADDR_ANY. If an IPv6
|
* check to find the relevant input format. The following format are supported :
|
||||||
* 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
|
* String format | address | port | low | high
|
||||||
* IPv6, use ":::port". NULL is returned if the host part cannot be resolved.
|
* addr | <addr> | 0 | 0 | 0
|
||||||
*/
|
* addr: | <addr> | 0 | 0 | 0
|
||||||
struct sockaddr_storage *str2sa(const char *str)
|
* addr:port | <addr> | <port> | <port> | <port>
|
||||||
{
|
* addr:pl-ph | <addr> | <pl> | <pl> | <ph>
|
||||||
struct sockaddr_storage *ret = NULL;
|
* addr:+port | <addr> | <port> | 0 | <port>
|
||||||
char *str2;
|
* addr:-port | <addr> |-<port> | <port> | 0
|
||||||
char *c;
|
*
|
||||||
int port;
|
* 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
|
||||||
str2 = strdup(str);
|
* was specified. The caller may pass NULL for <low> and <high> if it is not
|
||||||
if (str2 == NULL)
|
* interested in retrieving port ranges.
|
||||||
goto out;
|
*
|
||||||
|
* Note that <addr> above may also be :
|
||||||
if ((c = strrchr(str2, ':')) != NULL) { /* Port */
|
* - empty ("") => family will be AF_INET and address will be INADDR_ANY
|
||||||
*c++ = '\0';
|
* - "*" => family will be AF_INET and address will be INADDR_ANY
|
||||||
port = atol(c);
|
* - "::" => family will be AF_INET6 and address will be IN6ADDR_ANY
|
||||||
}
|
* - a host name => family and address will depend on host name resolving.
|
||||||
else
|
*
|
||||||
port = 0;
|
* 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
|
||||||
ret = str2ip(str2);
|
* returned if the address cannot be parsed. The <low> and <high> ports are
|
||||||
if (!ret)
|
* always initialized if non-null.
|
||||||
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 *str2sa_range(const char *str, int *low, int *high)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage *ret = NULL;
|
struct sockaddr_storage *ret = NULL;
|
||||||
char *str2;
|
char *str2;
|
||||||
char *c;
|
char *port1, *port2;
|
||||||
int portl, porth;
|
int portl, porth, porta;
|
||||||
|
|
||||||
|
portl = porth = porta = 0;
|
||||||
|
|
||||||
str2 = strdup(str);
|
str2 = strdup(str);
|
||||||
if (str2 == NULL)
|
if (str2 == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((c = strrchr(str2,':')) != NULL) { /* Port */
|
port1 = strrchr(str2, ':');
|
||||||
char *sep;
|
if (port1)
|
||||||
*c++ = '\0';
|
*port1++ = '\0';
|
||||||
sep = strchr(c, '-');
|
|
||||||
if (sep)
|
|
||||||
*sep++ = '\0';
|
|
||||||
else
|
else
|
||||||
sep = c;
|
port1 = "";
|
||||||
portl = atol(c);
|
|
||||||
porth = atol(sep);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
portl = 0;
|
|
||||||
porth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = str2ip(str2);
|
ret = str2ip(str2);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
set_host_port(ret, portl);
|
if (isdigit(*port1)) { /* single port or range */
|
||||||
|
port2 = strchr(port1, '-');
|
||||||
|
if (port2)
|
||||||
|
*port2++ = '\0';
|
||||||
|
else
|
||||||
|
port2 = port1;
|
||||||
|
portl = atoi(port1);
|
||||||
|
porth = atoi(port2);
|
||||||
|
porta = portl;
|
||||||
|
}
|
||||||
|
else if (*port1 == '-') { /* negative offset */
|
||||||
|
portl = atoi(port1 + 1);
|
||||||
|
porta = -portl;
|
||||||
|
}
|
||||||
|
else if (*port1 == '+') { /* positive offset */
|
||||||
|
porth = atoi(port1 + 1);
|
||||||
|
porta = porth;
|
||||||
|
}
|
||||||
|
else if (*port1) /* other any unexpected char */
|
||||||
|
ret = NULL;
|
||||||
|
|
||||||
|
set_host_port(ret, porta);
|
||||||
|
|
||||||
*low = portl;
|
|
||||||
*high = porth;
|
|
||||||
out:
|
out:
|
||||||
|
if (low)
|
||||||
|
*low = portl;
|
||||||
|
if (high)
|
||||||
|
*high = porth;
|
||||||
free(str2);
|
free(str2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -889,7 +885,7 @@ int url2sa(const char *url, int ulen, struct sockaddr_storage *addr)
|
|||||||
/* HTTP url matching */
|
/* HTTP url matching */
|
||||||
if (http_code == 0x68747470) {
|
if (http_code == 0x68747470) {
|
||||||
/* We are looking for IP address. If you want to parse and
|
/* 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
|
* be warned this can slow down global daemon performances
|
||||||
* while handling lagging dns responses.
|
* while handling lagging dns responses.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user