chiark / gitweb /
sd-dhcp-client: only verify UDP messages
[elogind.git] / src / libsystemd-network / sd-dhcp-client.c
index d8a9d20e4c9ed9cda262d8dbaf132c5fd92fddbe..64c67b477c5a2bfd4ded4ae90209786002291f93 100644 (file)
@@ -48,6 +48,7 @@ struct sd_dhcp_client {
         int fd;
         union sockaddr_union link;
         sd_event_source *receive_message;
+        bool request_broadcast;
         uint8_t *req_opts;
         size_t req_opts_allocated;
         size_t req_opts_size;
@@ -57,6 +58,7 @@ struct sd_dhcp_client {
                 struct ether_addr mac_addr;
         } _packed_ client_id;
         char *hostname;
+        char *vendor_class_identifier;
         uint32_t xid;
         usec_t start_time;
         uint16_t secs;
@@ -95,6 +97,14 @@ int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
         return 0;
 }
 
+int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
+        assert_return(client, -EINVAL);
+
+        client->request_broadcast = !!broadcast;
+
+        return 0;
+}
+
 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
         size_t i;
 
@@ -200,6 +210,23 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
         return 0;
 }
 
+int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
+                                               const char *vci) {
+        char *new_vci = NULL;
+
+        assert_return(client, -EINVAL);
+
+        new_vci = strdup(vci);
+        if (!new_vci)
+                return -ENOMEM;
+
+        free(client->vendor_class_identifier);
+
+        client->vendor_class_identifier = new_vci;
+
+        return 0;
+}
+
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         assert_return(client, -EINVAL);
         assert_return(ret, -EINVAL);
@@ -304,8 +331,13 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
            BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
            DHCPREQUEST messages that client sends.  The BROADCAST bit will
            provide a hint to the DHCP server and BOOTP relay agent to broadcast
-           any messages to the client on the client's subnet. */
-        packet->dhcp.flags = htobe16(0x8000);
+           any messages to the client on the client's subnet.
+
+           Note: some interfaces needs this to be enabled, but some networks
+           needs this to be disabled as broadcasts are filteretd, so this
+           needs to be configurable */
+        if (client->request_broadcast)
+                packet->dhcp.flags = htobe16(0x8000);
 
         /* RFC2132 section 4.1.1:
            The client MUST include its hardware address in the â€™chaddr’ field, if
@@ -380,7 +412,7 @@ static int client_send_discover(sd_dhcp_client *client) {
 
         /* See RFC2131 section 4.4.1 */
 
-        r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
+        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
                 return r;
         assert(time_now >= client->start_time);
@@ -419,6 +451,15 @@ static int client_send_discover(sd_dhcp_client *client) {
                         return r;
         }
 
+        if (client->vendor_class_identifier) {
+                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                                       DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
+                                       strlen(client->vendor_class_identifier),
+                                       client->vendor_class_identifier);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -571,7 +612,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         assert(client);
         assert(client->event);
 
-        r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
+        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
                 goto error;
 
@@ -633,7 +674,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
 
         r = sd_event_add_time(client->event,
                               &client->timeout_resend,
-                              CLOCK_MONOTONIC,
+                              clock_boottime_or_monotonic(),
                               next_timeout, 10 * USEC_PER_MSEC,
                               client_timeout_resend, client);
         if (r < 0)
