135 lines
2.9 KiB
C
135 lines
2.9 KiB
C
#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);
|
|
}
|