summaryrefslogtreecommitdiff
path: root/core/fs/pxe/dnsresolv.c
blob: afb9e219c7d7c594aa80288aef69b21357c4ea41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdio.h>
#include <string.h>
#include <core.h>
#include "pxe.h"
#include "lwip/api.h"
#include "lwip/dns.h"

/* DNS CLASS values we care about */
#define CLASS_IN	1

/* DNS TYPE values we care about */
#define TYPE_A		1
#define TYPE_CNAME	5

/*
 * 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, };

/*
 * parse the ip_str and return the ip address with *res.
 * return true if the whole string was consumed and the result
 * was valid.
 *
 */
static bool parse_dotquad(const char *ip_str, uint32_t *res)
{
    const char *p = ip_str;
    uint8_t part = 0;
    uint32_t ip = 0;
    int i;

    for (i = 0; i < 4; i++) {
        while (is_digit(*p)) {
            part = part * 10 + *p - '0';
            p++;
        }
        if (i != 3 && *p != '.')
            return false;

        ip = (ip << 8) | part;
        part = 0;
        p++;
    }
    p--;

    *res = htonl(ip);
    return *p == '\0';
}

/*
 * Actual resolver function.
 *
 * Points to a null-terminated 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
 */
__export uint32_t dns_resolv(const char *name)
{
    err_t err;
    struct ip_addr ip;
    char fullname[512];

    /*
     * Return failure on an empty input... this can happen during
     * some types of URL parsing, and this is the easiest place to
     * check for it.
     */
    if (!name || !*name)
	return 0;

    /* If it is a valid dot quad, just return that value */
    if (parse_dotquad(name, &ip.addr))
	return ip.addr;

    /* Make sure we have at least one valid DNS server */
    if (!dns_getserver(0).addr)
	return 0;

    /* Is it a local (unqualified) domain name? */
    if (!strchr(name, '.') && LocalDomain[0]) {
	snprintf(fullname, sizeof fullname, "%s.%s", name, LocalDomain);
	name = fullname;
    }

    err = netconn_gethostbyname(name, &ip);
    if (err)
	return 0;

    return ip.addr;
}

/*
 * the one should be called from ASM file
 */
void pm_pxe_dns_resolv(com32sys_t *regs)
{
    const char *name = MK_PTR(regs->ds, regs->esi.w[0]);

    regs->eax.l = dns_resolv(name);
}