Blame src/systemd/src/libsystemd-network/sd-dhcp6-lease.c

Packit Service b23acc
/* SPDX-License-Identifier: LGPL-2.1+ */
Packit Service b23acc
/***
Packit Service b23acc
  Copyright © 2014-2015 Intel Corporation. All rights reserved.
Packit Service b23acc
***/
Packit Service b23acc
Packit Service b23acc
#include "nm-sd-adapt-core.h"
Packit Service b23acc
Packit Service b23acc
#include <errno.h>
Packit Service b23acc
Packit Service b23acc
#include "alloc-util.h"
Packit Service b23acc
#include "dhcp6-lease-internal.h"
Packit Service b23acc
#include "dhcp6-protocol.h"
Packit Service b23acc
#include "strv.h"
Packit Service b23acc
#include "util.h"
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
Packit Service b23acc
        DHCP6Address *addr;
Packit Service b23acc
        uint32_t valid = 0, t;
Packit Service b23acc
Packit Service b23acc
        assert_return(ia, -EINVAL);
Packit Service b23acc
        assert_return(expire, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        LIST_FOREACH(addresses, addr, ia->addresses) {
Packit Service b23acc
                t = be32toh(addr->iaaddr.lifetime_valid);
Packit Service b23acc
                if (valid < t)
Packit Service b23acc
                        valid = t;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        t = be32toh(ia->ia_na.lifetime_t2);
Packit Service b23acc
        if (t > valid)
Packit Service b23acc
                return -EINVAL;
Packit Service b23acc
Packit Service b23acc
        *expire = valid - t;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
Packit Service b23acc
        DHCP6Address *address;
Packit Service b23acc
Packit Service b23acc
        if (!ia)
Packit Service b23acc
                return NULL;
Packit Service b23acc
Packit Service b23acc
        while (ia->addresses) {
Packit Service b23acc
                address = ia->addresses;
Packit Service b23acc
Packit Service b23acc
                LIST_REMOVE(addresses, ia->addresses, address);
Packit Service b23acc
Packit Service b23acc
                free(address);
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        return NULL;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
Packit Service b23acc
                             size_t len) {
Packit Service b23acc
        uint8_t *serverid;
Packit Service b23acc
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(id, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        serverid = memdup(id, len);
Packit Service b23acc
        if (!serverid)
Packit Service b23acc
                return -ENOMEM;
Packit Service b23acc
Packit Service b23acc
        free_and_replace(lease->serverid, serverid);
Packit Service b23acc
        lease->serverid_len = len;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!lease->serverid)
Packit Service b23acc
                return -ENOMSG;
Packit Service b23acc
Packit Service b23acc
        if (id)
Packit Service b23acc
                *id = lease->serverid;
Packit Service b23acc
        if (len)
Packit Service b23acc
                *len = lease->serverid_len;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        lease->preference = preference;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
Packit Service b23acc
        assert_return(preference, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!lease)
Packit Service b23acc
                return -EINVAL;
Packit Service b23acc
Packit Service b23acc
        *preference = lease->preference;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        lease->rapid_commit = true;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(rapid_commit, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        *rapid_commit = lease->rapid_commit;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(iaid, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        *iaid = lease->ia.ia_na.id;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(iaid, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        *iaid = lease->pd.ia_pd.id;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
Packit Service b23acc
                               uint32_t *lifetime_preferred,
Packit Service b23acc
                               uint32_t *lifetime_valid) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(addr, -EINVAL);
Packit Service b23acc
        assert_return(lifetime_preferred, -EINVAL);
Packit Service b23acc
        assert_return(lifetime_valid, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!lease->addr_iter)
Packit Service b23acc
                return -ENOMSG;
Packit Service b23acc
Packit Service b23acc
        memcpy(addr, &lease->addr_iter->iaaddr.address,
Packit Service b23acc
                sizeof(struct in6_addr));
Packit Service b23acc
        *lifetime_preferred =
Packit Service b23acc
                be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
Packit Service b23acc
        *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
Packit Service b23acc
Packit Service b23acc
        lease->addr_iter = lease->addr_iter->addresses_next;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
Packit Service b23acc
        if (lease)
Packit Service b23acc
                lease->addr_iter = lease->ia.addresses;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
Packit Service b23acc
                          uint8_t *prefix_len,
Packit Service b23acc
                          uint32_t *lifetime_preferred,
Packit Service b23acc
                          uint32_t *lifetime_valid) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(prefix, -EINVAL);
Packit Service b23acc
        assert_return(prefix_len, -EINVAL);
Packit Service b23acc
        assert_return(lifetime_preferred, -EINVAL);
Packit Service b23acc
        assert_return(lifetime_valid, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!lease->prefix_iter)
Packit Service b23acc
                return -ENOMSG;
Packit Service b23acc
Packit Service b23acc
        memcpy(prefix, &lease->prefix_iter->iapdprefix.address,
Packit Service b23acc
               sizeof(struct in6_addr));
Packit Service b23acc
        *prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
Packit Service b23acc
        *lifetime_preferred =
Packit Service b23acc
                be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
Packit Service b23acc
        *lifetime_valid =
Packit Service b23acc
                be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
Packit Service b23acc
Packit Service b23acc
        lease->prefix_iter = lease->prefix_iter->addresses_next;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
Packit Service b23acc
        if (lease)
Packit Service b23acc
                lease->prefix_iter = lease->pd.addresses;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
Packit Service b23acc
        int r;
Packit Service b23acc
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(optval, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!optlen)
Packit Service b23acc
                return 0;
Packit Service b23acc
Packit Service b23acc
        r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns,
Packit Service b23acc
                                        lease->dns_count,
Packit Service b23acc
                                        &lease->dns_allocated);
Packit Service b23acc
        if (r < 0)
Packit Service b23acc
                return log_dhcp6_client_errno(client, r, "Invalid DNS server option: %m");
Packit Service b23acc
Packit Service b23acc
        lease->dns_count = r;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(addrs, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (lease->dns_count) {
Packit Service b23acc
                *addrs = lease->dns;
Packit Service b23acc
                return lease->dns_count;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        return -ENOENT;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
Packit Service b23acc
                            size_t optlen) {
Packit Service b23acc
        int r;
Packit Service b23acc
        char **domains;
Packit Service b23acc
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(optval, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!optlen)
Packit Service b23acc
                return 0;
Packit Service b23acc
Packit Service b4886a
        r = dhcp6_option_parse_domainname(optval, optlen, &domains);
Packit Service b23acc
        if (r < 0)
Packit Service b23acc
                return 0;
Packit Service b23acc
Packit Service b23acc
        strv_free_and_replace(lease->domains, domains);
Packit Service b23acc
        lease->domains_count = r;
Packit Service b23acc
Packit Service b23acc
        return r;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(domains, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (lease->domains_count) {
Packit Service b23acc
                *domains = lease->domains;
Packit Service b23acc
                return lease->domains_count;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        return -ENOENT;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
Packit Service b23acc
        int r;
Packit Service b23acc
        uint16_t subopt;
Packit Service b23acc
        size_t sublen;
Packit Service b23acc
        uint8_t *subval;
Packit Service b23acc
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(optval, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        lease->ntp = mfree(lease->ntp);
Packit Service b23acc
        lease->ntp_count = 0;
Packit Service b23acc
        lease->ntp_allocated = 0;
Packit Service b23acc
Packit Service b23acc
        while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
Packit Service b23acc
                                       &subval)) >= 0) {
Packit Service b23acc
                int s;
Packit Service b23acc
                char **servers;
Packit Service b23acc
Packit Service b23acc
                switch(subopt) {
Packit Service b23acc
                case DHCP6_NTP_SUBOPTION_SRV_ADDR:
Packit Service b23acc
                case DHCP6_NTP_SUBOPTION_MC_ADDR:
Packit Service b23acc
                        if (sublen != 16)
Packit Service b23acc
                                return 0;
Packit Service b23acc
Packit Service b23acc
                        s = dhcp6_option_parse_ip6addrs(subval, sublen,
Packit Service b23acc
                                                        &lease->ntp,
Packit Service b23acc
                                                        lease->ntp_count,
Packit Service b23acc
                                                        &lease->ntp_allocated);
Packit Service b23acc
                        if (s < 0)
Packit Service b23acc
                                return s;
Packit Service b23acc
Packit Service b23acc
                        lease->ntp_count = s;
Packit Service b23acc
Packit Service b23acc
                        break;
Packit Service b23acc
Packit Service b23acc
                case DHCP6_NTP_SUBOPTION_SRV_FQDN:
Packit Service b4886a
                        r = dhcp6_option_parse_domainname(subval, sublen,
Packit Service b4886a
                                                          &servers);
Packit Service b23acc
                        if (r < 0)
Packit Service b23acc
                                return 0;
Packit Service b23acc
Packit Service b23acc
                        strv_free_and_replace(lease->ntp_fqdn, servers);
Packit Service b23acc
                        lease->ntp_fqdn_count = r;
Packit Service b23acc
Packit Service b23acc
                        break;
Packit Service b23acc
                }
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        if (r != -ENOMSG)
Packit Service b23acc
                return r;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
Packit Service b23acc
        int r;
Packit Service b23acc
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(optval, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (!optlen)
Packit Service b23acc
                return 0;
Packit Service b23acc
Packit Service b23acc
        if (lease->ntp || lease->ntp_fqdn) {
Packit Service b23acc
                log_dhcp6_client(client, "NTP information already provided");
Packit Service b23acc
Packit Service b23acc
                return 0;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        log_dhcp6_client(client, "Using deprecated SNTP information");
Packit Service b23acc
Packit Service b23acc
        r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
Packit Service b23acc
                                        lease->ntp_count,
Packit Service b23acc
                                        &lease->ntp_allocated);
Packit Service b23acc
        if (r < 0)
Packit Service b23acc
                return log_dhcp6_client_errno(client, r, "Invalid SNTP server option: %m");
Packit Service b23acc
Packit Service b23acc
        lease->ntp_count = r;
Packit Service b23acc
Packit Service b23acc
        return 0;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
Packit Service b23acc
                                 const struct in6_addr **addrs) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(addrs, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (lease->ntp_count) {
Packit Service b23acc
                *addrs = lease->ntp;
Packit Service b23acc
                return lease->ntp_count;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        return -ENOENT;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
Packit Service b23acc
        assert_return(lease, -EINVAL);
Packit Service b23acc
        assert_return(ntp_fqdn, -EINVAL);
Packit Service b23acc
Packit Service b23acc
        if (lease->ntp_fqdn_count) {
Packit Service b23acc
                *ntp_fqdn = lease->ntp_fqdn;
Packit Service b23acc
                return lease->ntp_fqdn_count;
Packit Service b23acc
        }
Packit Service b23acc
Packit Service b23acc
        return -ENOENT;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
Packit Service b23acc
        assert(lease);
Packit Service b23acc
Packit Service b23acc
        free(lease->serverid);
Packit Service b23acc
        dhcp6_lease_free_ia(&lease->ia);
Packit Service b23acc
        dhcp6_lease_free_ia(&lease->pd);
Packit Service b23acc
Packit Service b23acc
        free(lease->dns);
Packit Service b23acc
Packit Service b23acc
        lease->domains = strv_free(lease->domains);
Packit Service b23acc
Packit Service b23acc
        free(lease->ntp);
Packit Service b23acc
Packit Service b23acc
        lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
Packit Service b23acc
        return mfree(lease);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
Packit Service b23acc
Packit Service b23acc
int dhcp6_lease_new(sd_dhcp6_lease **ret) {
Packit Service b23acc
        sd_dhcp6_lease *lease;
Packit Service b23acc
Packit Service b23acc
        lease = new0(sd_dhcp6_lease, 1);
Packit Service b23acc
        if (!lease)
Packit Service b23acc
                return -ENOMEM;
Packit Service b23acc
Packit Service b23acc
        lease->n_ref = 1;
Packit Service b23acc
Packit Service b23acc
        LIST_HEAD_INIT(lease->ia.addresses);
Packit Service b23acc
Packit Service b23acc
        *ret = lease;
Packit Service b23acc
        return 0;
Packit Service b23acc
}