You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.7 KiB
233 lines
6.7 KiB
/* udns_init.c
|
|
resolver initialisation stuff
|
|
|
|
Copyright (C) 2006 Michael Tokarev <mjt@corpit.ru>
|
|
This file is part of UDNS library, an async DNS stub resolver.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library, in file named COPYING.LGPL; if not,
|
|
write to the Free Software Foundation, Inc., 59 Temple Place,
|
|
Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
#ifdef __MINGW32__
|
|
# include <winsock2.h> /* includes <windows.h> */
|
|
# include <iphlpapi.h> /* for dns server addresses etc */
|
|
#else
|
|
# include <sys/types.h>
|
|
# include <unistd.h>
|
|
# include <fcntl.h>
|
|
#endif /* !__MINGW32__ */
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "udns.h"
|
|
|
|
#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
|
|
|
|
static const char space[] = " \t\r\n";
|
|
|
|
static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) {
|
|
dns_add_serv(ctx, NULL);
|
|
for(serv = strtok(serv, space); serv; serv = strtok(NULL, space))
|
|
dns_add_serv(ctx, serv);
|
|
}
|
|
|
|
static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
|
|
dns_add_srch(ctx, NULL);
|
|
for(srch = strtok(srch, space); srch; srch = strtok(NULL, space))
|
|
dns_add_srch(ctx, srch);
|
|
}
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
#define NO_IPHLPAPI
|
|
|
|
#ifndef NO_IPHLPAPI
|
|
/* Apparently, some systems does not have proper headers for IPHLPAIP to work.
|
|
* The best is to upgrade headers, but here's another, ugly workaround for
|
|
* this: compile with -DNO_IPHLPAPI.
|
|
*/
|
|
|
|
typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(
|
|
ULONG Family, DWORD Flags, PVOID Reserved,
|
|
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
|
|
PULONG pOutBufLen);
|
|
|
|
static int dns_initns_iphlpapi(struct dns_ctx *ctx) {
|
|
HANDLE h_iphlpapi;
|
|
GetAdaptersAddressesFunc pfnGetAdAddrs;
|
|
PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf;
|
|
PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
|
|
ULONG ulOutBufLen;
|
|
DWORD dwRetVal;
|
|
int ret = -1;
|
|
|
|
h_iphlpapi = LoadLibrary("iphlpapi.dll");
|
|
if (!h_iphlpapi)
|
|
return -1;
|
|
pfnGetAdAddrs = (GetAdaptersAddressesFunc)
|
|
GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
|
|
if (!pfnGetAdAddrs) goto freelib;
|
|
ulOutBufLen = 0;
|
|
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
|
|
if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
|
|
pAddrBuf = malloc(ulOutBufLen);
|
|
if (!pAddrBuf) goto freelib;
|
|
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
|
|
if (dwRetVal != ERROR_SUCCESS) goto freemem;
|
|
for (pAddr = pAddrBuf; pAddr; pAddr = pAddr->Next)
|
|
for (pDnsAddr = pAddr->FirstDnsServerAddress;
|
|
pDnsAddr;
|
|
pDnsAddr = pDnsAddr->Next)
|
|
dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr);
|
|
ret = 0;
|
|
freemem:
|
|
free(pAddrBuf);
|
|
freelib:
|
|
FreeLibrary(h_iphlpapi);
|
|
return ret;
|
|
}
|
|
|
|
#else /* NO_IPHLPAPI */
|
|
|
|
#define dns_initns_iphlpapi(ctx) (-1)
|
|
|
|
#endif /* NO_IPHLPAPI */
|
|
|
|
static int dns_initns_registry(struct dns_ctx *ctx) {
|
|
LONG res;
|
|
HKEY hk;
|
|
DWORD type = REG_EXPAND_SZ | REG_SZ;
|
|
DWORD len;
|
|
char valBuf[1024];
|
|
|
|
#define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
|
#define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
|
|
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk);
|
|
if (res != ERROR_SUCCESS)
|
|
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x,
|
|
0, KEY_QUERY_VALUE, &hk);
|
|
if (res != ERROR_SUCCESS)
|
|
return -1;
|
|
len = sizeof(valBuf) - 1;
|
|
res = RegQueryValueEx(hk, "NameServer", NULL, &type, (BYTE*)valBuf, &len);
|
|
if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
|
|
len = sizeof(valBuf) - 1;
|
|
res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type,
|
|
(BYTE*)valBuf, &len);
|
|
}
|
|
RegCloseKey(hk);
|
|
if (res != ERROR_SUCCESS || !len || !valBuf[0])
|
|
return -1;
|
|
valBuf[len] = '\0';
|
|
/* nameservers are stored as a whitespace-seperate list:
|
|
* "192.168.1.1 123.21.32.12" */
|
|
dns_set_serv_internal(ctx, valBuf);
|
|
return 0;
|
|
}
|
|
|
|
#else /* !__MINGW32__ */
|
|
|
|
static int dns_init_resolvconf(struct dns_ctx *ctx) {
|
|
char *v;
|
|
char buf[2049]; /* this buffer is used to hold /etc/resolv.conf */
|
|
int has_srch = 0;
|
|
|
|
/* read resolv.conf... */
|
|
{ int fd = open("/etc/resolv.conf", O_RDONLY);
|
|
if (fd >= 0) {
|
|
int l = read(fd, buf, sizeof(buf) - 1);
|
|
close(fd);
|
|
buf[l < 0 ? 0 : l] = '\0';
|
|
}
|
|
else
|
|
buf[0] = '\0';
|
|
}
|
|
if (buf[0]) { /* ...and parse it */
|
|
char *line, *nextline;
|
|
line = buf;
|
|
do {
|
|
nextline = strchr(line, '\n');
|
|
if (nextline) *nextline++ = '\0';
|
|
v = line;
|
|
while(*v && !ISSPACE(*v)) ++v;
|
|
if (!*v) continue;
|
|
*v++ = '\0';
|
|
while(ISSPACE(*v)) ++v;
|
|
if (!*v) continue;
|
|
if (strcmp(line, "domain") == 0) {
|
|
dns_set_srch_internal(ctx, strtok(v, space));
|
|
has_srch = 1;
|
|
}
|
|
else if (strcmp(line, "search") == 0) {
|
|
dns_set_srch_internal(ctx, v);
|
|
has_srch = 1;
|
|
}
|
|
else if (strcmp(line, "nameserver") == 0)
|
|
dns_add_serv(ctx, strtok(v, space));
|
|
else if (strcmp(line, "options") == 0)
|
|
dns_set_opts(ctx, v);
|
|
} while((line = nextline) != NULL);
|
|
}
|
|
|
|
buf[sizeof(buf)-1] = '\0';
|
|
|
|
/* get list of nameservers from env. vars. */
|
|
if ((v = getenv("NSCACHEIP")) != NULL ||
|
|
(v = getenv("NAMESERVERS")) != NULL) {
|
|
strncpy(buf, v, sizeof(buf) - 1);
|
|
dns_set_serv_internal(ctx, buf);
|
|
}
|
|
/* if $LOCALDOMAIN is set, use it for search list */
|
|
if ((v = getenv("LOCALDOMAIN")) != NULL) {
|
|
strncpy(buf, v, sizeof(buf) - 1);
|
|
dns_set_srch_internal(ctx, buf);
|
|
has_srch = 1;
|
|
}
|
|
if ((v = getenv("RES_OPTIONS")) != NULL)
|
|
dns_set_opts(ctx, v);
|
|
|
|
/* if still no search list, use local domain name */
|
|
if (has_srch &&
|
|
gethostname(buf, sizeof(buf) - 1) == 0 &&
|
|
(v = strchr(buf, '.')) != NULL &&
|
|
*++v != '\0')
|
|
dns_add_srch(ctx, v);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* !__MINGW32__ */
|
|
|
|
int dns_init(struct dns_ctx *ctx, int do_open) {
|
|
if (!ctx)
|
|
ctx = &dns_defctx;
|
|
dns_reset(ctx);
|
|
|
|
#ifdef __MINGW32__
|
|
if (dns_initns_iphlpapi(ctx) != 0)
|
|
dns_initns_registry(ctx);
|
|
/*XXX __MINGW32__: probably good to get default domain and search list too...
|
|
* And options. Something is in registry. */
|
|
/*XXX __MINGW32__: maybe environment variables are also useful? */
|
|
#else
|
|
dns_init_resolvconf(ctx);
|
|
#endif
|
|
|
|
return do_open ? dns_open(ctx) : 0;
|
|
}
|