Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[dns] Support DNS search lists
Update the DNS resolver to support DNS search lists (as provided by
DHCP option 119, DHCPv6 option 24, or NDP option 31).

Add validation code to ensure that parsing of DNS packets does not
overrun the input, get stuck in infinite loops, or (worse) write
beyond the end of allocated buffers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Feb 5, 2014
1 parent 3fa7a3b commit d4c0226
Show file tree
Hide file tree
Showing 9 changed files with 1,450 additions and 326 deletions.
3 changes: 3 additions & 0 deletions src/include/ipxe/dhcp.h
Expand Up @@ -290,6 +290,9 @@ struct dhcp_client_uuid {

#define DHCP_CLIENT_UUID_TYPE 0

/** DNS domain search list */
#define DHCP_DOMAIN_SEARCH 119

/** Etherboot-specific encapsulated options
*
* This encapsulated options field is used to contain all options
Expand Down
178 changes: 117 additions & 61 deletions src/include/ipxe/dns.h
Expand Up @@ -12,88 +12,144 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <ipxe/in.h>

/*
* Constants
/** DNS server port */
#define DNS_PORT 53

/** An RFC1035-encoded DNS name */
struct dns_name {
/** Start of data */
void *data;
/** Offset of name within data */
size_t offset;
/** Total length of data */
size_t len;
};

/**
* Test for a DNS compression pointer
*
* @v byte Initial byte
* @ret is_compressed Is a compression pointer
*/
#define DNS_IS_COMPRESSED( byte ) ( (byte) & 0xc0 )

/**
* Extract DNS compression pointer
*
* @v word Initial word
* @ret offset Offset
*/
#define DNS_COMPRESSED_OFFSET( word ) ( (word) & ~0xc000 )

/**
* Extract DNS label length
*
* @v byte Initial byte
* @ret len Label length
*/
#define DNS_LABEL_LEN( byte ) ( (byte) & ~0xc0 )

#define DNS_TYPE_A 1
#define DNS_TYPE_CNAME 5
#define DNS_TYPE_AAAA 28
#define DNS_TYPE_ANY 255

#define DNS_CLASS_IN 1
#define DNS_CLASS_CS 2
#define DNS_CLASS_CH 3
#define DNS_CLASS_HS 4

#define DNS_FLAG_QUERY ( 0x00 << 15 )
#define DNS_FLAG_RESPONSE ( 0x01 << 15 )
#define DNS_FLAG_QR(flags) ( (flags) & ( 0x01 << 15 ) )
#define DNS_FLAG_OPCODE_QUERY ( 0x00 << 11 )
#define DNS_FLAG_OPCODE_IQUERY ( 0x01 << 11 )
#define DNS_FLAG_OPCODE_STATUS ( 0x02 << 11 )
#define DNS_FLAG_OPCODE(flags) ( (flags) & ( 0x0f << 11 ) )
#define DNS_FLAG_RD ( 0x01 << 8 )
#define DNS_FLAG_RA ( 0x01 << 7 )
#define DNS_FLAG_RCODE_OK ( 0x00 << 0 )
#define DNS_FLAG_RCODE_NX ( 0x03 << 0 )
#define DNS_FLAG_RCODE(flags) ( (flags) & ( 0x0f << 0 ) )

#define DNS_PORT 53
#define DNS_MAX_RETRIES 3
#define DNS_MAX_CNAME_RECURSION 0x30

/*
* DNS protocol structures
/** Maximum length of a single DNS label */
#define DNS_MAX_LABEL_LEN 0x3f

/** Maximum length of a DNS name (mandated by RFC1035 section 2.3.4) */
#define DNS_MAX_NAME_LEN 255

/** Maximum depth of CNAME recursion
*
* This is a policy decision.
*/
#define DNS_MAX_CNAME_RECURSION 32

/** A DNS packet header */
struct dns_header {
uint16_t id;
uint16_t flags;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
/** Query identifier */
uint16_t id;
/** Flags */
uint16_t flags;
/** Number of question records */
uint16_t qdcount;
/** Number of answer records */
uint16_t ancount;
/** Number of name server records */
uint16_t nscount;
/** Number of additional records */
uint16_t arcount;
} __attribute__ (( packed ));

struct dns_query_info {
uint16_t qtype;
uint16_t qclass;
} __attribute__ (( packed ));
/** Recursion desired flag */
#define DNS_FLAG_RD 0x0100

struct dns_query {
struct dns_header dns;
char payload[ 256 + sizeof ( struct dns_query_info ) ];
/** A DNS question */
struct dns_question {
/** Query type */
uint16_t qtype;
/** Query class */
uint16_t qclass;
} __attribute__ (( packed ));

struct dns_rr_info_common {
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t rdlength;
/** DNS class "IN" */
#define DNS_CLASS_IN 1

/** A DNS resource record */
struct dns_rr_common {
/** Type */
uint16_t type;
/** Class */
uint16_t class;
/** Time to live */
uint32_t ttl;
/** Resource data length */
uint16_t rdlength;
} __attribute__ (( packed ));

struct dns_rr_info_a {
struct dns_rr_info_common common;
/** Type of a DNS "A" record */
#define DNS_TYPE_A 1

/** A DNS "A" record */
struct dns_rr_a {
/** Common fields */
struct dns_rr_common common;
/** IPv4 address */
struct in_addr in_addr;
} __attribute__ (( packed ));

struct dns_rr_info_aaaa {
struct dns_rr_info_common common;
/** Type of a DNS "AAAA" record */
#define DNS_TYPE_AAAA 28

/** A DNS "AAAA" record */
struct dns_rr_aaaa {
/** Common fields */
struct dns_rr_common common;
/** IPv6 address */
struct in6_addr in6_addr;
} __attribute__ (( packed ));

struct dns_rr_info_cname {
struct dns_rr_info_common common;
char cname[0];
/** Type of a DNS "NAME" record */
#define DNS_TYPE_CNAME 5

/** A DNS "CNAME" record */
struct dns_rr_cname {
/** Common fields */
struct dns_rr_common common;
} __attribute__ (( packed ));

union dns_rr_info {
struct dns_rr_info_common common;
struct dns_rr_info_a a;
struct dns_rr_info_aaaa aaaa;
struct dns_rr_info_cname cname;
/** A DNS resource record */
union dns_rr {
/** Common fields */
struct dns_rr_common common;
/** "A" record */
struct dns_rr_a a;
/** "AAAA" record */
struct dns_rr_aaaa aaaa;
/** "CNAME" record */
struct dns_rr_cname cname;
};

extern int dns_encode ( const char *string, struct dns_name *name );
extern int dns_decode ( struct dns_name *name, char *data, size_t len );
extern int dns_compare ( struct dns_name *first, struct dns_name *second );
extern int dns_copy ( struct dns_name *src, struct dns_name *dst );
extern int dns_skip ( struct dns_name *name );

#endif /* _IPXE_DNS_H */
1 change: 1 addition & 0 deletions src/include/ipxe/settings.h
Expand Up @@ -417,6 +417,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
extern const struct setting_type setting_type_hexraw __setting_type;
extern const struct setting_type setting_type_uuid __setting_type;
extern const struct setting_type setting_type_busdevfn __setting_type;
extern const struct setting_type setting_type_dnssl __setting_type;

extern const struct setting
ip_setting __setting ( SETTING_IP, ip );
Expand Down
10 changes: 10 additions & 0 deletions src/net/ndp.c
Expand Up @@ -786,6 +786,16 @@ const struct setting ndp_dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = {
.scope = &ndp_settings_scope,
};

/** DNS search list setting */
const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
.name = "dnssl",
.description = "DNS search list",
.tag = NDP_TAG ( NDP_OPT_DNSSL,
offsetof ( struct ndp_dnssl_option, names ) ),
.type = &setting_type_dnssl,
.scope = &ndp_settings_scope,
};

/****************************************************************************
*
* IPv6 autoconfiguration
Expand Down
1 change: 1 addition & 0 deletions src/net/udp/dhcp.c
Expand Up @@ -86,6 +86,7 @@ static uint8_t dhcp_request_options_data[] = {
DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
DHCP_DOMAIN_SEARCH,
128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */
DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
DHCP_END
Expand Down
9 changes: 9 additions & 0 deletions src/net/udp/dhcpv6.c
Expand Up @@ -979,3 +979,12 @@ const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = {
.type = &setting_type_string,
.scope = &ipv6_scope,
};

/** DNS search list setting */
const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
.name = "dnssl",
.description = "DNS search list",
.tag = DHCPV6_DOMAIN_LIST,
.type = &setting_type_dnssl,
.scope = &ipv6_scope,
};

0 comments on commit d4c0226

Please sign in to comment.