2 resolver initialisation stuff
4 Copyright (C) 2006 Michael Tokarev <mjt@corpit.ru>
5 This file is part of UDNS library, an async DNS stub resolver.
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library, in file named COPYING.LGPL; if not,
19 write to the Free Software Foundation, Inc., 59 Temple Place,
20 Suite 330, Boston, MA 02111-1307 USA
28 # include <winsock2.h> /* includes <windows.h> */
29 # include <iphlpapi.h> /* for dns server addresses etc */
31 # include <sys/types.h>
40 #define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
42 static const char space[] = " \t\r\n";
44 static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) {
45 dns_add_serv(ctx, NULL);
46 for(serv = strtok(serv, space); serv; serv = strtok(NULL, space))
47 dns_add_serv(ctx, serv);
50 static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
51 dns_add_srch(ctx, NULL);
52 for(srch = strtok(srch, space); srch; srch = strtok(NULL, space))
53 dns_add_srch(ctx, srch);
59 /* Apparently, some systems does not have proper headers for IPHLPAIP to work.
60 * The best is to upgrade headers, but here's another, ugly workaround for
61 * this: compile with -DNO_IPHLPAPI.
64 typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(
65 ULONG Family, DWORD Flags, PVOID Reserved,
66 PIP_ADAPTER_ADDRESSES pAdapterAddresses,
69 static int dns_initns_iphlpapi(struct dns_ctx *ctx) {
71 GetAdaptersAddressesFunc pfnGetAdAddrs;
72 PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf;
73 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
78 h_iphlpapi = LoadLibrary("iphlpapi.dll");
81 pfnGetAdAddrs = (GetAdaptersAddressesFunc)
82 GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
83 if (!pfnGetAdAddrs) goto freelib;
85 dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
86 if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
87 pAddrBuf = malloc(ulOutBufLen);
88 if (!pAddrBuf) goto freelib;
89 dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
90 if (dwRetVal != ERROR_SUCCESS) goto freemem;
91 for (pAddr = pAddrBuf; pAddr; pAddr = pAddr->Next)
92 for (pDnsAddr = pAddr->FirstDnsServerAddress;
94 pDnsAddr = pDnsAddr->Next)
95 dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr);
100 FreeLibrary(h_iphlpapi);
104 #else /* NO_IPHLPAPI */
106 #define dns_initns_iphlpapi(ctx) (-1)
108 #endif /* NO_IPHLPAPI */
110 static int dns_initns_registry(struct dns_ctx *ctx) {
113 DWORD type = REG_EXPAND_SZ | REG_SZ;
117 #define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
118 #define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
119 res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk);
120 if (res != ERROR_SUCCESS)
121 res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x,
122 0, KEY_QUERY_VALUE, &hk);
123 if (res != ERROR_SUCCESS)
125 len = sizeof(valBuf) - 1;
126 res = RegQueryValueEx(hk, "NameServer", NULL, &type, (BYTE*)valBuf, &len);
127 if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
128 len = sizeof(valBuf) - 1;
129 res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type,
130 (BYTE*)valBuf, &len);
133 if (res != ERROR_SUCCESS || !len || !valBuf[0])
136 /* nameservers are stored as a whitespace-seperate list:
137 * "192.168.1.1 123.21.32.12" */
138 dns_set_serv_internal(ctx, valBuf);
144 static int dns_init_resolvconf(struct dns_ctx *ctx) {
146 char buf[2049]; /* this buffer is used to hold /etc/resolv.conf */
149 /* read resolv.conf... */
150 { int fd = open("/etc/resolv.conf", O_RDONLY);
152 int l = read(fd, buf, sizeof(buf) - 1);
154 buf[l < 0 ? 0 : l] = '\0';
159 if (buf[0]) { /* ...and parse it */
160 char *line, *nextline;
163 nextline = strchr(line, '\n');
164 if (nextline) *nextline++ = '\0';
166 while(*v && !ISSPACE(*v)) ++v;
169 while(ISSPACE(*v)) ++v;
171 if (strcmp(line, "domain") == 0) {
172 dns_set_srch_internal(ctx, strtok(v, space));
175 else if (strcmp(line, "search") == 0) {
176 dns_set_srch_internal(ctx, v);
179 else if (strcmp(line, "nameserver") == 0)
180 dns_add_serv(ctx, strtok(v, space));
181 else if (strcmp(line, "options") == 0)
182 dns_set_opts(ctx, v);
183 } while((line = nextline) != NULL);
186 buf[sizeof(buf)-1] = '\0';
188 /* get list of nameservers from env. vars. */
189 if ((v = getenv("NSCACHEIP")) != NULL ||
190 (v = getenv("NAMESERVERS")) != NULL) {
191 strncpy(buf, v, sizeof(buf) - 1);
192 dns_set_serv_internal(ctx, buf);
194 /* if $LOCALDOMAIN is set, use it for search list */
195 if ((v = getenv("LOCALDOMAIN")) != NULL) {
196 strncpy(buf, v, sizeof(buf) - 1);
197 dns_set_srch_internal(ctx, buf);
200 if ((v = getenv("RES_OPTIONS")) != NULL)
201 dns_set_opts(ctx, v);
203 /* if still no search list, use local domain name */
205 gethostname(buf, sizeof(buf) - 1) == 0 &&
206 (v = strchr(buf, '.')) != NULL &&
208 dns_add_srch(ctx, v);
213 #endif /* !WINDOWS */
215 int dns_init(struct dns_ctx *ctx, int do_open) {
221 if (dns_initns_iphlpapi(ctx) != 0)
222 dns_initns_registry(ctx);
223 /*XXX WINDOWS: probably good to get default domain and search list too...
224 * And options. Something is in registry. */
225 /*XXX WINDOWS: maybe environment variables are also useful? */
227 dns_init_resolvconf(ctx);
230 return do_open ? dns_open(ctx) : 0;