155682Smarkm/*
2233294Sstas * Copyright (c) 1998 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include <config.h>
3555682Smarkm
36178825Sdfr#include "roken.h"
3755682Smarkm
3855682Smarkm#undef roken_gethostbyname
3955682Smarkm#undef roken_gethostbyaddr
4055682Smarkm
4155682Smarkmstatic struct sockaddr_in dns_addr;
4255682Smarkmstatic char *dns_req;
4355682Smarkm
4455682Smarkmstatic int
4555682Smarkmmake_address(const char *address, struct in_addr *ip)
4655682Smarkm{
4755682Smarkm    if(inet_aton(address, ip) == 0){
4855682Smarkm	/* try to resolve as hostname, it might work if the address we
4955682Smarkm           are trying to lookup is local, for instance a web proxy */
5055682Smarkm	struct hostent *he = gethostbyname(address);
5155682Smarkm	if(he) {
5255682Smarkm	    unsigned char *p = (unsigned char*)he->h_addr;
5355682Smarkm	    ip->s_addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
5455682Smarkm	} else {
5555682Smarkm	    return -1;
5655682Smarkm	}
5755682Smarkm    }
5855682Smarkm    return 0;
5955682Smarkm}
6055682Smarkm
6155682Smarkmstatic int
6255682Smarkmsetup_int(const char *proxy_host, short proxy_port,
6355682Smarkm	  const char *dns_host, short dns_port,
6455682Smarkm	  const char *dns_path)
6555682Smarkm{
6655682Smarkm    memset(&dns_addr, 0, sizeof(dns_addr));
6755682Smarkm    if(dns_req)
6855682Smarkm	free(dns_req);
69233294Sstas    dns_req = NULL;
7055682Smarkm    if(proxy_host) {
7155682Smarkm	if(make_address(proxy_host, &dns_addr.sin_addr) != 0)
7255682Smarkm	    return -1;
7355682Smarkm	dns_addr.sin_port = htons(proxy_port);
74233294Sstas	if (asprintf(&dns_req, "http://%s:%d%s", dns_host, dns_port, dns_path) < 0)
75233294Sstas	    return -1;
7655682Smarkm    } else {
7755682Smarkm	if(make_address(dns_host, &dns_addr.sin_addr) != 0)
7855682Smarkm	    return -1;
7955682Smarkm	dns_addr.sin_port = htons(dns_port);
8055682Smarkm	asprintf(&dns_req, "%s", dns_path);
8155682Smarkm    }
8255682Smarkm    dns_addr.sin_family = AF_INET;
8355682Smarkm    return 0;
8455682Smarkm}
8555682Smarkm
8655682Smarkmstatic void
8755682Smarkmsplit_spec(const char *spec, char **host, int *port, char **path, int def_port)
8855682Smarkm{
8955682Smarkm    char *p;
9055682Smarkm    *host = strdup(spec);
9155682Smarkm    p = strchr(*host, ':');
9255682Smarkm    if(p) {
9355682Smarkm	*p++ = '\0';
9455682Smarkm	if(sscanf(p, "%d", port) != 1)
9555682Smarkm	    *port = def_port;
9655682Smarkm    } else
9755682Smarkm	*port = def_port;
9855682Smarkm    p = strchr(p ? p : *host, '/');
9955682Smarkm    if(p) {
100233294Sstas	if(path)
10155682Smarkm	    *path = strdup(p);
10255682Smarkm	*p = '\0';
10355682Smarkm    }else
104233294Sstas	if(path)
10555682Smarkm	    *path = NULL;
10655682Smarkm}
10755682Smarkm
10855682Smarkm
109233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
11055682Smarkmroken_gethostby_setup(const char *proxy_spec, const char *dns_spec)
11155682Smarkm{
11255682Smarkm    char *proxy_host = NULL;
113178825Sdfr    int proxy_port = 0;
11455682Smarkm    char *dns_host, *dns_path;
11555682Smarkm    int dns_port;
116233294Sstas
11755682Smarkm    int ret = -1;
118233294Sstas
11955682Smarkm    split_spec(dns_spec, &dns_host, &dns_port, &dns_path, 80);
12055682Smarkm    if(dns_path == NULL)
12155682Smarkm	goto out;
12255682Smarkm    if(proxy_spec)
12355682Smarkm	split_spec(proxy_spec, &proxy_host, &proxy_port, NULL, 80);
12455682Smarkm    ret = setup_int(proxy_host, proxy_port, dns_host, dns_port, dns_path);
12555682Smarkmout:
12655682Smarkm    free(proxy_host);
12755682Smarkm    free(dns_host);
12855682Smarkm    free(dns_path);
12955682Smarkm    return ret;
13055682Smarkm}
13155682Smarkm
132233294Sstas
13355682Smarkm/* Try to lookup a name or an ip-address using http as transport
13455682Smarkm   mechanism. See the end of this file for an example program. */
13555682Smarkmstatic struct hostent*
13655682Smarkmroken_gethostby(const char *hostname)
13755682Smarkm{
13855682Smarkm    int s;
139178825Sdfr    struct sockaddr_in addr;
140233294Sstas    char *request = NULL;
14155682Smarkm    char buf[1024];
14255682Smarkm    int offset = 0;
14355682Smarkm    int n;
14455682Smarkm    char *p, *foo;
145233294Sstas    size_t len;
146233294Sstas
14755682Smarkm    if(dns_addr.sin_family == 0)
14855682Smarkm	return NULL; /* no configured host */
149178825Sdfr    addr = dns_addr;
150233294Sstas    if (asprintf(&request, "GET %s?%s HTTP/1.0\r\n\r\n", dns_req, hostname) < 0)
151233294Sstas	return NULL;
15255682Smarkm    if(request == NULL)
15355682Smarkm	return NULL;
15455682Smarkm    s  = socket(AF_INET, SOCK_STREAM, 0);
15555682Smarkm    if(s < 0) {
15655682Smarkm	free(request);
15755682Smarkm	return NULL;
15855682Smarkm    }
159178825Sdfr    if(connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
16055682Smarkm	close(s);
16155682Smarkm	free(request);
16255682Smarkm	return NULL;
16355682Smarkm    }
164233294Sstas
165233294Sstas    len = strlen(request);
166233294Sstas    if(write(s, request, len) != (ssize_t)len) {
16755682Smarkm	close(s);
16855682Smarkm	free(request);
16955682Smarkm	return NULL;
17055682Smarkm    }
17155682Smarkm    free(request);
17255682Smarkm    while(1) {
17355682Smarkm	n = read(s, buf + offset, sizeof(buf) - offset);
17455682Smarkm	if(n <= 0)
17555682Smarkm	    break;
17655682Smarkm	offset += n;
17755682Smarkm    }
17855682Smarkm    buf[offset] = '\0';
17955682Smarkm    close(s);
18055682Smarkm    p = strstr(buf, "\r\n\r\n"); /* find end of header */
18155682Smarkm    if(p) p += 4;
18255682Smarkm    else return NULL;
18355682Smarkm    foo = NULL;
18455682Smarkm    p = strtok_r(p, " \t\r\n", &foo);
18555682Smarkm    if(p == NULL)
18655682Smarkm	return NULL;
18755682Smarkm    {
18855682Smarkm	/* make a hostent to return */
18955682Smarkm#define MAX_ADDRS 16
19055682Smarkm	static struct hostent he;
19155682Smarkm	static char addrs[4 * MAX_ADDRS];
192178825Sdfr	static char *addr_list[MAX_ADDRS + 1];
19355682Smarkm	int num_addrs = 0;
194233294Sstas
19555682Smarkm	he.h_name = p;
19655682Smarkm	he.h_aliases = NULL;
19755682Smarkm	he.h_addrtype = AF_INET;
19855682Smarkm	he.h_length = 4;
199233294Sstas
20055682Smarkm	while((p = strtok_r(NULL, " \t\r\n", &foo)) && num_addrs < MAX_ADDRS) {
20155682Smarkm	    struct in_addr ip;
20255682Smarkm	    inet_aton(p, &ip);
20355682Smarkm	    ip.s_addr = ntohl(ip.s_addr);
20455682Smarkm	    addr_list[num_addrs] = &addrs[num_addrs * 4];
20555682Smarkm	    addrs[num_addrs * 4 + 0] = (ip.s_addr >> 24) & 0xff;
20655682Smarkm	    addrs[num_addrs * 4 + 1] = (ip.s_addr >> 16) & 0xff;
20755682Smarkm	    addrs[num_addrs * 4 + 2] = (ip.s_addr >> 8) & 0xff;
20855682Smarkm	    addrs[num_addrs * 4 + 3] = (ip.s_addr >> 0) & 0xff;
20955682Smarkm	    addr_list[++num_addrs] = NULL;
21055682Smarkm	}
21155682Smarkm	he.h_addr_list = addr_list;
21255682Smarkm	return &he;
21355682Smarkm    }
21455682Smarkm}
21555682Smarkm
216233294SstasROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
21755682Smarkmroken_gethostbyname(const char *hostname)
21855682Smarkm{
21955682Smarkm    struct hostent *he;
22055682Smarkm    he = gethostbyname(hostname);
22155682Smarkm    if(he)
22255682Smarkm	return he;
22355682Smarkm    return roken_gethostby(hostname);
22455682Smarkm}
22555682Smarkm
226233294SstasROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
22755682Smarkmroken_gethostbyaddr(const void *addr, size_t len, int type)
22855682Smarkm{
22955682Smarkm    struct in_addr a;
23055682Smarkm    const char *p;
23155682Smarkm    struct hostent *he;
23255682Smarkm    he = gethostbyaddr(addr, len, type);
23355682Smarkm    if(he)
23455682Smarkm	return he;
23555682Smarkm    if(type != AF_INET || len != 4)
23655682Smarkm	return NULL;
23755682Smarkm    p = addr;
23855682Smarkm    a.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
23955682Smarkm    return roken_gethostby(inet_ntoa(a));
24055682Smarkm}
24155682Smarkm
24255682Smarkm#if 0
24355682Smarkm
24455682Smarkm/* this program can be used as a cgi `script' to lookup names and
24555682Smarkm   ip-addresses */
24655682Smarkm
24755682Smarkm#include <stdio.h>
24855682Smarkm#include <stdlib.h>
24955682Smarkm#include <netdb.h>
25055682Smarkm#include <sys/param.h>
25155682Smarkm
25255682Smarkmint
25355682Smarkmmain(int argc, char **argv)
25455682Smarkm{
25555682Smarkm    char *query = getenv("QUERY_STRING");
25655682Smarkm    char host[MAXHOSTNAMELEN];
25755682Smarkm    int i;
25855682Smarkm    struct hostent *he;
259233294Sstas
26055682Smarkm    printf("Content-type: text/plain\n\n");
26155682Smarkm    if(query == NULL)
26255682Smarkm	exit(0);
26355682Smarkm    he = gethostbyname(query);
26455682Smarkm    strncpy(host, he->h_name, sizeof(host));
26555682Smarkm    host[sizeof(host) - 1] = '\0';
26655682Smarkm    he = gethostbyaddr(he->h_addr, he->h_length, AF_INET);
26755682Smarkm    printf("%s\n", he->h_name);
26855682Smarkm    for(i = 0; he->h_addr_list[i]; i++) {
26955682Smarkm	struct in_addr ip;
27055682Smarkm	unsigned char *p = (unsigned char*)he->h_addr_list[i];
27155682Smarkm	ip.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
27255682Smarkm	printf("%s\n", inet_ntoa(ip));
27355682Smarkm    }
27455682Smarkm    exit(0);
27555682Smarkm}
27655682Smarkm
27755682Smarkm#endif
278