summaryrefslogtreecommitdiffstats
path: root/src/libutil/addr.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-04-01 15:33:46 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-04-01 15:33:46 +0100
commitfd6eab56f4f13174b0cfeee2b30f0e956b7ba97c (patch)
tree7f443e1f6a592de1cbd83ff6d097ff85b664a04c /src/libutil/addr.c
parent2249d3ba5ab3254581c84ac1d0c5ed5ffbc79ed8 (diff)
downloadrspamd-fd6eab56f4f13174b0cfeee2b30f0e956b7ba97c.tar.gz
rspamd-fd6eab56f4f13174b0cfeee2b30f0e956b7ba97c.zip
Parse more forms of IP addresses.
[::1]:port [::1] 127.0.0.1:port
Diffstat (limited to 'src/libutil/addr.c')
-rw-r--r--src/libutil/addr.c94
1 files changed, 82 insertions, 12 deletions
diff --git a/src/libutil/addr.c b/src/libutil/addr.c
index 38cd73200..4a48ab7e8 100644
--- a/src/libutil/addr.c
+++ b/src/libutil/addr.c
@@ -346,6 +346,10 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
gboolean ret = FALSE;
rspamd_inet_addr_t *addr = NULL;
union sa_inet su;
+ const char *end;
+ char ipbuf[INET6_ADDRSTRLEN + 1];
+ guint iplen;
+ guint portnum;
g_assert (src != NULL);
g_assert (target != NULL);
@@ -355,18 +359,84 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
if (src[0] == '/' || src[0] == '.') {
return rspamd_parse_unix_path (target, src);
}
- else if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
- addr = rspamd_inet_addr_create (AF_INET);
- memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
- sizeof (struct in_addr));
- ret = TRUE;
- }
- else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
- inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
- addr = rspamd_inet_addr_create (AF_INET6);
- memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
- sizeof (struct in6_addr));
- ret = TRUE;
+
+ if (src[0] == '[') {
+ /* Ipv6 address in format [::1]:port or just [::1] */
+ end = strrchr (src + 1, ']');
+
+ if (end == NULL) {
+ return FALSE;
+ }
+
+ iplen = end - src - 1;
+
+ if (iplen == 0 || iplen > sizeof (ipbuf)) {
+ return FALSE;
+ }
+
+ rspamd_strlcpy (ipbuf, src + 1, iplen);
+
+ if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
+ inet_pton (AF_INET6, ipbuf, &su.s6.sin6_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+ sizeof (struct in6_addr));
+ ret = TRUE;
+ }
+
+ if (ret && end[1] == ':') {
+ /* Port part */
+ portnum = strtoul (end + 1, NULL, 10);
+ rspamd_inet_address_set_port (addr, portnum);
+ }
+ }
+ else {
+
+ if ((end = strchr (src, ':')) != NULL) {
+ /* This is either port number and ipv4 addr or ipv6 addr */
+ if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
+ inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+ sizeof (struct in6_addr));
+ ret = TRUE;
+ }
+ else {
+ /* Not ipv6, so try ip:port */
+ iplen = end - src;
+
+ if (iplen > sizeof (ipbuf)) {
+ return FALSE;
+ }
+ else {
+ rspamd_strlcpy (ipbuf, src, iplen);
+ }
+
+ if (inet_pton (AF_INET, ipbuf, &su.s4.sin_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET);
+ memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
+ sizeof (struct in_addr));
+ portnum = strtoul (end + 1, NULL, 10);
+ rspamd_inet_address_set_port (addr, portnum);
+ ret = TRUE;
+ }
+ }
+ }
+ else {
+ if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET);
+ memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
+ sizeof (struct in_addr));
+ ret = TRUE;
+ }
+ else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
+ inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+ sizeof (struct in6_addr));
+ ret = TRUE;
+ }
+ }
}
if (ret && target) {