84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/***
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering This file is part of systemd.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is free software; you can redistribute it and/or modify it
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering under the terms of the GNU Lesser General Public License as published by
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering (at your option) any later version.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is distributed in the hope that it will be useful, but
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Lesser General Public License for more details.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering You should have received a copy of the GNU Lesser General Public License
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering***/
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <errno.h>
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <netinet/in.h>
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <string.h>
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "sd-dhcp6-client.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "alloc-util.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "dhcp6-internal.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "dhcp6-protocol.h"
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "dns-domain.h"
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include "sparse-endian.h"
b11d6a7bed4d867fb9f6ff4e7eb4ab20fcdc9301Lennart Poettering#include "strv.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "unaligned.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "util.h"
b11d6a7bed4d867fb9f6ff4e7eb4ab20fcdc9301Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#define DHCP6_OPTION_IA_NA_LEN 12
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#define DHCP6_OPTION_IA_TA_LEN 4
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringtypedef struct DHCP6Option {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering be16_t code;
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger be16_t len;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering uint8_t data[];
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering} _packed_ DHCP6Option;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t optlen) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering DHCP6Option *option = (DHCP6Option*) *buf;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(buf, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(*buf, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(buflen, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return -ENOBUFS;
8372da448f3c738e0154d988538d497f7e2e1f83Filipe Brandenburger
8372da448f3c738e0154d988538d497f7e2e1f83Filipe Brandenburger option->code = htobe16(optcode);
8372da448f3c738e0154d988538d497f7e2e1f83Filipe Brandenburger option->len = htobe16(optlen);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += sizeof(DHCP6Option);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= sizeof(DHCP6Option);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger}
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburgerint dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t optlen, const void *optval) {
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger int r;
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger assert_return(optval || optlen == 0, -EINVAL);
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger r = option_append_hdr(buf, buflen, code, optlen);
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger if (r < 0)
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger return r;
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger if (optval)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(*buf, optval, optlen);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburgerint dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger uint16_t len;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering uint8_t *ia_hdr;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t ia_buflen, ia_addrlen = 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering DHCP6Address *addr;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int r;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(buf && *buf && buflen && ia, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering switch (ia->type) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering case SD_DHCP6_OPTION_IA_NA:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering len = DHCP6_OPTION_IA_NA_LEN;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering case SD_DHCP6_OPTION_IA_TA:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering len = DHCP6_OPTION_IA_TA_LEN;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering default:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return -EINVAL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (*buflen < len)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return -ENOBUFS;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek ia_hdr = *buf;
c932fb71cc90461b88ecdffe47c071d001d78fb4Shawn Landden ia_buflen = *buflen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek *buf += sizeof(DHCP6Option);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= sizeof(DHCP6Option);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(*buf, &ia->id, len);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger *buf += len;
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger *buflen -= len;
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger LIST_FOREACH(addresses, addr, ia->addresses) {
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR,
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek sizeof(addr->iaaddr));
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek if (r < 0)
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger return r;
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += sizeof(addr->iaaddr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= sizeof(addr->iaaddr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (r < 0)
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger return r;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger return 0;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger}
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
c89f52ac6938374972253d8752ed65f3af0b3ef4Lennart Poettering
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburgerstatic int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger DHCP6Option *option = (DHCP6Option*) *buf;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger uint16_t len;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger assert_return(buf, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(optcode, -EINVAL);
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger assert_return(optlen, -EINVAL);
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (*buflen < sizeof(DHCP6Option))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return -ENOMSG;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger len = be16toh(option->len);
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (len > *buflen)
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger return -ENOMSG;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger *optcode = be16toh(option->code);
c89f52ac6938374972253d8752ed65f3af0b3ef4Lennart Poettering *optlen = len;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger *buf += 4;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger *buflen -= 4;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger return 0;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger}
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburgerint dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger size_t *optlen, uint8_t **optvalue) {
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger int r;
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger assert_return(buf && buflen && optcode && optlen && optvalue, -EINVAL);
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger r = option_parse_hdr(buf, buflen, optcode, optlen);
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger if (r < 0)
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger return r;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (*optlen > *buflen)
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger return -ENOBUFS;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger *optvalue = *buf;
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger *buflen -= *optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += *optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringint dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering DHCP6IA *ia) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int r;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering uint16_t opt, status;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t iaaddr_offset;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering DHCP6Address *addr;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering uint32_t lt_t1, lt_t2, lt_valid, lt_pref, lt_min = ~0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(ia, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert_return(!ia->addresses, -EINVAL);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering switch (iatype) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering case SD_DHCP6_OPTION_IA_NA:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) +
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering sizeof(addr->iaaddr)) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -ENOBUFS;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering iaaddr_offset = DHCP6_OPTION_IA_NA_LEN;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(&ia->id, *buf, iaaddr_offset);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_t1 = be32toh(ia->lifetime_t1);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_t2 = be32toh(ia->lifetime_t2);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering log_dhcp6_client(client, "IA T1 %ds > T2 %ds",
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering lt_t1, lt_t2);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -EINVAL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering case SD_DHCP6_OPTION_IA_TA:
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) +
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering sizeof(addr->iaaddr)) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -ENOBUFS;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering iaaddr_offset = DHCP6_OPTION_IA_TA_LEN;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering memcpy(&ia->id, *buf, iaaddr_offset);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering ia->lifetime_t1 = 0;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering ia->lifetime_t2 = 0;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering break;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering default:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -ENOMSG;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering }
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering ia->type = iatype;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= iaaddr_offset;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += iaaddr_offset;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering switch (opt) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering case SD_DHCP6_OPTION_IAADDR:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering addr = new0(DHCP6Address, 1);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (!addr) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -ENOMEM;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_INIT(addresses, addr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_valid = be32toh(addr->iaaddr.lifetime_valid);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_pref = be32toh(addr->iaaddr.lifetime_valid);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (!lt_valid || lt_pref > lt_valid) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_dhcp6_client(client, "IA preferred %ds > valid %ds",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_pref, lt_valid);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering free(addr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering } else {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_PREPEND(addresses, ia->addresses, addr);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (lt_valid < lt_min)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering lt_min = lt_valid;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering case SD_DHCP6_OPTION_STATUS_CODE:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (optlen < sizeof(status))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering status = (*buf)[0] << 8 | (*buf)[1];
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (status) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_dhcp6_client(client, "IA status %d",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering status);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = -EINVAL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering goto error;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering default:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_dhcp6_client(client, "Unknown IA option %d", opt);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering break;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buflen -= optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *buf += optlen;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
if (r == -ENOMSG)
r = 0;
if (!ia->lifetime_t1 && !ia->lifetime_t2) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->lifetime_t1 = htobe32(lt_t1);
ia->lifetime_t2 = htobe32(lt_t2);
log_dhcp6_client(client, "Computed IA T1 %ds and T2 %ds as both were zero",
lt_t1, lt_t2);
}
if (*buflen)
r = -ENOMSG;
error:
*buf += *buflen;
*buflen = 0;
return r;
}
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count,
size_t *allocated) {
if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0)
return -EINVAL;
if (!GREEDY_REALLOC(*addrs, *allocated,
count * sizeof(struct in6_addr) + optlen))
return -ENOMEM;
memcpy(*addrs + count, optval, optlen);
count += optlen / sizeof(struct in6_addr);
return count;
}
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
size_t pos = 0, idx = 0;
_cleanup_free_ char **names = NULL;
int r;
assert_return(optlen > 1, -ENODATA);
assert_return(optval[optlen - 1] == '\0', -EINVAL);
while (pos < optlen) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
for (;;) {
uint8_t c;
c = optval[pos++];
if (c == 0)
/* End of name */
break;
else if (c <= 63) {
const char *label;
/* Literal label */
label = (const char *)&optval[pos];
pos += c;
if (pos > optlen)
return -EMSGSIZE;
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
r = -ENOMEM;
goto fail;
}
if (first)
first = false;
else
ret[n++] = '.';
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
goto fail;
n += r;
continue;
} else {
r = -EBADMSG;
goto fail;
}
}
if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
r = -ENOMEM;
goto fail;
}
ret[n] = 0;
r = strv_extend(&names, ret);
if (r < 0)
goto fail;
idx++;
}
*str_arr = names;
names = NULL;
return idx;
fail:
return r;
}