chiark / gitweb /
sd-resolve: Allocate objects with new()
[elogind.git] / src / libsystemd / sd-dhcp-client.c
index 76abcbd2ac9d08d9a4da3cd7597973b91f15415c..908f844671df015dbf8837ba6751102b5307fcd8 100644 (file)
@@ -41,8 +41,11 @@ struct DHCPLease {
         be32_t server_address;
         be32_t subnet_mask;
         be32_t router;
-        struct in_addr **dns;
+        struct in_addr *dns;
+        size_t dns_size;
         uint16_t mtu;
+        char *domainname;
+        char *hostname;
 };
 
 typedef struct DHCPLease DHCPLease;
@@ -85,8 +88,7 @@ static int client_receive_message(sd_event_source *s, int fd,
                                   uint32_t revents, void *userdata);
 
 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
-                                void *userdata)
-{
+                                void *userdata) {
         assert_return(client, -EINVAL);
 
         client->cb = cb;
@@ -95,8 +97,7 @@ int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
         return 0;
 }
 
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option)
-{
+int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
         size_t i;
 
         assert_return(client, -EINVAL);
@@ -128,8 +129,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option)
 }
 
 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
-                                       const struct in_addr *last_addr)
-{
+                                       const struct in_addr *last_addr) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
 
@@ -141,8 +141,7 @@ int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
         return 0;
 }
 
-int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
-{
+int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
         assert_return(interface_index >= -1, -EINVAL);
@@ -153,8 +152,7 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
 }
 
 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
-                           const struct ether_addr *addr)
-{
+                           const struct ether_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
 
@@ -163,8 +161,7 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client,
         return 0;
 }
 
-int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -187,8 +184,7 @@ int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu)
-{
+int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu) {
         assert_return(client, -EINVAL);
         assert_return(mtu, -EINVAL);
 
@@ -214,10 +210,10 @@ int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu)
         return 0;
 }
 
