On Fri, Jun 13, 2014 at 04:45:06PM +0300, Patrik Flykt wrote: > When receiving DHCPv6 messages, discard the ones that are not meant > for DHCPv6 clients and verify the transaction id. Once that is done, > process the Advertise message and select the Advertise with the > highest preference. > > Create a separate function for lease information parsing so that it > can be reused in other parts of the protocol. Verify both DUID and > IAID in the received message and store other necessary information > with the lease structure. > --- > src/libsystemd-network/dhcp6-internal.h | 2 + > src/libsystemd-network/dhcp6-protocol.h | 6 + > src/libsystemd-network/sd-dhcp6-client.c | 219 > ++++++++++++++++++++++++++++++- > 3 files changed, 225 insertions(+), 2 deletions(-) > > diff --git a/src/libsystemd-network/dhcp6-internal.h > b/src/libsystemd-network/dhcp6-internal.h > index ec1d82a..94e3a5d 100644 > --- a/src/libsystemd-network/dhcp6-internal.h > +++ b/src/libsystemd-network/dhcp6-internal.h > @@ -75,3 +75,5 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr > *address, > > const char *dhcp6_message_type_to_string(int s) _const_; > int dhcp6_message_type_from_string(const char *s) _pure_; > +const char *dhcp6_message_status_to_string(int s) _const_; > +int dhcp6_message_status_from_string(const char *s) _pure_; > diff --git a/src/libsystemd-network/dhcp6-protocol.h > b/src/libsystemd-network/dhcp6-protocol.h > index de100d7..e8df509 100644 > --- a/src/libsystemd-network/dhcp6-protocol.h > +++ b/src/libsystemd-network/dhcp6-protocol.h > @@ -21,6 +21,9 @@ > along with systemd; If not, see <http://www.gnu.org/licenses/>. > ***/ > > +#include <netinet/ip6.h> > +#include <netinet/udp.h> > + > #include "macro.h" > #include "sparse-endian.h" > > @@ -36,6 +39,9 @@ struct DHCP6Message { > > typedef struct DHCP6Message DHCP6Message; > > +#define DHCP6_MIN_OPTIONS_SIZE \ > + 1280 - sizeof(struct ip6_hdr) - sizeof(struct udphdr) > + > #define IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT \ > { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ > 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } } > diff --git a/src/libsystemd-network/sd-dhcp6-client.c > b/src/libsystemd-network/sd-dhcp6-client.c > index bdd9177..a18698c 100644 > --- a/src/libsystemd-network/sd-dhcp6-client.c > +++ b/src/libsystemd-network/sd-dhcp6-client.c > @@ -21,6 +21,7 @@ > > #include <errno.h> > #include <string.h> > +#include <sys/ioctl.h> > > #include "udev.h" > #include "udev-util.h" > @@ -34,6 +35,7 @@ > #include "dhcp6-protocol.h" > #include "dhcp6-internal.h" > #include "icmp6-nd.h" > +#include "dhcp6-lease-internal.h" > > #define SYSTEMD_PEN 43793 > #define HASH_KEY > SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) > @@ -49,6 +51,7 @@ struct sd_dhcp6_client { > icmp6_nd *ra; > DHCP6IA ia_na; > be32_t transaction_id; > + struct sd_dhcp6_lease *lease; > int fd; > sd_event_source *receive_message; > usec_t retransmit_time; > @@ -83,6 +86,17 @@ const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] > = { > > DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int); > > +const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = { > + [DHCP6_STATUS_SUCCESS] = "Success", > + [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure", > + [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available", > + [DHCP6_STATUS_NO_BINDING] = "Binding unavailable", > + [DHCP6_STATUS_NOT_ON_LINK] = "Not on link", > + [DHCP6_STATUS_USE_MULTICAST] = "Use multicast", > +}; > + > +DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); > + > int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, > sd_dhcp6_client_cb_t cb, void *userdata) > { > @@ -381,9 +395,210 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { > return 0; > } > > +static int client_parse_message(sd_dhcp6_client *client, > + DHCP6Message *message, size_t len, > + sd_dhcp6_lease *lease) { > + int r; > + uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL; > + uint16_t optcode, status; > + size_t optlen, id_len; > + bool clientid = false; > + be32_t iaid_lease; > + > + while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, > + &optval)) >= 0) { > + switch (optcode) { > + case DHCP6_OPTION_CLIENTID: > + if (clientid) { > + log_dhcp6_client(client, "%s contains > multiple clientids", > + > dhcp6_message_type_to_string(message->type)); > + return -EINVAL; > + } > + > + if (optlen != sizeof(client->duid) || > + memcmp(&client->duid, optval, optlen) != 0) { > + log_dhcp6_client(client, "%s DUID does not > match", > + > dhcp6_message_type_to_string(message->type)); > + > + return -EINVAL; > + } > + clientid = true; > + > + break; > + > + case DHCP6_OPTION_SERVERID: > + r = dhcp6_lease_get_serverid(lease, &id, &id_len); > + if (r >= 0 && id) { > + log_dhcp6_client(client, "%s contains > multiple serverids", > + > dhcp6_message_type_to_string(message->type)); > + return -EINVAL; > + } > + > + r = dhcp6_lease_set_serverid(lease, optval, optlen); > + if (r < 0) > + return r; > + > + break; > + > + case DHCP6_OPTION_PREFERENCE: > + if (optlen != 1) > + return -EINVAL; > + > + r = dhcp6_lease_set_preference(lease, *optval); > + if (r < 0) > + return r; > + > + break; > + > + case DHCP6_OPTION_STATUS_CODE: > + if (optlen < 2) > + return -EINVAL; > + > + status = optval[0] << 8 | optval[1]; > + if (status) { > + log_dhcp6_client(client, "%s Status %s", > + > dhcp6_message_type_to_string(message->type), > + > dhcp6_message_status_to_string(status)); > + return -EINVAL; > + } > + > + break; > + > + case DHCP6_OPTION_IA_NA: > + r = dhcp6_option_parse_ia(&optval, &optlen, optcode, > + &lease->ia); > + if (r < 0 && r != -ENOMSG) > + return r; > + > + r = dhcp6_lease_get_iaid(lease, &iaid_lease); > + if (r < 0) > + return r; > + > + if (client->ia_na.id != iaid_lease) { > + log_dhcp6_client(client, "%s has wrong IAID", > + > dhcp6_message_type_to_string(message->type)); > + return -EINVAL; > + } > + > + break; > + } > + } > + > + if ((r < 0 && r != -ENOMSG) || !clientid) { > + log_dhcp6_client(client, "%s has incomplete options", > + > dhcp6_message_type_to_string(message->type)); > + return -EINVAL; > + } > + > + r = dhcp6_lease_get_serverid(lease, &id, &id_len); > + if (r < 0) > + log_dhcp6_client(client, "%s has no server id", > + > dhcp6_message_type_to_string(message->type)); > + > +return r; Indentation.
> +} > + > +static int client_receive_advertise(sd_dhcp6_client *client, > + DHCP6Message *advertise, size_t len) { > + int r; Zbyszek _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel