]> git.ipfire.org Git - people/stevee/aiccu.git/blob - common/resolver.c
Add setup script functionality to Linux client
[people/stevee/aiccu.git] / common / resolver.c
1 /**********************************************************
2 SixXS - Automatic IPv6 Connectivity Configuration Utility
3 ***********************************************************
4 Copyright 2003-2005 SixXS - http://www.sixxs.net
5 ***********************************************************
6 common/resolver.c - Simple DNS RR lookup function
7 ***********************************************************
8 $Author: jeroen $
9 $Id: resolver.c,v 1.3 2006-07-23 14:13:57 jeroen Exp $
10 $Date: 2006-07-23 14:13:57 $
11 **********************************************************/
12
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #include "resolver.h"
19
20 #ifndef _WIN32
21 #include <unistd.h>
22 #include <netinet/in.h>
23 #include <arpa/nameser.h>
24 #include <resolv.h>
25 #include <netdb.h>
26
27 int getrrs(const char *label, int rrtype, void gotrec(unsigned int num, int type, const char *record))
28 {
29 #ifdef _LINUX
30 struct __res_state res;
31 #endif
32 unsigned char answer[8192];
33 HEADER *header = (HEADER *)answer;
34 char buf[2048];
35 int ret, count;
36 unsigned int i,j,k,rrnum = 0;
37 unsigned char *startptr, *endptr, *ptr;
38 uint16_t type = 0, class = 0;
39 uint32_t ttl = 0;
40
41 #ifdef _LINUX
42 memset(&res, 0, sizeof(res));
43 res.options = RES_DEBUG;
44 res_ninit(&res);
45 #else
46 res_init();
47 #endif
48
49 memset(answer, 0, sizeof(answer));
50 #ifdef _LINUX
51 ret = res_nquery(&res, label, C_IN, rrtype, answer, sizeof(answer));
52 #else
53 ret = res_query(label, C_IN, rrtype, answer, sizeof(answer));
54 #endif
55 if (ret < 0) return -1;
56
57 /* Our start and end */
58 startptr = &answer[0];
59 endptr = &answer[ret];
60
61 /* Skip the header */
62 ptr = startptr + HFIXEDSZ;
63
64 /* Skip Query part */
65 for (count = ntohs(header->qdcount); count--; ptr += ret + QFIXEDSZ)
66 {
67 if ((ret = dn_skipname(ptr, endptr)) < 0) return -1;
68 }
69
70 /* Only look at the Answer section */
71 count = ntohs(header->ancount);
72
73 /* Go through all the Answer records */
74 while (ptr < endptr && count > 0)
75 {
76 rrnum++;
77
78 memset(buf, 0, sizeof(buf));
79 ret = dn_expand (startptr, endptr, ptr, buf, sizeof(buf));
80 if (ret < 0) break;
81 ptr += ret;
82
83 if (ptr + INT16SZ + INT16SZ + INT32SZ >= endptr) break;
84
85 /* Get the type */
86 NS_GET16(type, ptr);
87
88 /* Get the class */
89 NS_GET16(class, ptr);
90
91 /* Get the TTL */
92 NS_GET32(ttl, ptr);
93
94 /* Get the RDLength */
95 NS_GET16(ret, ptr);
96
97 memset(buf, 0, sizeof(buf));
98
99 switch (type)
100 {
101 case T_TXT:
102 for (k = ret, j = 0; j < k && &ptr[j] < endptr; j += (i+1))
103 {
104 i = ptr[j];
105 memcpy(buf, &ptr[j+1], i > sizeof(buf) ? sizeof(buf) : i);
106 buf[i > sizeof(buf) ? sizeof(buf) : i] = '\0';
107 if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf);
108 }
109 break;
110
111 case T_A:
112 inet_ntop(AF_INET, ptr, buf, sizeof(buf));
113 if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf);
114 break;
115
116 case T_AAAA:
117 inet_ntop(AF_INET6, ptr, buf, sizeof(buf));
118 if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf);
119 break;
120
121 case T_MX:
122 /* Get the MX preference */
123 NS_GET16(ttl, ptr);
124 ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf));
125 if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf);
126 break;
127
128 case T_NS:
129 ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf));
130 if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf);
131 break;
132
133 default:
134 /* Unhandled */
135 break;
136 }
137
138 ptr += ret;
139 count--;
140 }
141 return 0;
142 }
143 #else
144 /*
145 * Windows Resolver Code, as per:
146 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dns/dns/dnsquery.asp
147 * http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B831226
148 */
149 #include <windns.h>
150
151 int getrrs(const char *label, int rrtype, void gotrec(unsigned int num, int type, const char *record))
152 {
153 DNS_STATUS status; /* Return value of DnsQuery_A() function */
154 PDNS_RECORD pResult, pRec; /* Pointer to DNS_RECORD structure */
155 unsigned int rrnum = 0, i;
156 uint16_t type;
157
158 status = DnsQuery(label, /* Pointer to OwnerName */
159 rrtype, /* Type of the record to be queried */
160 DNS_QUERY_STANDARD, /* Standard Query */
161 NULL, /* Contains DNS server IP address */
162 &pResult, /* Resource record that contains the response */
163 NULL); /* Reserved for future use */
164
165 if (status) return -1;
166 else
167 {
168 for (pRec = pResult; pRec; pRec = pRec->pNext)
169 {
170 rrnum++;
171 type = pRec->wType;
172
173 if (rrtype != type && rrtype != ns_t_any) continue;
174
175 switch (type)
176 {
177 case ns_t_txt:
178 for (i=0; i < pRec->Data.TXT.dwStringCount; i++)
179 {
180 gotrec(rrnum, type, pRec->Data.TXT.pStringArray[i]);
181 }
182 break;
183
184 case ns_t_a:
185 gotrec(rrnum, type, (const char *)&pRec->Data.A.IpAddress);
186 break;
187
188 case ns_t_aaaa:
189 gotrec(rrnum, type, (const char *)&pRec->Data.AAAA.Ip6Address);
190 break;
191
192 case ns_t_mx:
193 gotrec(rrnum, type, pRec->Data.MX.pNameExchange);
194 break;
195
196 case ns_t_ns:
197 gotrec(rrnum, type, pRec->Data.NS.pNameHost);
198 break;
199 }
200 }
201 }
202
203 /* Free memory allocated for DNS records. */
204 DnsRecordListFree(pResult, DnsFreeRecordListDeep);
205
206 return 0;
207 }
208 #endif
209