diff options
Diffstat (limited to 'hostport.c')
-rw-r--r-- | hostport.c | 311 |
1 files changed, 0 insertions, 311 deletions
diff --git a/hostport.c b/hostport.c deleted file mode 100644 index 54c1d74..0000000 --- a/hostport.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -/* Code contributions from: - * - * Simon Leinen <simon.leinen@switch.ch> - */ - -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <netdb.h> -#include <netinet/in.h> -#include "debug.h" -#include "util.h" -#include "list.h" -#include "hostport.h" - -void freehostport(struct hostportres *hp) { - if (hp) { - free(hp->host); - free(hp->port); - if (hp->addrinfo) - freeaddrinfo(hp->addrinfo); - free(hp); - } -} - -static int parsehostport(struct hostportres *hp, char *hostport, char *default_port) { - char *p, *field; - int ipv6 = 0; - - if (!hostport) { - hp->port = default_port ? stringcopy(default_port, 0) : NULL; - return 1; - } - p = hostport; - /* allow literal addresses and port, e.g. [2001:db8::1]:1812 */ - if (*p == '[') { - p++; - field = p; - for (; *p && *p != ']' && *p != ' ' && *p != '\t' && *p != '\n'; p++); - if (*p != ']') { - debug(DBG_ERR, "no ] matching initial ["); - return 0; - } - ipv6 = 1; - } else { - field = p; - for (; *p && *p != ':' && *p != '/' && *p != ' ' && *p != '\t' && *p != '\n'; p++); - } - if (field == p) { - debug(DBG_ERR, "missing host/address"); - return 0; - } - - hp->host = stringcopy(field, p - field); - if (ipv6) { - p++; - if (*p && *p != ':' && *p != '/' && *p != ' ' && *p != '\t' && *p != '\n') { - debug(DBG_ERR, "unexpected character after ]"); - return 0; - } - } - if (*p == ':') { - /* port number or service name is specified */; - field = ++p; - for (; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++); - if (field == p) { - debug(DBG_ERR, "syntax error, : but no following port"); - return 0; - } - hp->port = stringcopy(field, p - field); - } else - hp->port = default_port ? stringcopy(default_port, 0) : NULL; - return 1; -} - -struct hostportres *newhostport(char *hostport, char *default_port, uint8_t prefixok) { - struct hostportres *hp; - char *slash, *s; - int plen; - - hp = malloc(sizeof(struct hostportres)); - if (!hp) { - debug(DBG_ERR, "resolve_newhostport: malloc failed"); - goto errexit; - } - memset(hp, 0, sizeof(struct hostportres)); - - if (!parsehostport(hp, hostport, default_port)) - goto errexit; - - if (hp->host && !strcmp(hp->host, "*")) { - free(hp->host); - hp->host = NULL; - } - - slash = hostport ? strchr(hostport, '/') : NULL; - if (slash) { - if (!prefixok) { - debug(DBG_WARN, "newhostport: prefix not allowed here", hp->host); - goto errexit; - } - s = slash + 1; - if (!*s) { - debug(DBG_WARN, "newhostport: prefix length must be specified after the / in %s", hp->host); - goto errexit; - } - for (; *s; s++) - if (*s < '0' || *s > '9') { - debug(DBG_WARN, "newhostport: %s in %s is not a valid prefix length", slash + 1, hp->host); - goto errexit; - } - plen = atoi(slash + 1); - if (plen < 0 || plen > 128) { - debug(DBG_WARN, "newhostport: %s in %s is not a valid prefix length", slash + 1, hp->host); - goto errexit; - } - hp->prefixlen = plen; - } else - hp->prefixlen = 255; - return hp; - -errexit: - freehostport(hp); - return NULL; -} - -int resolvehostport(struct hostportres *hp, int socktype, uint8_t passive) { - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = socktype; - hints.ai_family = AF_UNSPEC; - if (passive) - hints.ai_flags = AI_PASSIVE; - - if (!hp->host && !hp->port) { - /* getaddrinfo() doesn't like host and port to be NULL */ - if (getaddrinfo(hp->host, "1812" /* can be anything */, &hints, &hp->addrinfo)) { - debug(DBG_WARN, "resolvehostport: can't resolve (null) port (null)"); - goto errexit; - } - for (res = hp->addrinfo; res; res = res->ai_next) - port_set(res->ai_addr, 0); - } else { - if (hp->prefixlen != 255) - hints.ai_flags |= AI_NUMERICHOST; - if (getaddrinfo(hp->host, hp->port, &hints, &hp->addrinfo)) { - debug(DBG_WARN, "resolvehostport: can't resolve %s port %s", hp->host ? hp->host : "(null)", hp->port ? hp->port : "(null)"); - goto errexit; - } - if (hp->prefixlen != 255) { - switch (hp->addrinfo->ai_family) { - case AF_INET: - if (hp->prefixlen > 32) { - debug(DBG_WARN, "resolvehostport: prefix length must be <= 32 in %s", hp->host); - goto errexit; - } - break; - case AF_INET6: - break; - default: - debug(DBG_WARN, "resolvehostport: prefix must be IPv4 or IPv6 in %s", hp->host); - goto errexit; - } - } - } - return 1; - -errexit: - if (hp->addrinfo) - freeaddrinfo(hp->addrinfo); - return 0; -} - -int addhostport(struct list **hostports, char **hostport, char *portdefault, uint8_t prefixok) { - struct hostportres *hp; - int i; - - if (!*hostports) { - *hostports = list_create(); - if (!*hostports) { - debug(DBG_ERR, "addhostport: malloc failed"); - return 0; - } - } - - for (i = 0; hostport[i]; i++) { - hp = newhostport(hostport[i], portdefault, prefixok); - if (!hp) - return 0; - if (!list_push(*hostports, hp)) { - freehostport(hp); - debug(DBG_ERR, "addhostport: malloc failed"); - return 0; - } - } - return 1; -} - -void freehostports(struct list *hostports) { - struct hostportres *hp; - - while ((hp = (struct hostportres *)list_shift(hostports))) - freehostport(hp); - list_destroy(hostports); -} - -int resolvehostports(struct list *hostports, int socktype) { - struct list_node *entry; - struct hostportres *hp; - - for (entry = list_first(hostports); entry; entry = list_next(entry)) { - hp = (struct hostportres *)entry->data; - if (!hp->addrinfo && !resolvehostport(hp, socktype, 0)) - return 0; - } - return 1; -} - -struct addrinfo *resolvepassiveaddrinfo(char *hostport, char *default_port, int socktype) { - struct addrinfo *ai = NULL; - struct hostportres *hp = newhostport(hostport, default_port, 0); - if (hp && resolvehostport(hp, socktype, 1)) { - ai = hp->addrinfo; - hp->addrinfo = NULL; - } - freehostport(hp); - return ai; -} - -/* returns 1 if the len first bits are equal, else 0 */ -static int prefixmatch(void *a1, void *a2, uint8_t len) { - static uint8_t mask[] = { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; - uint8_t r, l = len / 8; - if (l && memcmp(a1, a2, l)) - return 0; - r = len % 8; - if (!r) - return 1; - return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]); -} - -int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport) { - struct sockaddr_in6 *sa6 = NULL; - struct in_addr *a4 = NULL; - struct addrinfo *res; - struct list_node *entry; - struct hostportres *hp = NULL; - - if (addr->sa_family == AF_INET6) { - sa6 = (struct sockaddr_in6 *)addr; - if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { - a4 = (struct in_addr *)&sa6->sin6_addr.s6_addr[12]; - sa6 = NULL; - } - } else - a4 = &((struct sockaddr_in *)addr)->sin_addr; - - for (entry = list_first(hostports); entry; entry = list_next(entry)) { - hp = (struct hostportres *)entry->data; - for (res = hp->addrinfo; res; res = res->ai_next) - if (hp->prefixlen == 255) { - if ((a4 && res->ai_family == AF_INET && - !memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4) && - (!checkport || ((struct sockaddr_in *)res->ai_addr)->sin_port == - ((struct sockaddr_in *)addr)->sin_port)) || - (sa6 && res->ai_family == AF_INET6 && - !memcmp(&sa6->sin6_addr, - &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16) && - (!checkport || ((struct sockaddr_in6 *)res->ai_addr)->sin6_port == - ((struct sockaddr_in6 *)addr)->sin6_port))) - return 1; - } else { - if ((a4 && res->ai_family == AF_INET && - prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, hp->prefixlen)) || - (sa6 && res->ai_family == AF_INET6 && - prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, hp->prefixlen))) - return 1; - } - } - return 0; -} - -int connecttcphostlist(struct list *hostports, struct addrinfo *src) { - int s; - struct list_node *entry; - struct hostportres *hp = NULL; - - for (entry = list_first(hostports); entry; entry = list_next(entry)) { - hp = (struct hostportres *)entry->data; - debug(DBG_WARN, "connecttcphostlist: trying to open TCP connection to %s port %s", hp->host, hp->port); - if ((s = connecttcp(hp->addrinfo, src, list_count(hostports) > 1 ? 5 : 30)) >= 0) { - debug(DBG_WARN, "connecttcphostlist: TCP connection to %s port %s up", hp->host, hp->port); - return s; - } - } - debug(DBG_ERR, "connecttcphostlist: failed"); - return -1; -} - -/* Local Variables: */ -/* c-file-style: "stroustrup" */ -/* End: */ |