~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libiris/src/jdns/src/jdns/jdns_sys.c

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005-2008  Justin Karneges
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the
 
6
 * "Software"), to deal in the Software without restriction, including
 
7
 * without limitation the rights to use, copy, modify, merge, publish,
 
8
 * distribute, sublicense, and/or sell copies of the Software, and to
 
9
 * permit persons to whom the Software is furnished to do so, subject to
 
10
 * the following conditions:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included
 
13
 * in all copies or substantial portions of the Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
19
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
21
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 */
 
23
 
 
24
/*
 
25
this code probes the system for dns settings.  blah.
 
26
 
 
27
q3dns strategies
 
28
----------------
 
29
 
 
30
windows:
 
31
 
 
32
domain name, name server, "search list" found in windows registry here:
 
33
 
 
34
  HKEY_LOCAL_MACHINE
 
35
  System\CurrentControlSet\Services\Tcpip\Parameters  <-- win nt+
 
36
  System\CurrentControlSet\Services\VxD\MSTCP  <-- win 98
 
37
 
 
38
  for domain, try DhcpDomain else Domain
 
39
  for name servers, try DhcpNameServer, else NameServer
 
40
  for search list, try SearchList
 
41
 
 
42
iphlpapi.dll : GetNetworkParams(PFIXED_INFO, PULONG);
 
43
 
 
44
  info->DomainName
 
45
  info->DnsServerList (if not null, use it, and loop through ->Next until
 
46
    null)
 
47
  no search list
 
48
 
 
49
first try getnetworkparams.  if that fails, try the nt regkey then the 98
 
50
  regkey.  it seems that search list can only come from the registry, so
 
51
  maybe we need to grab that entry even if getnetworkparams works.
 
52
 
 
53
in the case of the registry, the nameserver and searchlist entries are
 
54
  delimited by spaces on win nt and commas on win 98.  probably a good
 
55
  idea to simplify white space first (chop away space at start and end,
 
56
  reduce all sections of spaces to one char).  also, lowercase the search
 
57
  list.
 
58
 
 
59
qt doesn't read the hosts file on windows.  this might be a good idea, but
 
60
  probably not worth it.
 
61
 
 
62
unix:
 
63
 
 
64
read /etc/resolv.conf manually:
 
65
  for each line, split at spaces
 
66
  if the first item is "nameserver", then there should be an IP address
 
67
    following it.  note: may contain mixed ipv4 and ipv6 addresses
 
68
  if the first item is "search", all other items are added to the domain
 
69
    list
 
70
  if the first item is "domain", then the next item should be added to the
 
71
    domain list.
 
72
  do case-insensitive matching for the item types
 
73
  for search/domain, the items are in the 8-bit system locale
 
74
 
 
75
info can also be fetched using system calls.  we use the res_* stuff here.
 
76
  first we should detect for a "modern res api".  this is available from
 
77
  glibc 2.3 and onward.  use the following scheme to check for it:
 
78
 
 
79
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2)
 
80
  && (__GLIBC_MINOR__ >= 3)))
 
81
  // modern res api
 
82
#endif
 
83
 
 
84
on mac we should look up res_init in the system library.  see:
 
85
  qt_mac_resolve_sys(RTLD_NEXT, "res_init"); for a hint.
 
86
otherwise we can just use res_init() straight.
 
87
 
 
88
under a modern res api, we do:
 
89
  struct __res_state res;
 
90
  res_ninit(&res);
 
91
otherwise, we simply call res_init().  for the modern api, we use the "res"
 
92
  struct that we made.  otherwise, we use the global "_res" struct.
 
93
 
 
94
read the res struct to obtain the name servers, search list, and domain.
 
95
  lowercase the search list and domain.
 
96
 
 
97
qt tries the file, and if that fails it tries the syscalls.  we may want to
 
98
  do the syscalls first, or even just do both all the time.
 
99
 
 
100
read /etc/hosts manually:
 
101
  for each line
 
102
    if there is a '#' character in the line, remove it and everything to
 
103
      the right
 
104
    simplify white space
 
105
    convert to lowercase
 
106
  split the line at spaces
 
107
  first item is the ip address
 
108
  all remaining items are hostnames
 
109
 
 
110
  note: these hosts could also be used for reverse-dns too
 
111
  note2: Windows has a hosts file as well (like C:\WINDOWS\hosts)
 
112
*/
 
