6 /* DNS CLASS values we care about */
9 /* DNS TYPE values we care about */
14 * The DNS header structure
19 /* number of entries in the question section */
21 /* number of resource records in the answer section */
23 /* number of name server resource records in the authority records section*/
25 /* number of resource records in the additional records section */
27 } __attribute__ ((packed
));
30 * The DNS query structure
35 } __attribute__ ((packed
));
38 * The DNS Resource recodes structure
44 uint16_t rdlength
; /* The lenght of this rr data */
46 } __attribute__ ((packed
));
49 #define DNS_PORT htons(53) /* Default DNS port */
50 #define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
52 uint32_t dns_server
[DNS_MAX_SERVERS
] = {0, };
56 * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
57 * number of dots encountered. On return, *dst is updated.
59 int dns_mangle(char **dst
, const char *p
)
71 if (c
== 0 || c
== ':' || c
== '/')
87 /* update the strings */
94 * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
95 * is allowed pointers relative to a packet in buf.
98 static bool dns_compare(const void *s1
, const void *s2
, const void *buf
)
100 const uint8_t *q
= s1
;
101 const uint8_t *p
= s2
;
109 p
= (const uint8_t *)buf
+ ((c0
- 0xc0) << 8) + c1
;
111 c0
++; /* Include the length byte */
112 if (memcmp(q
, p
, c0
))
123 * Copy a DNS label into a buffer, considering the possibility that we might
124 * have to follow pointers relative to "buf".
125 * Returns a pointer to the first free byte *after* the terminal null.
127 static void *dns_copylabel(void *dst
, const void *src
, const void *buf
)
130 const uint8_t *p
= src
;
138 p
= (const uint8_t *)buf
+ ((c0
- 0xc0) << 8) + c1
;
140 c0
++; /* Include the length byte */
152 * Skip past a DNS label set in DS:SI
154 static char *dns_skiplabel(char *label
)
161 return ++label
; /* pointer is two bytes */
168 extern const uint8_t TimeoutTable
[];
169 extern uint16_t get_port(void);
170 extern void free_port(uint16_t port
);
173 * parse the ip_str and return the ip address with *res.
174 * return true if the whole string was consumed and the result
178 static bool parse_dotquad(const char *ip_str
, uint32_t *res
)
180 const char *p
= ip_str
;
185 for (i
= 0; i
< 4; i
++) {
186 while (is_digit(*p
)) {
187 part
= part
* 10 + *p
- '0';
190 if (i
!= 3 && *p
!= '.')
193 ip
= (ip
<< 8) | part
;
204 * Actual resolver function
205 * Points to a null-terminated or :-terminated string in _name_
206 * and returns the ip addr in _ip_ if it exists and can be found.
207 * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
209 * XXX: probably need some caching here.
211 __export
uint32_t dns_resolv(const char *name
)
213 static char __lowmem DNSSendBuf
[PKTBUF_SIZE
];
214 static char __lowmem DNSRecvBuf
[PKTBUF_SIZE
];
220 int ques
, reps
; /* number of questions and replies */
222 const uint8_t *timeout_ptr
= TimeoutTable
;
226 struct dnshdr
*hd1
= (struct dnshdr
*)DNSSendBuf
;
227 struct dnshdr
*hd2
= (struct dnshdr
*)DNSRecvBuf
;
228 struct dnsquery
*query
;
230 static __lowmem
struct s_PXENV_UDP_WRITE udp_write
;
231 static __lowmem
struct s_PXENV_UDP_READ udp_read
;
236 * Return failure on an empty input... this can happen during
237 * some types of URL parsing, and this is the easiest place to
243 /* If it is a valid dot quad, just return that value */
244 if (parse_dotquad(name
, &result
))
247 /* Make sure we have at least one valid DNS server */
251 /* Get a local port number */
252 local_port
= get_port();
254 /* First, fill the DNS header struct */
255 hd1
->id
++; /* New query ID */
256 hd1
->flags
= htons(0x0100); /* Recursion requested */
257 hd1
->qdcount
= htons(1); /* One question */
258 hd1
->ancount
= 0; /* No answers */
259 hd1
->nscount
= 0; /* No NS */
260 hd1
->arcount
= 0; /* No AR */
262 p
= DNSSendBuf
+ sizeof(struct dnshdr
);
263 dots
= dns_mangle(&p
, name
); /* store the CNAME */
266 p
--; /* Remove final null */
267 /* Uncompressed DNS label set so it ends in null */
268 p
= stpcpy(p
, LocalDomain
);
271 /* Fill the DNS query packet */
272 query
= (struct dnsquery
*)p
;
273 query
->qtype
= htons(TYPE_A
);
274 query
->qclass
= htons(CLASS_IN
);
275 p
+= sizeof(struct dnsquery
);
277 /* Now send it to name server */
278 timeout_ptr
= TimeoutTable
;
279 timeout
= *timeout_ptr
++;
280 srv_ptr
= dns_server
;
284 srv_ptr
= dns_server
;
288 udp_write
.status
= 0;
290 udp_write
.gw
= gateway(srv
);
291 udp_write
.src_port
= local_port
;
292 udp_write
.dst_port
= DNS_PORT
;
293 udp_write
.buffer_size
= p
- DNSSendBuf
;
294 udp_write
.buffer
= FAR_PTR(DNSSendBuf
);
295 err
= pxe_call(PXENV_UDP_WRITE
, &udp_write
);
296 if (err
|| udp_write
.status
)
301 if (jiffies() - oldtime
>= timeout
)
305 udp_read
.src_ip
= srv
;
306 udp_read
.dest_ip
= IPInfo
.myip
;
307 udp_read
.s_port
= DNS_PORT
;
308 udp_read
.d_port
= local_port
;
309 udp_read
.buffer_size
= PKTBUF_SIZE
;
310 udp_read
.buffer
= FAR_PTR(DNSRecvBuf
);
311 err
= pxe_call(PXENV_UDP_READ
, &udp_read
);
312 } while (err
|| udp_read
.status
|| hd2
->id
!= hd1
->id
);
314 if ((hd2
->flags
^ 0x80) & htons(0xf80f))
317 ques
= htons(hd2
->qdcount
); /* Questions */
318 reps
= htons(hd2
->ancount
); /* Replies */
319 p
= DNSRecvBuf
+ sizeof(struct dnshdr
);
321 p
= dns_skiplabel(p
); /* Skip name */
322 p
+= 4; /* Skip question trailer */
325 /* Parse the replies */
327 same
= dns_compare(DNSSendBuf
+ sizeof(struct dnshdr
),
329 p
= dns_skiplabel(p
);
330 rr
= (struct dnsrr
*)p
;
331 rd_len
= ntohs(rr
->rdlength
);
332 if (same
&& ntohs(rr
->class) == CLASS_IN
) {
333 switch (ntohs(rr
->type
)) {
336 result
= *(uint32_t *)rr
->rdata
;
341 dns_copylabel(DNSSendBuf
+ sizeof(struct dnshdr
),
342 rr
->rdata
, DNSRecvBuf
);
344 * We should probably rescan the packet from the top
345 * here, and technically we might have to send a whole
346 * new request here...
354 /* not the one we want, try next */
355 p
+= sizeof(struct dnsrr
) + rd_len
;
361 ; We got back no data from this server.
362 ; Unfortunately, for a recursive, non-authoritative
363 ; query there is no such thing as an NXDOMAIN reply,
364 ; which technically means we can't draw any
365 ; conclusions. However, in practice that means the
366 ; domain doesn't exist. If this turns out to be a
367 ; problem, we may want to add code to go through all
368 ; the servers before giving up.
370 ; If the DNS server wasn't capable of recursion, and
371 ; isn't capable of giving us an authoritative reply
372 ; (i.e. neither AA or RA set), then at least try a
373 ; different setver...
375 if (hd2
->flags
== htons(0x480))
385 free_port(local_port
); /* Return port number to the free pool */