(2006-08-06) rescue-bootcd
This commit is contained in:
378
extra/syslinux-3.09/dnsresolv.inc
Normal file
378
extra/syslinux-3.09/dnsresolv.inc
Normal file
@@ -0,0 +1,378 @@
|
||||
; -*- fundamental -*-
|
||||
; -----------------------------------------------------------------------
|
||||
;
|
||||
; Copyright 2004 H. Peter Anvin - All Rights Reserved
|
||||
;
|
||||
; This program is free software; you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
||||
; Bostom MA 02111-1307, USA; either version 2 of the License, or
|
||||
; (at your option) any later version; incorporated herein by reference.
|
||||
;
|
||||
; -----------------------------------------------------------------------
|
||||
|
||||
;
|
||||
; dnsresolv.inc
|
||||
;
|
||||
; Very simple DNS resolver (assumes recursion-enabled DNS server;
|
||||
; this should be the normal thing for client-serving DNS servers.)
|
||||
;
|
||||
|
||||
DNS_PORT equ htons(53) ; Default DNS port
|
||||
DNS_MAX_PACKET equ 512 ; Defined by protocol
|
||||
; TFTP uses the range 49152-57343
|
||||
DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port #
|
||||
DNS_MAX_SERVERS equ 4 ; Max no of DNS servers
|
||||
|
||||
section .text
|
||||
|
||||
;
|
||||
; Turn a string in DS:SI into a DNS "label set" in ES:DI.
|
||||
; On return, DI points to the first byte after the label set,
|
||||
; and SI to the terminating byte.
|
||||
;
|
||||
; On return, DX contains the number of dots encountered.
|
||||
;
|
||||
dns_mangle:
|
||||
push ax
|
||||
push bx
|
||||
xor dx,dx
|
||||
.isdot:
|
||||
inc dx
|
||||
xor al,al
|
||||
mov bx,di
|
||||
stosb
|
||||
.getbyte:
|
||||
lodsb
|
||||
and al,al
|
||||
jz .endstring
|
||||
cmp al,':'
|
||||
jz .endstring
|
||||
cmp al,'.'
|
||||
je .isdot
|
||||
inc byte [es:bx]
|
||||
stosb
|
||||
jmp .getbyte
|
||||
.endstring:
|
||||
dec si
|
||||
dec dx ; We always counted one high
|
||||
cmp byte [es:bx],0
|
||||
jz .done
|
||||
xor al,al
|
||||
stosb
|
||||
.done:
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;
|
||||
; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI
|
||||
; is allowed pointers relative to a packet in DNSRecvBuf.
|
||||
;
|
||||
; Assumes DS == ES. ZF = 1 if same; no registers changed.
|
||||
; (Note: change reference to [di] to [es:di] to remove DS == ES assumption)
|
||||
;
|
||||
dns_compare:
|
||||
pusha
|
||||
%if 0
|
||||
|
||||
.label:
|
||||
lodsb
|
||||
cmp al,0C0h
|
||||
jb .noptr
|
||||
and al,03Fh ; Get pointer value
|
||||
mov ah,al ; ... in network byte order!
|
||||
lodsb
|
||||
mov si,DNSRecvBuf
|
||||
add si,ax
|
||||
jmp .label
|
||||
.noptr:
|
||||
cmp al,[di]
|
||||
jne .done ; Mismatch
|
||||
inc di
|
||||
movzx cx,al ; End label?
|
||||
and cx,cx ; ZF = 1 if match
|
||||
jz .done
|
||||
|
||||
; We have a string of bytes that need to match now
|
||||
repe cmpsb
|
||||
je .label
|
||||
|
||||
.done:
|
||||
%else
|
||||
xor ax,ax
|
||||
%endif
|
||||
popa
|
||||
ret
|
||||
|
||||
;
|
||||
; Skip past a DNS label set in DS:SI.
|
||||
;
|
||||
dns_skiplabel:
|
||||
push ax
|
||||
xor ax,ax ; AH == 0
|
||||
.loop:
|
||||
lodsb
|
||||
cmp al,0C0h ; Pointer?
|
||||
jae .ptr
|
||||
and al,al
|
||||
jz .done
|
||||
add si,ax
|
||||
jmp .loop
|
||||
.ptr:
|
||||
inc si ; Pointer is two bytes
|
||||
.done:
|
||||
pop ax
|
||||
ret
|
||||
|
||||
; DNS header format
|
||||
struc dnshdr
|
||||
.id: resw 1
|
||||
.flags: resw 1
|
||||
.qdcount: resw 1
|
||||
.ancount: resw 1
|
||||
.nscount: resw 1
|
||||
.arcount: resw 1
|
||||
endstruc
|
||||
|
||||
; DNS query
|
||||
struc dnsquery
|
||||
.qtype: resw 1
|
||||
.qclass: resw 1
|
||||
endstruc
|
||||
|
||||
; DNS RR
|
||||
struc dnsrr
|
||||
.type: resw 1
|
||||
.class: resw 1
|
||||
.ttl: resd 1
|
||||
.rdlength: resw 1
|
||||
.rdata: equ $
|
||||
endstruc
|
||||
|
||||
section .bss
|
||||
alignb 2, db 0
|
||||
DNSSendBuf resb DNS_MAX_PACKET
|
||||
DNSRecvBuf resb DNS_MAX_PACKET
|
||||
LocalDomain resb 256 ; Max possible length
|
||||
DNSServers resd DNS_MAX_SERVERS
|
||||
|
||||
section .data
|
||||
pxe_udp_write_pkt_dns:
|
||||
.status: dw 0 ; Status
|
||||
.sip: dd 0 ; Server IP
|
||||
.gip: dd 0 ; Gateway IP
|
||||
.lport: dw DNS_LOCAL_PORT ; Local port
|
||||
.rport: dw DNS_PORT ; Remote port
|
||||
.buffersize: dw 0 ; Size of packet
|
||||
.buffer: dw DNSSendBuf, 0 ; off, seg of buffer
|
||||
|
||||
pxe_udp_read_pkt_dns:
|
||||
.status: dw 0 ; Status
|
||||
.sip: dd 0 ; Source IP
|
||||
.dip: dd 0 ; Destination (our) IP
|
||||
.rport: dw DNS_PORT ; Remote port
|
||||
.lport: dw DNS_LOCAL_PORT ; Local port
|
||||
.buffersize: dw DNS_MAX_PACKET ; Max packet size
|
||||
.buffer: dw DNSRecvBuf, 0 ; off, seg of buffer
|
||||
|
||||
LastDNSServer dw DNSServers
|
||||
|
||||
; Actual resolver function
|
||||
; Points to a null-terminated or :-terminated string in DS:SI
|
||||
; and returns the name in EAX if it exists and can be found.
|
||||
; If EAX = 0 on exit, the lookup failed.
|
||||
|
||||
section .text
|
||||
dns_resolv:
|
||||
push ds
|
||||
push es
|
||||
push di
|
||||
push cx
|
||||
push dx
|
||||
|
||||
push cs
|
||||
pop es ; ES <- CS
|
||||
|
||||
; First, build query packet
|
||||
mov di,DNSSendBuf+dnshdr.flags
|
||||
inc word [es:di-2] ; New query ID
|
||||
mov ax,htons(0100h) ; Recursion requested
|
||||
stosw
|
||||
mov ax,htons(1) ; One question
|
||||
stosw
|
||||
xor ax,ax ; No answers, NS or ARs
|
||||
stosw
|
||||
stosw
|
||||
stosw
|
||||
|
||||
call dns_mangle ; Convert name to DNS labels
|
||||
|
||||
push cs ; DS <- CS
|
||||
pop ds
|
||||
|
||||
push si ; Save pointer to after DNS string
|
||||
|
||||
; Initialize...
|
||||
mov eax,[MyIP]
|
||||
mov [pxe_udp_read_pkt_dns.dip],eax
|
||||
|
||||
and dx,dx
|
||||
jnz .fqdn ; If we have dots, assume it's FQDN
|
||||
dec di ; Remove final null
|
||||
mov si,LocalDomain
|
||||
call strcpy ; Uncompressed DNS label set so it ends in null
|
||||
.fqdn:
|
||||
|
||||
mov ax,htons(1)
|
||||
stosw ; QTYPE = 1 = A
|
||||
stosw ; QCLASS = 1 = IN
|
||||
|
||||
sub di,DNSSendBuf
|
||||
mov [pxe_udp_write_pkt_dns.buffersize],di
|
||||
|
||||
; Now, send it to the nameserver(s)
|
||||
; Outer loop: exponential backoff
|
||||
; Inner loop: scan the various DNS servers
|
||||
|
||||
mov dx,PKT_TIMEOUT
|
||||
mov cx,PKT_RETRY
|
||||
.backoff:
|
||||
mov si,DNSServers
|
||||
.servers:
|
||||
cmp si,[LastDNSServer]
|
||||
jb .moreservers
|
||||
|
||||
.nomoreservers:
|
||||
add dx,dx ; Exponential backoff
|
||||
loop .backoff
|
||||
|
||||
xor eax,eax ; Nothing...
|
||||
.done:
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop di
|
||||
pop es
|
||||
pop ds
|
||||
ret
|
||||
|
||||
.moreservers:
|
||||
lodsd ; EAX <- next server
|
||||
push si
|
||||
push cx
|
||||
push dx
|
||||
|
||||
mov word [pxe_udp_write_pkt_dns.status],0
|
||||
|
||||
mov [pxe_udp_write_pkt_dns.sip],eax
|
||||
mov [pxe_udp_read_pkt_dns.sip],eax
|
||||
xor eax,[MyIP]
|
||||
and eax,[Netmask]
|
||||
jz .nogw
|
||||
mov eax,[Gateway]
|
||||
.nogw:
|
||||
mov [pxe_udp_write_pkt_dns.gip],eax
|
||||
|
||||
mov di,pxe_udp_write_pkt_dns
|
||||
mov bx,PXENV_UDP_WRITE
|
||||
call pxenv
|
||||
jc .timeout ; Treat failed transmit as timeout
|
||||
cmp word [pxe_udp_write_pkt_dns.status],0
|
||||
jne .timeout
|
||||
|
||||
mov cx,[BIOS_timer]
|
||||
.waitrecv:
|
||||
mov ax,[BIOS_timer]
|
||||
sub ax,cx
|
||||
cmp ax,dx
|
||||
jae .timeout
|
||||
|
||||
mov word [pxe_udp_read_pkt_dns.status],0
|
||||
mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET
|
||||
mov di,pxe_udp_read_pkt_dns
|
||||
mov bx,PXENV_UDP_READ
|
||||
call pxenv
|
||||
and ax,ax
|
||||
jnz .waitrecv
|
||||
cmp [pxe_udp_read_pkt_dns.status],ax
|
||||
jnz .waitrecv
|
||||
|
||||
; Got a packet, deal with it...
|
||||
mov si,DNSRecvBuf
|
||||
lodsw
|
||||
cmp ax,[DNSSendBuf] ; ID
|
||||
jne .waitrecv ; Not ours
|
||||
|
||||
lodsw ; flags
|
||||
xor al,80h ; Query#/Answer bit
|
||||
test ax,htons(0F80Fh)
|
||||
jnz .badness
|
||||
|
||||
lodsw
|
||||
xchg ah,al ; ntohs
|
||||
mov cx,ax ; Questions echoed
|
||||
lodsw
|
||||
xchg ah,al ; ntohs
|
||||
push ax ; Replies
|
||||
lodsw ; NS records
|
||||
lodsw ; Authority records
|
||||
|
||||
jcxz .qskipped
|
||||
.skipq:
|
||||
call dns_skiplabel ; Skip name
|
||||
add si,4 ; Skip question trailer
|
||||
loop .skipq
|
||||
|
||||
.qskipped:
|
||||
pop cx ; Number of replies
|
||||
jcxz .badness
|
||||
|
||||
.parseanswer:
|
||||
mov di,DNSSendBuf+dnshdr_size
|
||||
call dns_compare
|
||||
pushf
|
||||
call dns_skiplabel
|
||||
mov ax,[si+8] ; RDLENGTH
|
||||
xchg ah,al ; ntohs
|
||||
popf
|
||||
jnz .notsame
|
||||
cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN?
|
||||
jne .notsame
|
||||
cmp ax,4 ; RDLENGTH = 4?
|
||||
jne .notsame
|
||||
;
|
||||
; We hit paydirt here...
|
||||
;
|
||||
mov eax,[si+10]
|
||||
.gotresult:
|
||||
add sp,6 ; Drop timeout information
|
||||
jmp .done
|
||||
|
||||
.notsame:
|
||||
add si,10
|
||||
add si,ax
|
||||
loop .parseanswer
|
||||
|
||||
.badness:
|
||||
; We got back no data from this server. Unfortunately, for a recursive,
|
||||
; non-authoritative query there is no such thing as an NXDOMAIN reply,
|
||||
; which technically means we can't draw any conclusions. However,
|
||||
; in practice that means the domain doesn't exist. If this turns out
|
||||
; to be a problem, we may want to add code to go through all the servers
|
||||
; before giving up.
|
||||
|
||||
; If the DNS server wasn't capable of recursion, and isn't capable
|
||||
; of giving us an authoritative reply (i.e. neither AA or RA set),
|
||||
; then at least try a different setver...
|
||||
test word [DNSRecvBuf+dnshdr.flags],htons(0480h)
|
||||
jz .timeout
|
||||
|
||||
xor eax,eax
|
||||
jmp .gotresult
|
||||
|
||||
.timeout:
|
||||
pop dx
|
||||
pop cx
|
||||
pop si
|
||||
jmp .servers
|
||||
Reference in New Issue
Block a user