113
 
 
114
#include "jdns_p.h"
 
115
 
 
116
#ifdef JDNS_OS_WIN
 
117
# include <windows.h>
 
118
#endif
 
119
 
 
120
#ifdef JDNS_OS_UNIX
 
121
# include <netinet/in.h>
 
122
# include <arpa/nameser.h>
 
123
# include <resolv.h>
 
124
# include <dlfcn.h>
 
125
#endif
 
126
 
 
127
#define string_indexOf jdns_string_indexOf
 
128
#define string_split jdns_string_split
 
129
 
 
130
static int char_isspace(unsigned char c)
 
131
{
 
132
        if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
 
133
                return 1;
 
134
        return 0;
 
135
}
 
136
 
 
137
static unsigned char *string_getnextword(unsigned char *in, int size, int pos, int *newpos)
 
138
{
 
139
        int n;
 
140
        int at;
 
141
        int len;
 
142
        unsigned char *out;
 
143
 
 
144
        at = pos;
 
145
 
 
146
        // skip any space at the start
 
147
        while(at < size && char_isspace(in[at]))
 
148
                ++at;
 
149
 
 
150
        // all space?  no word then
 
151
        if(at >= size)
 
152
                return 0;
 
153
 
 
154
        // skip until a space or end
 
155
        n = at;
 
156
        while(n < size && !char_isspace(in[n]))
 
157
                ++n;
 
158
        len = n - at;
 
159
 
 
160
        // allocate length + zero byte
 
161
        out = (unsigned char *)jdns_alloc(len + 1);
 
162
        if(!out)
 
163
                return 0;
 
164
        memcpy(out, in + at, len);
 
165
        out[len] = 0;
 
166
        *newpos = at + len;
 
167
        return out;
 
168
}
 
169
 
 
170
static jdns_string_t *string_simplify(const jdns_string_t *in)
 
171
{
 
172
        int n;
 
173
        int pos;
 
174
        int total;
 
175
        unsigned char *out;
 
176
        int outlen;
 
177
        jdns_string_t *outstr;
 
178
        jdns_stringlist_t *wordlist;
 
179
 
 
180
        // gather words and total of lengths
 
181
        pos = 0;
 
182
        total = 0;
 
183
        wordlist = jdns_stringlist_new();
 
184
        while(1)
 
185
        {
 
186
                jdns_string_t *word;
 
187
                unsigned char *str = string_getnextword(in->data, in->size, pos, &pos);
 
188
                if(!str)
 
189
                        break;
 
190
                word = jdns_string_new();
 
191
                jdns_string_set_cstr(word, (char *)str);
 
192
                jdns_free(str);
 
193
                jdns_stringlist_append(wordlist, word);
 
194
                total += word->size;
 
195
                jdns_string_delete(word);
 
196
        }
 
197
 
 
198
        if(total == 0)
 
199
        {
 
200
                jdns_stringlist_delete(wordlist);
 
201
 
 
202
                outstr = jdns_string_new();
 
203
                jdns_string_set_cstr(outstr, "");
 
204
                return outstr;
 
205
        }
 
206
 
 
207
        // we need to allocate space for total lengths and wordcount-1 spaces
 
208
        outlen = total + (wordlist->count - 1);
 
209
        out = (unsigned char *)jdns_alloc(outlen);
 
210
 
 
211
        // lay out the words
 
212
        pos = 0;
 
213
        for(n = 0; n < wordlist->count; ++n)
 
214
        {
 
215
                unsigned char *data = wordlist->item[n]->data;
 
216
                int size = wordlist->item[n]->size;
 
217
                memcpy(out + pos, data, size);
 
218
                pos += size;
 
219
 
 
220
                // if this is not the last word, append a space
 
221
                if(n + 1 < wordlist->count)
 
222
                        out[pos++] = ' ';
 
223
        }
 
224
        jdns_stringlist_delete(wordlist);
 
225
 
 
226
        outstr = jdns_string_new();
 
227
        jdns_string_set(outstr, out, outlen);
 
228
        jdns_free(out);
 
229
        return outstr;
 
230
}
 
