summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/sock_any.c99
-rw-r--r--common/sock_any.h2
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))