[systemd-devel] [PATCH 16/24] sd-dhcp6-client: Receive and parse Advertise messages
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Wed Jun 18 07:11:59 PDT 2014
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
More information about the systemd-devel
mailing list