2 ; -----------------------------------------------------------------------
4 ; Copyright 2004-2008 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 ; -----------------------------------------------------------------------
17 ; Very simple DNS resolver (assumes recursion-enabled DNS server;
18 ; this should be the normal thing for client-serving DNS servers.)
21 DNS_PORT equ htons(53) ; Default DNS port
22 DNS_MAX_PACKET equ 512 ; Defined by protocol
23 ; TFTP uses the range 49152-57343
24 DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port #
25 DNS_MAX_SERVERS equ 4 ; Max no of DNS servers
30 ; Turn a string in DS:SI into a DNS "label set" in ES:DI.
31 ; On return, DI points to the first byte after the label set,
32 ; and SI to the terminating byte.
34 ; On return, DX contains the number of dots encountered.
58 dec dx ; We always counted one high
69 ; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI
70 ; is allowed pointers relative to a packet in DNSRecvBuf.
72 ; Assumes DS == ES. ZF = 1 if same; no registers changed.
73 ; (Note: change reference to [di] to [es:di] to remove DS == ES assumption)
83 and al,03Fh ; Get pointer value
84 mov ah,al ; ... in network byte order!
93 movzx cx,al ; End label?
94 and cx,cx ; ZF = 1 if match
97 ; We have a string of bytes that need to match now
109 ; Skip past a DNS label set in DS:SI.
116 cmp al,0C0h ; Pointer?
123 inc si ; Pointer is two bytes
155 DNSSendBuf resb DNS_MAX_PACKET
156 DNSRecvBuf resb DNS_MAX_PACKET
157 LocalDomain resb 256 ; Max possible length
158 DNSServers resd DNS_MAX_SERVERS
161 pxe_udp_write_pkt_dns:
162 .status: dw 0 ; Status
163 .sip: dd 0 ; Server IP
164 .gip: dd 0 ; Gateway IP
165 .lport: dw DNS_LOCAL_PORT ; Local port
166 .rport: dw DNS_PORT ; Remote port
167 .buffersize: dw 0 ; Size of packet
168 .buffer: dw DNSSendBuf, 0 ; off, seg of buffer
170 pxe_udp_read_pkt_dns:
171 .status: dw 0 ; Status
172 .sip: dd 0 ; Source IP
173 .dip: dd 0 ; Destination (our) IP
174 .rport: dw DNS_PORT ; Remote port
175 .lport: dw DNS_LOCAL_PORT ; Local port
176 .buffersize: dw DNS_MAX_PACKET ; Max packet size
177 .buffer: dw DNSRecvBuf, 0 ; off, seg of buffer
179 LastDNSServer dw DNSServers
181 ; Actual resolver function
182 ; Points to a null-terminated or :-terminated string in DS:SI
183 ; and returns the name in EAX if it exists and can be found.
184 ; If EAX = 0 on exit, the lookup failed.
186 ; No segment assumptions permitted.
199 ; First, build query packet
200 mov di,DNSSendBuf+dnshdr.flags
201 inc word [es:di-2] ; New query ID
202 mov ax,htons(0100h) ; Recursion requested
204 mov ax,htons(1) ; One question
206 xor ax,ax ; No answers, NS or ARs
211 call dns_mangle ; Convert name to DNS labels
216 push si ; Save pointer to after DNS string
220 mov [pxe_udp_read_pkt_dns.dip],eax
223 jnz .fqdn ; If we have dots, assume it's FQDN
224 dec di ; Remove final null
226 call strcpy ; Uncompressed DNS label set so it ends in null
230 stosw ; QTYPE = 1 = A
231 stosw ; QCLASS = 1 = IN
234 mov [pxe_udp_write_pkt_dns.buffersize],di
236 ; Now, send it to the nameserver(s)
237 ; Outer loop: exponential backoff
238 ; Inner loop: scan the various DNS servers
245 cmp si,[LastDNSServer]
249 add dx,dx ; Exponential backoff
252 xor eax,eax ; Nothing...
263 lodsd ; EAX <- next server
268 mov word [pxe_udp_write_pkt_dns.status],0
270 mov [pxe_udp_write_pkt_dns.sip],eax
271 mov [pxe_udp_read_pkt_dns.sip],eax
277 mov [pxe_udp_write_pkt_dns.gip],eax
279 mov di,pxe_udp_write_pkt_dns
280 mov bx,PXENV_UDP_WRITE
282 jc .timeout ; Treat failed transmit as timeout
283 cmp word [pxe_udp_write_pkt_dns.status],0
293 mov word [pxe_udp_read_pkt_dns.status],0
294 mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET
295 mov di,pxe_udp_read_pkt_dns
296 mov bx,PXENV_UDP_READ
300 cmp [pxe_udp_read_pkt_dns.status],ax
303 ; Got a packet, deal with it...
306 cmp ax,[DNSSendBuf] ; ID
307 jne .waitrecv ; Not ours
310 xor al,80h ; Query#/Answer bit
311 test ax,htons(0F80Fh)
316 mov cx,ax ; Questions echoed
321 lodsw ; Authority records
325 call dns_skiplabel ; Skip name
326 add si,4 ; Skip question trailer
330 pop cx ; Number of replies
334 mov di,DNSSendBuf+dnshdr_size
338 mov ax,[si+8] ; RDLENGTH
342 cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN?
344 cmp ax,4 ; RDLENGTH = 4?
347 ; We hit paydirt here...
351 add sp,6 ; Drop timeout information
360 ; We got back no data from this server. Unfortunately, for a recursive,
361 ; non-authoritative query there is no such thing as an NXDOMAIN reply,
362 ; which technically means we can't draw any conclusions. However,
363 ; in practice that means the domain doesn't exist. If this turns out
364 ; to be a problem, we may want to add code to go through all the servers
367 ; If the DNS server wasn't capable of recursion, and isn't capable
368 ; of giving us an authoritative reply (i.e. neither AA or RA set),
369 ; then at least try a different setver...
370 test word [DNSRecvBuf+dnshdr.flags],htons(0480h)