-int resolvepeer(struct clsrvconf *conf, int ai_flags) {
- struct addrinfo hints, *addrinfo, *res;
- char *slash, *s;
- int plen = 0;
-
- slash = conf->host ? strchr(conf->host, '/') : NULL;
- if (slash) {
- s = slash + 1;
- if (!*s) {
- debug(DBG_WARN, "resolvepeer: prefix length must be specified after the / in %s", conf->host);
- return 0;
- }
- for (; *s; s++)
- if (*s < '0' || *s > '9') {
- debug(DBG_WARN, "resolvepeer: %s in %s is not a valid prefix length", slash + 1, conf->host);
- return 0;
- }
- plen = atoi(slash + 1);
- if (plen < 0 || plen > 128) {
- debug(DBG_WARN, "resolvepeer: %s in %s is not a valid prefix length", slash + 1, conf->host);
- return 0;
- }
- *slash = '\0';
- }
- memset(&hints, 0, sizeof(hints));
- hints.ai_socktype = conf->pdef->socktype;
- hints.ai_family = AF_UNSPEC;
- hints.ai_flags = ai_flags;
- if (!conf->host && !conf->port) {
- /* getaddrinfo() doesn't like host and port to be NULL */
- if (getaddrinfo(conf->host, conf->pdef->portdefault, &hints, &addrinfo)) {
- debug(DBG_WARN, "resolvepeer: can't resolve (null) port (null)");
- return 0;
- }
- for (res = addrinfo; res; res = res->ai_next)
- port_set(res->ai_addr, 0);
- } else {
- if (slash)
- hints.ai_flags |= AI_NUMERICHOST;
- if (getaddrinfo(conf->host, conf->port, &hints, &addrinfo)) {
- debug(DBG_WARN, "resolvepeer: can't resolve %s port %s", conf->host ? conf->host : "(null)", conf->port ? conf->port : "(null)");
- return 0;
- }
- if (slash) {
- *slash = '/';
- switch (addrinfo->ai_family) {
- case AF_INET:
- if (plen > 32) {
- debug(DBG_WARN, "resolvepeer: prefix length must be <= 32 in %s", conf->host);
- freeaddrinfo(addrinfo);
- return 0;
- }
- break;
- case AF_INET6:
- break;
- default:
- debug(DBG_WARN, "resolvepeer: prefix must be IPv4 or IPv6 in %s", conf->host);
- freeaddrinfo(addrinfo);
- return 0;
- }
- conf->prefixlen = (uint8_t)plen;
- } else
- conf->prefixlen = 255;
- }
- if (conf->addrinfo)
- freeaddrinfo(conf->addrinfo);
- conf->addrinfo = addrinfo;
- return 1;
-}
-
-char *parsehostport(char *s, struct clsrvconf *conf, char *default_port) {
- char *p, *field;
- int ipv6 = 0;
-
- p = s;
- /* 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 != ']')
- debugx(1, DBG_ERR, "no ] matching initial [");
- ipv6 = 1;
- } else {
- field = p;
- for (; *p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n'; p++);
- }
- if (field == p)
- debugx(1, DBG_ERR, "missing host/address");
-
- conf->host = stringcopy(field, p - field);
- if (ipv6) {
- p++;
- if (*p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n')
- debugx(1, DBG_ERR, "unexpected character after ]");
- }
- if (*p == ':') {
- /* port number or service name is specified */;
- field = ++p;
- for (; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++);
- if (field == p)
- debugx(1, DBG_ERR, "syntax error, : but no following port");
- conf->port = stringcopy(field, p - field);
- } else
- conf->port = default_port ? stringcopy(default_port, 0) : NULL;
- return p;
-}
-
-struct clsrvconf *resolve_hostport(uint8_t type, char *lconf, char *default_port) {
- struct clsrvconf *conf;
-
- conf = malloc(sizeof(struct clsrvconf));
- if (!conf)
- debugx(1, DBG_ERR, "malloc failed");
- memset(conf, 0, sizeof(struct clsrvconf));
- conf->type = type;
- conf->pdef = protodefs[conf->type];
- if (lconf) {
- parsehostport(lconf, conf, default_port);
- if (!strcmp(conf->host, "*")) {
- free(conf->host);
- conf->host = NULL;
- }
- } else
- conf->port = default_port ? stringcopy(default_port, 0) : NULL;
- if (!resolvepeer(conf, AI_PASSIVE))
- debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", conf->host ? conf->host : "(null)", conf->port ? conf->port : "(null)");
- return conf;
-}
-
-void freeclsrvres(struct clsrvconf *res) {
- free(res->host);
- free(res->port);
- if (res->addrinfo)
- freeaddrinfo(res->addrinfo);
- free(res);
-}
-
-struct addrinfo *resolve_hostport_addrinfo(uint8_t type, char *hostport) {
- struct addrinfo *ai;
- struct clsrvconf *res;
-
- res = resolve_hostport(type, hostport, NULL);
- ai = res->addrinfo;
- res->addrinfo = NULL;
- freeclsrvres(res);
- return ai;
-}
-