2 * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
16 void resolve_freehostport(struct hostportres *hp) {
21 freeaddrinfo(hp->addrinfo);
26 static int resolve_parsehostport(struct hostportres *hp, char *hostport, char *default_port) {
31 /* allow literal addresses and port, e.g. [2001:db8::1]:1812 */
35 for (; *p && *p != ']' && *p != ' ' && *p != '\t' && *p != '\n'; p++);
37 debug(DBG_ERR, "no ] matching initial [");
43 for (; *p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n'; p++);
46 debug(DBG_ERR, "missing host/address");
50 hp->host = stringcopy(field, p - field);
53 if (*p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n') {
54 debug(DBG_ERR, "unexpected character after ]");
59 /* port number or service name is specified */;
61 for (; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++);
63 debug(DBG_ERR, "syntax error, : but no following port");
66 hp->port = stringcopy(field, p - field);
68 hp->port = default_port ? stringcopy(default_port, 0) : NULL;
72 struct hostportres *resolve_newhostport(char *hostport, char *default_port, uint8_t prefixok) {
73 struct hostportres *hp;
77 hp = malloc(sizeof(struct hostportres));
79 debug(DBG_ERR, "resolve_newhostport: malloc failed");
82 memset(hp, 0, sizeof(struct hostportres));
84 if (!resolve_parsehostport(hp, hostport, default_port))
87 if (!strcmp(hp->host, "*")) {
92 slash = hp->host ? strchr(hp->host, '/') : NULL;
95 debug(DBG_WARN, "resolve_newhostport: prefix not allowed here", hp->host);
100 debug(DBG_WARN, "resolve_newhostport: prefix length must be specified after the / in %s", hp->host);
104 if (*s < '0' || *s > '9') {
105 debug(DBG_WARN, "resolve_newhostport: %s in %s is not a valid prefix length", slash + 1, hp->host);
108 plen = atoi(slash + 1);
109 if (plen < 0 || plen > 128) {
110 debug(DBG_WARN, "resolve_newhostport: %s in %s is not a valid prefix length", slash + 1, hp->host);
113 hp->prefixlen = plen;
120 resolve_freehostport(hp);
124 static int resolve_resolve(struct hostportres *hp, int socktype, uint8_t passive) {
125 struct addrinfo hints, *res;
127 memset(&hints, 0, sizeof(hints));
128 hints.ai_socktype = socktype;
129 hints.ai_family = AF_UNSPEC;
131 hints.ai_flags = AI_PASSIVE;
133 if (!hp->host && !hp->port) {
134 /* getaddrinfo() doesn't like host and port to be NULL */
135 if (getaddrinfo(hp->host, "1812" /* can be anything */, &hints, &hp->addrinfo)) {
136 debug(DBG_WARN, "resolve_resolve: can't resolve (null) port (null)");
139 for (res = hp->addrinfo; res; res = res->ai_next)
140 port_set(res->ai_addr, 0);
142 if (hp->prefixlen != 255)
143 hints.ai_flags |= AI_NUMERICHOST;
144 if (getaddrinfo(hp->host, hp->port, &hints, &hp->addrinfo)) {
145 debug(DBG_WARN, "resolve_resolve: can't resolve %s port %s", hp->host ? hp->host : "(null)", hp->port ? hp->port : "(null)");
148 if (hp->prefixlen != 255) {
149 switch (hp->addrinfo->ai_family) {
151 if (hp->prefixlen > 32) {
152 debug(DBG_WARN, "resolve_resolve: prefix length must be <= 32 in %s", hp->host);
159 debug(DBG_WARN, "resolve_resolve: prefix must be IPv4 or IPv6 in %s", hp->host);
168 freeaddrinfo(hp->addrinfo);
172 int resolve_hostports(struct list *hostports, int socktype) {
173 struct list_node *entry;
174 struct hostportres *hp;
176 for (entry = list_first(hostports); entry; entry = list_next(entry)) {
177 hp = (struct hostportres *)entry->data;
178 if (!hp->addrinfo && !resolve_resolve(hp, socktype, 0))
184 struct addrinfo *resolve_passiveaddrinfo(char *hostport, char *default_port, int socktype) {
185 struct addrinfo *ai = NULL;
186 struct hostportres *hp = resolve_newhostport(hostport, default_port, 0);
187 if (hp && resolve_resolve(hp, socktype, 1)) {
191 resolve_freehostport(hp);
195 /* returns 1 if the len first bits are equal, else 0 */
196 static int prefixmatch(void *a1, void *a2, uint8_t len) {
197 static uint8_t mask[] = { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
198 uint8_t r, l = len / 8;
199 if (l && memcmp(a1, a2, l))
204 return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);