* 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"
ipv6 = 1;
} else {
field = p;
- for (; *p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n'; p++);
+ for (; *p && *p != ':' && *p != '/' && *p != ' ' && *p != '\t' && *p != '\n'; p++);
}
if (field == p) {
debug(DBG_ERR, "missing host/address");
hp->host = stringcopy(field, p - field);
if (ipv6) {
p++;
- if (*p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n') {
+ 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);
+ /* 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");
hp->host = NULL;
}
- slash = hp->host ? strchr(hp->host, '/') : NULL;
+ slash = hostport ? strchr(hostport, '/') : NULL;
if (slash) {
if (!prefixok) {
debug(DBG_WARN, "newhostport: prefix not allowed here", hp->host);
goto errexit;
}
hp->prefixlen = plen;
- *slash = '\0';
} else
hp->prefixlen = 255;
return hp;
- errexit:
+errexit:
freehostport(hp);
return NULL;
}
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)) {
}
return 1;
- errexit:
+errexit:
if (hp->addrinfo)
freeaddrinfo(hp->addrinfo);
return 0;
-}
+}
-int addhostport(struct list **hostports, char *hostport, char *portdefault, uint8_t prefixok) {
+int addhostport(struct list **hostports, char **hostport, char *portdefault, uint8_t prefixok) {
struct hostportres *hp;
+ int i;
- hp = newhostport(hostport, portdefault, prefixok);
- if (!hp)
- return 0;
- if (!*hostports)
+ if (!*hostports) {
*hostports = list_create();
- if (!*hostports || !list_push(*hostports, hp)) {
- freehostport(hp);
- debug(DBG_ERR, "addhostport: malloc failed");
- return 0;
+ 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;
}
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 (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
}
-int addressmatches(struct list *hostports, struct sockaddr *addr) {
+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)) {
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)) ||
+ !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)))
+ !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 &&
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)) >= 0) {
+ 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: */