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 uint32_t dns_server
[DNS_MAX_SERVERS
] = {0, };
53 * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
54 * number of dots encountered. On return, *dst is updated.
56 int dns_mangle(char **dst
, const char *p
)
68 if (c
== 0 || c
== ':' || c
== '/')
84 /* update the strings */
91 * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
92 * is allowed pointers relative to a packet in buf.
95 static bool dns_compare(const void *s1
, const void *s2
, const void *buf
)
97 const uint8_t *q
= s1
;
98 const uint8_t *p
= s2
;
106 p
= (const uint8_t *)buf
+ ((c0
- 0xc0) << 8) + c1
;
108 c0
++; /* Include the length byte */
109 if (memcmp(q
, p
, c0
))
120 * Copy a DNS label into a buffer, considering the possibility that we might
121 * have to follow pointers relative to "buf".
122 * Returns a pointer to the first free byte *after* the terminal null.
124 static void *dns_copylabel(void *dst
, const void *src
, const void *buf
)
127 const uint8_t *p
= src
;
135 p
= (const uint8_t *)buf
+ ((c0
- 0xc0) << 8) + c1
;
137 c0
++; /* Include the length byte */
149 * Skip past a DNS label set in DS:SI
151 static char *dns_skiplabel(char *label
)
158 return ++label
; /* pointer is two bytes */
166 * Actual resolver function
167 * Points to a null-terminated or :-terminated string in _name_
168 * and returns the ip addr in _ip_ if it exists and can be found.
169 * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
171 * XXX: probably need some caching here.
173 __export
uint32_t dns_resolv(const char *name
)
175 static char __lowmem DNSSendBuf
[PKTBUF_SIZE
];
176 static char __lowmem DNSRecvBuf
[PKTBUF_SIZE
];
182 int ques
, reps
; /* number of questions and replies */
184 const uint8_t *timeout_ptr
= TimeoutTable
;
188 struct dnshdr
*hd1
= (struct dnshdr
*)DNSSendBuf
;
189 struct dnshdr
*hd2
= (struct dnshdr
*)DNSRecvBuf
;
190 struct dnsquery
*query
;
192 static __lowmem
struct s_PXENV_UDP_WRITE udp_write
;
193 static __lowmem
struct s_PXENV_UDP_READ udp_read
;
197 /* Make sure we have at least one valid DNS server */
201 /* Get a local port number */
202 local_port
= get_port();
204 /* First, fill the DNS header struct */
205 hd1
->id
++; /* New query ID */
206 hd1
->flags
= htons(0x0100); /* Recursion requested */
207 hd1
->qdcount
= htons(1); /* One question */
208 hd1
->ancount
= 0; /* No answers */
209 hd1
->nscount
= 0; /* No NS */
210 hd1
->arcount
= 0; /* No AR */
212 p
= DNSSendBuf
+ sizeof(struct dnshdr
);
213 dots
= dns_mangle(&p
, name
); /* store the CNAME */
216 p
--; /* Remove final null */
217 /* Uncompressed DNS label set so it ends in null */
218 p
= stpcpy(p
, LocalDomain
);
221 /* Fill the DNS query packet */
222 query
= (struct dnsquery
*)p
;
223 query
->qtype
= htons(TYPE_A
);
224 query
->qclass
= htons(CLASS_IN
);
225 p
+= sizeof(struct dnsquery
);
227 /* Now send it to name server */
228 timeout_ptr
= TimeoutTable
;
229 timeout
= *timeout_ptr
++;
230 srv_ptr
= dns_server
;
234 srv_ptr
= dns_server
;
238 udp_write
.status
= 0;
240 udp_write
.gw
= gateway(srv
);
241 udp_write
.src_port
= local_port
;
242 udp_write
.dst_port
= DNS_PORT
;
243 udp_write
.buffer_size
= p
- DNSSendBuf
;
244 udp_write
.buffer
= FAR_PTR(DNSSendBuf
);
245 err
= pxe_call(PXENV_UDP_WRITE
, &udp_write
);
246 if (err
|| udp_write
.status
)
251 if (jiffies() - oldtime
>= timeout
)
255 udp_read
.src_ip
= srv
;
256 udp_read
.dest_ip
= IPInfo
.myip
;
257 udp_read
.s_port
= DNS_PORT
;
258 udp_read
.d_port
= local_port
;
259 udp_read
.buffer_size
= PKTBUF_SIZE
;
260 udp_read
.buffer
= FAR_PTR(DNSRecvBuf
);
261 err
= pxe_call(PXENV_UDP_READ
, &udp_read
);
262 } while (err
|| udp_read
.status
|| hd2
->id
!= hd1
->id
);
264 if ((hd2
->flags
^ 0x80) & htons(0xf80f))
267 ques
= htons(hd2
->qdcount
); /* Questions */
268 reps
= htons(hd2
->ancount
); /* Replies */
269 p
= DNSRecvBuf
+ sizeof(struct dnshdr
);
271 p
= dns_skiplabel(p
); /* Skip name */
272 p
+= 4; /* Skip question trailer */
275 /* Parse the replies */
277 same
= dns_compare(DNSSendBuf
+ sizeof(struct dnshdr
),
279 p
= dns_skiplabel(p
);
280 rr
= (struct dnsrr
*)p
;
281 rd_len
= ntohs(rr
->rdlength
);
282 if (same
&& ntohs(rr
->class) == CLASS_IN
) {
283 switch (ntohs(rr
->type
)) {
286 result
= *(uint32_t *)rr
->rdata
;
291 dns_copylabel(DNSSendBuf
+ sizeof(struct dnshdr
),
292 rr
->rdata
, DNSRecvBuf
);
294 * We should probably rescan the packet from the top
295 * here, and technically we might have to send a whole
296 * new request here...
304 /* not the one we want, try next */
305 p
+= sizeof(struct dnsrr
) + rd_len
;
311 ; We got back no data from this server.
312 ; Unfortunately, for a recursive, non-authoritative
313 ; query there is no such thing as an NXDOMAIN reply,
314 ; which technically means we can't draw any
315 ; conclusions. However, in practice that means the
316 ; domain doesn't exist. If this turns out to be a
317 ; problem, we may want to add code to go through all
318 ; the servers before giving up.
320 ; If the DNS server wasn't capable of recursion, and
321 ; isn't capable of giving us an authoritative reply
322 ; (i.e. neither AA or RA set), then at least try a
323 ; different setver...
325 if (hd2
->flags
== htons(0x480))
335 free_port(local_port
); /* Return port number to the free pool */
340 void pm_pxe_dns_resolv(com32sys_t
*regs
)
342 const char *name
= MK_PTR(regs
->ds
, regs
->esi
.w
[0]);
344 regs
->eax
.l
= dns_resolv(name
);