VirtualBox

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

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

NAT: {ip,udp}_next macro used.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.9 KB
Line 
1#ifndef RT_OS_WINDOWS
2# include <netdb.h>
3#endif
4# include <iprt/ctype.h>
5# include <iprt/assert.h>
6# include <slirp.h>
7# include "alias.h"
8# include "alias_local.h"
9# include "alias_mod.h"
10
11#define DNS_CONTROL_PORT_NUMBER 53
12/* see RFC 1035(4.1.1) */
13union dnsmsg_header
14{
15 struct {
16 uint16_t id;
17 uint16_t rd:1;
18 uint16_t tc:1;
19 uint16_t aa:1;
20 uint16_t opcode:4;
21 uint16_t qr:1;
22 uint16_t rcode:4;
23 uint16_t Z:3;
24 uint16_t ra:1;
25 uint16_t qdcount;
26 uint16_t ancount;
27 uint16_t nscount;
28 uint16_t arcount;
29 } X;
30 uint16_t raw[5];
31};
32struct dnsmsg_answer
33{
34 uint16_t name;
35 uint16_t type;
36 uint16_t class;
37 uint16_t ttl[2];
38 uint16_t rdata_len;
39 uint8_t rdata[1]; /*depends on value at rdata_len */
40};
41
42/* see RFC 1035(4.1) */
43static int dns_alias_handler(PNATState pData, int type);
44static void cstr2qstr(char *cstr, char *qstr);
45static void qstr2cstr(char *qstr, char *cstr);
46
47static int
48fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
49{
50
51 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
52 return (-1);
53 fprintf(stderr, "NAT:%s: ah(dport: %hd, sport: %hd) oaddr:%R[IP4] aaddr:%R[IP4]\n",
54 __FUNCTION__, ntohs(*ah->dport), ntohs(*ah->sport),
55 &ah->oaddr, &ah->aaddr);
56 if ( (ntohs(*ah->dport) == DNS_CONTROL_PORT_NUMBER
57 || ntohs(*ah->sport) == DNS_CONTROL_PORT_NUMBER)
58 && (ah->oaddr->s_addr == htonl(ntohl(la->special_addr.s_addr)|CTL_DNS)))
59 return (0);
60 return (-1);
61}
62
63static void doanswer(struct libalias *la, union dnsmsg_header *hdr,char *qname, struct ip *pip, struct hostent *h)
64{
65 int i;
66 if (h == NULL)
67 {
68 hdr->X.qr = 1; /*response*/
69 hdr->X.aa = 1;
70 hdr->X.rd = 1;
71 hdr->X.rcode = 3;
72 }
73 else
74 {
75 /*!!! We need to be sure that */
76 struct mbuf *m = NULL;
77 char *query;
78 char *answers;
79 uint16_t off;
80 char **cstr;
81 char *c;
82 uint16_t packet_len = 0;
83 uint16_t addr_off = (uint16_t)~0;
84
85 m = dtom(la->pData, hdr);
86 Assert((m));
87
88#if 0
89 /*here is no compressed names+answers + new query*/
90 m_inc(m, h->h_length * sizeof(struct dnsmsg_answer) + strlen(qname) + 2 * sizeof(uint16_t));
91#endif
92 packet_len = (pip->ip_hl << 2) + sizeof(struct udphdr) + sizeof(union dnsmsg_header)
93 + strlen(qname) + 2 * sizeof(uint16_t); /* ip + udp + header + query */
94 fprintf(stderr,"got %d addresses for target:%s (m_len: %d)\n", h->h_length, h->h_name, m->m_len);
95 query = (char *)&hdr[1];
96
97 strcpy(query, qname);
98 query += strlen(qname);
99 query ++;
100
101 *(uint16_t *)query = htons(1);
102 ((uint16_t *)query)[1] = htons(1);
103 answers = (char *)&((uint16_t *)query)[2];
104
105 off = (char *)&hdr[1] - (char *)hdr;
106 off |= (0x3 << 14);
107 /*add aliases */
108 cstr = h->h_aliases;
109 while(*cstr)
110 {
111 uint16_t len;
112 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
113 ans->name = htons(off);
114 ans->type = htons(5); /*CNAME*/
115 ans->class = htons(1);
116 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
117 c = (addr_off == (uint16_t)~0?h->h_name : *cstr);
118 len = strlen(c) + 2;
119 ans->rdata_len = htons(len);
120 ans->rdata[len - 1] = 0;
121 cstr2qstr(c, (char *)ans->rdata);
122 off = (char *)&ans->rdata - (char *)hdr;
123 off |= (0x3 << 14);
124 if (addr_off == (uint16_t)~0)
125 addr_off = off;
126 answers = (char *)&ans[1] + len - 2; /* note: 1 symbol already counted */
127 packet_len += sizeof(struct dnsmsg_answer) + len - 2;
128 hdr->X.ancount++;
129 cstr++;
130 }
131 /*add addresses */
132
133 for(i = 0; i < h->h_length && h->h_addr_list[i] != NULL; ++i)
134 {
135 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers;
136
137 ans->name = htons(off);
138 ans->type = htons(1);
139 ans->class = htons(1);
140 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */
141 ans->rdata_len = htons(4); /* IPv4 */
142 *(uint32_t *)ans->rdata = *(uint32_t *)h->h_addr_list[i];
143 answers = (char *)&ans[1] + 2;
144 packet_len += sizeof(struct dnsmsg_answer) + 3;
145 hdr->X.ancount++;
146 }
147 hdr->X.qr = 1; /*response*/
148 hdr->X.aa = 1;
149 hdr->X.rd = 1;
150 hdr->X.ra = 1;
151 hdr->X.rcode = 0;
152 HTONS(hdr->X.ancount);
153 /*don't forget update m_len*/
154 m->m_len = packet_len;
155 pip->ip_len = htons(m->m_len);
156 }
157}
158static int
159protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
160{
161 int i;
162 /*Parse dns request */
163 char *qw_qname = NULL;
164 uint16_t *qw_qtype = NULL;
165 uint16_t *qw_qclass = NULL;
166 struct hostent *h = NULL;
167 char *cname[255]; /* ??? */
168
169 struct udphdr *udp = NULL;
170 union dnsmsg_header *hdr = NULL;
171 udp = (struct udphdr *)ip_next(pip);
172 hdr = (union dnsmsg_header *)udp_next(udp);
173
174 if (hdr->X.qr == 1)
175 return 0; /* this is respose*/
176
177 qw_qname = (char *)&hdr[1];
178 Assert((ntohs(hdr->X.qdcount) == 1));
179
180 for (i = 0; i < ntohs(hdr->X.qdcount); ++i)
181 {
182 qw_qtype = (uint16_t *)(qw_qname + strlen(qw_qname) + 1);
183 qw_qclass = &qw_qtype[1];
184 fprintf(stderr, "qname:%s qtype:%hd qclass:%hd\n",
185 qw_qname, ntohs(*qw_qtype), ntohs(*qw_qclass));
186 }
187 qstr2cstr(qw_qname, (char *)cname);
188 h = gethostbyname((char *)cname);
189 fprintf(stderr, "cname:%s\n", cname);
190 doanswer(la, hdr, qw_qname, pip, h);
191 /*we've chenged size and conten of udp, to avoid double csum calcualtion
192 *will assign to zero
193 */
194 udp->uh_sum = 0;
195 udp->uh_ulen = ntohs(htons(pip->ip_len) - (pip->ip_hl << 2));
196 pip->ip_sum = 0;
197 pip->ip_sum = LibAliasInternetChecksum(la, (uint16_t *)pip, pip->ip_hl << 2);
198 return (0);
199}
200/*
201 * qstr is z-string with -dot- replaced with \count to next -dot-
202 * e.g. ya.ru is \02ya\02ru
203 * Note: it's assumed that caller allocates buffer for cstr
204 */
205static void qstr2cstr(char *qname, char *cname)
206{
207 char *q = qname;
208 char *c = cname;
209 while(*q != 0)
210 {
211 if (isalpha(*q) || isdigit(*q))
212 {
213 *c = *q;
214 c++;
215 }
216 else if (c != &cname[0])
217 {
218 *c = '.';
219 c++;
220 }
221 q++;
222 }
223 q = 0;
224}
225/*
226 *
227 */
228static void cstr2qstr(char *cstr, char *qstr)
229{
230 char *c, *pc, *q;
231 c = cstr;
232 q = qstr;
233 while(*c != 0)
234 {
235 /* a the begining or at -dot- position */
236 if (*c == '.' || (c == cstr && q == qstr))
237 {
238 if (c != cstr) c++;
239 pc = strchr(c, '.');
240 *q = pc != NULL ? (pc - c) : strlen(c);
241 q++;
242 continue;
243 }
244 (*q) = (*c); /*direct copy*/
245 q++;
246 c++;
247 }
248 q = 0;
249}
250
251
252int
253dns_alias_load(PNATState pData)
254{
255 return dns_alias_handler(pData, MOD_LOAD);
256}
257
258int
259dns_alias_unload(PNATState pData)
260{
261 return dns_alias_handler(pData, MOD_UNLOAD);
262}
263
264#define handlers pData->dns_module
265static int
266dns_alias_handler(PNATState pData, int type)
267{
268 int error;
269 if (handlers == NULL)
270 handlers = RTMemAllocZ(2 * sizeof(struct proto_handler));
271 handlers[0].pri = 20;
272 handlers[0].dir = IN;
273 handlers[0].proto = UDP;
274 handlers[0].fingerprint = &fingerprint;
275 handlers[0].protohandler = &protohandler;
276 handlers[1].pri = EOH;
277
278 switch (type) {
279 case MOD_LOAD:
280 error = 0;
281 LibAliasAttachHandlers(pData, handlers);
282 break;
283 case MOD_UNLOAD:
284 error = 0;
285 LibAliasDetachHandlers(pData, handlers);
286 RTMemFree(handlers);
287 handlers = NULL;
288 break;
289 default:
290 error = EINVAL;
291 }
292 return (error);
293}
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