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