1#include <stdio.h>
2#include <string.h>
3#include <core.h>
4#include "pxe.h"
5#include "lwip/api.h"
6#include "lwip/dns.h"
7
8/* DNS CLASS values we care about */
9#define CLASS_IN	1
10
11/* DNS TYPE values we care about */
12#define TYPE_A		1
13#define TYPE_CNAME	5
14
15/*
16 * The DNS header structure
17 */
18struct dnshdr {
19    uint16_t id;
20    uint16_t flags;
21    /* number of entries in the question section */
22    uint16_t qdcount;
23    /* number of resource records in the answer section */
24    uint16_t ancount;
25    /* number of name server resource records in the authority records section*/
26    uint16_t nscount;
27    /* number of resource records in the additional records section */
28    uint16_t arcount;
29} __attribute__ ((packed));
30
31/*
32 * The DNS query structure
33 */
34struct dnsquery {
35    uint16_t qtype;
36    uint16_t qclass;
37} __attribute__ ((packed));
38
39/*
40 * The DNS Resource recodes structure
41 */
42struct dnsrr {
43    uint16_t type;
44    uint16_t class;
45    uint32_t ttl;
46    uint16_t rdlength;   /* The lenght of this rr data */
47    char     rdata[];
48} __attribute__ ((packed));
49
50
51uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
52
53/*
54 * parse the ip_str and return the ip address with *res.
55 * return true if the whole string was consumed and the result
56 * was valid.
57 *
58 */
59static bool parse_dotquad(const char *ip_str, uint32_t *res)
60{
61    const char *p = ip_str;
62    uint8_t part = 0;
63    uint32_t ip = 0;
64    int i;
65
66    for (i = 0; i < 4; i++) {
67        while (is_digit(*p)) {
68            part = part * 10 + *p - '0';
69            p++;
70        }
71        if (i != 3 && *p != '.')
72            return false;
73
74        ip = (ip << 8) | part;
75        part = 0;
76        p++;
77    }
78    p--;
79
80    *res = htonl(ip);
81    return *p == '\0';
82}
83
84/*
85 * Actual resolver function.
86 *
87 * Points to a null-terminated in _name_ and returns the ip addr in
88 * _ip_ if it exists and can be found.  If _ip_ = 0 on exit, the
89 * lookup failed. _name_ will be updated
90 */
91__export uint32_t dns_resolv(const char *name)
92{
93    err_t err;
94    struct ip_addr ip;
95    char fullname[512];
96
97    /*
98     * Return failure on an empty input... this can happen during
99     * some types of URL parsing, and this is the easiest place to
100     * check for it.
101     */
102    if (!name || !*name)
103	return 0;
104
105    /* If it is a valid dot quad, just return that value */
106    if (parse_dotquad(name, &ip.addr))
107	return ip.addr;
108
109    /* Make sure we have at least one valid DNS server */
110    if (!dns_getserver(0).addr)
111	return 0;
112
113    /* Is it a local (unqualified) domain name? */
114    if (!strchr(name, '.') && LocalDomain[0]) {
115	snprintf(fullname, sizeof fullname, "%s.%s", name, LocalDomain);
116	name = fullname;
117    }
118
119    err = netconn_gethostbyname(name, &ip);
120    if (err)
121	return 0;
122
123    return ip.addr;
124}
125
126/*
127 * the one should be called from ASM file
128 */
129void pm_pxe_dns_resolv(com32sys_t *regs)
130{
131    const char *name = MK_PTR(regs->ds, regs->esi.w[0]);
132
133    regs->eax.l = dns_resolv(name);
134}
135