~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

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
        for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount; ++n)
 
757
        {
 
758
                jdns_address_t *addr;
 
759
                struct sockaddr_in6 *sa6;
 
760
 
 
761
#ifdef USE_EXTEXT
 
762
                /*  seems _ext.ext can be null in some cases... */
 
763
                if(RESVAR._u._ext.ext == NULL)
 
764
                        break;
 
765
 
 
766
                sa6 = ((struct sockaddr_in6 *)RESVAR._u._ext.ext) + n;
 
767
#else
 
768
                sa6 = RESVAR._u._ext.nsaddrs[n];
 
769
#endif
 
770
 
 
771
                if(sa6 == NULL)
 
772
                        continue;
 
773
                addr = jdns_address_new();
 
774
                jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr);
 
775
                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
776
                jdns_address_delete(addr);
 
777
        }
 
778
 
 
779
        /*  nameservers - ipv4 */
 
780
        for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n)
 
781
        {
 
782
                jdns_address_t *addr = jdns_address_new();
 
783
                jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr));
 
784
                jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
 
785
                jdns_address_delete(addr);
 
786
        }
 
787
 
 
788
        /*  domain name */
 
789
        if(strlen(RESVAR.defdname) > 0)
 
790
        {
 
791
                jdns_string_t *str;
 
792
                jdns_string_t *p;
 
793
                str = jdns_string_new();
 
794
                jdns_string_set_cstr(str, RESVAR.defdname);
 
795
                p = string_tolower(str);
 
796
                jdns_string_delete(str);
 
797
                str = p;
 
798
                jdns_dnsparams_append_domain(params, str);
 
799
                jdns_string_delete(str);
 
800
        }
 
801
 
 
802
        /*  search list */
 
803
#ifdef MAXDFLSRCH
 
804
        for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n)
 
805
        {
 
806
                if(strlen(RESVAR.dnsrch[n]) > 0)
 
807
                {
 
808
                        jdns_string_t *str;
 
809
                        jdns_string_t *p;
 
810
                        str = jdns_string_new();
 
811
                        jdns_string_set_cstr(str, RESVAR.dnsrch[n]);
 
812
                        p = string_tolower(str);
 
813
                        jdns_string_delete(str);
 
814
                        str = p;
 
815
 
 
816
                        /*  don't add dups */
 
817
                        if(!dnsparams_have_domain(params, str))
 
818
                                jdns_dnsparams_append_domain(params, str);
 
819
 
 
820
                        jdns_string_delete(str);
 
821
                }
 
822
        }
 
823
#endif
 
824
 
 
825
        return params;
 
826
}
 
827
 
 
828
static jdns_dnsparams_t *dnsparams_get_unix()
 
829
{
 
830
        jdns_dnsparams_t *params;
 
831
 
 
832
        /*  prefer system calls over files */
 
833
        params = dnsparams_get_unixsys();
 
834
        if(params->nameservers->count == 0)
 
835
        {
 
836
                jdns_dnsparams_delete(params);
 
837
                params = dnsparams_get_unixfiles();
 
838
        }
 
839
 
 
840
        apply_hosts_file(params, "/etc/hosts");
 
841
 
 
842
        return params;
 
843
}
 
844
 
 
845
#endif
 
846
 
 
847
jdns_dnsparams_t *jdns_system_dnsparams()
 
848
{
 
849
#ifdef JDNS_OS_WIN
 
850
        return dnsparams_get_win();
 
851
#else
 
852
        return dnsparams_get_unix();
 
853
#endif
 
854
}