2 * Copyright (C) 2019-2022 Internet Systems Consortium, Inc. ("ISC")
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 * Internet Systems Consortium, Inc.
18 * Newmarket, NH 03857 USA
20 * https://www.isc.org/
26 #include <omapip/omapip_p.h>
29 /* @brief Externs for dhcrelay.c functions under test */
30 extern int add_agent_options
;
31 extern int add_relay_agent_options(struct interface_info
*,
32 struct dhcp_packet
*, unsigned,
35 extern int find_interface_by_agent_option(struct dhcp_packet
*,
36 struct interface_info
**,
39 extern int strip_relay_agent_options(struct interface_info
*,
40 struct interface_info
**,
41 struct dhcp_packet
*, unsigned);
43 /* @brief Add the given option data to a DHCPv4 packet
45 * It first fills the packet.options buffer with the given pad character.
46 * Next it copies the DHCP magic cookie value into the beginning of the
47 * options buffer. Finally it appends the given data after the cookie.
49 * @param packet pointer to the packet
50 * @param data pointer to the option data to copy into the packet's options
52 * @param len length of the option data to copy
53 * @param pad byte value with which to initialize the packet's options buffer
55 * @return returns the new length of the packet
57 unsigned set_packet_options(struct dhcp_packet
*packet
,
58 unsigned char* data
, unsigned len
,
61 memset(packet
->options
, pad
, DHCP_MAX_OPTION_LEN
);
65 memcpy(packet
->options
, DHCP_OPTIONS_COOKIE
, new_len
);
68 if (new_len
> DHCP_MAX_OPTION_LEN
) {
72 memcpy(&packet
->options
[4], data
, len
);
73 return(new_len
+ DHCP_FIXED_NON_UDP
);
76 /* @brief Checks two sets of option data for equalit
78 * It constructs the expected options content by creating an options buffer
79 * filled with the pad value. Next it copies the DHCP magic cookie value
80 * into the beginning of the buffer and then appends the expected data after
81 * the cookie. It the compares this buffer to the actual buffer passed in
82 * for equality and returns the result.
84 * @param actual_options pointer to the packet::options to be checked
85 * @param expected_data pointer to the expected options data (everything after
87 * @param data_len length of the expected options data
88 * @param pad byte value with which to initialize the packet's options buffer
90 * @return zero it the sets of data match, non-zero otherwise
92 int check_with_pad(unsigned char* actual_options
,
93 unsigned char *expected_data
,
94 unsigned data_len
, unsigned char pad
) {
96 unsigned char exp_options
[DHCP_MAX_OPTION_LEN
];
99 memset(exp_options
, pad
, DHCP_MAX_OPTION_LEN
);
101 memcpy(exp_options
, DHCP_OPTIONS_COOKIE
, new_len
);
104 if (new_len
> DHCP_MAX_OPTION_LEN
) {
108 memcpy(&exp_options
[4], expected_data
, data_len
);
109 return (memcmp(actual_options
, exp_options
, DHCP_MAX_OPTION_LEN
));
112 ATF_TC(strip_relay_agent_options_test
);
114 ATF_TC_HEAD(strip_relay_agent_options_test
, tc
) {
115 atf_tc_set_md_var(tc
, "descr", "tests strip_relay-agent_options");
118 /* This Test exercises strip_relay_agent_options() function */
119 ATF_TC_BODY(strip_relay_agent_options_test
, tc
) {
121 struct interface_info ifaces
;
122 struct interface_info
*matched
;
123 struct dhcp_packet packet
;
127 memset(&ifaces
, 0x0, sizeof(ifaces
));
129 memset(&packet
, 0x0, sizeof(packet
));
132 /* Make sure an empty packet is harmless. We set add_agent_options = 1
133 * to avoid early return when it's 0. */
134 add_agent_options
= 1;
135 ret
= strip_relay_agent_options(&ifaces
, &matched
, &packet
, len
);
137 atf_tc_fail("empty packet failed");
142 * Uses valid input option data to verify that:
143 * - When add_agent_options is false, the output option data is the
144 * the same as the input option data (i.e. nothing removed)
145 * - When add_agent_options is true, 0 length relay agent option has
146 * been removed from the output option data
147 * - When add_agent_options is true, a relay agent option has
148 * been removed from the output option data
152 unsigned char input_data
[] = {
153 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
154 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */
155 0x6e, 0x70, 0x30, 0x73, 0x4f,
157 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
158 0x43, 0x00 /* Opt 0x43, len = 0 */
161 unsigned char input_data2
[] = {
162 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
163 0x52, 0x00, /* Relay Agent Option, len = 0 */
164 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
165 0x43, 0x00 /* Opt 0x43, len = 0 */
168 unsigned char output_data
[] = {
169 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
170 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
171 0x43, 0x00 /* Opt 0x43, len = 0 */
174 unsigned char pad
= 0x0;
175 len
= set_packet_options(&packet
, input_data
, sizeof(input_data
), pad
);
177 atf_tc_fail("input_data: set_packet_options failed");
180 /* When add_agent_options = 0, no change should occur */
181 add_agent_options
= 0;
182 ret
= strip_relay_agent_options(&ifaces
, &matched
, &packet
, len
);
184 atf_tc_fail("expected unchanged len %d, returned %d", len
, ret
);
187 if (check_with_pad(packet
.options
, input_data
, sizeof(input_data
),
189 atf_tc_fail("expected unchanged data, does not match");
192 /* When add_agent_options = 1, it should remove the eight byte
193 * relay agent option. */
194 add_agent_options
= 1;
196 /* Beause the inbound option data is less than the BOOTP_MIN_LEN,
197 * the output data should get padded out to BOOTP_MIN_LEN
198 * padded out to BOOTP_MIN_LEN */
199 ret
= strip_relay_agent_options(&ifaces
, &matched
, &packet
, len
);
200 if (ret
!= BOOTP_MIN_LEN
) {
201 atf_tc_fail("input_data: len of %d, returned %d",
205 if (check_with_pad(packet
.options
, output_data
, sizeof(output_data
),
207 atf_tc_fail("input_data: expected data does not match");
210 /* Now let's repeat it with a relay agent option 0 bytes in length. */
211 len
= set_packet_options(&packet
, input_data2
, sizeof(input_data2
), pad
);
213 atf_tc_fail("input_data2 set_packet_options failed");
216 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
217 * the output data should get padded out to BOOTP_MIN_LEN
218 * padded out to BOOTP_MIN_LEN */
219 ret
= strip_relay_agent_options(&ifaces
, &matched
, &packet
, len
);
220 if (ret
!= BOOTP_MIN_LEN
) {
221 atf_tc_fail("input_data2: len of %d, returned %d",
225 if (check_with_pad(packet
.options
, output_data
, sizeof(output_data
),
227 atf_tc_fail("input_data2: expected output does not match");
232 /* Verify that oversized packet filled with long options does not
235 /* We borrowed this union from discover.c:got_one() */
237 unsigned char packbuf
[4095]; /* Packet input buffer.
238 * Must be as large as largest
240 struct dhcp_packet packet
;
243 unsigned char input_data
[] = {
244 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
245 0x52, 0x00, /* Relay Agent Option, len = 0 */
246 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
247 0x43, 0x00 /* Opt 0x43, len = 0 */
250 /* We'll pad it 0xFE, that way wherever we hit for "length" we'll
251 * have length of 254. Increasing the odds we'll push over the end. */
252 unsigned char pad
= 0xFE;
253 memset(u
.packbuf
, pad
, 4095);
255 len
= set_packet_options(&u
.packet
, input_data
, sizeof(input_data
), pad
);
257 atf_tc_fail("overrun: set_packet_options failed");
260 /* Enable option stripping by setting add_agent_options = 1 */
261 add_agent_options
= 1;
263 /* strip_relay_agent_options() should detect the overrun and return 0 */
264 ret
= strip_relay_agent_options(&ifaces
, &matched
, &u
.packet
, 4095);
266 atf_tc_fail("overrun expected return len = 0, we got %d", ret
);
271 ATF_TC(add_relay_agent_options_test
);
273 ATF_TC_HEAD(add_relay_agent_options_test
, tc
) {
274 atf_tc_set_md_var(tc
, "descr", "tests agent_relay-agent_options");
277 /* This Test exercises add_relay_agent_options() function */
278 ATF_TC_BODY(add_relay_agent_options_test
, tc
) {
280 struct interface_info ifc
;
281 struct dhcp_packet packet
;
284 struct in_addr giaddr
;
286 giaddr
.s_addr
= inet_addr("192.0.1.1");
288 u_int8_t circuit_id
[] = { 0x01,0x02,0x03,0x04,0x05,0x06 };
289 u_int8_t remote_id
[] = { 0x11,0x22,0x33,0x44,0x55,0x66 };
291 memset(&ifc
, 0x0, sizeof(ifc
));
292 ifc
.circuit_id
= circuit_id
;
293 ifc
.circuit_id_len
= sizeof(circuit_id
);
294 ifc
.remote_id
= remote_id
;
295 ifc
.remote_id_len
= sizeof(remote_id
);
297 memset(&packet
, 0x0, sizeof(packet
));
300 /* Make sure an empty packet is harmless */
301 ret
= add_relay_agent_options(&ifc
, &packet
, len
, giaddr
);
303 atf_tc_fail("empty packet failed");
308 * Uses valid input option data to verify that:
309 * - When add_agent_options is false, the output option data is the
310 * the same as the input option data (i.e. nothing removed)
311 * - When add_agent_options is true, the relay agent option has
312 * been removed from the output option data
313 * - When add_agent_options is true, 0 length relay agent option has
314 * been removed from the output option data
318 unsigned char input_data
[] = {
319 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
320 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */
321 0x6e, 0x70, 0x30, 0x73, 0x4f,
322 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
323 0x43, 0x00 /* Opt 0x43, len = 0 */
326 unsigned char input_data2
[] = {
327 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
328 0x52, 0x00, /* Relay Agent Option, len = 0 */
329 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
330 0x43, 0x00 /* Opt 0x43, len = 0 */
333 unsigned char output_data
[] = {
334 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
335 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
336 0x43, 0x00, /* Opt 0x43, len = 0 */
337 0x52, 0x10, /* Relay Agent, len = 16 */
338 0x1, 0x6, /* Circuit id, len = 6 */
339 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
340 0x2, 0x6, /* Remete id, len = 6 */
341 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xff
344 unsigned char pad
= 0x0;
345 len
= set_packet_options(&packet
, input_data
, sizeof(input_data
), pad
);
347 atf_tc_fail("input_data: set_packet_options failed");
350 /* When add_agent_options = 0, no change should occur */
351 add_agent_options
= 0;
352 ret
= add_relay_agent_options(&ifc
, &packet
, len
, giaddr
);
354 atf_tc_fail("expected unchanged len %d, returned %d", len
, ret
);
357 if (check_with_pad(packet
.options
, input_data
, sizeof(input_data
),
359 atf_tc_fail("expected unchanged data, does not match");
362 /* When add_agent_options = 1, it should remove the eight byte
363 * relay agent option. */
364 add_agent_options
= 1;
366 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
367 * the output data should get padded out to BOOTP_MIN_LEN
368 * padded out to BOOTP_MIN_LEN */
369 ret
= add_relay_agent_options(&ifc
, &packet
, len
, giaddr
);
370 if (ret
!= BOOTP_MIN_LEN
) {
371 atf_tc_fail("input_data: len of %d, returned %d",
375 if (check_with_pad(packet
.options
, output_data
, sizeof(output_data
),
377 atf_tc_fail("input_data: expected data does not match");
380 /* Now let's repeat it with a relay agent option 0 bytes in length. */
381 len
= set_packet_options(&packet
, input_data2
, sizeof(input_data2
),
384 atf_tc_fail("input_data2 set_packet_options failed");
387 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
388 * the output data should get padded out to BOOTP_MIN_LEN
389 * padded out to BOOTP_MIN_LEN */
390 ret
= add_relay_agent_options(&ifc
, &packet
, len
, giaddr
);
391 if (ret
!= BOOTP_MIN_LEN
) {
392 atf_tc_fail("input_data2: len of %d, returned %d",
396 if (check_with_pad(packet
.options
, output_data
, sizeof(output_data
),
398 atf_tc_fail("input_data2: expected output does not match");
403 ATF_TC(gwaddr_override_test
);
405 ATF_TC_HEAD(gwaddr_override_test
, tc
) {
406 atf_tc_set_md_var(tc
, "descr", "tests that gateway addr (giaddr) field can be overridden");
409 extern isc_boolean_t use_fake_gw
;
410 extern struct in_addr gw
;
412 /* This basic test checks if the new gwaddr override (-g) option is disabled by default */
413 ATF_TC_BODY(gwaddr_override_test
, tc
) {
415 if (use_fake_gw
== ISC_TRUE
) {
416 atf_tc_fail("the gwaddr override should be disabled by default");
419 inet_ntop(AF_INET
, &gw
, txt
, sizeof(txt
));
420 if (strncmp(txt
, "0.0.0.0", 8) != 0) {
421 atf_tc_fail("the default gwaddr override value should be 0.0.0.0, but is %s", txt
);
426 ATF_TP_ADD_TC(tp
, strip_relay_agent_options_test
);
427 ATF_TP_ADD_TC(tp
, add_relay_agent_options_test
);
428 ATF_TP_ADD_TC(tp
, gwaddr_override_test
);
430 return (atf_no_error());