VirtualBox

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

Last change on this file since 32353 was 30921, checked in by vboxsync, 15 years ago

NAT/hostresolver: trim ending dots confusing host resolver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/* $Id: alias_dns.c 30921 2010-07-20 04:09:30Z 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 dnsmsg_answer
55{
56 uint16_t name;
57 uint16_t type;
58 uint16_t class;
59 uint16_t ttl[2];
60 uint16_t rdata_len;
61 uint8_t rdata[1]; /* depends on value at rdata_len */
62};
63
64/* see RFC 1035(4.1) */
65static int dns_alias_handler(PNATState pData, int type);
66static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr);
67static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr);
68
69static int
70fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
71{
72
73 if (!ah->dport || !ah->sport || !ah->lnk)
74 return -1;
75
76 fprintf(stderr, "NAT:%s: ah(dport: %hd, sport: %hd) oaddr:%R[IP4] aaddr:%R[IP4]\n",
77 __FUNCTION__, ntohs(*ah->dport), ntohs(*ah->sport),
78 &ah->oaddr, &ah->aaddr);
79
80 if ( (ntohs(*ah->dport) == DNS_CONTROL_PORT_NUMBER
81 || ntohs(*ah->sport) == DNS_CONTROL_PORT_NUMBER)
82 && (ah->oaddr->s_addr == htonl(ntohl(la->pData->special_addr.s_addr)|CTL_DNS)))
83 return 0;
84
85 return -1;
86}
87
88static void doanswer(struct libalias *la, union dnsmsg_header *hdr,char *qname, struct ip *pip, struct hostent *h)
89{
90 int i;
91
92 if (!h)
93 {
94 hdr->X.qr = 1; /* response */
95 hdr->X.aa = 1;
96 hdr->X.rd = 1;
97 hdr->X.rcode = 3;
98 }
99 else
100 {
101 char *query;
102 char *answers;
103 uint16_t off;
104 char **cstr;
105 char *c;
106 uint16_t packet_len = 0;
107 uint16_t addr_off = (uint16_t)~0;
108
109#if 0
110 /* here is no compressed names+answers + new query */
111 m_inc(m, h->h_length * sizeof(struct dnsmsg_answer) + strlen(qname) + 2 * sizeof(uint16_t));
112#endif
113 packet_len = (pip->ip_hl << 2)
114 + sizeof(struct udphdr)
115 + sizeof(union dnsmsg_header)
116 + strlen(qname)
117 + 2 * sizeof(uint16_t); /* ip + udp + header + query */
118 query = (char *)&hdr[1];
119
120 strcpy(query, qname);
121 query += strlen(qname) + 1;
122
123 *(uint16_t *)query = htons(1);
124 ((uint16_t *)query)[1] = htons(1);
125 answers = (char *)&((uint16_t *)query)[2];
126
127 off = (char *)&hdr[1] - (char *)hdr;
128 off |= (0x3 << 14);
129
130 /* add aliases */
131 for (cstr = h->h_aliases; *cstr; cstr++)
132 {
133 uint16_t len;
134 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
135 ans->name = htons(off);
136 ans->type = htons(5); /* CNAME */
137 ans->class = htons(1);
138 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
139 c = (addr_off == (uint16_t)~0 ? h->h_name : *cstr);
140 len = strlen(c) + 2;
141 ans->rdata_len = htons(len);
142 ans->rdata[len - 1] = 0;
143 CStr2QStr(c, (char *)ans->rdata, len);
144 off = (char *)&ans->rdata - (char *)hdr;
145 off |= (0x3 << 14);
146 if (addr_off == (uint16_t)~0)
147 addr_off = off;
148 answers = (char *)&ans[1] + len - 2; /* note: 1 symbol already counted */
149 packet_len += sizeof(struct dnsmsg_answer) + len - 2;
150 hdr->X.ancount++;
151 }
152 /* add addresses */
153
154 for(i = 0; i < h->h_length && h->h_addr_list[i] != NULL; ++i)
155 {
156 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
157
158 ans->name = htons(off);
159 ans->type = htons(1);
160 ans->class = htons(1);
161 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
162 ans->rdata_len = htons(4); /* IPv4 */
163 *(uint32_t *)ans->rdata = *(uint32_t *)h->h_addr_list[i];
164 answers = (char *)&ans[1] + 2;
165 packet_len += sizeof(struct dnsmsg_answer) + 3;
166 hdr->X.ancount++;
167 }
168 hdr->X.qr = 1; /* response */
169 hdr->X.aa = 1;
170 hdr->X.rd = 1;
171 hdr->X.ra = 1;
172 hdr->X.rcode = 0;
173 HTONS(hdr->X.ancount);
174 /* don't forget update m_len */
175 pip->ip_len = htons(packet_len);
176 }
177}
178static int
179protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
180{
181 int i;
182 /* Parse dns request */
183 char *qw_qname = NULL;
184 uint16_t *qw_qtype = NULL;
185 uint16_t *qw_qclass = NULL;
186 struct hostent *h = NULL;
187 char cname[255];
188 int cname_len = 0;
189
190 struct udphdr *udp = NULL;
191 union dnsmsg_header *hdr = NULL;
192 udp = (struct udphdr *)ip_next(pip);
193 hdr = (union dnsmsg_header *)udp_next(udp);
194
195 if (hdr->X.qr == 1)
196 return 0; /* this is respose */
197
198 memset(cname, 0, sizeof(cname));
199 qw_qname = (char *)&hdr[1];
200 Assert((ntohs(hdr->X.qdcount) == 1));
201
202 for (i = 0; i < ntohs(hdr->X.qdcount); ++i)
203 {
204 qw_qtype = (uint16_t *)(qw_qname + strlen(qw_qname) + 1);
205 qw_qclass = &qw_qtype[1];
206 fprintf(stderr, "qname:%s qtype:%hd qclass:%hd\n",
207 qw_qname, ntohs(*qw_qtype), ntohs(*qw_qclass));
208 }
209
210 QStr2CStr(qw_qname, cname, sizeof(cname));
211 cname_len = RTStrNLen(cname, sizeof(cname));
212 /* Some guests like win-xp adds _dot_ after host name
213 * and after domain name (not passed with host resolver)
214 * that confuses host resolver.
215 */
216 if ( cname_len > 2
217 && cname[cname_len - 1] == '.'
218 && cname[cname_len - 2] == '.')
219 {
220 cname[cname_len - 1] = 0;
221 cname[cname_len - 2] = 0;
222 }
223 h = gethostbyname(cname);
224 fprintf(stderr, "cname:%s\n", cname);
225 doanswer(la, hdr, qw_qname, pip, h);
226
227 /*
228 * We have changed the size and the content of udp, to avoid double csum calculation
229 * will assign to zero
230 */
231 udp->uh_sum = 0;
232 udp->uh_ulen = ntohs(htons(pip->ip_len) - (pip->ip_hl << 2));
233 pip->ip_sum = 0;
234 pip->ip_sum = LibAliasInternetChecksum(la, (uint16_t *)pip, pip->ip_hl << 2);
235 return 0;
236}
237
238/*
239 * qstr is z-string with -dot- replaced with \count to next -dot-
240 * e.g. ya.ru is \02ya\02ru
241 * Note: it's assumed that caller allocates buffer for cstr
242 */
243static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr)
244{
245 const char *q;
246 char *c;
247 size_t cLen = 0;
248
249 Assert(cStr > 0);
250 for (q = pcszQStr, c = pszStr; *q != '\0' && cLen < cStr-1; q++, cLen++)
251 {
252 if ( isalpha(*q)
253 || isdigit(*q)
254 || *q == '-'
255 || *q == '_')
256 {
257 *c = *q;
258 c++;
259 }
260 else if (c != &pszStr[0])
261 {
262 *c = '.';
263 c++;
264 }
265 }
266 *c = '\0';
267}
268
269/*
270 *
271 */
272static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr)
273{
274 const char *c;
275 const char *pc;
276 char *q;
277 size_t cLen = 0;
278
279 Assert(cQStr > 0);
280 for (c = pcszStr, q = pszQStr; *c != '\0' && cLen < cQStr-1; q++, cLen++)
281 {
282 /* at the begining or at -dot- position */
283 if (*c == '.' || (c == pcszStr && q == pszQStr))
284 {
285 if (c != pcszStr)
286 c++;
287 pc = strchr(c, '.');
288 *q = pc ? (pc - c) : strlen(c);
289 }
290 else
291 {
292 *q = *c;
293 c++;
294 }
295 }
296 *q = '\0';
297}
298
299
300int
301dns_alias_load(PNATState pData)
302{
303 return dns_alias_handler(pData, MOD_LOAD);
304}
305
306int
307dns_alias_unload(PNATState pData)
308{
309 return dns_alias_handler(pData, MOD_UNLOAD);
310}
311
312#define handlers pData->dns_module
313static int
314dns_alias_handler(PNATState pData, int type)
315{
316 int error;
317
318 if (!handlers)
319 handlers = RTMemAllocZ(2 * sizeof(struct proto_handler));
320
321 handlers[0].pri = 20;
322 handlers[0].dir = IN;
323 handlers[0].proto = UDP;
324 handlers[0].fingerprint = &fingerprint;
325 handlers[0].protohandler = &protohandler;
326 handlers[1].pri = EOH;
327
328 switch (type)
329 {
330 case MOD_LOAD:
331 error = 0;
332 LibAliasAttachHandlers(pData, handlers);
333 break;
334
335 case MOD_UNLOAD:
336 error = 0;
337 LibAliasDetachHandlers(pData, handlers);
338 RTMemFree(handlers);
339 handlers = NULL;
340 break;
341
342 default:
343 error = EINVAL;
344 }
345 return error;
346}
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