1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "sd-dhcp6-client.h"
8 #include "dhcp6-internal.h"
9 #include "event-util.h"
13 static int test_dhcp_fd
[2] = PIPE_EBADF
;
15 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
, const void *packet
, size_t len
) {
19 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
20 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_dhcp_fd
) >= 0);
21 return TAKE_FD(test_dhcp_fd
[0]);
24 static void fuzz_client(sd_dhcp6_client
*client
, const uint8_t *data
, size_t size
, DHCP6State state
) {
25 assert_se(sd_dhcp6_client_set_information_request(client
, state
== DHCP6_STATE_INFORMATION_REQUEST
) >= 0);
26 assert_se(sd_dhcp6_client_start(client
) >= 0);
28 client
->state
= state
;
30 if (size
>= sizeof(DHCP6Message
))
31 assert_se(dhcp6_client_set_transaction_id(client
, ((const DHCP6Message
*) data
)->transaction_id
) == 0);
33 /* These states does not require lease to send message. */
34 if (IN_SET(client
->state
, DHCP6_STATE_INFORMATION_REQUEST
, DHCP6_STATE_SOLICITATION
))
35 assert_se(dhcp6_client_send_message(client
) >= 0);
37 assert_se(write(test_dhcp_fd
[1], data
, size
) == (ssize_t
) size
);
39 assert_se(sd_event_run(sd_dhcp6_client_get_event(client
), UINT64_MAX
) > 0);
41 /* Check the state transition. */
42 if (client
->state
!= state
)
44 case DHCP6_STATE_INFORMATION_REQUEST
:
45 assert_se(client
->state
== DHCP6_STATE_STOPPED
);
47 case DHCP6_STATE_SOLICITATION
:
48 assert_se(IN_SET(client
->state
, DHCP6_STATE_REQUEST
, DHCP6_STATE_BOUND
));
50 case DHCP6_STATE_REQUEST
:
51 assert_se(IN_SET(client
->state
, DHCP6_STATE_BOUND
, DHCP6_STATE_SOLICITATION
));
57 /* Send message if the client has a lease. */
58 if (state
!= DHCP6_STATE_INFORMATION_REQUEST
&& sd_dhcp6_client_get_lease(client
, NULL
) >= 0) {
59 client
->state
= DHCP6_STATE_REQUEST
;
60 dhcp6_client_send_message(client
);
63 assert_se(sd_dhcp6_client_stop(client
) >= 0);
65 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
68 int LLVMFuzzerTestOneInput(const uint8_t *data
, size_t size
) {
69 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
70 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
71 _cleanup_(sd_dhcp6_option_unrefp
) sd_dhcp6_option
*v1
= NULL
, *v2
= NULL
;
72 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
73 struct in6_addr hint
= { { { 0x3f, 0xfe, 0x05, 0x01, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } };
74 static const char *v1_data
= "hogehoge", *v2_data
= "foobar";
76 if (outside_size_range(size
, 0, 65536))
79 assert_se(sd_event_new(&e
) >= 0);
80 assert_se(sd_dhcp6_client_new(&client
) >= 0);
81 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
82 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
83 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
84 dhcp6_client_set_test_mode(client
, true);
86 /* Used when sending message. */
87 assert_se(sd_dhcp6_client_set_fqdn(client
, "example.com") == 1);
88 assert_se(sd_dhcp6_client_set_request_mud_url(client
, "https://www.example.com/mudfile.json") >= 0);
89 assert_se(sd_dhcp6_client_set_request_user_class(client
, STRV_MAKE("u1", "u2", "u3")) >= 0);
90 assert_se(sd_dhcp6_client_set_request_vendor_class(client
, STRV_MAKE("v1", "v2", "v3")) >= 0);
91 assert_se(sd_dhcp6_client_set_prefix_delegation_hint(client
, 48, &hint
) >= 0);
92 assert_se(sd_dhcp6_option_new(123, v1_data
, strlen(v1_data
), 12345, &v1
) >= 0);
93 assert_se(sd_dhcp6_option_new(456, v2_data
, strlen(v2_data
), 45678, &v2
) >= 0);
94 assert_se(sd_dhcp6_client_add_vendor_option(client
, v1
) >= 0);
95 assert_se(sd_dhcp6_client_add_vendor_option(client
, v2
) >= 0);
97 fuzz_client(client
, data
, size
, DHCP6_STATE_INFORMATION_REQUEST
);
98 fuzz_client(client
, data
, size
, DHCP6_STATE_SOLICITATION
);
100 /* If size is zero, then the resend timer will be triggered at first,
101 * but in the REQUEST state the client must have a lease. */
105 fuzz_client(client
, data
, size
, DHCP6_STATE_REQUEST
);