231
 
 
232
static jdns_string_t *string_tolower(const jdns_string_t *in)
 
233
{
 
234
        int n;
 
235
        jdns_string_t *out = jdns_string_copy(in);
 
236
        for(n = 0; n < out->size; ++n)
 
237
                out->data[n] = tolower(out->data[n]);
 
238
        return out;
 
239
}
 
240
 
 
241
static jdns_string_t *file_nextline(FILE *f)
 
242
{
 
243
        int at, size;
 
244
        unsigned char *buf;
 
245
        jdns_string_t *str;
 
246
 
 
247
        size = 1023;
 
248
        buf = (unsigned char *)jdns_alloc(size);
 
249
        at = 0;
 
250
        while(1)
 
251
        {
 
252
                unsigned char c = fgetc(f);
 
253
                if(feof(f))
 
254
                {
 
255
                        if(at > 0)
 
256
                        {
 
257
                                // if we read at least one char, take it as a
 
258
                                //   line
 
259
                                break;
 
260
                        }
 
261
                        else
 
262
                        {
 
263
                                jdns_free(buf);
 
264
                                return 0;
 
265
                        }
 
266
                }
 
267
                if(c == '\n')
 
268
                        break;
 
269
                if(c == '\r')
 
270
                        continue;
 
271
                if(at < 1023)
 
272
                        buf[at++] = c;
 
273
        }
 
274
 
 
275
        str = jdns_string_new();
 
276
        jdns_string_set(str, buf, at);
 
277
        jdns_free(buf);
 
278
        return str;
 
279
}
 
280
 
 
281
static jdns_dnshostlist_t *read_hosts_file(const char *path)
 
282
{
 
283
        jdns_dnshostlist_t *out;
 
284
        FILE *f;
 
285
        jdns_string_t *line, *simp;
 
286
        jdns_stringlist_t *parts;
 
287
        jdns_address_t *addr;
 
288
        int n;
 
289
 
 
290
        out = jdns_dnshostlist_new();
 
291
 
 
292
        f = jdns_fopen(path, "r");
 
293
        if(!f)
 
294
                return out;
 
295
        while(1)
 
296
        {
 
297
                line = file_nextline(f);
 
298
                if(!line)
 
299
                        break;
 
300
 
 
301
                // truncate at comment
 
302
                n = string_indexOf(line, '#', 0);
 
303
                if(n != -1)
 
304
                {
 
305
                        line->size = n;
 
306
                        line->data[n] = 0;
 
307
                }
 
308
 
 
309
                simp = string_simplify(line);
 
310
                jdns_string_delete(line);
 
311
 
 
312
                parts = string_split(simp, ' ');
 
313
                jdns_string_delete(simp);
 
314
 
 
315
                if(parts->count < 2)
 
316
                {
 
317
                        jdns_stringlist_delete(parts);
 
318
                        continue;
 
319
                }
 
320
 
 
321
                addr = jdns_address_new();
 
322
                if(!jdns_address_set_cstr(addr, (const char *)parts->item[0]->data))
 
323
                {
 
324
                        jdns_address_delete(addr);
 
325
                        jdns_stringlist_delete(parts);
 
326
                        continue;
 
327
                }
 
328
 
 
329
                for(n = 1; n < parts->count; ++n)
 
330
                {
 
331
                        jdns_dnshost_t *h = jdns_dnshost_new();
 
332
                        h->name = jdns_string_copy(parts->item[n]);
 
333
                        h->address = jdns_address_copy(addr);
 
334
                        jdns_dnshostlist_append(out, h);
 
335
                        jdns_dnshost_delete(h);
 
336
                }
 
337
 
 
338
                jdns_address_delete(addr);
 
339
                jdns_stringlist_delete(parts);
 
340
        }
 
341
        fclose(f);
 
342
        return out;
 
343
}
 