-int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
-{
+int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr **addr, size_t *addr_size) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
+        assert_return(addr_size, -EINVAL);
 
         switch (client->state) {
         case DHCP_STATE_INIT:
@@ -230,8 +226,35 @@ int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
         case DHCP_STATE_BOUND:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
-                if (client->lease->dns)
+                if (client->lease->dns_size) {
+                        *addr_size = client->lease->dns_size;
                         *addr = client->lease->dns;
+                } else
+                        return -ENOENT;
+
+                break;
+        }
+
+        return 0;
+}
+
+int sd_dhcp_client_get_domainname(sd_dhcp_client *client, const char **domainname) {
+        assert_return(client, -EINVAL);
+        assert_return(domainname, -EINVAL);
+
+        switch (client->state) {
+        case DHCP_STATE_INIT:
+        case DHCP_STATE_SELECTING:
+        case DHCP_STATE_INIT_REBOOT:
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_REQUESTING:
+                return -EADDRNOTAVAIL;
+
+        case DHCP_STATE_BOUND:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+                if (client->lease->domainname)
+                        *domainname = client->lease->domainname;
                 else
                         return -ENOENT;
 
@@ -241,8 +264,33 @@ int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
         return 0;
 }
 
-int sd_dhcp_client_prefixlen(const struct in_addr *addr)
-{
+int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) {
+        assert_return(client, -EINVAL);
+        assert_return(hostname, -EINVAL);
+
+        switch (client->state) {
+        case DHCP_STATE_INIT:
+        case DHCP_STATE_SELECTING:
+        case DHCP_STATE_INIT_REBOOT:
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_REQUESTING:
+                return -EADDRNOTAVAIL;
+
+        case DHCP_STATE_BOUND:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+                if (client->lease->hostname)
+                        *hostname = client->lease->hostname;
+                else
+                        return -ENOENT;
+
+                break;
+        }
+
+        return 0;
+}
+
+int sd_dhcp_client_prefixlen(const struct in_addr *addr) {
         int len = 0;
         uint32_t mask;
 
@@ -257,8 +305,7 @@ int sd_dhcp_client_prefixlen(const struct in_addr *addr)
         return len;
 }
 
-int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -281,8 +328,7 @@ int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -305,28 +351,27 @@ int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-static int client_notify(sd_dhcp_client *client, int event)
-{
+static int client_notify(sd_dhcp_client *client, int event) {
         if (client->cb)
                 client->cb(client, event, client->userdata);
 
         return 0;
 }
 
-static void in_addrs_free(struct in_addr **addrs) {
-        unsigned i;
-
-        if (!addrs)
+static void lease_free(DHCPLease *lease) {
+        if (!lease)
                 return;
 
-        for (i = 0; addrs[i]; i++)
-                free(addrs[i]);
-
-        free(addrs);
+        free(lease->hostname);
+        free(lease->domainname);
+        free(lease->dns);
+        free(lease);
 }
 
-static int client_stop(sd_dhcp_client *client, int error)
-{
+DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, lease_free);
+#define _cleanup_lease_free_ _cleanup_(lease_freep)
+
+static int client_stop(sd_dhcp_client *client, int error) {
         assert_return(client, -EINVAL);
 
         client->receive_message =
@@ -366,8 +411,7 @@ static int client_stop(sd_dhcp_client *client, int error)
         }
 
         if (client->lease) {
-                in_addrs_free(client->lease->dns);
-                free(client->lease);
+                lease_free(client->lease);
                 client->lease = NULL;
         }
 
@@ -376,8 +420,7 @@ static int client_stop(sd_dhcp_client *client, int error)
 
 static int client_packet_init(sd_dhcp_client *client, uint8_t type,
                               DHCPMessage *message, uint16_t secs,
-                              uint8_t **opt, size_t *optlen)
-{
+                              uint8_t **opt, size_t *optlen) {
         int err;
         be16_t max_size;
 
@@ -443,8 +486,7 @@ static int client_packet_init(sd_dhcp_client *client, uint8_t type,
         return 0;
 }
 
-static uint16_t client_checksum(void *buf, int len)
-{
+static uint16_t client_checksum(void *buf, int len) {
         uint32_t sum;
         uint16_t *check;
         int i;
@@ -467,8 +509,7 @@ static uint16_t client_checksum(void *buf, int len)
         return ~sum;
 }
 
-static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
-{
+static void client_append_ip_headers(DHCPPacket *packet, uint16_t len) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
@@ -489,8 +530,7 @@ static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
         packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
 }
 
-static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
-{
+static int client_send_discover(sd_dhcp_client *client, uint16_t secs) {
         int err = 0;
         _cleanup_free_ DHCPPacket *discover;
         size_t optlen, len;
@@ -529,8 +569,7 @@ static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
         return err;
 }
 
-static int client_send_request(sd_dhcp_client *client, uint16_t secs)
-{
+static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
         _cleanup_free_ DHCPPacket *request;
         size_t optlen, len;
         int err;
@@ -582,8 +621,7 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs)
 }
 
 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
-                                 void *userdata)
-{
+                                 void *userdata) {
         sd_dhcp_client *client = userdata;
         usec_t next_timeout = 0;
         uint32_t time_left;
@@ -684,8 +722,7 @@ error:
         return 0;
 }
 
-static int client_initialize_events(sd_dhcp_client *client, usec_t usec)
-{
+static int client_initialize_events(sd_dhcp_client *client, usec_t usec) {
         int r;
 
         r = sd_event_add_io(client->event, client->fd, EPOLLIN,
@@ -707,8 +744,7 @@ error:
 }
 
 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
-                                 void *userdata)
-{
+                                 void *userdata) {
         sd_dhcp_client *client = userdata;
 
         client_stop(client, DHCP_EVENT_EXPIRED);
@@ -716,8 +752,7 @@ static int client_timeout_expire(sd_event_source *s, uint64_t usec,
         return 0;
 }
 
-static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
-{
+static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
         sd_dhcp_client *client = userdata;
         int r;
 
@@ -742,8 +777,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         return client_initialize_events(client, usec);
 }
 
-static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
-{
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
         sd_dhcp_client *client = userdata;
         int r;
 
@@ -763,8 +797,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
 }
 
 static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
-                              void *user_data)
-{
+                              void *user_data) {
         DHCPLease *lease = user_data;
         be32_t val;
 
@@ -800,18 +833,16 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
                 if (len >= 4) {
                         unsigned i;
 
-                        in_addrs_free(lease->dns);
+                        lease->dns_size = len / 4;
 
-                        lease->dns = new0(struct in_addr*, len / 4 + 1);
+                        free(lease->dns);
+                        lease->dns = new0(struct in_addr, lease->dns_size);
                         if (!lease->dns)
                                 return -ENOMEM;
 
-                        for (i = 0; i < len / 4; i++) {
-                                lease->dns[i] = new0(struct in_addr, 1);
-                                memcpy(&lease->dns[i]->s_addr, option + 4 * i, 4);
+                        for (i = 0; i < lease->dns_size; i++) {
+                                memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
                         }
-
-                        lease->dns[len / 4] = NULL;
                 }
 
                 break;
@@ -829,6 +860,22 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
 
                 break;
 
+        case DHCP_OPTION_DOMAIN_NAME:
+                if (len >= 1) {
+                        free(lease->domainname);
+                        lease->domainname = strndup((const char *)option, len);
+                }
+
+                break;
+
+        case DHCP_OPTION_HOST_NAME:
+                if (len >= 1) {
+                        free(lease->hostname);
+                        lease->hostname = strndup((const char *)option, len);
+                }
+
+                break;
+
         case DHCP_OPTION_RENEWAL_T1_TIME:
                 if (len == 4) {
                         memcpy(&val, option, 4);
@@ -850,8 +897,7 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
 }
 
 static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
-                                 size_t len)
-{
+                                 size_t len) {
         size_t hdrlen;
 
         if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
@@ -887,23 +933,23 @@ static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
 }
 
 static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
-                                size_t len)
-{
-        int err;
-        DHCPLease *lease;
+                                size_t len) {
+        _cleanup_lease_free_ DHCPLease *lease = NULL;
+        int r;
 
-        err = client_verify_headers(client, offer, len);
-        if (err < 0)
-                return err;
+        r = client_verify_headers(client, offer, len);
+        if (r < 0)
+                return r;
 
         lease = new0(DHCPLease, 1);
         if (!lease)
                 return -ENOMEM;
 
         len = len - DHCP_IP_UDP_SIZE;
-        if (dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
-                              lease) != DHCP_OFFER)
-                goto error;
+        r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
+                              lease);
+        if (r != DHCP_OFFER)
+                return -ENOMSG;
 
         lease->address = offer->dhcp.yiaddr;
 
@@ -911,25 +957,20 @@ static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
             lease->server_address == INADDR_ANY ||
             lease->subnet_mask == INADDR_ANY ||
             lease->lifetime == 0)
-                goto error;
+                return -ENOMSG;
 
         client->lease = lease;
+        lease = NULL;
 
         return 0;
-
-error:
-        free(lease);
-
-        return -ENOMSG;
 }
 
 static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
-                              size_t len)
-{
-        int r;
+                              size_t len) {
         DHCPPacket *ack;
         DHCPMessage *dhcp;
-        DHCPLease *lease;
+        _cleanup_lease_free_ DHCPLease *lease = NULL;
+        int r;
 
         if (client->state == DHCP_STATE_RENEWING) {
                 dhcp = (DHCPMessage *)buf;
@@ -949,25 +990,18 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
                 return -ENOMEM;
 
         r = dhcp_option_parse(dhcp, len, client_parse_offer, lease);
+        if (r == DHCP_NAK)
+                return DHCP_EVENT_NO_LEASE;
 
-        if (r == DHCP_NAK) {
-                r = DHCP_EVENT_NO_LEASE;
-                goto error;
-        }
-
-        if (r != DHCP_ACK) {
-                r = -ENOMSG;
-                goto error;
-        }
+        if (r != DHCP_ACK)
+                return -ENOMSG;
 
         lease->address = dhcp->yiaddr;
 
         if (lease->address == INADDR_ANY ||
             lease->server_address == INADDR_ANY ||
-            lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
-                r = -ENOMSG;
-                goto error;
-        }
+            lease->subnet_mask == INADDR_ANY || lease->lifetime == 0)
+                return -ENOMSG;
 
         r = DHCP_EVENT_IP_ACQUIRE;
         if (client->lease) {
@@ -977,30 +1011,24 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
                         r = DHCP_EVENT_IP_CHANGE;
                 }
 
-                free(client->lease);
+                lease_free(client->lease);
         }
 
         client->lease = lease;
-
-        return r;
-
-error:
-        free(lease);
+        lease = NULL;
 
         return r;
 }
 
 static uint64_t client_compute_timeout(uint64_t request_sent,
-                                       uint32_t lifetime)
-{
+                                       uint32_t lifetime) {
         return request_sent + (lifetime - 3) * USEC_PER_SEC +
                 + (random_u32() & 0x1fffff);
 }
 
