mirror of
https://github.com/systemd/systemd.git
synced 2024-11-01 17:51:22 +03:00
commit
827661914a
@ -47,8 +47,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_
|
|||||||
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
|
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
|
||||||
const void *option, void *userdata);
|
const void *option, void *userdata);
|
||||||
|
|
||||||
int dhcp_option_parse(DHCPMessage *message, size_t len,
|
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
|
||||||
dhcp_option_cb_t cb, void *userdata);
|
|
||||||
|
|
||||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||||
uint8_t type, uint16_t arp_type, size_t optlen,
|
uint8_t type, uint16_t arp_type, size_t optlen,
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "alloc-util.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
|
||||||
#include "dhcp-internal.h"
|
#include "dhcp-internal.h"
|
||||||
|
|
||||||
static int option_append(uint8_t options[], size_t size, size_t *offset,
|
static int option_append(uint8_t options[], size_t size, size_t *offset,
|
||||||
@ -139,72 +142,84 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
|
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
|
||||||
uint8_t *message_type, dhcp_option_cb_t cb,
|
uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
uint8_t code, len;
|
uint8_t code, len;
|
||||||
|
const uint8_t *option;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
while (offset < buflen) {
|
while (offset < buflen) {
|
||||||
switch (options[offset]) {
|
code = options[offset ++];
|
||||||
case DHCP_OPTION_PAD:
|
|
||||||
offset++;
|
|
||||||
|
|
||||||
break;
|
switch (code) {
|
||||||
|
case DHCP_OPTION_PAD:
|
||||||
|
continue;
|
||||||
|
|
||||||
case DHCP_OPTION_END:
|
case DHCP_OPTION_END:
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
case DHCP_OPTION_MESSAGE_TYPE:
|
if (buflen < offset + 1)
|
||||||
if (buflen < offset + 3)
|
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
|
||||||
len = options[++offset];
|
len = options[offset ++];
|
||||||
|
|
||||||
|
if (buflen < offset + len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
option = &options[offset];
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case DHCP_OPTION_MESSAGE_TYPE:
|
||||||
if (len != 1)
|
if (len != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (message_type)
|
if (message_type)
|
||||||
*message_type = options[++offset];
|
*message_type = *option;
|
||||||
else
|
|
||||||
offset++;
|
|
||||||
|
|
||||||
offset++;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP_OPTION_OVERLOAD:
|
case DHCP_OPTION_ERROR_MESSAGE:
|
||||||
if (buflen < offset + 3)
|
if (len == 0)
|
||||||
return -ENOBUFS;
|
return -EINVAL;
|
||||||
|
|
||||||
len = options[++offset];
|
if (error_message) {
|
||||||
|
_cleanup_free_ char *string = NULL;
|
||||||
|
|
||||||
|
/* Accept a trailing NUL byte */
|
||||||
|
if (memchr(option, 0, len - 1))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
string = strndup((const char *) option, len);
|
||||||
|
if (!string)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!ascii_is_valid(string))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
free(*error_message);
|
||||||
|
*error_message = string;
|
||||||
|
string = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DHCP_OPTION_OVERLOAD:
|
||||||
if (len != 1)
|
if (len != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (overload)
|
if (overload)
|
||||||
*overload = options[++offset];
|
*overload = *option;
|
||||||
else
|
|
||||||
offset++;
|
|
||||||
|
|
||||||
offset++;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (buflen < offset + 3)
|
|
||||||
return -ENOBUFS;
|
|
||||||
|
|
||||||
code = options[offset];
|
|
||||||
len = options[++offset];
|
|
||||||
|
|
||||||
if (buflen < ++offset + len)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cb(code, len, &options[offset], userdata);
|
cb(code, len, option, userdata);
|
||||||
|
|
||||||
offset += len;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset < buflen)
|
if (offset < buflen)
|
||||||
@ -213,8 +228,8 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp_option_parse(DHCPMessage *message, size_t len,
|
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
|
||||||
dhcp_option_cb_t cb, void *userdata) {
|
_cleanup_free_ char *error_message = NULL;
|
||||||
uint8_t overload = 0;
|
uint8_t overload = 0;
|
||||||
uint8_t message_type = 0;
|
uint8_t message_type = 0;
|
||||||
int r;
|
int r;
|
||||||
@ -227,27 +242,29 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
|
|||||||
|
|
||||||
len -= sizeof(DHCPMessage);
|
len -= sizeof(DHCPMessage);
|
||||||
|
|
||||||
r = parse_options(message->options, len, &overload, &message_type,
|
r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
|
||||||
cb, userdata);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (overload & DHCP_OVERLOAD_FILE) {
|
if (overload & DHCP_OVERLOAD_FILE) {
|
||||||
r = parse_options(message->file, sizeof(message->file),
|
r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
|
||||||
NULL, &message_type, cb, userdata);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overload & DHCP_OVERLOAD_SNAME) {
|
if (overload & DHCP_OVERLOAD_SNAME) {
|
||||||
r = parse_options(message->sname, sizeof(message->sname),
|
r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
|
||||||
NULL, &message_type, cb, userdata);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message_type)
|
if (message_type == 0)
|
||||||
return message_type;
|
|
||||||
|
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
|
if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) {
|
||||||
|
*_error_message = error_message;
|
||||||
|
error_message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return message_type;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,7 @@ enum {
|
|||||||
DHCP_OPTION_MESSAGE_TYPE = 53,
|
DHCP_OPTION_MESSAGE_TYPE = 53,
|
||||||
DHCP_OPTION_SERVER_IDENTIFIER = 54,
|
DHCP_OPTION_SERVER_IDENTIFIER = 54,
|
||||||
DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
|
DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
|
||||||
|
DHCP_OPTION_ERROR_MESSAGE = 56,
|
||||||
DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
|
DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
|
||||||
DHCP_OPTION_RENEWAL_T1_TIME = 58,
|
DHCP_OPTION_RENEWAL_T1_TIME = 58,
|
||||||
DHCP_OPTION_REBINDING_T2_TIME = 59,
|
DHCP_OPTION_REBINDING_T2_TIME = 59,
|
||||||
|
@ -47,17 +47,15 @@ int icmp6_bind_router_solicitation(int index) {
|
|||||||
.ipv6mr_interface = index,
|
.ipv6mr_interface = index,
|
||||||
};
|
};
|
||||||
_cleanup_close_ int s = -1;
|
_cleanup_close_ int s = -1;
|
||||||
int r, zero = 0, hops = 255;
|
int r, zero = 0, one = 1, hops = 255;
|
||||||
|
|
||||||
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
|
||||||
IPPROTO_ICMPV6);
|
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
||||||
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
|
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter));
|
||||||
sizeof(filter));
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -65,23 +63,23 @@ int icmp6_bind_router_solicitation(int index) {
|
|||||||
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
|
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
|
||||||
Empirical experiments indicates otherwise and therefore an
|
Empirical experiments indicates otherwise and therefore an
|
||||||
IPV6_MULTICAST_IF socket option is used here instead */
|
IPV6_MULTICAST_IF socket option is used here instead */
|
||||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
|
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index));
|
||||||
sizeof(index));
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
|
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero));
|
||||||
sizeof(zero));
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
|
||||||
sizeof(hops));
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
|
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||||
sizeof(mreq));
|
if (r < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
r = setsockopt(s, SOL_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -101,25 +99,25 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
|
|||||||
struct ether_addr rs_opt_mac;
|
struct ether_addr rs_opt_mac;
|
||||||
} _packed_ rs = {
|
} _packed_ rs = {
|
||||||
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
|
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
|
||||||
|
.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR,
|
||||||
|
.rs_opt.nd_opt_len = 1,
|
||||||
};
|
};
|
||||||
struct iovec iov[1] = {
|
struct iovec iov = {
|
||||||
{ &rs, },
|
.iov_base = &rs,
|
||||||
|
.iov_len = sizeof(rs),
|
||||||
};
|
};
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_name = &dst,
|
.msg_name = &dst,
|
||||||
.msg_namelen = sizeof(dst),
|
.msg_namelen = sizeof(dst),
|
||||||
.msg_iov = iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (ether_addr) {
|
assert(s >= 0);
|
||||||
memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
|
assert(ether_addr);
|
||||||
rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
|
||||||
rs.rs_opt.nd_opt_len = 1;
|
rs.rs_opt_mac = *ether_addr;
|
||||||
iov[0].iov_len = sizeof(rs);
|
|
||||||
} else
|
|
||||||
iov[0].iov_len = sizeof(rs.rs);
|
|
||||||
|
|
||||||
r = sendmsg(s, &msg, 0);
|
r = sendmsg(s, &msg, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1082,7 +1082,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
|
r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
|
||||||
if (r != DHCP_OFFER) {
|
if (r != DHCP_OFFER) {
|
||||||
log_dhcp_client(client, "received message was not an OFFER, ignoring");
|
log_dhcp_client(client, "received message was not an OFFER, ignoring");
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
@ -1121,7 +1121,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
|
|||||||
size_t len) {
|
size_t len) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dhcp_option_parse(force, len, NULL, NULL);
|
r = dhcp_option_parse(force, len, NULL, NULL, NULL);
|
||||||
if (r != DHCP_FORCERENEW)
|
if (r != DHCP_FORCERENEW)
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
@ -1133,6 +1133,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
|
|||||||
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
|
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
|
||||||
size_t len) {
|
size_t len) {
|
||||||
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
|
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
|
||||||
|
_cleanup_free_ char *error_message = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dhcp_lease_new(&lease);
|
r = dhcp_lease_new(&lease);
|
||||||
@ -1147,9 +1148,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
|
r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
|
||||||
if (r == DHCP_NAK) {
|
if (r == DHCP_NAK) {
|
||||||
log_dhcp_client(client, "NAK");
|
log_dhcp_client(client, "NAK: %s", strna(error_message));
|
||||||
return -EADDRNOTAVAIL;
|
return -EADDRNOTAVAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1513,9 +1514,8 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
|||||||
|
|
||||||
r = ioctl(fd, FIONREAD, &buflen);
|
r = ioctl(fd, FIONREAD, &buflen);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return -errno;
|
||||||
|
else if (buflen < 0)
|
||||||
if (buflen < 0)
|
|
||||||
/* this can't be right */
|
/* this can't be right */
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
@ -1525,26 +1525,28 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
|||||||
|
|
||||||
len = read(fd, message, buflen);
|
len = read(fd, message, buflen);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
log_dhcp_client(client, "could not receive message from UDP "
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
"socket: %m");
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
log_dhcp_client(client, "Could not receive message from UDP socket: %m");
|
||||||
|
return -errno;
|
||||||
} 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");
|
log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
|
if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
|
||||||
log_dhcp_client(client, "not a DHCP message: ignoring");
|
log_dhcp_client(client, "Not a DHCP message: ignoring");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message->op != BOOTREPLY) {
|
if (message->op != BOOTREPLY) {
|
||||||
log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
|
log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message->htype != client->arp_type) {
|
if (message->htype != client->arp_type) {
|
||||||
log_dhcp_client(client, "packet type does not match client type");
|
log_dhcp_client(client, "Packet type does not match client type");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1558,13 +1560,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message->hlen != expected_hlen) {
|
if (message->hlen != expected_hlen) {
|
||||||
log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
|
log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
|
if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
|
||||||
log_dhcp_client(client, "received chaddr does not match "
|
log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
|
||||||
"expected: ignoring");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1572,8 +1573,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
|||||||
be32toh(message->xid) != client->xid) {
|
be32toh(message->xid) != client->xid) {
|
||||||
/* in BOUND state, we may receive FORCERENEW with xid set by server,
|
/* in BOUND state, we may receive FORCERENEW with xid set by server,
|
||||||
so ignore the xid in this case */
|
so ignore the xid in this case */
|
||||||
log_dhcp_client(client, "received xid (%u) does not match "
|
log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
|
||||||
"expected (%u): ignoring",
|
|
||||||
be32toh(message->xid), client->xid);
|
be32toh(message->xid), client->xid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1602,9 +1602,8 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
|
|||||||
|
|
||||||
r = ioctl(fd, FIONREAD, &buflen);
|
r = ioctl(fd, FIONREAD, &buflen);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return -errno;
|
||||||
|
else if (buflen < 0)
|
||||||
if (buflen < 0)
|
|
||||||
/* this can't be right */
|
/* this can't be right */
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
@ -1617,9 +1616,12 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
|
|||||||
|
|
||||||
len = recvmsg(fd, &msg, 0);
|
len = recvmsg(fd, &msg, 0);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
log_dhcp_client(client, "could not receive message from raw "
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
"socket: %m");
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
log_dhcp_client(client, "Could not receive message from raw socket: %m");
|
||||||
|
|
||||||
|
return -errno;
|
||||||
} else if ((size_t)len < sizeof(DHCPPacket))
|
} else if ((size_t)len < sizeof(DHCPPacket))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -661,7 +661,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_debug("Ignoring option DHCP option %i while parsing.", code);
|
log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,6 +699,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
|
|||||||
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
|
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
|
||||||
size_t length) {
|
size_t length) {
|
||||||
_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
|
_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
|
||||||
|
_cleanup_free_ char *error_message = NULL;
|
||||||
DHCPLease *existing_lease;
|
DHCPLease *existing_lease;
|
||||||
int type, r;
|
int type, r;
|
||||||
|
|
||||||
@ -714,7 +715,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
|
|||||||
if (!req)
|
if (!req)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
type = dhcp_option_parse(message, length, parse_request, req);
|
type = dhcp_option_parse(message, length, parse_request, req, &error_message);
|
||||||
if (type < 0)
|
if (type < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -784,8 +785,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DHCP_DECLINE:
|
case DHCP_DECLINE:
|
||||||
log_dhcp_server(server, "DECLINE (0x%x)",
|
log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
|
||||||
be32toh(req->message->xid));
|
|
||||||
|
|
||||||
/* TODO: make sure we don't offer this address again */
|
/* TODO: make sure we don't offer this address again */
|
||||||
|
|
||||||
@ -963,10 +963,10 @@ static int server_receive_message(sd_event_source *s, int fd,
|
|||||||
|
|
||||||
if (ioctl(fd, FIONREAD, &buflen) < 0)
|
if (ioctl(fd, FIONREAD, &buflen) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
if (buflen < 0)
|
else if (buflen < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
message = malloc0(buflen);
|
message = malloc(buflen);
|
||||||
if (!message)
|
if (!message)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -974,9 +974,12 @@ static int server_receive_message(sd_event_source *s, int fd,
|
|||||||
iov.iov_len = buflen;
|
iov.iov_len = buflen;
|
||||||
|
|
||||||
len = recvmsg(fd, &msg, 0);
|
len = recvmsg(fd, &msg, 0);
|
||||||
if (len < buflen)
|
if (len < 0) {
|
||||||
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
return 0;
|
return 0;
|
||||||
else if ((size_t)len < sizeof(DHCPMessage))
|
|
||||||
|
return -errno;
|
||||||
|
} else if ((size_t)len < sizeof(DHCPMessage))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
CMSG_FOREACH(cmsg, &msg) {
|
CMSG_FOREACH(cmsg, &msg) {
|
||||||
|
@ -895,7 +895,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
|
|||||||
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
sd_dhcp6_client *client = userdata;
|
sd_dhcp6_client *client = userdata;
|
||||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||||
_cleanup_free_ DHCP6Message *message;
|
_cleanup_free_ DHCP6Message *message = NULL;
|
||||||
int r, buflen, len;
|
int r, buflen, len;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
@ -903,18 +903,26 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||||||
assert(client->event);
|
assert(client->event);
|
||||||
|
|
||||||
r = ioctl(fd, FIONREAD, &buflen);
|
r = ioctl(fd, FIONREAD, &buflen);
|
||||||
if (r < 0 || buflen <= 0)
|
if (r < 0)
|
||||||
buflen = DHCP6_MIN_OPTIONS_SIZE;
|
return -errno;
|
||||||
|
else if (buflen < 0)
|
||||||
|
/* This really should not happen */
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
message = malloc0(buflen);
|
message = malloc(buflen);
|
||||||
if (!message)
|
if (!message)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
len = read(fd, message, buflen);
|
len = read(fd, message, buflen);
|
||||||
if ((size_t)len < sizeof(DHCP6Message)) {
|
if (len < 0) {
|
||||||
log_dhcp6_client(client, "could not receive message from UDP socket: %m");
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
} else if ((size_t)len < sizeof(DHCP6Message))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
switch(message->type) {
|
switch(message->type) {
|
||||||
case DHCP6_SOLICIT:
|
case DHCP6_SOLICIT:
|
||||||
|
@ -418,8 +418,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
|
static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) {
|
||||||
ssize_t len) {
|
|
||||||
void *opt;
|
void *opt;
|
||||||
struct nd_opt_hdr *opt_hdr;
|
struct nd_opt_hdr *opt_hdr;
|
||||||
|
|
||||||
@ -482,36 +481,79 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
|
|||||||
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
_cleanup_free_ struct nd_router_advert *ra = NULL;
|
_cleanup_free_ struct nd_router_advert *ra = NULL;
|
||||||
sd_ndisc *nd = userdata;
|
sd_ndisc *nd = userdata;
|
||||||
int r, buflen = 0, pref, stateful;
|
union {
|
||||||
union sockaddr_union router = {};
|
struct cmsghdr cmsghdr;
|
||||||
socklen_t router_len = sizeof(router);
|
uint8_t buf[CMSG_LEN(sizeof(int))];
|
||||||
|
} control = {};
|
||||||
|
struct iovec iov = {};
|
||||||
|
union sockaddr_union sa = {};
|
||||||
|
struct msghdr msg = {
|
||||||
|
.msg_name = &sa.sa,
|
||||||
|
.msg_namelen = sizeof(sa),
|
||||||
|
.msg_iov = &iov,
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_control = &control,
|
||||||
|
.msg_controllen = sizeof(control),
|
||||||
|
};
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
struct in6_addr *gw;
|
struct in6_addr *gw;
|
||||||
unsigned lifetime;
|
unsigned lifetime;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
int r, pref, stateful, buflen = 0;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(nd);
|
assert(nd);
|
||||||
assert(nd->event);
|
assert(nd->event);
|
||||||
|
|
||||||
r = ioctl(fd, FIONREAD, &buflen);
|
r = ioctl(fd, FIONREAD, &buflen);
|
||||||
if (r < 0 || buflen <= 0)
|
if (r < 0)
|
||||||
buflen = ICMP6_RECV_SIZE;
|
return -errno;
|
||||||
|
else if (buflen < 0)
|
||||||
|
/* This really should not happen */
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
ra = malloc(buflen);
|
iov.iov_len = buflen;
|
||||||
|
|
||||||
|
ra = malloc(iov.iov_len);
|
||||||
if (!ra)
|
if (!ra)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len);
|
iov.iov_base = ra;
|
||||||
|
|
||||||
|
len = recvmsg(fd, &msg, 0);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
return 0;
|
return 0;
|
||||||
} else if (router_len == 0)
|
|
||||||
|
log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
|
||||||
|
return -errno;
|
||||||
|
} else if ((size_t)len < sizeof(struct nd_router_advert)) {
|
||||||
|
return 0;
|
||||||
|
} else if (msg.msg_namelen == 0)
|
||||||
gw = NULL; /* only happens when running the test-suite over a socketpair */
|
gw = NULL; /* only happens when running the test-suite over a socketpair */
|
||||||
else if (router_len != sizeof(router.in6)) {
|
else if (msg.msg_namelen != sizeof(sa.in6)) {
|
||||||
log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len);
|
log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen);
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
gw = &router.in6.sin6_addr;
|
gw = &sa.in6.sin6_addr;
|
||||||
|
|
||||||
|
assert(!(msg.msg_flags & MSG_CTRUNC));
|
||||||
|
assert(!(msg.msg_flags & MSG_TRUNC));
|
||||||
|
|
||||||
|
CMSG_FOREACH(cmsg, &msg) {
|
||||||
|
if (cmsg->cmsg_level == SOL_IPV6 &&
|
||||||
|
cmsg->cmsg_type == IPV6_HOPLIMIT &&
|
||||||
|
cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
|
||||||
|
int hops = *(int*)CMSG_DATA(cmsg);
|
||||||
|
|
||||||
|
if (hops != 255) {
|
||||||
|
log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) {
|
if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) {
|
||||||
_cleanup_free_ char *addr = NULL;
|
_cleanup_free_ char *addr = NULL;
|
||||||
@ -566,8 +608,6 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
|||||||
static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
sd_ndisc *nd = userdata;
|
sd_ndisc *nd = userdata;
|
||||||
uint64_t time_now, next_timeout;
|
uint64_t time_now, next_timeout;
|
||||||
struct ether_addr unset = { };
|
|
||||||
struct ether_addr *addr = NULL;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
@ -581,10 +621,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
|
|||||||
nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
|
nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
|
||||||
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
||||||
} else {
|
} else {
|
||||||
if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
|
r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
|
||||||
addr = &nd->mac_addr;
|
|
||||||
|
|
||||||
r = icmp6_send_router_solicitation(nd->fd, addr);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_ndisc(nd, "Error sending Router Solicitation");
|
log_ndisc(nd, "Error sending Router Solicitation");
|
||||||
else {
|
else {
|
||||||
|
@ -223,7 +223,7 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const voi
|
|||||||
static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
|
static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = dhcp_option_parse(dhcp, size, check_options, NULL);
|
res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
|
||||||
assert_se(res == DHCP_DISCOVER);
|
assert_se(res == DHCP_DISCOVER);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@ -390,7 +390,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
|
|||||||
uint8_t *msg_bytes = (uint8_t *)request;
|
uint8_t *msg_bytes = (uint8_t *)request;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = dhcp_option_parse(request, size, check_options, NULL);
|
res = dhcp_option_parse(request, size, check_options, NULL, NULL);
|
||||||
assert_se(res == DHCP_REQUEST);
|
assert_se(res == DHCP_REQUEST);
|
||||||
assert_se(xid == request->xid);
|
assert_se(xid == request->xid);
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
|
|||||||
uint8_t *msg_bytes = (uint8_t *)discover;
|
uint8_t *msg_bytes = (uint8_t *)discover;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = dhcp_option_parse(discover, size, check_options, NULL);
|
res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
|
||||||
assert_se(res == DHCP_DISCOVER);
|
assert_se(res == DHCP_DISCOVER);
|
||||||
|
|
||||||
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
|
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
|
||||||
|
@ -75,9 +75,8 @@ static const char *dhcp_type(int type) {
|
|||||||
static void test_invalid_buffer_length(void) {
|
static void test_invalid_buffer_length(void) {
|
||||||
DHCPMessage message;
|
DHCPMessage message;
|
||||||
|
|
||||||
assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
|
assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
|
||||||
assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL)
|
assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
|
||||||
== -EINVAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_message_init(void) {
|
static void test_message_init(void) {
|
||||||
@ -101,7 +100,7 @@ static void test_message_init(void) {
|
|||||||
assert_se(magic[2] == 83);
|
assert_se(magic[2] == 83);
|
||||||
assert_se(magic[3] == 99);
|
assert_se(magic[3] == 99);
|
||||||
|
|
||||||
assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0);
|
assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
|
static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
|
||||||
@ -264,19 +263,12 @@ static void test_options(struct option_desc *desc) {
|
|||||||
buflen = sizeof(DHCPMessage) + optlen;
|
buflen = sizeof(DHCPMessage) + optlen;
|
||||||
|
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
assert_se((res = dhcp_option_parse(message, buflen,
|
assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
|
||||||
test_options_cb,
|
|
||||||
NULL)) == -ENOMSG);
|
|
||||||
} else if (desc->success) {
|
} else if (desc->success) {
|
||||||
assert_se((res = dhcp_option_parse(message, buflen,
|
assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
|
||||||
test_options_cb,
|
assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
|
||||||
desc)) >= 0);
|
|
||||||
assert_se(desc->pos == -1 && desc->filepos == -1 &&
|
|
||||||
desc->snamepos == -1);
|
|
||||||
} else
|
} else
|
||||||
assert_se((res = dhcp_option_parse(message, buflen,
|
assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
|
||||||
test_options_cb,
|
|
||||||
desc)) < 0);
|
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("DHCP type %s\n", dhcp_type(res));
|
printf("DHCP type %s\n", dhcp_type(res));
|
||||||
|
Loading…
Reference in New Issue
Block a user