]> git.mxchange.org Git - simgear.git/blob - 3rdparty/udns/udns_init.c
HTTP: Always use absolute paths for hashes
[simgear.git] / 3rdparty / udns / udns_init.c
1 /* udns_init.c
2    resolver initialisation stuff
3
4    Copyright (C) 2006  Michael Tokarev <mjt@corpit.ru>
5    This file is part of UDNS library, an async DNS stub resolver.
6
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.
11
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.
16
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
21
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #ifdef WINDOWS
28 # include <winsock2.h>          /* includes <windows.h> */
29 # include <iphlpapi.h>          /* for dns server addresses etc */
30 #else
31 # include <sys/types.h>
32 # include <unistd.h>
33 # include <fcntl.h>
34 #endif  /* !WINDOWS */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include "udns.h"
39
40 #define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
41
42 static const char space[] = " \t\r\n";
43
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);
48 }
49
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);
54 }
55
56 #ifdef WINDOWS
57
58 #ifndef NO_IPHLPAPI
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.
62  */
63
64 typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(
65   ULONG Family, DWORD Flags, PVOID Reserved,
66   PIP_ADAPTER_ADDRESSES pAdapterAddresses,
67   PULONG pOutBufLen);
68
69 static int dns_initns_iphlpapi(struct dns_ctx *ctx) {
70   HANDLE h_iphlpapi;
71   GetAdaptersAddressesFunc pfnGetAdAddrs;
72   PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf;
73   PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
74   ULONG ulOutBufLen;
75   DWORD dwRetVal;
76   int ret = -1;
77
78   h_iphlpapi = LoadLibrary("iphlpapi.dll");
79   if (!h_iphlpapi)
80     return -1;
81   pfnGetAdAddrs = (GetAdaptersAddressesFunc)
82     GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
83   if (!pfnGetAdAddrs) goto freelib;
84   ulOutBufLen = 0;
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;
93          pDnsAddr;
94          pDnsAddr = pDnsAddr->Next)
95       dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr);
96   ret = 0;
97 freemem:
98   free(pAddrBuf);
99 freelib:
100   FreeLibrary(h_iphlpapi);
101   return ret;
102 }
103
104 #else /* NO_IPHLPAPI */
105
106 #define dns_initns_iphlpapi(ctx) (-1)
107
108 #endif /* NO_IPHLPAPI */
109
110 static int dns_initns_registry(struct dns_ctx *ctx) {
111   LONG res;
112   HKEY hk;
113   DWORD type = REG_EXPAND_SZ | REG_SZ;
114   DWORD len;
115   char valBuf[1024];
116
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)
124     return -1;
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);
131   }
132   RegCloseKey(hk);
133   if (res != ERROR_SUCCESS || !len || !valBuf[0])
134     return -1;
135   valBuf[len] = '\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);
139   return 0;
140 }
141
142 #else /* !WINDOWS */
143
144 static int dns_init_resolvconf(struct dns_ctx *ctx) {
145   char *v;
146   char buf[2049];       /* this buffer is used to hold /etc/resolv.conf */
147   int has_srch = 0;
148
149   /* read resolv.conf... */
150   { int fd = open("/etc/resolv.conf", O_RDONLY);
151     if (fd >= 0) {
152       int l = read(fd, buf, sizeof(buf) - 1);
153       close(fd);
154       buf[l < 0 ? 0 : l] = '\0';
155     }
156     else
157       buf[0] = '\0';
158   }
159   if (buf[0]) { /* ...and parse it */
160     char *line, *nextline;
161     line = buf;
162     do {
163       nextline = strchr(line, '\n');
164       if (nextline) *nextline++ = '\0';
165       v = line;
166       while(*v && !ISSPACE(*v)) ++v;
167       if (!*v) continue;
168       *v++ = '\0';
169       while(ISSPACE(*v)) ++v;
170       if (!*v) continue;
171       if (strcmp(line, "domain") == 0) {
172         dns_set_srch_internal(ctx, strtok(v, space));
173         has_srch = 1;
174       }
175       else if (strcmp(line, "search") == 0) {
176         dns_set_srch_internal(ctx, v);
177         has_srch = 1;
178       }
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);
184   }
185
186   buf[sizeof(buf)-1] = '\0';
187
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);
193   }
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);
198     has_srch = 1;
199   }
200   if ((v = getenv("RES_OPTIONS")) != NULL)
201     dns_set_opts(ctx, v);
202
203   /* if still no search list, use local domain name */
204   if (has_srch &&
205       gethostname(buf, sizeof(buf) - 1) == 0 &&
206       (v = strchr(buf, '.')) != NULL &&
207       *++v != '\0')
208     dns_add_srch(ctx, v);
209
210   return 0;
211 }
212
213 #endif /* !WINDOWS */
214
215 int dns_init(struct dns_ctx *ctx, int do_open) {
216   if (!ctx)
217     ctx = &dns_defctx;
218   dns_reset(ctx);
219
220 #ifdef WINDOWS
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? */
226 #else
227   dns_init_resolvconf(ctx);
228 #endif
229
230   return do_open ? dns_open(ctx) : 0;
231 }