344
 
 
345
static void apply_hosts_file(jdns_dnsparams_t *a, const char *path)
 
346
{
 
347
        int n;
 
348
        jdns_dnshostlist_t *list;
 
349
 
 
350
        list = read_hosts_file(path);
 
351
        for(n = 0; n < list->count; ++n)
 
352
                jdns_dnshostlist_append(a->hosts, list->item[n]);
 
353
        jdns_dnshostlist_delete(list);
 
354
}
 
355
 
 
356
static int dnsparams_have_domain(const jdns_dnsparams_t *a, const jdns_string_t *domain)
 
357
{
 
358
        int n;
 
359
        for(n = 0; n < a->domains->count; ++n)
 
360
        {
 
361
                jdns_string_t *str = a->domains->item[n];
 
362
                if(strcmp((const char *)str->data, (const char *)domain->data) == 0)
 
363
                        return 1;
 
364
        }
 
365
        return 0;
 
366
}
 
367
 
 
368
#ifdef JDNS_OS_WIN
 
369
 
 
370
// from Microsoft IPTypes.h
 
371
#ifndef IP_TYPES_INCLUDED
 
372
#define MAX_HOSTNAME_LEN    128
 
373
#define MAX_DOMAIN_NAME_LEN 128
 
374
#define MAX_SCOPE_ID_LEN    256
 
375
typedef struct {
 
376
    char String[4 * 4];
 
377
} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
 
378
typedef struct _IP_ADDR_STRING {
 
379
    struct _IP_ADDR_STRING* Next;
 
380
    IP_ADDRESS_STRING IpAddress;
 
381
    IP_MASK_STRING IpMask;
 
382
    DWORD Context;
 
383
} IP_ADDR_STRING, *PIP_ADDR_STRING;
 
384
typedef struct {
 
385
    char HostName[MAX_HOSTNAME_LEN + 4] ;
 
386
    char DomainName[MAX_DOMAIN_NAME_LEN + 4];
 
387
    PIP_ADDR_STRING CurrentDnsServer;
 
388
    IP_ADDR_STRING DnsServerList;
 
389
    UINT NodeType;
 
390
    char ScopeId[MAX_SCOPE_ID_LEN + 4];
 
391
    UINT EnableRouting;
 
392
    UINT EnableProxy;
 
393
    UINT EnableDns;
 
394
} FIXED_INFO, *PFIXED_INFO;
 
395
#endif
 
396
 
 
397
typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PULONG);
 
398
 
 
399
static jdns_string_t *reg_readString(HKEY hk, const char *subkey)
 
400
{
 
401
        char *buf;
 
402
        DWORD bufsize;
 
403
        int ret;
 
404
        jdns_string_t *str = 0;
 
405
 
 
406
        bufsize = 1024;
 
407
        buf = (char *)jdns_alloc((int)bufsize);
 
408
        if(!buf)
 
409
                return 0;
 
410
        ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
 
411
        if(ret == ERROR_MORE_DATA)
 
412
        {
 
413
                buf = (char *)jdns_realloc(buf, bufsize);
 
414
                if(!buf)
 
415
                {
 
416
                        jdns_free(buf);
 
417
                        return 0;
 
418
                }
 
419
                ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
 
420
        }
 
421
        if(ret == ERROR_SUCCESS)
 
422
        {
 
423
                str = jdns_string_new();
 
424
                jdns_string_set_cstr(str, (char *)buf);
 
425
        }
 
426
        jdns_free(buf);
 
427
        return str;
 
428
}
 
429
 
 
430
static jdns_dnsparams_t *dnsparams_get_winreg()
 
431
{
 
432
        int n;
 
433
        jdns_dnsparams_t *params;
 
434
        HKEY key;
 
435
        int ret;
 
436
        char sep;
 
437
        jdns_string_t *str_domain, *str_nameserver, *str_searchlist;
 
438
        jdns_stringlist_t *list_nameserver, *list_searchlist;
 
439
 
 
440
        sep = ' ';
 
441
        ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
 
442
                "System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
 
443
                0, KEY_READ, &key);
 
