2 ; -----------------------------------------------------------------------
4 ; Copyright 2004-2005 H. Peter Anvin - All Rights Reserved
6 ; This program is free software; you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ; Bostom MA 02111-1307, USA; either version 2 of the License, or
10 ; (at your option) any later version; incorporated herein by reference.
12 ; -----------------------------------------------------------------------
18 ; Very simple DNS resolver (assumes recursion-enabled DNS server;
19 ; this should be the normal thing for client-serving DNS servers.)
22 DNS_PORT equ htons(53) ; Default DNS port
23 DNS_MAX_PACKET equ 512 ; Defined by protocol
24 ; TFTP uses the range 49152-57343
25 DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port #
26 DNS_MAX_SERVERS equ 4 ; Max no of DNS servers
31 ; Turn a string in DS:SI into a DNS "label set" in ES:DI.
32 ; On return, DI points to the first byte after the label set,
33 ; and SI to the terminating byte.
35 ; On return, DX contains the number of dots encountered.
59 dec dx ; We always counted one high
70 ; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI
71 ; is allowed pointers relative to a packet in DNSRecvBuf.
73 ; Assumes DS == ES. ZF = 1 if same; no registers changed.
74 ; (Note: change reference to [di] to [es:di] to remove DS == ES assumption)
84 and al,03Fh ; Get pointer value
85 mov ah,al ; ... in network byte order!
94 movzx cx,al ; End label?
95 and cx,cx ; ZF = 1 if match
98 ; We have a string of bytes that need to match now
110 ; Skip past a DNS label set in DS:SI.
117 cmp al,0C0h ; Pointer?
124 inc si ; Pointer is two bytes
156 DNSSendBuf resb DNS_MAX_PACKET
157 DNSRecvBuf resb DNS_MAX_PACKET
158 LocalDomain resb 256 ; Max possible length
159 DNSServers resd DNS_MAX_SERVERS
162 pxe_udp_write_pkt_dns:
163 .status: dw 0 ; Status
164 .sip: dd 0 ; Server IP
165 .gip: dd 0 ; Gateway IP
166 .lport: dw DNS_LOCAL_PORT ; Local port
167 .rport: dw DNS_PORT ; Remote port
168 .buffersize: dw 0 ; Size of packet
169 .buffer: dw DNSSendBuf, 0 ; off, seg of buffer
171 pxe_udp_read_pkt_dns:
172 .status: dw 0 ; Status
173 .sip: dd 0 ; Source IP
174 .dip: dd 0 ; Destination (our) IP
175 .rport: dw DNS_PORT ; Remote port
176 .lport: dw DNS_LOCAL_PORT ; Local port
177 .buffersize: dw DNS_MAX_PACKET ; Max packet size
178 .buffer: dw DNSRecvBuf, 0 ; off, seg of buffer
180 LastDNSServer dw DNSServers
182 ; Actual resolver function
183 ; Points to a null-terminated or :-terminated string in DS:SI
184 ; and returns the name in EAX if it exists and can be found.
185 ; If EAX = 0 on exit, the lookup failed.
198 ; First, build query packet
199 mov di,DNSSendBuf+dnshdr.flags
200 inc word [es:di-2] ; New query ID
201 mov ax,htons(0100h) ; Recursion requested
203 mov ax,htons(1) ; One question
205 xor ax,ax ; No answers, NS or ARs
210 call dns_mangle ; Convert name to DNS labels
215 push si ; Save pointer to after DNS string
219 mov [pxe_udp_read_pkt_dns.dip],eax
222 jnz .fqdn ; If we have dots, assume it's FQDN
223 dec di ; Remove final null
225 call strcpy ; Uncompressed DNS label set so it ends in null
229 stosw ; QTYPE = 1 = A
230 stosw ; QCLASS = 1 = IN
233 mov [pxe_udp_write_pkt_dns.buffersize],di
235 ; Now, send it to the nameserver(s)
236 ; Outer loop: exponential backoff
237 ; Inner loop: scan the various DNS servers
244 cmp si,[LastDNSServer]
248 add dx,dx ; Exponential backoff
251 xor eax,eax ; Nothing...
262 lodsd ; EAX <- next server
267 mov word [pxe_udp_write_pkt_dns.status],0
269 mov [pxe_udp_write_pkt_dns.sip],eax
270 mov [pxe_udp_read_pkt_dns.sip],eax
276 mov [pxe_udp_write_pkt_dns.gip],eax
278 mov di,pxe_udp_write_pkt_dns
279 mov bx,PXENV_UDP_WRITE
281 jc .timeout ; Treat failed transmit as timeout
282 cmp word [pxe_udp_write_pkt_dns.status],0
292 mov word [pxe_udp_read_pkt_dns.status],0
293 mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET
294 mov di,pxe_udp_read_pkt_dns
295 mov bx,PXENV_UDP_READ
299 cmp [pxe_udp_read_pkt_dns.status],ax
302 ; Got a packet, deal with it...
305 cmp ax,[DNSSendBuf] ; ID
306 jne .waitrecv ; Not ours
309 xor al,80h ; Query#/Answer bit
310 test ax,htons(0F80Fh)
315 mov cx,ax ; Questions echoed
320 lodsw ; Authority records
324 call dns_skiplabel ; Skip name
325 add si,4 ; Skip question trailer
329 pop cx ; Number of replies
333 mov di,DNSSendBuf+dnshdr_size
337 mov ax,[si+8] ; RDLENGTH
341 cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN?
343 cmp ax,4 ; RDLENGTH = 4?
346 ; We hit paydirt here...
350 add sp,6 ; Drop timeout information
359 ; We got back no data from this server. Unfortunately, for a recursive,
360 ; non-authoritative query there is no such thing as an NXDOMAIN reply,
361 ; which technically means we can't draw any conclusions. However,
362 ; in practice that means the domain doesn't exist. If this turns out
363 ; to be a problem, we may want to add code to go through all the servers
366 ; If the DNS server wasn't capable of recursion, and isn't capable
367 ; of giving us an authoritative reply (i.e. neither AA or RA set),
368 ; then at least try a different setver...
369 test word [DNSRecvBuf+dnshdr.flags],htons(0480h)