chiark / gitweb /
sd-dhcp-leaes: use newdup()
[elogind.git] / src / libsystemd-network / sd-dhcp-lease.c
index 6bd97283774f86e5327387187850d00d86780b18..61822abd267b06ca127a269cff05778ade3e8124 100644 (file)
@@ -72,6 +72,20 @@ int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *a
         return 0;
 }
 
+int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
+        assert_return(lease, -EINVAL);
+        assert_return(addr, -EINVAL);
+        assert_return(addr_size, -EINVAL);
+
+        if (lease->ntp_size) {
+                *addr_size = lease->ntp_size;
+                *addr = lease->ntp;
+        } else
+                return -ENOENT;
+
+        return 0;
+}
+
 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
         assert_return(lease, -EINVAL);
         assert_return(domainname, -EINVAL);
@@ -135,6 +149,15 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad
         return 0;
 }
 
+int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
+        assert_return(lease, -EINVAL);
+        assert_return(addr, -EINVAL);
+
+        addr->s_addr = lease->next_server;
+
+        return 0;
+}
+
 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
         if (lease)
                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
@@ -188,18 +211,24 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 
         case DHCP_OPTION_DOMAIN_NAME_SERVER:
                 if (len && !(len % 4)) {
-                        unsigned i;
-
                         lease->dns_size = len / 4;
 
                         free(lease->dns);
-                        lease->dns = new0(struct in_addr, lease->dns_size);
+                        lease->dns = newdup(struct in_addr, option, lease->dns_size);
                         if (!lease->dns)
                                 return -ENOMEM;
+                }
+
+                break;
 
-                        for (i = 0; i < lease->dns_size; i++) {
-                                memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
-                        }
+        case DHCP_OPTION_NTP_SERVER:
+                if (len && !(len % 4)) {
+                        lease->ntp_size = len / 4;
+
+                        free(lease->ntp);
+                        lease->ntp = newdup(struct in_addr, option, lease->ntp_size);
+                        if (!lease->ntp)
+                                return -ENOMEM;
                 }
 
                 break;
@@ -262,7 +291,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 }
 
 int dhcp_lease_new(sd_dhcp_lease **ret) {
-        _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
+        sd_dhcp_lease *lease;
 
         lease = new0(sd_dhcp_lease, 1);
         if (!lease)
@@ -271,8 +300,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
         lease->n_ref = REFCNT_INIT;
 
         *ret = lease;
-        lease = NULL;
-
         return 0;
 }
 
@@ -288,10 +315,6 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         assert(lease);
         assert(lease_file);
 
-        r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
-        if (r < 0)
-                goto finish;
-
         r = fopen_temporary(lease_file, &f, &temp_path);
         if (r < 0)
                 goto finish;
@@ -350,6 +373,18 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
                         "SERVER_ADDRESS=%s\n", string);
         }
 
+        r = sd_dhcp_lease_get_next_server(lease, &address);
+        if (r >= 0) {
+                string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
+                if (!string) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                fprintf(f,
+                        "NEXT_SERVER=%s\n", string);
+        }
+
         r = sd_dhcp_lease_get_mtu(lease, &mtu);
         if (r >= 0)
                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
@@ -388,7 +423,8 @@ finish:
 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
-                            *server_address = NULL, *mtu = NULL;
+                            *server_address = NULL, *next_server = NULL,
+                            *mtu = NULL;
         struct in_addr addr;
         int r;
 
@@ -404,6 +440,7 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
                            "ROUTER", &router,
                            "NETMASK", &netmask,
                            "SERVER_IDENTIFIER", &server_address,
+                           "NEXT_SERVER", &next_server,
                            "MTU", &mtu,
                            "DOMAINNAME", &lease->domainname,
                            "HOSTNAME", &lease->hostname,
@@ -443,6 +480,14 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
                 lease->server_address = addr.s_addr;
         }
 
+        if (next_server) {
+                r = inet_pton(AF_INET, next_server, &addr);
+                if (r < 0)
+                        return r;
+
+                lease->next_server = addr.s_addr;
+        }
+
         if (mtu) {
                 uint16_t u;
                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
@@ -454,3 +499,29 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
 
         return 0;
 }
+
+int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
+        uint32_t address;
+
+        assert(lease);
+        assert(lease->address != INADDR_ANY);
+
+        address = be32toh(lease->address);
+
+        /* fall back to the default subnet masks based on address class */
+
+        if ((address >> 31) == 0x0)
+                /* class A, leading bits: 0 */
+                lease->subnet_mask = htobe32(0xff000000);
+        else if ((address >> 30) == 0x2)
+                /* class B, leading bits 10 */
+                lease->subnet_mask = htobe32(0xffff0000);
+        else if ((address >> 29) == 0x6)
+                /* class C, leading bits 110 */
+                lease->subnet_mask = htobe32(0xffffff00);
+        else
+                /* class D or E, no default mask. give up */
+                return -ERANGE;
+
+        return 0;
+}