444
        if(ret != ERROR_SUCCESS)
 
445
        {
 
446
                sep = ',';
 
447
                ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
 
448
                        "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
 
449
                        0, KEY_READ, &key);
 
450
                if(ret != ERROR_SUCCESS)
 
451
                        return 0;
 
452
        }
 
453
 
 
454
        str_domain = reg_readString(key, "DhcpDomain");
 
455
        if(!str_domain)
 
456
                str_domain = reg_readString(key, "Domain");
 
457
        str_nameserver = reg_readString(key, "DhcpNameServer");
 
458
        if(!str_nameserver)
 
459
                str_nameserver = reg_readString(key, "NameServer");
 
460
        str_searchlist = reg_readString(key, "SearchList");
 
461
 
 
462
        RegCloseKey(key);
 
463
 
 
464
        list_nameserver = 0;
 
465
        if(str_nameserver)
 
466
        {
 
467
                list_nameserver = string_split(str_nameserver, sep);
 
468
                jdns_string_delete(str_nameserver);
 
469
        }
 
470
        list_searchlist = 0;
 
471
        if(str_searchlist)
 
472
        {
 
473
                // lowercase the string
 
474
                jdns_string_t *p = string_tolower(str_searchlist);
 
475
                jdns_string_delete(str_searchlist);
 
476
                str_searchlist = p;
 
477
 
 
478
                list_searchlist = string_split(str_searchlist, sep);
 
479
                jdns_string_delete(str_searchlist);
 
480
        }
 
481
 
 
482
        params = jdns_dnsparams_new();
 
483
        if(list_nameserver)
 
484
        {
 
485
                // qt seems to do a strange thing here by running each name
 
486
                //   server address through the q3dns setLabel function, and
 
487
                //   then pulls the result as a list of addresses.  i have
 
488
                //   no idea why they do this, or how one IP address would
 
489
                //   turn into anything else, let alone several addresses.
 
490
                // so, uh, we're not going to do that.
 
491
                for(n = 0; n < list_nameserver->count; ++n)
 
492
                {
 
493
                        jdns_address_t *addr = jdns_address_new();
 
494
                        if(jdns_address_set_cstr(addr, (char *)list_nameserver->item[n]->data))
 
495
                                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
496
                        jdns_address_delete(addr);
 
497
                }
 
498
                jdns_stringlist_delete(list_nameserver);
 
499
        }
 
500
        if(str_domain)
 
501
        {
 
502
                if(str_domain->size > 0)
 
503
                        jdns_dnsparams_append_domain(params, str_domain);
 
504
                jdns_string_delete(str_domain);
 
505
        }
 
506
        if(list_searchlist)
 
507
        {
 
508
                for(n = 0; n < list_searchlist->count; ++n)
 
509
                {
 
510
                        if(list_searchlist->item[n]->size > 0)
 
511
                                jdns_dnsparams_append_domain(params, list_searchlist->item[n]);
 
512
                }
 
513
                jdns_stringlist_delete(list_searchlist);
 
514
        }
 
515
 
 
516
        return params;
 
517
}
 
518
 
 
519
static jdns_dnsparams_t *dnsparams_get_winsys()
 