@@ -721,7 +762,7 @@ static int client_initialize_events(sd_dhcp_client *client,
 
         r = sd_event_add_time(client->event,
                               &client->timeout_resend,
-                              CLOCK_MONOTONIC,
+                              clock_boottime_or_monotonic(),
                               0, 0,
                               client_timeout_resend, client);
         if (r < 0)
@@ -751,7 +792,7 @@ static int client_start(sd_dhcp_client *client) {
 
         client->xid = random_u32();
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
         if (r < 0) {
                 client_stop(client, r);
                 return r;
@@ -759,7 +800,7 @@ static int client_start(sd_dhcp_client *client) {
         client->fd = r;
 
         if (client->state == DHCP_STATE_INIT) {
-                client->start_time = now(CLOCK_MONOTONIC);
+                client->start_time = now(clock_boottime_or_monotonic());
                 client->secs = 0;
         }
 
@@ -795,7 +836,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         client->state = DHCP_STATE_REBINDING;
         client->attempt = 1;
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
         if (r < 0) {
                 client_stop(client, r);
                 return 0;
@@ -965,7 +1006,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
         if (client->lease->lifetime == 0xffffffff)
                 return 0;
 
-        r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
+        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
                 return r;
         assert(client->request_sent <= time_now);
@@ -1016,7 +1057,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
 
         /* arm lifetime timeout */
         r = sd_event_add_time(client->event, &client->timeout_expire,
-                              CLOCK_MONOTONIC,
+                              clock_boottime_or_monotonic(),
                               lifetime_timeout, 10 * USEC_PER_MSEC,
                               client_timeout_expire, client);
         if (r < 0)
@@ -1038,7 +1079,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
         /* arm T2 timeout */
         r = sd_event_add_time(client->event,
                               &client->timeout_t2,
-                              CLOCK_MONOTONIC,
+                              clock_boottime_or_monotonic(),
                               t2_timeout,
                               10 * USEC_PER_MSEC,
                               client_timeout_t2, client);
@@ -1061,7 +1102,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
         /* arm T1 timeout */
         r = sd_event_add_time(client->event,
                               &client->timeout_t1,
-                              CLOCK_MONOTONIC,
+                              clock_boottime_or_monotonic(),
                               t1_timeout, 10 * USEC_PER_MSEC,
                               client_timeout_t1, client);
         if (r < 0)
@@ -1088,35 +1129,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
         assert(client->event);
         assert(message);
 
-        if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
-                log_dhcp_client(client, "not a DHCP message: ignoring");
-                return 0;
-        }
-
-        if (message->op != BOOTREPLY) {
-                log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
-                return 0;
-        }
-
-        if (be32toh(message->xid) != client->xid) {
-                log_dhcp_client(client, "received xid (%u) does not match "
-                                "expected (%u): ignoring",
-                                be32toh(message->xid), client->xid);
-                return 0;
-        }
-
-        if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
-                log_dhcp_client(client, "not an ethernet packet");
-                return 0;
-        }
-
-        if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
-                   ETH_ALEN)) {
-                log_dhcp_client(client, "received chaddr does not match "
-                                "expected: ignoring");
-                return 0;
-        }
-
         switch (client->state) {
         case DHCP_STATE_SELECTING:
 
@@ -1131,7 +1143,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
 
                         r = sd_event_add_time(client->event,
                                               &client->timeout_resend,
-                                              CLOCK_MONOTONIC,
+                                              clock_boottime_or_monotonic(),
                                               0, 0,
                                               client_timeout_resend, client);
                         if (r < 0)
@@ -1249,8 +1261,39 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
                 log_dhcp_client(client, "could not receive message from UDP "
                                 "socket: %m");
                 return 0;
-        } else if ((size_t)len < sizeof(DHCPMessage))
+        } else if ((size_t)len < sizeof(DHCPMessage)) {
+                log_dhcp_client(client, "too small to be a DHCP message: ignoring");
+                return 0;
+        }
+
+        if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
+                log_dhcp_client(client, "not a DHCP message: ignoring");
+                return 0;
+        }
+
+        if (message->op != BOOTREPLY) {
+                log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
+                return 0;
+        }
+
+        if (be32toh(message->xid) != client->xid) {
+                log_dhcp_client(client, "received xid (%u) does not match "
+                                "expected (%u): ignoring",
+                                be32toh(message->xid), client->xid);
+                return 0;
+        }
+
+        if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
+                log_dhcp_client(client, "not an ethernet packet");
+                return 0;
+        }
+
+        if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
+                   ETH_ALEN)) {
+                log_dhcp_client(client, "received chaddr does not match "
+                                "expected: ignoring");
                 return 0;
+        }
 
         return client_handle_message(client, message, len);
 }
@@ -1406,6 +1449,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
 
                 free(client->req_opts);
                 free(client->hostname);
+                free(client->vendor_class_identifier);
                 free(client);
         }