diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/sock_any.c | 99 | ||||
-rw-r--r-- | common/sock_any.h | 2 |
2 files changed, 93 insertions, 8 deletions
diff --git a/common/sock_any.c b/common/sock_any.c index b2bde01..f01933b 100644 --- a/common/sock_any.c +++ b/common/sock_any.c @@ -3,6 +3,7 @@ #include <errno.h> #include <sys/types.h> #include <sys/socket.h> +#include <netdb.h> #include "sock_any.h" @@ -11,20 +12,47 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) { size_t l; - const char* t; + char buf[256]; /* TODO: Use a constant */ + char* t; + char* t2; memset(any, 0, sizeof(*any)); + /* Just a port? */ + do + { + #define PORT_CHARS "0123456789" + #define PORT_MIN 1 + #define PORT_MAX 5 + + int port = 0; + + l = strspn(addr, PORT_CHARS); + if(l < PORT_MIN || l > PORT_MAX || addr[l] != 0) + break; + + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + + any->s.in.sin_family = AF_INET; + any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); + any->s.in.sin_addr.s_addr = 0; + + any->namelen = sizeof(any->s.in); + return AF_INET; + } + while(0); + /* Look and see if we can parse an ipv4 address */ do { + #define IPV4_PORT_CHARS #define IPV4_CHARS "0123456789." #define IPV4_MIN 3 #define IPV4_MAX 18 int port = 0; - char buf[IPV4_MAX + 1]; - t = NULL; l = strlen(addr); @@ -51,7 +79,6 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) if(t) { - char* t2; port = strtol(t, &t2, 10); if(*t2 || port <= 0 || port >= 65536) break; @@ -76,8 +103,6 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) #define IPV6_MAX 48 int port = -1; - char buf[IPV6_MAX + 1]; - t = NULL; l = strlen(addr); @@ -131,9 +156,11 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) while(0); #endif + /* A unix socket path */ do { - if(strchr(addr, ':')) + /* No colon and must have a path component */ + if(strchr(addr, ':') || !strchr(addr, '/')) break; l = strlen(addr); @@ -148,6 +175,64 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) } while(0); + /* A DNS name and a port? */ + do + { + struct addrinfo* res; + int port = 0; + t = NULL; + + l = strlen(addr); + if(l < 255 && isalpha(addr[0])) + break; + + /* Some basic illegal character checks */ + if(strspn(addr, " /\\") != l) + break; + + strcpy(buf, addr); + + /* Find the last set that contains just numbers */ + t = strchr(buf, ':'); + if(t) + { + *t = 0; + t++; + } + + if(t) + { + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + } + + /* Try and resolve the domain name */ + if(getaddrinfo(buf, NULL, NULL, &res) != 0 || !res) + break; + + memcpy(&(any->s.a), res->ai_addr, sizeof(struct sockaddr)); + any->namelen = res->ai_addrlen; + freeaddrinfo(res); + + port = htons((unsigned short)(port <= 0 ? defport : port)); + + switch(any->s.a.sa_family) + { + case PF_INET: + any->s.in.sin_port = port; + break; +#ifdef HAVE_INET6 + case PF_INET6: + any->s.in6.sin6_port = port; + break; +#endif + }; + + return any->s.a.sa_family; + } + while(0); + return -1; } diff --git a/common/sock_any.h b/common/sock_any.h index f281020..5d733b1 100644 --- a/common/sock_any.h +++ b/common/sock_any.h @@ -8,7 +8,6 @@ struct sockaddr_any { - size_t namelen; union _sockaddr_any { /* The header */ @@ -21,6 +20,7 @@ struct sockaddr_any struct sockaddr_in6 in6; #endif } s; + size_t namelen; }; #define SANY_ADDR(any) (&((any).s.a)) |