520
{
 
521
        jdns_dnsparams_t *params;
 
522
        GetNetworkParamsFunc myGetNetworkParams;
 
523
        DWORD ret;
 
524
        HINSTANCE lib;
 
525
        jdns_address_t *addr;
 
526
        jdns_string_t *str;
 
527
        IP_ADDR_STRING *ipstr;
 
528
 
 
529
        lib = LoadLibraryA("iphlpapi");
 
530
        if(!lib)
 
531
                return 0;
 
532
 
 
533
        params = 0;
 
534
        myGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(lib, "GetNetworkParams");
 
535
        if(myGetNetworkParams)
 
536
        {
 
537
                ULONG bufsize = 0;
 
538
                ret = myGetNetworkParams(0, &bufsize);
 
539
                if(ret == ERROR_BUFFER_OVERFLOW)
 
540
                {
 
541
                        FIXED_INFO *info = (FIXED_INFO *)jdns_alloc((int)bufsize);
 
542
                        ret = myGetNetworkParams(info, &bufsize);
 
543
                        if(ret == ERROR_SUCCESS)
 
544
                        {
 
545
                                params = jdns_dnsparams_new();
 
546
                                ipstr = &info->DnsServerList;
 
547
                                while(ipstr)
 
548
                                {
 
549
                                        addr = jdns_address_new();
 
550
                                        if(jdns_address_set_cstr(addr, (char *)ipstr->IpAddress.String))
 
551
                                                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
552
                                        jdns_address_delete(addr);
 
553
                                        ipstr = ipstr->Next;
 
554
                                }
 
555
                                str = jdns_string_new();
 
556
                                jdns_string_set_cstr(str, info->DomainName);
 
557
                                if(str->size > 0)
 
558
                                        jdns_dnsparams_append_domain(params, str);
 
559
                                jdns_string_delete(str);
 
560
                        }
 
561
                        jdns_free(info);
 
562
                }
 
563
        }
 
564
        FreeLibrary(lib);
 
565
        return params;
 
566
}
 
567
 
 
568
static void apply_hosts_var_filepath(jdns_dnsparams_t *a, const char *envvar, const char *path)
 
569
{
 
570
        jdns_string_t *e;
 
571
        char *str;
 
572
        int elen, plen;
 
573
 
 
574
        e = jdns_getenv(envvar);
 
575
        if(!e)
 
576
                return;
 
577
        elen = strlen((char *)e->data);
 
578
        plen = strlen(path);
 
579
        str = (char *)jdns_alloc(elen + plen + 1);
 
580
        memcpy(str, e->data, elen);
 
581
        jdns_string_delete(e);
 
582
 
 
583
        jdns_strcpy(str + elen, path);
 
584
        apply_hosts_file(a, str);
 
585
        jdns_free(str);
 
586
}
 
587
 
 
588
static void apply_win_hosts_file(jdns_dnsparams_t *a)
 
589
{
 
590
        // windows 64-bit
 
591
        apply_hosts_var_filepath(a, "SystemRoot", "\\SysWOW64\\drivers\\etc\\hosts");
 
592
 
 
593
        // winnt+
 
594
        apply_hosts_var_filepath(a, "SystemRoot", "\\system32\\drivers\\etc\\hosts");
 
595
 
 
596
        // win9x
 
597
        apply_hosts_var_filepath(a, "WINDIR", "\\hosts");
 
598
}
 
599
 
 
600
static jdns_dnsparams_t *dnsparams_get_win()
 
601
{
 
602
        int n;
 
603
        jdns_dnsparams_t *sys_params, *reg_params;
 
604
 
 
605
        reg_params = dnsparams_get_winreg();
 
606
        sys_params = dnsparams_get_winsys();
 
607
 
 
608
        // no sys params?  take the reg params then
 
609
        if(!sys_params)
 
610
        {
 
611
                apply_win_hosts_file(reg_params);
 
612
                return reg_params;
 
613
        }
 
614
 
 
615
        // sys params don't have a search list, so merge the domains from
 
616
        //   the registry if possible
 
617
        if(reg_params)
 
618
        {
 
619
                for(n = 0; n < reg_params->domains->count; ++n)
 
620
                {
 
621
                        jdns_string_t *reg_str = reg_params->domains->item[n];
 
622
 
 
623
                        // don't add dups
 
624
                        if(!dnsparams_have_domain(sys_params, reg_str))
 
625
                                jdns_dnsparams_append_domain(sys_params, reg_str);
 
626
                }
 
627
                jdns_dnsparams_delete(reg_params);
 
628
        }
 
629
        apply_win_hosts_file(sys_params);
 
630
        return sys_params;
 
631
}
 
632
 
 
633
#endif
 