-static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
-{
-        int err;
+static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) {
         uint64_t next_timeout;
+        int r;
 
         if (client->lease->lifetime < 10)
                 return -EINVAL;
@@ -1017,12 +1045,12 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_t1, client,
                                      &client->timeout_t1);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
 
         if (!client->lease->t2)
                 client->lease->t2 = client->lease->lifetime * 7 / 8;
@@ -1038,31 +1066,30 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_t2, client,
                                      &client->timeout_t2);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
 
         next_timeout = client_compute_timeout(client->request_sent,
                                               client->lease->lifetime);
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_expire, client,
                                      &client->timeout_expire);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
 
         return 0;
 }
 
 static int client_receive_message(sd_event_source *s, int fd,
-                                  uint32_t revents, void *userdata)
-{
+                                  uint32_t revents, void *userdata) {
         sd_dhcp_client *client = userdata;
         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
         int buflen = sizeof(buf);
@@ -1156,8 +1183,7 @@ error:
         return 0;
 }
 
-int sd_dhcp_client_start(sd_dhcp_client *client)
-{
+int sd_dhcp_client_start(sd_dhcp_client *client) {
         int r;
 
         assert_return(client, -EINVAL);
@@ -1180,13 +1206,11 @@ int sd_dhcp_client_start(sd_dhcp_client *client)
         return client_initialize_events(client, client->start_time);
 }
 
-int sd_dhcp_client_stop(sd_dhcp_client *client)
-{
+int sd_dhcp_client_stop(sd_dhcp_client *client) {
         return client_stop(client, DHCP_EVENT_STOP);
 }
 
-sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
-{
+sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client) {
         assert_return(client, NULL);
 
         sd_dhcp_client_stop(client);
@@ -1198,8 +1222,7 @@ sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
         return NULL;
 }
 
-sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
-{
+sd_dhcp_client *sd_dhcp_client_new(sd_event *event) {
         sd_dhcp_client *client;
 
         assert_return(event, NULL);