The dnsrelov converted to C.
Signed-off-by: Liu Aleaxander <Aleaxander@gmail.com>
; INT 22h AX=0010h Resolve hostname
;
%if IS_PXELINUX
+ extern pxe_dns_resolv
comapi_dnsresolv:
mov ds,P_ES
mov si,P_BX
- call dns_resolv
+ pm_call pxe_dns_resolv
mov P_EAX,eax
clc
ret
;
; 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 .text16
-
-;
-; 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.
-;
- global dns_mangle
-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 .bss16
- global LocalDomain, DNSServers
+;
+DNS_MAX_PACKET equ 512 ;Defined by protocol
+
+ section .bss16
+ global LocalDomain
+ global DNSSendBuf, DNSRecvBuf
alignb 2
DNSSendBuf resb DNS_MAX_PACKET
DNSRecvBuf resb DNS_MAX_PACKET
LocalDomain resb 256 ; Max possible length
-DNSServers resd DNS_MAX_SERVERS
-
- section .data16
-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
-
- global LastDNSServer
-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.
-;
-; No segment assumptions permitted.
-;
- section .text16
- global dns_resolv
-dns_resolv:
- push ds
- push es
- push di
- push bx
- 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 bx,TimeoutTable
-.backoff:
- movzx dx,byte [bx]
- mov si,DNSServers
-.servers:
- cmp si,[LastDNSServer]
- jb .moreservers
-
-.nomoreservers:
- inc bx
- cmp bx,TimeoutTableEnd
- jb .backoff
-
- xor eax,eax ; Nothing...
-.done:
- pop si
- pop dx
- pop cx
- pop bx
- pop di
- pop es
- pop ds
- ret
-
-.moreservers:
- lodsd ; EAX <- next server
- push si
- push bx
- 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,8 ; 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 bx
- pop si
- jmp .servers
+ section .text16
\ No newline at end of file
num = DNS_MAX_SERVERS;
for (i = 0; i < num; i++) {
- DNSServers[i] = *(uint32_t *)data;
+ dns_server[i] = *(uint32_t *)data;
data += 4;
}
-
- /* NOT SURE FOR NOW */
- LastDNSServer = OFFS_WRT(&DNSServers[num - 1], 0);
}
static void local_domain(void *data, int opt_len)
{
- com32sys_t regs;
char *p = (char *)data + opt_len;
+ char *ld = LocalDomain;
char end = *p;
-
- memset(®s, 0, sizeof regs);
+
*p = '\0'; /* Zero-terminate option */
- regs.esi.w[0] = OFFS_WRT(data, 0);
- regs.edi.w[0] = OFFS_WRT(LocalDomain, 0);
- call16(dns_mangle, ®s, NULL);
+ dns_mangle(&ld, (char **)&data);
*p = end; /* Resotre ending byte */
}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include "pxe.h"
+
+/*
+ * The DNS header structure
+ */
+struct dnshdr {
+ uint16_t id;
+ uint16_t flags;
+ /* number of entries in the question section */
+ uint16_t qdcount;
+ /* number of resource records in the answer section */
+ uint16_t ancount;
+ /* number of name server resource records in the authority records section*/
+ uint16_t nscount;
+ /* number of resource records in the additional records section */
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+/*
+ * The DNS query structure
+ */
+struct dnsquery {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
+/*
+ * The DNS Resource recodes structure
+ */
+struct dnsrr {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength; /* The lenght of this rr data */
+ char rdata[];
+} __attribute__ ((packed));
+
+
+uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
+
+/*
+ * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
+ * number of dots encountered. On return, both src and dst are updated.
+ */
+int dns_mangle(char **dst, char **src)
+{
+ char *p = *src;
+ char *q = *dst;
+ int dots = 0;
+ int flag = 0;
+ char c;
+
+ while (1) {
+ c = *p++;
+ if (c == 0 || c == ':')
+ break;
+ if (c == '.') {
+ dots++;
+ flag = *q;
+ *q++ = 0;
+ continue;
+ }
+
+ flag++;
+ *q++ = c;
+ }
+
+ if (flag)
+ *dst++ = 0;
+
+ /* update the strings */
+ *src = --p;
+ *dst = q;
+ return dots;
+}
+
+
+/*
+ * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s1_
+ * is allowed pointers relative to a packet in DNSRecvBuf.
+ *
+ */
+static int dns_compare(char *s1, char *s2)
+{
+#if 0
+ while (1) {
+ if (*s1 < 0xc0)
+ break;
+ s1 = DNSRecvBuf + (((*s1++ & 0x3f) << 8) | (*s1++));
+ }
+ if (*s1 == 0)
+ return 1;
+ else if (*s1++ != *s2++)
+ return 0; /* not same */
+ else
+ return !strcmp(s1, s2);
+#else
+ (void)s1;
+ (void)s2;
+ return 1;
+#endif
+}
+
+/*
+ * Skip past a DNS label set in DS:SI
+ */
+static char *dns_skiplabel(char *dns)
+{
+ uint8_t c;
+
+ while (1) {
+ c = *dns++;
+ if (c >= 0xc0)
+ return ++dns; /* pointer is two bytes */
+ if (c == 0)
+ return dns;
+ dns += c;
+ }
+}
+
+/*
+ * Actual resolver function
+ * Points to a null-terminated or :-terminated string in _name_
+ * and returns the ip addr in _ip_ if it exists and can be found.
+ * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ *
+ */
+uint32_t dns_resolv(char **name)
+{
+ char *p;
+ int err;
+ int dots;
+ int same;
+ int rd_len;
+ int ques, reps; /* number of questions and replies */
+ uint8_t timeout;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint16_t oldtime;
+ uint32_t srv;
+ uint32_t *srv_ptr = dns_server;
+ struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
+ struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
+ struct dnsquery *query;
+ struct dnsrr *rr;
+ static __lowmem struct pxe_udp_write_pkt uw_pkt;
+ static __lowmem struct pxe_udp_read_pkt ur_pkt;
+
+ /* First, fill the DNS header struct */
+ hd1->id++; /* New query ID */
+ hd1->flags = htons(0x0100); /* Recursion requested */
+ hd1->qdcount = htons(1); /* One question */
+ hd1->ancount = 0; /* No answers */
+ hd1->nscount = 0; /* No NS */
+ hd1->arcount = 0; /* No AR */
+
+ p = DNSSendBuf + sizeof(struct dnshdr);
+ dots = dns_mangle(&p, name); /* store the CNAME */
+
+ if (!dots) {
+ p--; /* Remove final null */
+ /* Uncompressed DNS label set so it ends in null */
+ strcpy(p, LocalDomain);
+ }
+
+ /* Fill the DNS query packet */
+ query = (struct dnsquery *)p;
+ query->qtype = htons(1); /* QTYPE = 1 = A */
+ query->qclass = htons(1); /* QCLASS = 1 = IN */
+ p += sizeof(struct dnsquery);
+
+ /* Now send it to name server */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ while ((srv = *srv_ptr++)) {
+ uw_pkt.status = 0;
+ uw_pkt.sip = srv;
+ uw_pkt.gip = ((srv ^ MyIP) & Netmask) ? Gateway : 0;
+ uw_pkt.lport = DNS_LOCAL_PORT;
+ uw_pkt.rport = DNS_PORT;
+ uw_pkt.buffersize = p - DNSSendBuf;
+ uw_pkt.buffer[0] = OFFS_WRT(DNSSendBuf, 0);
+ uw_pkt.buffer[1] = 0;
+ err = pxe_call(PXENV_UDP_WRITE, &uw_pkt);
+ if (err || uw_pkt.status != 0)
+ continue;
+
+ oldtime = BIOS_timer;
+ while (oldtime + timeout <= BIOS_timer) {
+ ur_pkt.status = 0;
+ ur_pkt.sip = srv;
+ ur_pkt.dip = MyIP;
+ ur_pkt.rport = DNS_PORT;
+ ur_pkt.lport = DNS_LOCAL_PORT;
+ ur_pkt.buffersize = DNS_MAX_PACKET;
+ ur_pkt.buffer[0] = OFFS_WRT(DNSRecvBuf, 0);
+ ur_pkt.buffer[1] = 0;
+ err = pxe_call(PXENV_UDP_READ, &ur_pkt);
+ if (err || ur_pkt.status)
+ continue;
+
+ /* Got a packet, deal with it... */
+ if (hd2->id == hd1->id)
+ break;
+ }
+ if (BIOS_timer > oldtime + timeout) {
+ /* time out */
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ return 0; /* All time ticks run out */
+ else
+ continue; /* try next */
+ }
+ if ((hd2->flags ^ 0x80) & htons(0xf80f))
+ goto badness;
+
+ ques = htons(hd2->qdcount); /* Questions */
+ reps = htons(hd2->ancount); /* Replies */
+ p = DNSRecvBuf + sizeof(struct dnshdr);
+ while (ques--) {
+ p = dns_skiplabel(p); /* Skip name */
+ p += 4; /* Skip question trailer */
+ }
+
+ /* Parse the replies */
+ while (reps--) {
+ same = dns_compare(p, (char *)(DNSSendBuf + sizeof(struct dnshdr)));
+ rr = (struct dnsrr *)dns_skiplabel(p);
+ rd_len = htons(rr->rdlength);
+ if (same && rd_len == 4 &&
+ htons(rr->type) == 1 && /* TYPE == A */
+ htons(rr->class) == 1 ) /* CLASS == IN */
+ return *(uint32_t *)rr->rdata;
+
+ /* not the one we want, try next */
+ p += sizeof(struct dnsrr) + rd_len;
+ }
+
+ 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...
+ */
+ if (hd2->flags == htons(0x480))
+ continue;
+
+ break; /* failed */
+ }
+
+ return 0;
+}
+
+
+/*
+ * the one should be called from ASM file
+ */
+void pxe_dns_resolv(com32sys_t *regs)
+{
+ char *name = MK_PTR(regs->ds, regs->esi.w[0]);
+
+ regs->eax.l = dns_resolv(&name);
+}
static uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
int HaveUUID = 0;
-static const uint8_t TimeoutTable[] = {
+const uint8_t TimeoutTable[] = {
2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44, 53, 64, 77,
92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
};
* the ASM pxenv function wrapper, return 1 if error, or 0
*
*/
-static int pxe_call(int opcode, void *data)
+int pxe_call(int opcode, void *data)
{
extern void pxenv(void);
com32sys_t in_regs, out_regs;
*/
static void pxe_mangle_name(char *dst, const char *src)
{
- extern void dns_resolv(void);
const char *p = src;
uint32_t ip = ServerIP;
int i = 0;
p = src;
if ((p = parse_dotquad(p, &ip)) && !strncmp(p, "::", 2)) {
p += 2;
- } else {
- com32sys_t regs;
-
- memset(®s, 0, sizeof regs);
- regs.esi.w[0] = OFFS_WRT(p, 0);
- call16(dns_resolv, ®s, ®s);
- p = MK_PTR(regs.ds, regs.esi.w[0]);
- ip = regs.eax.l;
- if (!strncmp(p, "::", 2) && ip) {
+ } else {
+ ip = dns_resolv(&p);
+ if (ip && !strncmp(p, "::", 2)) {
p += 2;
} else {
/* no ip, too */
#define TFTP_BLOCKSIZE_LG2 9
#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
#define PKTBUF_SEG 0x4000
-#define DNS_MAX_SERVERS 4
#define is_digit(c) (((c) >= '0') && ((c) <= '9'))
#define BOOTP_OPTION_MAGIC htonl(0x63825363)
#define MAC_MAX 32
+/* Defines for DNS */
+#define DNS_PORT htons(53) /* Default DNS port */
+#define DNS_MAX_PACKET 512 /* Defined by protocol */
+/* All local DNS queries come from this port */
+#define DNS_LOCAL_PORT htons(60053)
+#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
+
+
/*
* structures
*/
} __attribute__ ((packed));
/*
- * functions
+ * functions
*/
+
+/* pxe.c */
int ip_ok(uint32_t);
+int pxe_call(int, void *);
+
+/* dhcp_options.c */
void parse_dhcp(int);
void parse_dhcp_options(void *, int, int);
+/* dnsresolv.c */
+int dns_mangle(char **, char **);
+uint32_t dns_resolve(char **);
+
+
#endif /* pxe.h */
/*
* externs for pxelinux
*/
-extern void dns_mangle(void);
-
extern uint32_t ServerIP;
extern uint32_t MyIP;
extern uint32_t Netmask;
extern char IPOption[];
extern char DotQuadBuf[];
-extern uint32_t DNSServers[];
-extern uint16_t LastDNSServer;
+extern uint32_t dns_server[];
+extern char DNSSendBuf[];
+extern char DNSRecvBuf[];
extern uint16_t RealBaseMem;
extern uint16_t APIVer;
extern char UUID[];
extern volatile uint16_t BIOS_timer;
+extern const uint8_t TimeoutTable[];
#endif /* CORE_H */