634
 
 
635
#ifdef JDNS_OS_UNIX
 
636
 
 
637
static jdns_dnsparams_t *dnsparams_get_unixfiles()
 
638
{
 
639
        FILE *f;
 
640
        int n;
 
641
        jdns_dnsparams_t *params;
 
642
        jdns_string_t *line, *simp;
 
643
        jdns_stringlist_t *parts;
 
644
 
 
645
        params = jdns_dnsparams_new();
 
646
 
 
647
        f = jdns_fopen("/etc/resolv.conf", "r");
 
648
        if(!f)
 
649
                return params;
 
650
        while(1)
 
651
        {
 
652
                line = file_nextline(f);
 
653
                if(!line)
 
654
                        break;
 
655
 
 
656
                // truncate at comment
 
657
                n = string_indexOf(line, '#', 0);
 
658
                if(n != -1)
 
659
                {
 
660
                        line->size = n;
 
661
                        line->data[n] = 0;
 
662
                }
 
663
 
 
664
                simp = string_simplify(line);
 
665
                jdns_string_delete(line);
 
666
 
 
667
                parts = string_split(simp, ' ');
 
668
                jdns_string_delete(simp);
 
669
 
 
670
                if(parts->count < 2)
 
671
                {
 
672
                        jdns_stringlist_delete(parts);
 
673
                        continue;
 
674
                }
 
675
 
 
676
                simp = string_tolower(parts->item[0]);
 
677
                if(strcmp((char *)simp->data, "nameserver") == 0)
 
678
                {
 
679
                        jdns_address_t *addr = jdns_address_new();
 
680
                        jdns_address_set_cstr(addr, (const char *)parts->item[1]->data);
 
681
                        jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
682
                        jdns_address_delete(addr);
 
683
                }
 
684
                else if(strcmp((char *)simp->data, "search") == 0)
 
685
                {
 
686
                        for(n = 1; n < parts->count; ++n)
 
687
                        {
 
688
                                jdns_dnsparams_append_domain(params, parts->item[n]);
 
689
                        }
 
690
                }
 
691
                else if(strcmp((char *)simp->data, "domain") == 0)
 
692
                {
 
693
                        jdns_dnsparams_append_domain(params, parts->item[1]);
 
694
                }
 
695
                jdns_string_delete(simp);
 
696
 
 
697
                jdns_stringlist_delete(parts);
 
698
        }
 
699
        fclose(f);
 
700
        return params;
 
701
}
 
702
 
 
703
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
 
704
# define JDNS_MODERN_RES_API
 
705
#endif
 
706
 
 
707
#ifndef JDNS_MODERN_RES_API
 
708
typedef int (*res_init_func)();
 
709
static int my_res_init()
 
710
{
 
711
#ifdef JDNS_OS_MAC
 
712
        res_init_func mac_res_init;
 
713
 
 
714
        // look up res_init in the system library (qt does this, not sure why)
 
715
        mac_res_init = (res_init_func)dlsym(RTLD_NEXT, "res_init");
 
716
        if(!mac_res_init)
 
717
                return -1;
 
718
        return mac_res_init();
 
719
#else
 
720
        return res_init();
 
721
#endif
 
722
}
 
723
#endif
 
724
 
 
725
// on some platforms, __res_state_ext exists as a struct but it is not
 
726
//   a define, so the #ifdef doesn't work.  as a workaround, we'll explicitly
 
727
//   specify the platforms that have __res_state_ext
 
728
//#ifdef __res_state_ext
 
729
#if defined(JDNS_OS_MAC) || defined(JDNS_OS_FREEBSD) || \
 
730
    defined(JDNS_OS_NETBSD) || defined (JDNS_OS_SOLARIS)
 
731
# define USE_EXTEXT
 
732
#endif
 
733
 
 
734
static jdns_dnsparams_t *dnsparams_get_unixsys()
 
