Browse Source

[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>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
d4c0226a6c
9 changed files with 1450 additions and 326 deletions
  1. 3
    0
      src/include/ipxe/dhcp.h
  2. 117
    61
      src/include/ipxe/dns.h
  3. 1
    0
      src/include/ipxe/settings.h
  4. 10
    0
      src/net/ndp.c
  5. 1
    0
      src/net/udp/dhcp.c
  6. 9
    0
      src/net/udp/dhcpv6.c
  7. 703
    265
      src/net/udp/dns.c
  8. 605
    0
      src/tests/dns_test.c
  9. 1
    0
      src/tests/tests.c

+ 3
- 0
src/include/ipxe/dhcp.h View File

@@ -290,6 +290,9 @@ struct dhcp_client_uuid {
290 290
 
291 291
 #define DHCP_CLIENT_UUID_TYPE 0
292 292
 
293
+/** DNS domain search list */
294
+#define DHCP_DOMAIN_SEARCH 119
295
+
293 296
 /** Etherboot-specific encapsulated options
294 297
  *
295 298
  * This encapsulated options field is used to contain all options

+ 117
- 61
src/include/ipxe/dns.h View File

@@ -12,88 +12,144 @@ FILE_LICENCE ( GPL2_OR_LATER );
12 12
 #include <stdint.h>
13 13
 #include <ipxe/in.h>
14 14
 
15
-/*
16
- * Constants
15
+/** DNS server port */
16
+#define DNS_PORT 53
17
+
18
+/** An RFC1035-encoded DNS name */
19
+struct dns_name {
20
+	/** Start of data */
21
+	void *data;
22
+	/** Offset of name within data */
23
+	size_t offset;
24
+	/** Total length of data */
25
+	size_t len;
26
+};
27
+
28
+/**
29
+ * Test for a DNS compression pointer
30
+ *
31
+ * @v byte		Initial byte
32
+ * @ret is_compressed	Is a compression pointer
33
+ */
34
+#define DNS_IS_COMPRESSED( byte ) ( (byte) & 0xc0 )
35
+
36
+/**
37
+ * Extract DNS compression pointer
38
+ *
39
+ * @v word		Initial word
40
+ * @ret offset		Offset
41
+ */
42
+#define DNS_COMPRESSED_OFFSET( word ) ( (word) & ~0xc000 )
43
+
44
+/**
45
+ * Extract DNS label length
17 46
  *
47
+ * @v byte		Initial byte
48
+ * @ret len		Label length
18 49
  */
50
+#define DNS_LABEL_LEN( byte ) ( (byte) & ~0xc0 )
19 51
 
20
-#define DNS_TYPE_A		1
21
-#define DNS_TYPE_CNAME		5
22
-#define DNS_TYPE_AAAA		28
23
-#define DNS_TYPE_ANY		255
24
-
25
-#define DNS_CLASS_IN		1
26
-#define DNS_CLASS_CS		2
27
-#define DNS_CLASS_CH		3
28
-#define DNS_CLASS_HS		4
29
-
30
-#define DNS_FLAG_QUERY		( 0x00 << 15 )
31
-#define DNS_FLAG_RESPONSE	( 0x01 << 15 )
32
-#define DNS_FLAG_QR(flags)	( (flags) & ( 0x01 << 15 ) )
33
-#define DNS_FLAG_OPCODE_QUERY	( 0x00 << 11 )
34
-#define DNS_FLAG_OPCODE_IQUERY	( 0x01 << 11 )
35
-#define DNS_FLAG_OPCODE_STATUS	( 0x02 << 11 )
36
-#define DNS_FLAG_OPCODE(flags)	( (flags) & ( 0x0f << 11 ) )
37
-#define DNS_FLAG_RD		( 0x01 << 8 )
38
-#define DNS_FLAG_RA		( 0x01 << 7 )
39
-#define DNS_FLAG_RCODE_OK	( 0x00 << 0 )
40
-#define DNS_FLAG_RCODE_NX	( 0x03 << 0 )
41
-#define DNS_FLAG_RCODE(flags)	( (flags) & ( 0x0f << 0 ) )
42
-
43
-#define	DNS_PORT		53
44
-#define	DNS_MAX_RETRIES		3
45
-#define	DNS_MAX_CNAME_RECURSION	0x30
46
-
47
-/*
48
- * DNS protocol structures
52
+/** Maximum length of a single DNS label */
53
+#define DNS_MAX_LABEL_LEN 0x3f
54
+
55
+/** Maximum length of a DNS name (mandated by RFC1035 section 2.3.4) */
56
+#define DNS_MAX_NAME_LEN 255
57
+
58
+/** Maximum depth of CNAME recursion
49 59
  *
60
+ * This is a policy decision.
50 61
  */
62
+#define DNS_MAX_CNAME_RECURSION 32
63
+
64
+/** A DNS packet header */
51 65
 struct dns_header {
52
-	uint16_t	id;
53
-	uint16_t	flags;
54
-	uint16_t	qdcount;
55
-	uint16_t	ancount;
56
-	uint16_t	nscount;
57
-	uint16_t	arcount;
66
+	/** Query identifier */
67
+	uint16_t id;
68
+	/** Flags */
69
+	uint16_t flags;
70
+	/** Number of question records */
71
+	uint16_t qdcount;
72
+	/** Number of answer records */
73
+	uint16_t ancount;
74
+	/** Number of name server records */
75
+	uint16_t nscount;
76
+	/** Number of additional records */
77
+	uint16_t arcount;
58 78
 } __attribute__ (( packed ));
59 79
 
60
-struct dns_query_info {
61
-	uint16_t	qtype;
62
-	uint16_t	qclass;
63
-} __attribute__ (( packed ));
80
+/** Recursion desired flag */
81
+#define DNS_FLAG_RD 0x0100
64 82
 
65
-struct dns_query {
66
-	struct dns_header dns;
67
-	char		payload[ 256 + sizeof ( struct dns_query_info ) ];
83
+/** A DNS question */
84
+struct dns_question {
85
+	/** Query type */
86
+	uint16_t qtype;
87
+	/** Query class */
88
+	uint16_t qclass;
68 89
 } __attribute__ (( packed ));
69 90
 
70
-struct dns_rr_info_common {
71
-	uint16_t	type;
72
-	uint16_t	class;
73
-	uint32_t	ttl;
74
-	uint16_t	rdlength;
91
+/** DNS class "IN" */
92
+#define DNS_CLASS_IN 1
93
+
94
+/** A DNS resource record */
95
+struct dns_rr_common {
96
+	/** Type */
97
+	uint16_t type;
98
+	/** Class */
99
+	uint16_t class;
100
+	/** Time to live */
101
+	uint32_t ttl;
102
+	/** Resource data length */
103
+	uint16_t rdlength;
75 104
 } __attribute__ (( packed ));
76 105
 
77
-struct dns_rr_info_a {
78
-	struct dns_rr_info_common common;
106
+/** Type of a DNS "A" record */
107
+#define DNS_TYPE_A 1
108
+
109
+/** A DNS "A" record */
110
+struct dns_rr_a {
111
+	/** Common fields */
112
+	struct dns_rr_common common;
113
+	/** IPv4 address */
79 114
 	struct in_addr in_addr;
80 115
 } __attribute__ (( packed ));
81 116
 
82
-struct dns_rr_info_aaaa {
83
-	struct dns_rr_info_common common;
117
+/** Type of a DNS "AAAA" record */
118
+#define DNS_TYPE_AAAA 28
119
+
120
+/** A DNS "AAAA" record */
121
+struct dns_rr_aaaa {
122
+	/** Common fields */
123
+	struct dns_rr_common common;
124
+	/** IPv6 address */
84 125
 	struct in6_addr in6_addr;
85 126
 } __attribute__ (( packed ));
86 127
 
87
-struct dns_rr_info_cname {
88
-	struct dns_rr_info_common common;
89
-	char cname[0];
128
+/** Type of a DNS "NAME" record */
129
+#define DNS_TYPE_CNAME 5
130
+
131
+/** A DNS "CNAME" record */
132
+struct dns_rr_cname {
133
+	/** Common fields */
134
+	struct dns_rr_common common;
90 135
 } __attribute__ (( packed ));
91 136
 
92
-union dns_rr_info {
93
-	struct dns_rr_info_common common;
94
-	struct dns_rr_info_a a;
95
-	struct dns_rr_info_aaaa aaaa;
96
-	struct dns_rr_info_cname cname;
137
+/** A DNS resource record */
138
+union dns_rr {
139
+	/** Common fields */
140
+	struct dns_rr_common common;
141
+	/** "A" record */
142
+	struct dns_rr_a a;
143
+	/** "AAAA" record */
144
+	struct dns_rr_aaaa aaaa;
145
+	/** "CNAME" record */
146
+	struct dns_rr_cname cname;
97 147
 };
98 148
 
149
+extern int dns_encode ( const char *string, struct dns_name *name );
150
+extern int dns_decode ( struct dns_name *name, char *data, size_t len );
151
+extern int dns_compare ( struct dns_name *first, struct dns_name *second );
152
+extern int dns_copy ( struct dns_name *src, struct dns_name *dst );
153
+extern int dns_skip ( struct dns_name *name );
154
+
99 155
 #endif /* _IPXE_DNS_H */

+ 1
- 0
src/include/ipxe/settings.h View File

@@ -417,6 +417,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
417 417
 extern const struct setting_type setting_type_hexraw __setting_type;
418 418
 extern const struct setting_type setting_type_uuid __setting_type;
419 419
 extern const struct setting_type setting_type_busdevfn __setting_type;
420
+extern const struct setting_type setting_type_dnssl __setting_type;
420 421
 
421 422
 extern const struct setting
422 423
 ip_setting __setting ( SETTING_IP, ip );

+ 10
- 0
src/net/ndp.c View File

@@ -786,6 +786,16 @@ const struct setting ndp_dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = {
786 786
 	.scope = &ndp_settings_scope,
787 787
 };
788 788
 
789
+/** DNS search list setting */
790
+const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
791
+	.name = "dnssl",
792
+	.description = "DNS search list",
793
+	.tag = NDP_TAG ( NDP_OPT_DNSSL,
794
+			 offsetof ( struct ndp_dnssl_option, names ) ),
795
+	.type = &setting_type_dnssl,
796
+	.scope = &ndp_settings_scope,
797
+};
798
+
789 799
 /****************************************************************************
790 800
  *
791 801
  * IPv6 autoconfiguration

+ 1
- 0
src/net/udp/dhcp.c View File

@@ -86,6 +86,7 @@ static uint8_t dhcp_request_options_data[] = {
86 86
 		      DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
87 87
 		      DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
88 88
 		      DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
89
+		      DHCP_DOMAIN_SEARCH,
89 90
 		      128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */
90 91
 		      DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
91 92
 	DHCP_END

+ 9
- 0
src/net/udp/dhcpv6.c View File

@@ -979,3 +979,12 @@ const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = {
979 979
 	.type = &setting_type_string,
980 980
 	.scope = &ipv6_scope,
981 981
 };
982
+
983
+/** DNS search list setting */
984
+const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
985
+	.name = "dnssl",
986
+	.description = "DNS search list",
987
+	.tag = DHCPV6_DOMAIN_LIST,
988
+	.type = &setting_type_dnssl,
989
+	.scope = &ipv6_scope,
990
+};

+ 703
- 265
src/net/udp/dns.c
File diff suppressed because it is too large
View File


+ 605
- 0
src/tests/dns_test.c View File

@@ -0,0 +1,605 @@
1
+/*
2
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+/** @file
23
+ *
24
+ * DNS self-tests
25
+ *
26
+ */
27
+
28
+/* Forcibly enable assertions */
29
+#undef NDEBUG
30
+
31
+#include <string.h>
32
+#include <assert.h>
33
+#include <ipxe/dns.h>
34
+#include <ipxe/test.h>
35
+
36
+/** Define inline data */
37
+#define DATA(...) { __VA_ARGS__ }
38
+
39
+/** A DNS encoding test */
40
+struct dns_encode_test {
41
+	/** String */
42
+	const char *string;
43
+	/** Encoded string */
44
+	const void *data;
45
+	/** Length of encoded string */
46
+	int len;
47
+};
48
+
49
+/**
50
+ * Define a DNS encoding test
51
+ *
52
+ * @v _name		Test name
53
+ * @v _string		Test string
54
+ * @v _data		Expected encoded data
55
+ * @ret test		DNS encoding test
56
+ */
57
+#define DNS_ENCODE( _name, _string, _data )				\
58
+	static const uint8_t _name ## __data[] = _data;			\
59
+	static struct dns_encode_test _name = {				\
60
+		.string = _string,					\
61
+		.data =	_name ## __data,				\
62
+		.len = sizeof ( _name ## __data ),			\
63
+	}
64
+
65
+/**
66
+ * Report DNS encoding test result
67
+ *
68
+ * @v test		DNS encoding test
69
+ * @v file		Test code file
70
+ * @v line		Test code line
71
+ */
72
+static void dns_encode_okx ( struct dns_encode_test *test, const char *file,
73
+			     unsigned int line ) {
74
+	uint8_t data[ test->len ];
75
+	struct dns_name name;
76
+	int len;
77
+
78
+	/* Check ability to determine length with no buffer */
79
+	memset ( &name, 0, sizeof ( name ) );
80
+	len = dns_encode ( test->string, &name );
81
+	okx ( len >= 0, file, line );
82
+	okx ( len == test->len, file, line );
83
+
84
+	/* Check encoded name */
85
+	name.data = data;
86
+	name.len = sizeof ( data );
87
+	len = dns_encode ( test->string, &name );
88
+	okx ( len >= 0, file, line );
89
+	if ( len >= 0 ) {
90
+		okx ( len == test->len, file, line );
91
+		okx ( memcmp ( data, test->data, test->len ) == 0, file, line );
92
+		DBGC ( test, "DNS encoded \"%s\" to:\n", test->string );
93
+		DBGC_HDA ( test, 0, data, len );
94
+	}
95
+}
96
+#define dns_encode_ok( test ) dns_encode_okx ( test, __FILE__, __LINE__ )
97
+
98
+/**
99
+ * Report DNS encoding failure test result
100
+ *
101
+ * @v test		DNS encoding test
102
+ * @v file		Test code file
103
+ * @v line		Test code line
104
+ */
105
+static void dns_encode_fail_okx ( struct dns_encode_test *test,
106
+				  const char *file, unsigned int line ) {
107
+	struct dns_name name = { .data = NULL, .len = 0 };
108
+	int len;
109
+
110
+	len = dns_encode ( test->string, &name );
111
+	okx ( len < 0, file, line );
112
+}
113
+#define dns_encode_fail_ok( test ) \
114
+	dns_encode_fail_okx ( test, __FILE__, __LINE__ )
115
+
116
+/** A DNS decoding test */
117
+struct dns_decode_test {
118
+	/** Name */
119
+	struct dns_name name;
120
+	/** Expected string */
121
+	const char *string;
122
+};
123
+
124
+/**
125
+ * Define a DNS decoding test
126
+ *
127
+ * @v _name		Test name
128
+ * @v _data		RFC1035-encoded data
129
+ * @v _offset		Starting offset within encoded data
130
+ * @v _string		Expected decoded string
131
+ * @ret test		DNS decoding test
132
+ */
133
+#define DNS_DECODE( _name, _data, _offset, _string )			\
134
+	static uint8_t _name ## __data[] = _data;			\
135
+	static struct dns_decode_test _name = {				\
136
+		.name = {						\
137
+			.data = _name ## __data,			\
138
+			.offset = _offset,				\
139
+			.len = sizeof ( _name ## __data ),		\
140
+		},							\
141
+		.string = _string,					\
142
+	}
143
+
144
+/**
145
+ * Report DNS decoding test result
146
+ *
147
+ * @v test		DNS decoding test
148
+ * @v file		Test code file
149
+ * @v line		Test code line
150
+ */
151
+static void dns_decode_okx ( struct dns_decode_test *test, const char *file,
152
+			     unsigned int line ) {
153
+	char string[ strlen ( test->string ) + 1 /* NUL */ ];
154
+	int len;
155
+
156
+	/* Check ability to determine length with no buffer */
157
+	len = dns_decode ( &test->name, NULL, 0 );
158
+	okx ( len >= 0, file, line );
159
+	okx ( len == ( ( int ) strlen ( test->string ) ), file, line );
160
+
161
+	/* Check decoded string */
162
+	len = dns_decode ( &test->name, string, sizeof ( string ) );
163
+	okx ( len >= 0, file, line );
164
+	if ( len >= 0 ) {
165
+		okx ( strcmp ( string, test->string ) == 0, file, line );
166
+		DBGC ( test, "DNS decoded \"%s\" from offset %#zx in:\n",
167
+		       string, test->name.offset );
168
+		DBGC_HDA ( test, 0, test->name.data, test->name.len );
169
+	}
170
+}
171
+#define dns_decode_ok( test ) dns_decode_okx ( test, __FILE__, __LINE__ )
172
+
173
+/**
174
+ * Report DNS decoding failure test result
175
+ *
176
+ * @v test		DNS decoding test
177
+ * @v file		Test code file
178
+ * @v line		Test code line
179
+ */
180
+static void dns_decode_fail_okx ( struct dns_decode_test *test,
181
+				  const char *file, unsigned int line ) {
182
+	int len;
183
+
184
+	len = dns_decode ( &test->name, NULL, 0 );
185
+	okx ( len < 0, file, line );
186
+}
187
+#define dns_decode_fail_ok( test ) \
188
+	dns_decode_fail_okx ( test, __FILE__, __LINE__ )
189
+
190
+/** A DNS comparison test */
191
+struct dns_compare_test {
192
+	/** First name */
193
+	struct dns_name first;
194
+	/** Second name */
195
+	struct dns_name second;
196
+};
197
+
198
+/**
199
+ * Define a DNS comparison test
200
+ *
201
+ * @v _name		Test name
202
+ * @v _first_data	First RFC1035-encoded data
203
+ * @v _first_offset	Starting offset within first encoded data
204
+ * @v _second_data	Second RFC1035-encoded data
205
+ * @v _second_offset	Starting offset within second encoded data
206
+ * @ret test		DNS comparison test
207
+ */
208
+#define DNS_COMPARE( _name, _first_data, _first_offset, _second_data,	\
209
+		     _second_offset )					\
210
+	static uint8_t _name ## __first_data[] = _first_data;		\
211
+	static uint8_t _name ## __second_data[] = _second_data;		\
212
+	static struct dns_compare_test _name = {			\
213
+		.first = {						\
214
+			.data = _name ## __first_data,			\
215
+			.offset = _first_offset,			\
216
+			.len = sizeof ( _name ## __first_data ),	\
217
+		},							\
218
+		.second = {						\
219
+			.data = _name ## __second_data,			\
220
+			.offset = _second_offset,			\
221
+			.len = sizeof ( _name ## __second_data ),	\
222
+		},							\
223
+	}
224
+
225
+/**
226
+ * Report DNS comparison test result
227
+ *
228
+ * @v test		DNS comparison test
229
+ * @v file		Test code file
230
+ * @v line		Test code line
231
+ */
232
+static void dns_compare_okx ( struct dns_compare_test *test, const char *file,
233
+			      unsigned int line ) {
234
+
235
+	okx ( dns_compare ( &test->first, &test->second ) == 0, file, line );
236
+}
237
+#define dns_compare_ok( test ) dns_compare_okx ( test, __FILE__, __LINE__ )
238
+
239
+/**
240
+ * Report DNS comparison test failure result
241
+ *
242
+ * @v test		DNS comparison test
243
+ * @v file		Test code file
244
+ * @v line		Test code line
245
+ */
246
+static void dns_compare_fail_okx ( struct dns_compare_test *test,
247
+				   const char *file, unsigned int line ) {
248
+
249
+	okx ( dns_compare ( &test->first, &test->second ) != 0, file, line );
250
+}
251
+#define dns_compare_fail_ok( test ) \
252
+	dns_compare_fail_okx ( test, __FILE__, __LINE__ )
253
+
254
+/** A DNS copying test */
255
+struct dns_copy_test {
256
+	/** Source name */
257
+	struct dns_name src;
258
+	/** Expected copied name */
259
+	struct dns_name dst;
260
+};
261
+
262
+/**
263
+ * Define a DNS copying test
264
+ *
265
+ * @v _name		Test name
266
+ * @v _src_data		Source RFC1035-encoded data
267
+ * @v _src_offset	Starting offset within source encoded data
268
+ * @v _dst_data		Expected copied RFC1035-encoded data
269
+ * @v _dst_offset	Starting offset withint copied encoded data
270
+ * @ret test		DNS copying test
271
+ */
272
+#define DNS_COPY( _name, _src_data, _src_offset, _dst_data,		\
273
+		  _dst_offset )						\
274
+	static uint8_t _name ## __src_data[] = _src_data;		\
275
+	static uint8_t _name ## __dst_data[] = _dst_data;		\
276
+	static struct dns_copy_test _name = {				\
277
+		.src = {						\
278
+			.data = _name ## __src_data,			\
279
+			.offset = _src_offset,				\
280
+			.len = sizeof ( _name ## __src_data ),		\
281
+		},							\
282
+		.dst = {						\
283
+			.data = _name ## __dst_data,			\
284
+			.offset = _dst_offset,				\
285
+			.len = sizeof ( _name ## __dst_data ),		\
286
+		},							\
287
+	}
288
+
289
+/**
290
+ * Report a DNS copying test result
291
+ *
292
+ * @v test		DNS copying test
293
+ * @v file		Test code file
294
+ * @v line		Test code line
295
+ */
296
+static void dns_copy_okx ( struct dns_copy_test *test,
297
+			   const char *file, unsigned int line ) {
298
+	uint8_t data[ test->dst.len ];
299
+	struct dns_name dst;
300
+	int len;
301
+
302
+	/* Check ability to determine length with no buffer */
303
+	memset ( &dst, 0, sizeof ( dst ) );
304
+	len = dns_copy ( &test->src, &dst );
305
+	okx ( len >= 0, file, line );
306
+	okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ),
307
+	      file, line );
308
+
309
+	/* Check copied name */
310
+	dst.data = data;
311
+	dst.offset = test->dst.offset;
312
+	dst.len = sizeof ( data );
313
+	memcpy ( dst.data, test->dst.data, test->dst.offset );
314
+	len = dns_copy ( &test->src, &dst );
315
+	okx ( len >= 0, file, line );
316
+	okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ),
317
+	      file, line );
318
+	okx ( memcmp ( data, test->dst.data, sizeof ( data ) ) == 0,
319
+	      file, line );
320
+	DBGC ( test, "DNS copied:\n" );
321
+	DBGC_HDA ( test, 0, test->src.data, test->src.len );
322
+	DBGC_HDA ( test, 0, data, ( test->dst.offset + len ) );
323
+}
324
+#define dns_copy_ok( test ) dns_copy_okx ( test, __FILE__, __LINE__ )
325
+
326
+/**
327
+ * Report a DNS copying failure test result
328
+ *
329
+ * @v test		DNS copying test
330
+ * @v file		Test code file
331
+ * @v line		Test code line
332
+ */
333
+static void dns_copy_fail_okx ( struct dns_copy_test *test,
334
+				const char *file, unsigned int line ) {
335
+	struct dns_name dst;
336
+	int len;
337
+
338
+	memset ( &dst, 0, sizeof ( dst ) );
339
+	len = dns_copy ( &test->src, &dst );
340
+	okx ( len < 0, file, line );
341
+}
342
+#define dns_copy_fail_ok( test ) dns_copy_fail_okx ( test, __FILE__, __LINE__ )
343
+
344
+/** A DNS search list test */
345
+struct dns_list_test {
346
+	/** Search list */
347
+	struct dns_name list;
348
+	/** Expected decoded search list */
349
+	const char **strings;
350
+	/** Number of expected decoded string */
351
+	unsigned int count;
352
+};
353
+
354
+/**
355
+ * Define a DNS search list test
356
+ *
357
+ * @v _name		Test name
358
+ * @v _list		RFC1035-encoded data
359
+ * @v _strings		Expected decoded strings
360
+ * @ret test		DNS search list test
361
+ */
362
+#define DNS_LIST( _name, _list, _strings )				\
363
+	static uint8_t _name ## __list[] = _list;			\
364
+	static const char * _name ## __strings[] = _strings;		\
365
+	static struct dns_list_test _name = {				\
366
+		.list = {						\
367
+			.data = _name ## __list,			\
368
+			.offset = 0,					\
369
+			.len = sizeof ( _name ## __list ),		\
370
+		},							\
371
+		.strings = _name ## __strings,				\
372
+		.count = ( sizeof ( _name ## __strings ) /		\
373
+			   sizeof ( _name ## __strings[0] ) ),		\
374
+	}
375
+
376
+/**
377
+ * Report DNS search list test result
378
+ *
379
+ * @v test		DNS search list test
380
+ * @v file		Test code file
381
+ * @v line		Test code line
382
+ */
383
+static void dns_list_okx ( struct dns_list_test *test, const char *file,
384
+			   unsigned int line ) {
385
+	struct dns_name name;
386
+	unsigned int i;
387
+
388
+	DBGC ( test, "DNS search list:\n" );
389
+	DBGC_HDA ( test, 0, test->list.data, test->list.len );
390
+	memcpy ( &name, &test->list, sizeof ( name ) );
391
+	for ( i = 0 ; i < test->count ; i++ ) {
392
+		char buf[ strlen ( test->strings[i] ) + 1 /* NUL */ ];
393
+		int len;
394
+		int offset;
395
+
396
+		/* Decode this name */
397
+		len = dns_decode ( &name, buf, sizeof ( buf ) );
398
+		okx ( len >= 0, file, line );
399
+		if ( len >= 0 ) {
400
+			okx ( len == ( ( int ) strlen ( test->strings[i] ) ),
401
+			      file, line );
402
+			okx ( strcmp ( buf, test->strings[i] ) == 0,
403
+			      file, line );
404
+			DBGC ( test, "DNS search list found \"%s\" at offset "
405
+			       "%#zx\n", buf, name.offset );
406
+		}
407
+
408
+		/* Skip to next name */
409
+		offset = dns_skip ( &name );
410
+		okx ( offset >= 0, file, line );
411
+		name.offset = offset;
412
+	}
413
+
414
+	/* Check that we have consumed the whole search list */
415
+	okx ( name.offset == name.len, file, line );
416
+}
417
+#define dns_list_ok( test ) dns_list_okx ( test, __FILE__, __LINE__ )
418
+
419
+/* Simple encoding test */
420
+DNS_ENCODE ( encode_simple, "ipxe.org",
421
+	     DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ) );
422
+
423
+/* Single-word encoding test */
424
+DNS_ENCODE ( encode_single, "foo", DATA ( 3, 'f', 'o', 'o', 0 ) );
425
+
426
+/* Absolute encoding test */
427
+DNS_ENCODE ( encode_absolute, "git.ipxe.org.",
428
+	     DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g',
429
+		    0 ) );
430
+
431
+/* Empty string encoding test */
432
+DNS_ENCODE ( encode_empty, "", DATA ( 0 ) );
433
+
434
+/* Root domain encoding test */
435
+DNS_ENCODE ( encode_root, ".", DATA ( 0 ) );
436
+
437
+/* Invalid initial dot encoding test */
438
+DNS_ENCODE ( encode_initial_dot, ".foo", DATA() );
439
+
440
+/* Invalid double dot encoding test */
441
+DNS_ENCODE ( encode_double_dot, "ipxe..org", DATA() );
442
+
443
+/* Invalid solo double dot encoding test */
444
+DNS_ENCODE ( encode_solo_double_dot, "..", DATA() );
445
+
446
+/* Invalid trailing double dot encoding test */
447
+DNS_ENCODE ( encode_trailing_double_dot, "ipxe.org..", DATA() );
448
+
449
+/* Invalid overlength label encoding test */
450
+DNS_ENCODE ( encode_overlength,
451
+	     "this-label-is-maliciously-long-in-an-attempt-to-overflow-the-"
452
+	     "length-field-and-generate-a-length-which-looks-like-a-"
453
+	     "compression-pointer", DATA() );
454
+
455
+/* Simple decoding test */
456
+DNS_DECODE ( decode_simple,
457
+	     DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
458
+	     "ipxe.org" );
459
+
460
+/* Compression pointer decoding test */
461
+DNS_DECODE ( decode_ptr,
462
+	     DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x',
463
+		    'e', 0xc0, 0x00 ), 5,
464
+	     "git.ipxe.org" );
465
+
466
+/* Root decoding test */
467
+DNS_DECODE ( decode_root,
468
+	     DATA ( 0 ), 0, "" );
469
+
470
+/* Incomplete name decoding test */
471
+DNS_DECODE ( decode_incomplete_name,
472
+	     DATA ( 4, 'i', 'p', 'x', 'e' ), 0, NULL );
473
+
474
+/* Incomplete label decoding test */
475
+DNS_DECODE ( decode_incomplete_label,
476
+	     DATA ( 4, 'i', 'p', 'x' ), 0, NULL );
477
+
478
+/* Incomplete compression pointer decoding test */
479
+DNS_DECODE ( decode_incomplete_ptr,
480
+	     DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e', 0xc0 ), 5,
481
+	     NULL );
482
+
483
+/* Forward reference decoding test */
484
+DNS_DECODE ( decode_forward,
485
+	     DATA ( 0xc0, 0x02, 3, 'f', 'o', 'o', 0 ), 0, NULL );
486
+
487
+/* Infinite loop decoding test */
488
+DNS_DECODE ( decode_infinite,
489
+	     DATA ( 4, 'i', 'p', 'x', 'e', 0xc0, 0x00 ), 0, NULL );
490
+
491
+/* Empty decoding test */
492
+DNS_DECODE ( decode_empty,
493
+	     DATA (), 0, NULL );
494
+
495
+/* Simple comparison test */
496
+DNS_COMPARE ( compare_simple,
497
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
498
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
499
+
500
+/* Compression pointer comparison test */
501
+DNS_COMPARE ( compare_ptr,
502
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
503
+	      DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e',
504
+		     0xc0, 0x00 ), 5 );
505
+
506
+/* Case insensitive comparison test */
507
+DNS_COMPARE ( compare_case,
508
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
509
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'O', 'R', 'G', 0 ), 0 );
510
+
511
+/* Mismatch comparison test */
512
+DNS_COMPARE ( compare_mismatch,
513
+	      DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
514
+	      DATA ( 4, 'g', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
515
+
516
+/* Infinite loop comparison test */
517
+DNS_COMPARE ( compare_infinite,
518
+	      DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0,
519
+	      DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0 );
520
+
521
+/* Simple copying test */
522
+DNS_COPY ( copy_simple,
523
+	   DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
524
+	   DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
525
+
526
+/* Simple copying test with offset */
527
+DNS_COPY ( copy_offset,
528
+	   DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
529
+	   DATA ( 'f', 'o', 'o', 0, 4, 'i', 'p', 'x', 'e',
530
+		  3, 'o', 'r', 'g', 0 ), 4 );
531
+
532
+/* Compression pointer copying test */
533
+DNS_COPY ( copy_ptr,
534
+	   DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e',
535
+		  0xc0, 0x00 ), 5,
536
+	   DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g',
537
+		  0 ), 0 );
538
+
539
+/* Infinite loop copying test */
540
+DNS_COPY ( copy_infinite,
541
+	   DATA ( 4, 'l', 'o', 'o', 'p', 7, 'f', 'o', 'r', 'e', 'v', 'e', 'r',
542
+		  0xc0, 0x05 ), 0,
543
+	   DATA (), 0 );
544
+
545
+/* DNS search list test */
546
+DNS_LIST ( search,
547
+	   DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0,
548
+		  4, 'b', 'o', 'o', 't', 0xc0, 0x00,
549
+		  3, 'd', 'e', 'v', 0xc0, 0x0a,
550
+		  11, 'n', 'e', 't', 'w', 'o', 'r', 'k', 'b', 'o', 'o', 't',
551
+		  0xc0, 0x05 ),
552
+	   DATA ( "ipxe.org", "boot.ipxe.org", "dev.boot.ipxe.org",
553
+		  "networkboot.org" ) );
554
+
555
+/**
556
+ * Perform DNS self-test
557
+ *
558
+ */
559
+static void dns_test_exec ( void ) {
560
+
561
+	/* Encoding tests */
562
+	dns_encode_ok ( &encode_simple );
563
+	dns_encode_ok ( &encode_single );
564
+	dns_encode_ok ( &encode_absolute );
565
+	dns_encode_ok ( &encode_empty );
566
+	dns_encode_ok ( &encode_root );
567
+	dns_encode_fail_ok ( &encode_initial_dot );
568
+	dns_encode_fail_ok ( &encode_double_dot );
569
+	dns_encode_fail_ok ( &encode_solo_double_dot );
570
+	dns_encode_fail_ok ( &encode_trailing_double_dot );
571
+	dns_encode_fail_ok ( &encode_overlength );
572
+
573
+	/* Decoding tests */
574
+	dns_decode_ok ( &decode_simple );
575
+	dns_decode_ok ( &decode_ptr );
576
+	dns_decode_ok ( &decode_root );
577
+	dns_decode_fail_ok ( &decode_incomplete_name );
578
+	dns_decode_fail_ok ( &decode_incomplete_label );
579
+	dns_decode_fail_ok ( &decode_incomplete_ptr );
580
+	dns_decode_fail_ok ( &decode_forward );
581
+	dns_decode_fail_ok ( &decode_infinite );
582
+	dns_decode_fail_ok ( &decode_empty );
583
+
584
+	/* Comparison tests */
585
+	dns_compare_ok ( &compare_simple );
586
+	dns_compare_ok ( &compare_ptr );
587
+	dns_compare_ok ( &compare_case );
588
+	dns_compare_fail_ok ( &compare_mismatch );
589
+	dns_compare_fail_ok ( &compare_infinite );
590
+
591
+	/* Copying tests */
592
+	dns_copy_ok ( &copy_simple );
593
+	dns_copy_ok ( &copy_offset );
594
+	dns_copy_ok ( &copy_ptr );
595
+	dns_copy_fail_ok ( &copy_infinite );
596
+
597
+	/* Search list tets */
598
+	dns_list_ok ( &search );
599
+}
600
+
601
+/** DNS self-test */
602
+struct self_test dns_test __self_test = {
603
+	.name = "dns",
604
+	.exec = dns_test_exec,
605
+};

+ 1
- 0
src/tests/tests.c View File

@@ -52,3 +52,4 @@ REQUIRE_OBJECT ( cms_test );
52 52
 REQUIRE_OBJECT ( pnm_test );
53 53
 REQUIRE_OBJECT ( deflate_test );
54 54
 REQUIRE_OBJECT ( png_test );
55
+REQUIRE_OBJECT ( dns_test );

Loading…
Cancel
Save