X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-dhcp%2Fsd-dhcp-client.c;h=01397cff398be59c3a4e1a1fee05109bf28e7688;hp=350675530466f2f472bcd2a5ab7b5a986de79e33;hb=0a1b6da82109c3b08b1f966a1625a77cc312135a;hpb=ee57a737a5b72bc3f3f46aafd2bbc452b61dcaa7 diff --git a/src/libsystemd-dhcp/sd-dhcp-client.c b/src/libsystemd-dhcp/sd-dhcp-client.c index 350675530..01397cff3 100644 --- a/src/libsystemd-dhcp/sd-dhcp-client.c +++ b/src/libsystemd-dhcp/sd-dhcp-client.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "util.h" #include "list.h" @@ -205,11 +206,17 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, size_t *optlen) { int r; - r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, - secs, opt, optlen); + assert(secs); + + r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt, + optlen); if (r < 0) return r; + /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers + refuse to issue an DHCP lease if 'secs' is set to zero */ + message->secs = htobe16(secs); + memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN); if (client->state == DHCP_STATE_RENEWING || @@ -279,7 +286,7 @@ static int client_send_discover(sd_dhcp_client *client, uint16_t secs) { if (err < 0) return err; - dhcp_packet_append_ip_headers(discover, BOOTREQUEST, len); + dhcp_packet_append_ip_headers(discover, len); err = dhcp_network_send_raw_socket(client->fd, &client->link, discover, len); @@ -332,7 +339,7 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) { &request->dhcp, len - DHCP_IP_UDP_SIZE); } else { - dhcp_packet_append_ip_headers(request, BOOTREQUEST, len); + dhcp_packet_append_ip_headers(request, len); err = dhcp_network_send_raw_socket(client->fd, &client->link, request, len); @@ -736,12 +743,30 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, assert(client->event); assert(message); - if (be32toh(message->xid) != client->xid) + if (len < DHCP_MESSAGE_SIZE) { + log_dhcp_client(client, "message too small (%d bytes): " + "ignoring", len); + 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 (memcmp(&message->chaddr[0], &client->mac_addr.ether_addr_octet, - ETHER_ADDR_LEN)) + ETHER_ADDR_LEN)) { + log_dhcp_client(client, "received chaddr does not match " + "expected: ignoring"); return 0; + } switch (client->state) { case DHCP_STATE_SELECTING: @@ -829,16 +854,23 @@ error: static int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp_client *client = userdata; - uint8_t buf[sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE]; - int buflen = sizeof(buf); - int len, r = 0; + _cleanup_free_ DHCPMessage *message = NULL; + int buflen = 0, len, r; usec_t time_now; assert(s); assert(client); assert(client->event); - len = read(fd, &buf, buflen); + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE; + + message = malloc0(buflen); + if (!message) + return -ENOMEM; + + len = read(fd, message, buflen); if (len < 0) return 0; @@ -846,34 +878,36 @@ static int client_receive_message_udp(sd_event_source *s, int fd, if (r < 0) return client_stop(client, r); - return client_handle_message(client, (DHCPMessage *) buf, len, + return client_handle_message(client, message, len, time_now); } static int client_receive_message_raw(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp_client *client = userdata; - uint8_t buf[sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE]; - int buflen = sizeof(buf); - int len, r = 0; - DHCPPacket *packet; + _cleanup_free_ DHCPPacket *packet = NULL; + int buflen = 0, len, r; usec_t time_now; assert(s); assert(client); assert(client->event); - len = read(fd, &buf, buflen); + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE; + + packet = malloc0(buflen); + if (!packet) + return -ENOMEM; + + len = read(fd, packet, buflen); if (len < 0) return 0; - packet = (DHCPPacket *) buf; - - r = dhcp_packet_verify_headers(packet, BOOTREPLY, len); - if (r < 0) { - log_dhcp_client(client, "ignoring DHCP packet with invalid headers"); + r = dhcp_packet_verify_headers(packet, len); + if (r < 0) return 0; - } len -= DHCP_IP_UDP_SIZE;