VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/libalias/alias_dns.c@ 39347

Last change on this file since 39347 was 39101, checked in by vboxsync, 13 years ago

NAT: warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/* $Id: alias_dns.c 39101 2011-10-25 02:44:01Z vboxsync $ */
2/** @file
3 * libalias helper for using the host resolver instead of dnsproxy.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef RT_OS_WINDOWS
19# include <netdb.h>
20#endif
21#include <iprt/ctype.h>
22#include <iprt/assert.h>
23#include <slirp.h>
24#include "alias.h"
25#include "alias_local.h"
26#include "alias_mod.h"
27#define isdigit(ch) RT_C_IS_DIGIT(ch)
28#define isalpha(ch) RT_C_IS_ALPHA(ch)
29
30#define DNS_CONTROL_PORT_NUMBER 53
31/* see RFC 1035(4.1.1) */
32union dnsmsg_header
33{
34 struct
35 {
36 unsigned id:16;
37 unsigned rd:1;
38 unsigned tc:1;
39 unsigned aa:1;
40 unsigned opcode:4;
41 unsigned qr:1;
42 unsigned rcode:4;
43 unsigned Z:3;
44 unsigned ra:1;
45 uint16_t qdcount;
46 uint16_t ancount;
47 uint16_t nscount;
48 uint16_t arcount;
49 } X;
50 uint16_t raw[6];
51};
52AssertCompileSize(union dnsmsg_header, 12);
53
54struct dns_meta_data
55{
56 uint16_t type;
57 uint16_t class;
58};
59
60struct dnsmsg_answer
61{
62 uint16_t name;
63 struct dns_meta_data meta;
64 uint16_t ttl[2];
65 uint16_t rdata_len;
66 uint8_t rdata[1]; /* depends on value at rdata_len */
67};
68
69/* see RFC 1035(4.1) */
70static int dns_alias_handler(PNATState pData, int type);
71static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr);
72static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr);
73
74static int
75fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
76{
77
78 NOREF(la);
79 NOREF(pip);
80 if (!ah->dport || !ah->sport || !ah->lnk)
81 return -1;
82
83 Log(("NAT:%s: ah(dport: %hd, sport: %hd) oaddr:%RTnaipv4 aaddr:%RTnaipv4\n",
84 __FUNCTION__, ntohs(*ah->dport), ntohs(*ah->sport),
85 ah->oaddr, ah->aaddr));
86
87 if ( (ntohs(*ah->dport) == DNS_CONTROL_PORT_NUMBER
88 || ntohs(*ah->sport) == DNS_CONTROL_PORT_NUMBER)
89 && (ah->oaddr->s_addr == htonl(ntohl(la->pData->special_addr.s_addr)|CTL_DNS)))
90 return 0;
91
92 return -1;
93}
94
95static void doanswer(union dnsmsg_header *hdr, struct dns_meta_data *pReqMeta, char *qname, struct ip *pip, struct hostent *h)
96{
97 int i;
98
99 if (!h)
100 {
101 hdr->X.qr = 1; /* response */
102 hdr->X.aa = 1;
103 hdr->X.rd = 1;
104 hdr->X.rcode = 3;
105 }
106 else
107 {
108 char *query;
109 char *answers;
110 uint16_t off;
111 char **cstr;
112 char *c;
113 uint16_t packet_len = 0;
114 uint16_t addr_off = (uint16_t)~0;
115 struct dns_meta_data *meta;
116
117#if 0
118 /* here is no compressed names+answers + new query */
119 m_inc(m, h->h_length * sizeof(struct dnsmsg_answer) + strlen(qname) + 2 * sizeof(uint16_t));
120#endif
121 packet_len = (pip->ip_hl << 2)
122 + sizeof(struct udphdr)
123 + sizeof(union dnsmsg_header)
124 + strlen(qname)
125 + sizeof(struct dns_meta_data); /* ip + udp + header + query */
126 query = (char *)&hdr[1];
127
128 strcpy(query, qname);
129 query += strlen(qname) + 1;
130 /* class & type informations lay right after symbolic inforamtion. */
131 meta = (struct dns_meta_data *)query;
132 meta->type = pReqMeta->type;
133 meta->class = pReqMeta->class;
134
135 /* answers zone lays after query in response packet */
136 answers = (char *)&meta[1];
137
138 off = (char *)&hdr[1] - (char *)hdr;
139 off |= (0x3 << 14);
140
141 /* add aliases */
142 for (cstr = h->h_aliases; *cstr; cstr++)
143 {
144 uint16_t len;
145 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
146 ans->name = htons(off);
147 ans->meta.type = htons(5); /* CNAME */
148 ans->meta.class = htons(1);
149 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
150 c = (addr_off == (uint16_t)~0 ? h->h_name : *cstr);
151 len = strlen(c) + 2;
152 ans->rdata_len = htons(len);
153 ans->rdata[len - 1] = 0;
154 CStr2QStr(c, (char *)ans->rdata, len);
155 off = (char *)&ans->rdata - (char *)hdr;
156 off |= (0x3 << 14);
157 if (addr_off == (uint16_t)~0)
158 addr_off = off;
159 answers = (char *)&ans[1] + len - 2; /* note: 1 symbol already counted */
160 packet_len += sizeof(struct dnsmsg_answer) + len - 2;
161 hdr->X.ancount++;
162 }
163 /* add addresses */
164
165 for(i = 0; i < h->h_length && h->h_addr_list[i] != NULL; ++i)
166 {
167 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
168
169 ans->name = htons(off);
170 ans->meta.type = htons(1);
171 ans->meta.class = htons(1);
172 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
173 ans->rdata_len = htons(4); /* IPv4 */
174 *(uint32_t *)ans->rdata = *(uint32_t *)h->h_addr_list[i];
175 answers = (char *)&ans[1] + 2;
176 packet_len += sizeof(struct dnsmsg_answer) + 3;
177 hdr->X.ancount++;
178 }
179 hdr->X.qr = 1; /* response */
180 hdr->X.aa = 1;
181 hdr->X.rd = 1;
182 hdr->X.ra = 1;
183 hdr->X.rcode = 0;
184 HTONS(hdr->X.ancount);
185 /* don't forget update m_len */
186 pip->ip_len = htons(packet_len);
187 }
188}
189
190static int
191protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
192{
193 int i;
194 /* Parse dns request */
195 char *qw_qname = NULL;
196 struct hostent *h = NULL;
197 char cname[255];
198 int cname_len = 0;
199 struct dns_meta_data *meta;
200
201 struct udphdr *udp = NULL;
202 union dnsmsg_header *hdr = NULL;
203 NOREF(la);
204 NOREF(ah);
205 udp = (struct udphdr *)ip_next(pip);
206 hdr = (union dnsmsg_header *)udp_next(udp);
207
208 if (hdr->X.qr == 1)
209 return 0; /* this is respose */
210
211 memset(cname, 0, sizeof(cname));
212 qw_qname = (char *)&hdr[1];
213 Assert((ntohs(hdr->X.qdcount) == 1));
214 if ((ntohs(hdr->X.qdcount) != 1))
215 {
216 static bool fMultiWarn;
217 if (!fMultiWarn)
218 {
219 LogRel(("NAT:alias_dns: multiple quieries isn't supported\n"));
220 fMultiWarn = true;
221 }
222 return 1;
223 }
224
225 for (i = 0; i < ntohs(hdr->X.qdcount); ++i)
226 {
227 meta = (struct dns_meta_data *)(qw_qname + strlen(qw_qname) + 1);
228 Log(("qname:%s qtype:%hd qclass:%hd\n",
229 qw_qname, ntohs(meta->type), ntohs(meta->class)));
230
231 QStr2CStr(qw_qname, cname, sizeof(cname));
232 cname_len = RTStrNLen(cname, sizeof(cname));
233 /* Some guests like win-xp adds _dot_ after host name
234 * and after domain name (not passed with host resolver)
235 * that confuses host resolver.
236 */
237 if ( cname_len > 2
238 && cname[cname_len - 1] == '.'
239 && cname[cname_len - 2] == '.')
240 {
241 cname[cname_len - 1] = 0;
242 cname[cname_len - 2] = 0;
243 }
244 h = gethostbyname(cname);
245 fprintf(stderr, "cname:%s\n", cname);
246 doanswer(hdr, meta, qw_qname, pip, h);
247 }
248
249 /*
250 * We have changed the size and the content of udp, to avoid double csum calculation
251 * will assign to zero
252 */
253 udp->uh_sum = 0;
254 udp->uh_ulen = ntohs(htons(pip->ip_len) - (pip->ip_hl << 2));
255 pip->ip_sum = 0;
256 pip->ip_sum = LibAliasInternetChecksum(la, (uint16_t *)pip, pip->ip_hl << 2);
257 return 0;
258}
259
260/*
261 * qstr is z-string with -dot- replaced with \count to next -dot-
262 * e.g. ya.ru is \02ya\02ru
263 * Note: it's assumed that caller allocates buffer for cstr
264 */
265static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr)
266{
267 const char *q;
268 char *c;
269 size_t cLen = 0;
270
271 Assert(cStr > 0);
272 for (q = pcszQStr, c = pszStr; *q != '\0' && cLen < cStr-1; q++, cLen++)
273 {
274 if ( isalpha(*q)
275 || isdigit(*q)
276 || *q == '-'
277 || *q == '_')
278 {
279 *c = *q;
280 c++;
281 }
282 else if (c != &pszStr[0])
283 {
284 *c = '.';
285 c++;
286 }
287 }
288 *c = '\0';
289}
290
291/*
292 *
293 */
294static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr)
295{
296 const char *c;
297 const char *pc;
298 char *q;
299 size_t cLen = 0;
300
301 Assert(cQStr > 0);
302 for (c = pcszStr, q = pszQStr; *c != '\0' && cLen < cQStr-1; q++, cLen++)
303 {
304 /* at the begining or at -dot- position */
305 if (*c == '.' || (c == pcszStr && q == pszQStr))
306 {
307 if (c != pcszStr)
308 c++;
309 pc = strchr(c, '.');
310 *q = pc ? (pc - c) : strlen(c);
311 }
312 else
313 {
314 *q = *c;
315 c++;
316 }
317 }
318 *q = '\0';
319}
320
321
322int
323dns_alias_load(PNATState pData)
324{
325 return dns_alias_handler(pData, MOD_LOAD);
326}
327
328int
329dns_alias_unload(PNATState pData)
330{
331 return dns_alias_handler(pData, MOD_UNLOAD);
332}
333
334#define handlers pData->dns_module
335static int
336dns_alias_handler(PNATState pData, int type)
337{
338 int error;
339
340 if (!handlers)
341 handlers = RTMemAllocZ(2 * sizeof(struct proto_handler));
342
343 handlers[0].pri = 20;
344 handlers[0].dir = IN;
345 handlers[0].proto = UDP;
346 handlers[0].fingerprint = &fingerprint;
347 handlers[0].protohandler = &protohandler;
348 handlers[1].pri = EOH;
349
350 switch (type)
351 {
352 case MOD_LOAD:
353 error = 0;
354 LibAliasAttachHandlers(pData, handlers);
355 break;
356
357 case MOD_UNLOAD:
358 error = 0;
359 LibAliasDetachHandlers(pData, handlers);
360 RTMemFree(handlers);
361 handlers = NULL;
362 break;
363
364 default:
365 error = EINVAL;
366 }
367 return error;
368}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette