File indexing completed on 2024-05-26 04:08:59

0001 /*
0002  * Copyright (C) 2005-2008  Justin Karneges
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the
0006  * "Software"), to deal in the Software without restriction, including
0007  * without limitation the rights to use, copy, modify, merge, publish,
0008  * distribute, sublicense, and/or sell copies of the Software, and to
0009  * permit persons to whom the Software is furnished to do so, subject to
0010  * the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included
0013  * in all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0018  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0019  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
0020  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
0021  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0022  */
0023 
0024 /*
0025 this code probes the system for dns settings.  blah.
0026 
0027 q3dns strategies
0028 ----------------
0029 
0030 windows:
0031 
0032 domain name, name server, "search list" found in windows registry here:
0033 
0034   HKEY_LOCAL_MACHINE
0035   System\CurrentControlSet\Services\Tcpip\Parameters  <-- win nt+
0036   System\CurrentControlSet\Services\VxD\MSTCP  <-- win 98
0037 
0038   for domain, try DhcpDomain else Domain
0039   for name servers, try DhcpNameServer, else NameServer
0040   for search list, try SearchList
0041 
0042 iphlpapi.dll : GetNetworkParams(PFIXED_INFO, PULONG);
0043 
0044   info->DomainName
0045   info->DnsServerList (if not null, use it, and loop through ->Next until
0046     null)
0047   no search list
0048 
0049 first try getnetworkparams.  if that fails, try the nt regkey then the 98
0050   regkey.  it seems that search list can only come from the registry, so
0051   maybe we need to grab that entry even if getnetworkparams works.
0052 
0053 in the case of the registry, the nameserver and searchlist entries are
0054   delimited by spaces on win nt and commas on win 98.  probably a good
0055   idea to simplify white space first (chop away space at start and end,
0056   reduce all sections of spaces to one char).  also, lowercase the search
0057   list.
0058 
0059 qt doesn't read the hosts file on windows.  this might be a good idea, but
0060   probably not worth it.
0061 
0062 unix:
0063 
0064 read /etc/resolv.conf manually:
0065   for each line, split at spaces
0066   if the first item is "nameserver", then there should be an IP address
0067     following it.  note: may contain mixed ipv4 and ipv6 addresses
0068   if the first item is "search", all other items are added to the domain
0069     list
0070   if the first item is "domain", then the next item should be added to the
0071     domain list.
0072   do case-insensitive matching for the item types
0073   for search/domain, the items are in the 8-bit system locale
0074 
0075 info can also be fetched using system calls.  we use the res_* stuff here.
0076   first we should detect for a "modern res api".  this is available from
0077   glibc 2.3 and onward.  use the following scheme to check for it:
0078 
0079 #if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2)
0080   && (__GLIBC_MINOR__ >= 3)))
0081   // modern res api 
0082 #endif
0083 
0084 on mac we should look up res_init in the system library.  see:
0085   qt_mac_resolve_sys(RTLD_NEXT, "res_init"); for a hint.
0086 otherwise we can just use res_init() straight.
0087 
0088 under a modern res api, we do:
0089   struct __res_state res;
0090   res_ninit(&res);
0091 otherwise, we simply call res_init().  for the modern api, we use the "res"
0092   struct that we made.  otherwise, we use the global "_res" struct.
0093 
0094 read the res struct to obtain the name servers, search list, and domain.
0095   lowercase the search list and domain.
0096 
0097 qt tries the file, and if that fails it tries the syscalls.  we may want to
0098   do the syscalls first, or even just do both all the time.
0099 
0100 read /etc/hosts manually:
0101   for each line
0102     if there is a '#' character in the line, remove it and everything to
0103       the right
0104     simplify white space
0105     convert to lowercase
0106   split the line at spaces
0107   first item is the ip address
0108   all remaining items are hostnames
0109 
0110   note: these hosts could also be used for reverse-dns too
0111   note2: Windows has a hosts file as well (like C:\WINDOWS\hosts)
0112 */
0113 
0114 #include "jdns_p.h"
0115 
0116 #ifdef JDNS_OS_WIN
0117 # include <windows.h>
0118 #endif
0119 
0120 #ifdef JDNS_OS_UNIX
0121 # include <netinet/in.h>
0122 # include <arpa/nameser.h>
0123 # include <resolv.h>
0124 # include <dlfcn.h>
0125 #endif
0126 
0127 #define string_indexOf jdns_string_indexOf
0128 #define string_split jdns_string_split
0129 
0130 static int char_isspace(unsigned char c)
0131 {
0132     if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
0133         return 1;
0134     return 0;
0135 }
0136 
0137 static unsigned char *string_getnextword(unsigned char *in, int size, int pos, int *newpos)
0138 {
0139     int n;
0140     int at;
0141     int len;
0142     unsigned char *out;
0143 
0144     at = pos;
0145 
0146     /* skip any space at the start */
0147     while(at < size && char_isspace(in[at]))
0148         ++at;
0149 
0150     /* all space?  no word then */
0151     if(at >= size)
0152         return 0;
0153 
0154     /* skip until a space or end */
0155     n = at;
0156     while(n < size && !char_isspace(in[n]))
0157         ++n;
0158     len = n - at;
0159 
0160     /* allocate length + zero byte */
0161     out = (unsigned char *)jdns_alloc(len + 1);
0162     if(!out)
0163         return 0;
0164     memcpy(out, in + at, len);
0165     out[len] = 0;
0166     *newpos = at + len;
0167     return out;
0168 }
0169 
0170 static jdns_string_t *string_simplify(const jdns_string_t *in)
0171 {
0172     int n;
0173     int pos;
0174     int total;
0175     unsigned char *out;
0176     int outlen;
0177     jdns_string_t *outstr;
0178     jdns_stringlist_t *wordlist;
0179 
0180     /* gather words and total of lengths */
0181     pos = 0;
0182     total = 0;
0183     wordlist = jdns_stringlist_new();
0184     while(1)
0185     {
0186         jdns_string_t *word;
0187         unsigned char *str = string_getnextword(in->data, in->size, pos, &pos);
0188         if(!str)
0189             break;
0190         word = jdns_string_new();
0191         jdns_string_set_cstr(word, (char *)str);
0192         jdns_free(str);
0193         jdns_stringlist_append(wordlist, word);
0194         total += word->size;
0195         jdns_string_delete(word);
0196     }
0197 
0198     if(total == 0)
0199     {
0200         jdns_stringlist_delete(wordlist);
0201 
0202         outstr = jdns_string_new();
0203         jdns_string_set_cstr(outstr, "");
0204         return outstr;
0205     }
0206 
0207     /* we need to allocate space for total lengths and wordcount-1 spaces */
0208     outlen = total + (wordlist->count - 1);
0209     out = (unsigned char *)jdns_alloc(outlen);
0210 
0211     /* lay out the words */
0212     pos = 0;
0213     for(n = 0; n < wordlist->count; ++n)
0214     {
0215         unsigned char *data = wordlist->item[n]->data;
0216         int size = wordlist->item[n]->size;
0217         memcpy(out + pos, data, size);
0218         pos += size;
0219 
0220         /* if this is not the last word, append a space */
0221         if(n + 1 < wordlist->count)
0222             out[pos++] = ' ';
0223     }
0224     jdns_stringlist_delete(wordlist);
0225 
0226     outstr = jdns_string_new();
0227     jdns_string_set(outstr, out, outlen);
0228     jdns_free(out);
0229     return outstr;
0230 }
0231 
0232 static jdns_string_t *string_tolower(const jdns_string_t *in)
0233 {
0234     int n;
0235     jdns_string_t *out = jdns_string_copy(in);
0236     for(n = 0; n < out->size; ++n)
0237         out->data[n] = tolower(out->data[n]);
0238     return out;
0239 }
0240 
0241 static jdns_string_t *file_nextline(FILE *f)
0242 {
0243     int at, size;
0244     unsigned char *buf;
0245     jdns_string_t *str;
0246 
0247     size = 1023;
0248     buf = (unsigned char *)jdns_alloc(size);
0249     at = 0;
0250     while(1)
0251     {
0252         unsigned char c = fgetc(f);
0253         if(feof(f))
0254         {
0255             jdns_free(buf);
0256             return 0;
0257         }
0258         if(c == '\n')
0259             break;
0260         if(c == '\r')
0261             continue;
0262         if(at < 1023)
0263             buf[at++] = c;
0264     }
0265 
0266     str = jdns_string_new();
0267     jdns_string_set(str, buf, at);
0268     jdns_free(buf);
0269     return str;
0270 }
0271 
0272 static jdns_dnshostlist_t *read_hosts_file(const char *path)
0273 {
0274     jdns_dnshostlist_t *out;
0275     FILE *f;
0276     jdns_string_t *line, *simp;
0277     jdns_stringlist_t *parts;
0278     jdns_address_t *addr;
0279     int n;
0280 
0281     out = jdns_dnshostlist_new();
0282 
0283     f = jdns_fopen(path, "r");
0284     if(!f)
0285         return out;
0286     while(1)
0287     {
0288         line = file_nextline(f);
0289         if(!line)
0290             break;
0291 
0292         /* truncate at comment */
0293         n = string_indexOf(line, '#', 0);
0294         if(n != -1)
0295         {
0296             line->size = n;
0297             line->data[n] = 0;
0298         }
0299 
0300         simp = string_simplify(line);
0301         jdns_string_delete(line);
0302 
0303         parts = string_split(simp, ' ');
0304         jdns_string_delete(simp);
0305 
0306         if(parts->count < 2)
0307         {
0308             jdns_stringlist_delete(parts);
0309             continue;
0310         }
0311 
0312         addr = jdns_address_new();
0313         if(!jdns_address_set_cstr(addr, (const char *)parts->item[0]->data))
0314         {
0315             jdns_address_delete(addr);
0316             jdns_stringlist_delete(parts);
0317             continue;
0318         }
0319 
0320         for(n = 1; n < parts->count; ++n)
0321         {
0322             jdns_dnshost_t *h = jdns_dnshost_new();
0323             h->name = jdns_string_copy(parts->item[n]);
0324             h->address = jdns_address_copy(addr);
0325             jdns_dnshostlist_append(out, h);
0326             jdns_dnshost_delete(h);
0327         }
0328 
0329         jdns_address_delete(addr);
0330         jdns_stringlist_delete(parts);
0331     }
0332     fclose(f);
0333     return out;
0334 }
0335 
0336 static void apply_hosts_file(jdns_dnsparams_t *a, const char *path)
0337 {
0338     int n;
0339     jdns_dnshostlist_t *list;
0340 
0341     list = read_hosts_file(path);
0342     for(n = 0; n < list->count; ++n)
0343         jdns_dnshostlist_append(a->hosts, list->item[n]);
0344     jdns_dnshostlist_delete(list);
0345 }
0346 
0347 static int dnsparams_have_domain(const jdns_dnsparams_t *a, const jdns_string_t *domain)
0348 {
0349     int n;
0350     for(n = 0; n < a->domains->count; ++n)
0351     {
0352         jdns_string_t *str = a->domains->item[n];
0353         if(strcmp((const char *)str->data, (const char *)domain->data) == 0)
0354             return 1;
0355     }
0356     return 0;
0357 }
0358 
0359 #ifdef JDNS_OS_WIN
0360 
0361 /* from Microsoft IPTypes.h */
0362 #ifndef IP_TYPES_INCLUDED
0363 #define MAX_HOSTNAME_LEN    128
0364 #define MAX_DOMAIN_NAME_LEN 128
0365 #define MAX_SCOPE_ID_LEN    256
0366 typedef struct {
0367     char String[4 * 4];
0368 } IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
0369 typedef struct _IP_ADDR_STRING {
0370     struct _IP_ADDR_STRING* Next;
0371     IP_ADDRESS_STRING IpAddress;
0372     IP_MASK_STRING IpMask;
0373     DWORD Context;
0374 } IP_ADDR_STRING, *PIP_ADDR_STRING;
0375 typedef struct {
0376     char HostName[MAX_HOSTNAME_LEN + 4] ;
0377     char DomainName[MAX_DOMAIN_NAME_LEN + 4];
0378     PIP_ADDR_STRING CurrentDnsServer;
0379     IP_ADDR_STRING DnsServerList;
0380     UINT NodeType;
0381     char ScopeId[MAX_SCOPE_ID_LEN + 4];
0382     UINT EnableRouting;
0383     UINT EnableProxy;
0384     UINT EnableDns;
0385 } FIXED_INFO, *PFIXED_INFO;
0386 #endif
0387 
0388 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PULONG);
0389 
0390 static jdns_string_t *reg_readString(HKEY hk, const char *subkey)
0391 {
0392     char *buf;
0393     DWORD bufsize;
0394     int ret;
0395     jdns_string_t *str = 0;
0396 
0397     bufsize = 1024;
0398     buf = (char *)jdns_alloc((int)bufsize);
0399     if(!buf)
0400         return 0;
0401     ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
0402     if(ret == ERROR_MORE_DATA)
0403     {
0404         buf = (char *)jdns_realloc(buf, bufsize);
0405         if(!buf)
0406         {
0407             jdns_free(buf);
0408             return 0;
0409         }
0410         ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
0411     }
0412     if(ret == ERROR_SUCCESS)
0413     {
0414         str = jdns_string_new();
0415         jdns_string_set_cstr(str, (char *)buf);
0416     }
0417     jdns_free(buf);
0418     return str;
0419 }
0420 
0421 static jdns_dnsparams_t *dnsparams_get_winreg()
0422 {
0423     int n;
0424     jdns_dnsparams_t *params;
0425     HKEY key;
0426     int ret;
0427     char sep;
0428     jdns_string_t *str_domain, *str_nameserver, *str_searchlist;
0429     jdns_stringlist_t *list_nameserver, *list_searchlist;
0430 
0431     sep = ' ';
0432     ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
0433         "System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
0434         0, KEY_READ, &key);
0435     if(ret != ERROR_SUCCESS)
0436     {
0437         sep = ',';
0438         ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
0439             "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
0440             0, KEY_READ, &key);
0441         if(ret != ERROR_SUCCESS)
0442             return 0;
0443     }
0444 
0445     str_domain = reg_readString(key, "DhcpDomain");
0446     if(!str_domain)
0447         str_domain = reg_readString(key, "Domain");
0448     str_nameserver = reg_readString(key, "DhcpNameServer");
0449     if(!str_nameserver)
0450         str_nameserver = reg_readString(key, "NameServer");
0451     str_searchlist = reg_readString(key, "SearchList");
0452 
0453     RegCloseKey(key);
0454 
0455     list_nameserver = 0;
0456     if(str_nameserver)
0457     {
0458         list_nameserver = string_split(str_nameserver, sep);
0459         jdns_string_delete(str_nameserver);
0460     }
0461     list_searchlist = 0;
0462     if(str_searchlist)
0463     {
0464         /* lowercase the string */
0465         jdns_string_t *p = string_tolower(str_searchlist);
0466         jdns_string_delete(str_searchlist);
0467         str_searchlist = p;
0468 
0469         list_searchlist = string_split(str_searchlist, sep);
0470         jdns_string_delete(str_searchlist);
0471     }
0472 
0473     params = jdns_dnsparams_new();
0474     if(list_nameserver)
0475     {
0476         /* qt seems to do a strange thing here by running each name */
0477         /*   server address through the q3dns setLabel function, and */
0478         /*   then pulls the result as a list of addresses.  i have */
0479         /*   no idea why they do this, or how one IP address would */
0480         /*   turn into anything else, let alone several addresses. */
0481         /* so, uh, we're not going to do that. */
0482         for(n = 0; n < list_nameserver->count; ++n)
0483         {
0484             jdns_address_t *addr = jdns_address_new();
0485             if(jdns_address_set_cstr(addr, (char *)list_nameserver->item[n]->data))
0486                 jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
0487             jdns_address_delete(addr);
0488         }
0489         jdns_stringlist_delete(list_nameserver);
0490     }
0491     if(str_domain)
0492     {
0493         if(str_domain->size > 0)
0494             jdns_dnsparams_append_domain(params, str_domain);
0495         jdns_string_delete(str_domain);
0496     }
0497     if(list_searchlist)
0498     {
0499         for(n = 0; n < list_searchlist->count; ++n)
0500         {
0501             if(list_searchlist->item[n]->size > 0)
0502                 jdns_dnsparams_append_domain(params, list_searchlist->item[n]);
0503         }
0504         jdns_stringlist_delete(list_searchlist);
0505     }
0506 
0507     return params;
0508 }
0509 
0510 static jdns_dnsparams_t *dnsparams_get_winsys()
0511 {
0512     jdns_dnsparams_t *params;
0513     GetNetworkParamsFunc myGetNetworkParams;
0514     DWORD ret;
0515     HINSTANCE lib;
0516     jdns_address_t *addr;
0517     jdns_string_t *str;
0518     IP_ADDR_STRING *ipstr;
0519 
0520     lib = LoadLibraryA("iphlpapi");
0521     if(!lib)
0522         return 0;
0523 
0524     params = 0;
0525     myGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(lib, "GetNetworkParams");
0526     if(myGetNetworkParams)
0527     {
0528         ULONG bufsize = 0;
0529         ret = myGetNetworkParams(0, &bufsize);
0530         if(ret == ERROR_BUFFER_OVERFLOW)
0531         {
0532             FIXED_INFO *info = (FIXED_INFO *)jdns_alloc((int)bufsize);
0533             ret = myGetNetworkParams(info, &bufsize);
0534             if(ret == ERROR_SUCCESS)
0535             {
0536                 params = jdns_dnsparams_new();
0537                 ipstr = &info->DnsServerList;
0538                 while(ipstr)
0539                 {
0540                     addr = jdns_address_new();
0541                     if(jdns_address_set_cstr(addr, (char *)ipstr->IpAddress.String))
0542                         jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
0543                     jdns_address_delete(addr);
0544                     ipstr = ipstr->Next;
0545                 }
0546                 str = jdns_string_new();
0547                 jdns_string_set_cstr(str, info->DomainName);
0548                 if(str->size > 0)
0549                     jdns_dnsparams_append_domain(params, str);
0550                 jdns_string_delete(str);
0551             }
0552             jdns_free(info);
0553         }
0554     }
0555     FreeLibrary(lib);
0556     return params;
0557 }
0558 
0559 static void apply_win_hosts_file(jdns_dnsparams_t *a)
0560 {
0561     jdns_string_t *p;
0562     char *str;
0563     int len;
0564 
0565     p = jdns_getenv("WINDIR");
0566     if(!p)
0567         return;
0568     len = strlen((char *)p->data);
0569     str = (char *)jdns_alloc(len + 100); /* should be enough */
0570     memcpy(str, p->data, len);
0571     jdns_string_delete(p);
0572     jdns_strcpy(str + len, "\\system32\\drivers\\etc\\hosts"); /* winnt+ */
0573     apply_hosts_file(a, str);
0574     jdns_strcpy(str + len, "\\hosts"); /* win9x */
0575     apply_hosts_file(a, str);
0576     jdns_free(str);
0577 }
0578 
0579 static jdns_dnsparams_t *dnsparams_get_win()
0580 {
0581     int n;
0582     jdns_dnsparams_t *sys_params, *reg_params;
0583 
0584     reg_params = dnsparams_get_winreg();
0585     sys_params = dnsparams_get_winsys();
0586 
0587     /* no sys params?  take the reg params then */
0588     if(!sys_params)
0589     {
0590         apply_win_hosts_file(reg_params);
0591         return reg_params;
0592     }
0593 
0594     /* sys params don't have a search list, so merge the domains from */
0595     /*   the registry if possible */
0596     if(reg_params)
0597     {
0598         for(n = 0; n < reg_params->domains->count; ++n)
0599         {
0600             jdns_string_t *reg_str = reg_params->domains->item[n];
0601 
0602             /* don't add dups */
0603             if(!dnsparams_have_domain(sys_params, reg_str))
0604                 jdns_dnsparams_append_domain(sys_params, reg_str);
0605         }
0606         jdns_dnsparams_delete(reg_params);
0607     }
0608     apply_win_hosts_file(sys_params);
0609     return sys_params;
0610 }
0611 
0612 #endif
0613 
0614 #ifdef JDNS_OS_UNIX
0615 
0616 static jdns_dnsparams_t *dnsparams_get_unixfiles()
0617 {
0618     FILE *f;
0619     int n;
0620     jdns_dnsparams_t *params;
0621     jdns_string_t *line, *simp;
0622     jdns_stringlist_t *parts;
0623 
0624     params = jdns_dnsparams_new();
0625 
0626     f = jdns_fopen("/etc/resolv.conf", "r");
0627     if(!f)
0628         return params;
0629     while(1)
0630     {
0631         line = file_nextline(f);
0632         if(!line)
0633             break;
0634 
0635         /* truncate at comment */
0636         n = string_indexOf(line, '#', 0);
0637         if(n != -1)
0638         {
0639             line->size = n;
0640             line->data[n] = 0;
0641         }
0642 
0643         simp = string_simplify(line);
0644         jdns_string_delete(line);
0645 
0646         parts = string_split(simp, ' ');
0647         jdns_string_delete(simp);
0648 
0649         if(parts->count < 2)
0650         {
0651             jdns_stringlist_delete(parts);
0652             continue;
0653         }
0654 
0655         simp = string_tolower(parts->item[0]);
0656         if(strcmp((char *)simp->data, "nameserver") == 0)
0657         {
0658             jdns_address_t *addr = jdns_address_new();
0659             jdns_address_set_cstr(addr, (const char *)parts->item[1]->data);
0660             jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
0661             jdns_address_delete(addr);
0662         }
0663         else if(strcmp((char *)simp->data, "search") == 0)
0664         {
0665             for(n = 1; n < parts->count; ++n)
0666             {
0667                 jdns_dnsparams_append_domain(params, parts->item[n]);
0668             }
0669         }
0670         else if(strcmp((char *)simp->data, "domain") == 0)
0671         {
0672             jdns_dnsparams_append_domain(params, parts->item[1]);
0673         }
0674         jdns_string_delete(simp);
0675 
0676         jdns_stringlist_delete(parts);
0677     }
0678     fclose(f);
0679     return params;
0680 }
0681 
0682 #if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
0683 # define JDNS_MODERN_RES_API
0684 #endif
0685 
0686 #ifndef JDNS_MODERN_RES_API
0687 typedef int (*res_init_func)();
0688 static int my_res_init()
0689 {
0690 #ifdef JDNS_OS_MAC
0691     res_init_func mac_res_init;
0692 
0693     /* look up res_init in the system library (qt does this, not sure why) */
0694     mac_res_init = (res_init_func)dlsym(RTLD_NEXT, "res_init");
0695     if(!mac_res_init)
0696         return -1;
0697     return mac_res_init();
0698 #else
0699     return res_init();
0700 #endif
0701 }
0702 #endif
0703 
0704 #if defined(JDNS_OS_MAC) || defined(JDNS_OS_FREEBSD) || \
0705 defined(JDNS_OS_NETBSD) || defined(JDNS_OS_OPENBSD) || defined (JDNS_OS_SOLARIS)
0706 # define USE_EXTEXT
0707 #endif
0708 
0709 static jdns_dnsparams_t *dnsparams_get_unixsys()
0710 {
0711     int n;
0712     jdns_dnsparams_t *params;
0713 
0714 #ifdef JDNS_MODERN_RES_API
0715     struct __res_state res;
0716     memset(&res, 0, sizeof(struct __res_state));
0717     n = res_ninit(&res);
0718 #define RESVAR res
0719 #else
0720     n = my_res_init();
0721 #define RESVAR _res
0722 #endif
0723 
0724 #ifdef JDNS_OS_OPENBSD
0725 #define RESVAREXT _res_ext
0726 #else
0727 #define RESVAREXT RESVAR._u._ext
0728 #endif
0729 
0730     params = jdns_dnsparams_new();
0731 
0732     /* error initializing? */
0733     if(n == -1)
0734         return params;
0735 
0736     /* nameservers - ipv6 */
0737 #ifdef JDNS_OS_OPENBSD
0738     for(n = 0; n < MAXNS; ++n)
0739 #else
0740     for(n = 0; n < MAXNS && n < RESVAREXT.nscount; ++n)
0741 #endif
0742     {
0743         jdns_address_t *addr;
0744         struct sockaddr_in6 *sa6;
0745 
0746 #if defined(USE_EXTEXT) && !defined(JDNS_OS_OPENBSD)
0747         sa6 = ((struct sockaddr_in6 *)RESVAREXT.ext) + n;
0748 #elif defined(JDNS_OS_OPENBSD)
0749         sa6 = &RESVAREXT.nsaddr_list[n];
0750 #else
0751         sa6 = RESVAREXT.nsaddrs[n];
0752 #endif
0753 
0754         if(sa6 == NULL)
0755             continue;
0756         addr = jdns_address_new();
0757         jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr);
0758         jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
0759         jdns_address_delete(addr);
0760     }
0761 
0762     /* nameservers - ipv4 */
0763     for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n)
0764     {
0765         jdns_address_t *addr = jdns_address_new();
0766         jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr));
0767         jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
0768         jdns_address_delete(addr);
0769     }
0770 
0771     /* domain name */
0772     if(strlen(RESVAR.defdname) > 0)
0773     {
0774         jdns_string_t *str;
0775         jdns_string_t *p;
0776         str = jdns_string_new();
0777         jdns_string_set_cstr(str, RESVAR.defdname);
0778         p = string_tolower(str);
0779         jdns_string_delete(str);
0780         str = p;
0781         jdns_dnsparams_append_domain(params, str);
0782         jdns_string_delete(str);
0783     }
0784 
0785     /* search list */
0786 #ifdef MAXDFLSRCH
0787     for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n)
0788     {
0789         if(strlen(RESVAR.dnsrch[n]) > 0)
0790         {
0791             jdns_string_t *str;
0792             jdns_string_t *p;
0793             str = jdns_string_new();
0794             jdns_string_set_cstr(str, RESVAR.dnsrch[n]);
0795             p = string_tolower(str);
0796             jdns_string_delete(str);
0797             str = p;
0798 
0799             /* don't add dups */
0800             if(!dnsparams_have_domain(params, str))
0801                 jdns_dnsparams_append_domain(params, str);
0802 
0803             jdns_string_delete(str);
0804         }
0805     }
0806 #endif
0807 
0808     return params;
0809 }
0810 
0811 static jdns_dnsparams_t *dnsparams_get_unix()
0812 {
0813     jdns_dnsparams_t *params;
0814 
0815     /* prefer system calls over files */
0816     params = dnsparams_get_unixsys();
0817     if(params->nameservers->count == 0)
0818     {
0819         jdns_dnsparams_delete(params);
0820         params = dnsparams_get_unixfiles();
0821     }
0822 
0823     apply_hosts_file(params, "/etc/hosts");
0824 
0825     return params;
0826 }
0827 
0828 #endif
0829 
0830 jdns_dnsparams_t *jdns_system_dnsparams()
0831 {
0832 #ifdef JDNS_OS_WIN
0833     return dnsparams_get_win();
0834 #else
0835     return dnsparams_get_unix();
0836 #endif
0837 }