735
{
 
736
        int n;
 
737
        jdns_dnsparams_t *params;
 
738
 
 
739
#ifdef JDNS_MODERN_RES_API
 
740
        struct __res_state res;
 
741
        memset(&res, 0, sizeof(struct __res_state));
 
742
        n = res_ninit(&res);
 
743
#define RESVAR res
 
744
#else
 
745
        n = my_res_init();
 
746
#define RESVAR _res
 
747
#endif
 
748
 
 
749
        params = jdns_dnsparams_new();
 
750
 
 
751
        // error initializing?
 
752
        if(n == -1)
 
753
                return params;
 
754
 
 
755
        // nameservers - ipv6
 
756
#ifdef __GLIBC__
 
757
        for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount6; ++n)
 
758
#else
 
759
        for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount; ++n)
 
760
#endif
 
761
        {
 
762
                jdns_address_t *addr;
 
763
                struct sockaddr_in6 *sa6;
 
764
 
 
765
#ifdef USE_EXTEXT
 
766
                // seems _ext.ext can be null in some cases...
 
767
                if(RESVAR._u._ext.ext == NULL)
 
768
                        break;
 
769
 
 
770
                sa6 = ((struct sockaddr_in6 *)RESVAR._u._ext.ext) + n;
 
771
#else
 
772
                sa6 = RESVAR._u._ext.nsaddrs[n];
 
773
#endif
 
774
 
 
775
                if(sa6 == NULL)
 
776
                        continue;
 
777
                addr = jdns_address_new();
 
778
                jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr);
 
779
                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
780
                jdns_address_delete(addr);
 
781
        }
 
782
 
 
783
        // nameservers - ipv4
 
784
        for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n)
 
785
        {
 
786
                jdns_address_t *addr = jdns_address_new();
 
787
                jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr));
 
788
                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
789
                jdns_address_delete(addr);
 
790
        }
 
791
 
 
792
        // domain name
 
793
        if(strlen(RESVAR.defdname) > 0)
 
794
        {
 
795
                jdns_string_t *str;
 
796
                jdns_string_t *p;
 
797
                str = jdns_string_new();
 
798
                jdns_string_set_cstr(str, RESVAR.defdname);
 
799
                p = string_tolower(str);
 
800
                jdns_string_delete(str);
 
801
                str = p;
 
802
                jdns_dnsparams_append_domain(params, str);
 
803
                jdns_string_delete(str);
 
804
        }
 
805
 
 
806
        // search list
 
807
#ifdef MAXDFLSRCH
 
808
        for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n)
 
809
        {
 
810
                if(strlen(RESVAR.dnsrch[n]) > 0)
 
811
                {
 
812
                        jdns_string_t *str;
 
813
                        jdns_string_t *p;
 
814
                        str = jdns_string_new();
 
815
                        jdns_string_set_cstr(str, RESVAR.dnsrch[n]);
 
816
                        p = string_tolower(str);
 
817
                        jdns_string_delete(str);
 
818
                        str = p;
 
819
 
 
820
                        // don't add dups
 
821
                        if(!dnsparams_have_domain(params, str))
 
822
                                jdns_dnsparams_append_domain(params, str);
 
823
 
 
824
                        jdns_string_delete(str);
 
825
                }
 
826
        }
 
827
#endif
 
828
 
 
829
        return params;
 
830
}
 
831
 
 
832
static jdns_dnsparams_t *dnsparams_get_unix()
 
833
{
 
834
        jdns_dnsparams_t *params;
 
835
 
 
836
        // prefer system calls over files
 
837
        params = dnsparams_get_unixsys();
 
838
        if(params->nameservers->count == 0)
 
839
        {
 
840
                jdns_dnsparams_delete(params);
 
841
                params = dnsparams_get_unixfiles();
 
842
        }
 
843
 
 
844
        apply_hosts_file(params, "/etc/hosts");
 
845
 
 
846
        return params;
 
847
}
 
848
 
 
849
#endif
 
850
 
 
851
jdns_dnsparams_t *jdns_system_dnsparams()
 
852
{
 
853
#ifdef JDNS_OS_WIN
 
854
        return dnsparams_get_win();
 
855
#else
 
856
        return dnsparams_get_unix();
 
857
#endif
 
858
}