chiark / gitweb /
dhcp: the localhost isn't valid as hostname either
[elogind.git] / src / libsystemd-network / sd-dhcp-lease.c
1 /***
2   This file is part of systemd.
3
4   Copyright (C) 2013 Intel Corporation. All rights reserved.
5   Copyright (C) 2014 Tom Gundersen
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <net/ethernet.h>
26 #include <arpa/inet.h>
27 #include <sys/param.h>
28
29 #include "util.h"
30 #include "list.h"
31 #include "mkdir.h"
32 #include "fileio.h"
33
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-lease.h"
38 #include "sd-dhcp-client.h"
39 #include "network-internal.h"
40
41 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
42         assert_return(lease, -EINVAL);
43         assert_return(addr, -EINVAL);
44
45         addr->s_addr = lease->address;
46
47         return 0;
48 }
49
50 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
51         assert_return(lease, -EINVAL);
52         assert_return(lease, -EINVAL);
53
54         *lifetime = lease->lifetime;
55
56         return 0;
57 }
58
59 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
60         assert_return(lease, -EINVAL);
61         assert_return(mtu, -EINVAL);
62
63         if (lease->mtu)
64                 *mtu = lease->mtu;
65         else
66                 return -ENOENT;
67
68         return 0;
69 }
70
71 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
72         assert_return(lease, -EINVAL);
73         assert_return(addr, -EINVAL);
74
75         if (lease->dns_size) {
76                 *addr = lease->dns;
77                 return lease->dns_size;
78         } else
79                 return -ENOENT;
80
81         return 0;
82 }
83
84 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
85         assert_return(lease, -EINVAL);
86         assert_return(addr, -EINVAL);
87
88         if (lease->ntp_size) {
89                 *addr = lease->ntp;
90                 return lease->ntp_size;
91         } else
92                 return -ENOENT;
93
94         return 0;
95 }
96
97 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
98         assert_return(lease, -EINVAL);
99         assert_return(domainname, -EINVAL);
100
101         if (lease->domainname)
102                 *domainname = lease->domainname;
103         else
104                 return -ENOENT;
105
106         return 0;
107 }
108
109 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
110         assert_return(lease, -EINVAL);
111         assert_return(hostname, -EINVAL);
112
113         if (lease->hostname)
114                 *hostname = lease->hostname;
115         else
116                 return -ENOENT;
117
118         return 0;
119 }
120
121 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
122         assert_return(lease, -EINVAL);
123         assert_return(root_path, -EINVAL);
124
125         if (lease->root_path)
126                 *root_path = lease->root_path;
127         else
128                 return -ENOENT;
129
130         return 0;
131 }
132
133 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
134         assert_return(lease, -EINVAL);
135         assert_return(addr, -EINVAL);
136
137         if (lease->router != INADDR_ANY)
138                 addr->s_addr = lease->router;
139         else
140                 return -ENOENT;
141
142         return 0;
143 }
144
145 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
146         assert_return(lease, -EINVAL);
147         assert_return(addr, -EINVAL);
148
149         addr->s_addr = lease->subnet_mask;
150
151         return 0;
152 }
153
154 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
155         assert_return(lease, -EINVAL);
156         assert_return(addr, -EINVAL);
157
158         addr->s_addr = lease->server_address;
159
160         return 0;
161 }
162
163 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
164         assert_return(lease, -EINVAL);
165         assert_return(addr, -EINVAL);
166
167         addr->s_addr = lease->next_server;
168
169         return 0;
170 }
171
172 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
173
174         assert_return(lease, -EINVAL);
175         assert_return(routes, -EINVAL);
176
177         if (lease->static_route_size) {
178                 *routes = lease->static_route;
179                 return lease->static_route_size;
180         } else
181                 return -ENOENT;
182
183         return 0;
184 }
185
186 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
187         if (lease)
188                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
189
190         return lease;
191 }
192
193 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
194         if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
195                 free(lease->hostname);
196                 free(lease->domainname);
197                 free(lease->dns);
198                 free(lease->ntp);
199                 free(lease->static_route);
200                 free(lease);
201         }
202
203         return NULL;
204 }
205
206 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
207         be32_t val;
208
209         assert(option);
210         assert(ret);
211
212         if (len == 4) {
213                 memcpy(&val, option, 4);
214                 *ret = be32toh(val);
215
216                 if (*ret < min)
217                         *ret = min;
218         }
219 }
220
221 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
222         lease_parse_u32(option, len, (uint32_t *)ret, 0);
223 }
224
225 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
226         be16_t val;
227
228         assert(option);
229         assert(ret);
230
231         if (len == 2) {
232                 memcpy(&val, option, 2);
233                 *ret = be16toh(val);
234
235                 if (*ret < min)
236                         *ret = min;
237         }
238 }
239
240 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
241         assert(option);
242         assert(ret);
243
244         if (len == 4)
245                 memcpy(ret, option, 4);
246 }
247
248 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
249         assert(option);
250         assert(ret);
251
252         if (len == 1)
253                 *ret = !!(*option);
254 }
255
256 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
257         assert(option);
258         assert(ret);
259
260         if (len == 1) {
261                 *ret = *option;
262
263                 if (*ret < min)
264                         *ret = min;
265         }
266 }
267
268 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
269         assert(option);
270         assert(ret);
271
272         if (len >= 1) {
273                 char *string;
274
275                 string = strndup((const char *)option, len);
276                 if (!string)
277                         return -errno;
278
279                 free(*ret);
280                 *ret = string;
281         }
282
283         return 0;
284 }
285
286 static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
287         assert(option);
288         assert(ret);
289         assert(ret_size);
290
291         if (len && !(len % (4 * mult))) {
292                 size_t size;
293                 struct in_addr *addresses;
294
295                 size = len / 4;
296
297                 addresses = newdup(struct in_addr, option, size);
298                 if (!addresses)
299                         return -ENOMEM;
300
301                 free(*ret);
302                 *ret = addresses;
303                 *ret_size = size;
304         }
305
306         return 0;
307 }
308
309 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
310         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
311 }
312
313 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
314         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
315 }
316
317 static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
318         if (msb_octet < 128)
319                 /* Class A */
320                 *ret = 8;
321         else if (msb_octet < 192)
322                 /* Class B */
323                 *ret = 16;
324         else if (msb_octet < 224)
325                 /* Class C */
326                 *ret = 24;
327         else
328                 /* Class D or E -- no subnet mask */
329                 return -ERANGE;
330
331         return 0;
332 }
333
334 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
335         size_t *routes_size, size_t *routes_allocated) {
336
337         struct in_addr addr;
338
339         assert(option);
340         assert(routes);
341         assert(routes_size);
342         assert(routes_allocated);
343
344         if (!len)
345                 return 0;
346
347         if (len % 8 != 0)
348                 return -EINVAL;
349
350         if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
351                 return -ENOMEM;
352
353         while (len >= 8) {
354                 struct sd_dhcp_route *route = *routes + *routes_size;
355
356                 if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
357                         log_error("Failed to determine destination prefix length from class based IP, ignoring");
358                         continue;
359                 }
360
361                 lease_parse_be32(option, 4, &addr.s_addr);
362                 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
363                 option += 4;
364
365                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
366                 option += 4;
367
368                 len -= 8;
369                 (*routes_size)++;
370         }
371
372         return 0;
373 }
374
375 /* parses RFC3442 Classless Static Route Option */
376 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
377         size_t *routes_size, size_t *routes_allocated) {
378
379         assert(option);
380         assert(routes);
381         assert(routes_size);
382         assert(routes_allocated);
383
384         /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)*  */
385
386         while (len > 0) {
387                 uint8_t dst_octets;
388                 struct sd_dhcp_route *route;
389
390                 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
391                     return -ENOMEM;
392
393                 route = *routes + *routes_size;
394
395                 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
396                 route->dst_prefixlen = *option;
397                 option++;
398                 len--;
399
400                 /* can't have more than 4 octets in IPv4 */
401                 if (dst_octets > 4 || len < dst_octets)
402                         return -EINVAL;
403
404                 route->dst_addr.s_addr = 0;
405                 memcpy(&route->dst_addr.s_addr, option, dst_octets);
406                 option += dst_octets;
407                 len -= dst_octets;
408
409                 if (len < 4)
410                         return -EINVAL;
411
412                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
413                 option += 4;
414                 len -= 4;
415
416                 (*routes_size)++;
417         }
418
419         return 0;
420 }
421
422 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
423                               void *user_data) {
424         sd_dhcp_lease *lease = user_data;
425         int r;
426
427         assert(lease);
428
429         switch(code) {
430
431         case DHCP_OPTION_TIME_OFFSET:
432                 lease_parse_s32(option, len, &lease->time_offset);
433
434                 break;
435
436         case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
437                 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
438
439                 break;
440
441         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
442                 lease_parse_u32(option, len, &lease->lifetime, 1);
443
444                 break;
445
446         case DHCP_OPTION_SERVER_IDENTIFIER:
447                 lease_parse_be32(option, len, &lease->server_address);
448
449                 break;
450
451         case DHCP_OPTION_SUBNET_MASK:
452                 lease_parse_be32(option, len, &lease->subnet_mask);
453
454                 break;
455
456         case DHCP_OPTION_BROADCAST:
457                 lease_parse_be32(option, len, &lease->broadcast);
458
459                 break;
460
461         case DHCP_OPTION_ROUTER:
462                 lease_parse_be32(option, len, &lease->router);
463
464                 break;
465
466         case DHCP_OPTION_DOMAIN_NAME_SERVER:
467                 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
468                 if (r < 0)
469                         return r;
470
471                 break;
472
473         case DHCP_OPTION_NTP_SERVER:
474                 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
475                 if (r < 0)
476                         return r;
477
478                 break;
479
480         case DHCP_OPTION_POLICY_FILTER:
481                 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
482                 if (r < 0)
483                         return r;
484
485                 break;
486
487         case DHCP_OPTION_STATIC_ROUTE:
488                 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
489                         &lease->static_route_allocated);
490                 if (r < 0)
491                         return r;
492
493                 break;
494
495         case DHCP_OPTION_INTERFACE_MTU:
496                 lease_parse_u16(option, len, &lease->mtu, 68);
497
498                 break;
499
500         case DHCP_OPTION_INTERFACE_MDR:
501                 lease_parse_u16(option, len, &lease->mdr, 576);
502
503                 break;
504
505         case DHCP_OPTION_INTERFACE_TTL:
506                 lease_parse_u8(option, len, &lease->ttl, 1);
507
508                 break;
509
510         case DHCP_OPTION_BOOT_FILE_SIZE:
511                 lease_parse_u16(option, len, &lease->boot_file_size, 0);
512
513                 break;
514
515         case DHCP_OPTION_DOMAIN_NAME:
516         {
517                 _cleanup_free_ char *domainname = NULL;
518
519                 r = lease_parse_string(option, len, &domainname);
520                 if (r < 0)
521                         return r;
522
523                 if (!hostname_is_valid(domainname) || is_localhost(domainname))
524                         break;
525
526                 free(lease->domainname);
527                 lease->domainname = domainname;
528                 domainname = NULL;
529
530                 break;
531         }
532         case DHCP_OPTION_HOST_NAME:
533         {
534                 _cleanup_free_ char *hostname = NULL;
535
536                 r = lease_parse_string(option, len, &hostname);
537                 if (r < 0)
538                         return r;
539
540                 if (!hostname_is_valid(hostname) || is_localhost(hostname))
541                         break;
542
543                 free(lease->hostname);
544                 lease->hostname = hostname;
545                 hostname = NULL;
546
547                 break;
548         }
549         case DHCP_OPTION_ROOT_PATH:
550                 r = lease_parse_string(option, len, &lease->root_path);
551                 if (r < 0)
552                         return r;
553
554                 break;
555
556         case DHCP_OPTION_RENEWAL_T1_TIME:
557                 lease_parse_u32(option, len, &lease->t1, 1);
558
559                 break;
560
561         case DHCP_OPTION_REBINDING_T2_TIME:
562                 lease_parse_u32(option, len, &lease->t2, 1);
563
564                 break;
565
566         case DHCP_OPTION_ENABLE_IP_FORWARDING:
567                 lease_parse_bool(option, len, &lease->ip_forward);
568
569                 break;
570
571         case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
572                 lease_parse_bool(option, len, &lease->ip_forward_non_local);
573
574                 break;
575
576         case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
577                 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
578                         &lease->static_route_allocated);
579                 if (r < 0)
580                         return r;
581
582                 break;
583         }
584
585         return 0;
586 }
587
588 int dhcp_lease_new(sd_dhcp_lease **ret) {
589         sd_dhcp_lease *lease;
590
591         lease = new0(sd_dhcp_lease, 1);
592         if (!lease)
593                 return -ENOMEM;
594
595         lease->router = INADDR_ANY;
596         lease->n_ref = REFCNT_INIT;
597
598         *ret = lease;
599         return 0;
600 }
601
602 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
603         _cleanup_free_ char *temp_path = NULL;
604         _cleanup_fclose_ FILE *f = NULL;
605         struct in_addr address;
606         const struct in_addr *addresses;
607         const char *string;
608         uint16_t mtu;
609         struct sd_dhcp_route *routes;
610         int r;
611
612         assert(lease);
613         assert(lease_file);
614
615         r = fopen_temporary(lease_file, &f, &temp_path);
616         if (r < 0)
617                 goto finish;
618
619         fchmod(fileno(f), 0644);
620
621         r = sd_dhcp_lease_get_address(lease, &address);
622         if (r < 0)
623                 goto finish;
624
625         fprintf(f,
626                 "# This is private data. Do not parse.\n"
627                 "ADDRESS=%s\n", inet_ntoa(address));
628
629         r = sd_dhcp_lease_get_netmask(lease, &address);
630         if (r < 0)
631                 goto finish;
632
633         fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
634
635         r = sd_dhcp_lease_get_router(lease, &address);
636         if (r >= 0)
637                 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
638
639         r = sd_dhcp_lease_get_server_identifier(lease, &address);
640         if (r >= 0)
641                 fprintf(f, "SERVER_ADDRESS=%s\n",
642                         inet_ntoa(address));
643
644         r = sd_dhcp_lease_get_next_server(lease, &address);
645         if (r >= 0)
646                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
647
648         r = sd_dhcp_lease_get_mtu(lease, &mtu);
649         if (r >= 0)
650                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
651
652         fputs("DNS=", f);
653         r = sd_dhcp_lease_get_dns(lease, &addresses);
654         if (r >= 0)
655                 serialize_in_addrs(f, addresses, r);
656         fputs("\n", f);
657
658         fputs("NTP=", f);
659         r = sd_dhcp_lease_get_ntp(lease, &addresses);
660         if (r >= 0)
661                 serialize_in_addrs(f, addresses, r);
662         fputs("\n", f);
663
664         r = sd_dhcp_lease_get_domainname(lease, &string);
665         if (r >= 0)
666                 fprintf(f, "DOMAINNAME=%s\n", string);
667
668         r = sd_dhcp_lease_get_hostname(lease, &string);
669         if (r >= 0)
670                 fprintf(f, "HOSTNAME=%s\n", string);
671
672         r = sd_dhcp_lease_get_root_path(lease, &string);
673         if (r >= 0)
674                 fprintf(f, "ROOT_PATH=%s\n", string);
675
676         r = sd_dhcp_lease_get_routes(lease, &routes);
677         if (r >= 0)
678                 serialize_dhcp_routes(f, "ROUTES", routes, r);
679
680         r = 0;
681
682         fflush(f);
683
684         if (ferror(f) || rename(temp_path, lease_file) < 0) {
685                 r = -errno;
686                 unlink(lease_file);
687                 unlink(temp_path);
688         }
689
690 finish:
691         if (r < 0)
692                 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
693
694         return r;
695 }
696
697 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
698         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
699         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
700                             *server_address = NULL, *next_server = NULL,
701                             *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
702         struct in_addr addr;
703         int r;
704
705         assert(lease_file);
706         assert(ret);
707
708         r = dhcp_lease_new(&lease);
709         if (r < 0)
710                 return r;
711
712         r = parse_env_file(lease_file, NEWLINE,
713                            "ADDRESS", &address,
714                            "ROUTER", &router,
715                            "NETMASK", &netmask,
716                            "SERVER_IDENTIFIER", &server_address,
717                            "NEXT_SERVER", &next_server,
718                            "DNS", &dns,
719                            "NTP", &ntp,
720                            "MTU", &mtu,
721                            "DOMAINNAME", &lease->domainname,
722                            "HOSTNAME", &lease->hostname,
723                            "ROOT_PATH", &lease->root_path,
724                            "ROUTES", &routes,
725                            NULL);
726         if (r < 0) {
727                 if (r == -ENOENT)
728                         return 0;
729
730                 log_error("Failed to read %s: %s", lease_file, strerror(-r));
731                 return r;
732         }
733
734         r = inet_pton(AF_INET, address, &addr);
735         if (r < 0)
736                 return r;
737
738         lease->address = addr.s_addr;
739
740         if (router) {
741                 r = inet_pton(AF_INET, router, &addr);
742                 if (r < 0)
743                         return r;
744
745                 lease->router = addr.s_addr;
746         }
747
748         r = inet_pton(AF_INET, netmask, &addr);
749         if (r < 0)
750                 return r;
751
752         lease->subnet_mask = addr.s_addr;
753
754         if (server_address) {
755                 r = inet_pton(AF_INET, server_address, &addr);
756                 if (r < 0)
757                         return r;
758
759                 lease->server_address = addr.s_addr;
760         }
761
762         if (next_server) {
763                 r = inet_pton(AF_INET, next_server, &addr);
764                 if (r < 0)
765                         return r;
766
767                 lease->next_server = addr.s_addr;
768         }
769
770         if (dns) {
771                 r = deserialize_in_addrs(&lease->dns, dns);
772                 if (r < 0)
773                         return r;
774
775                 lease->dns_size = r;
776         }
777
778         if (ntp) {
779                 r = deserialize_in_addrs(&lease->ntp, ntp);
780                 if (r < 0)
781                         return r;
782
783                 lease->ntp_size = r;
784         }
785
786         if (mtu) {
787                 uint16_t u;
788                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
789                         lease->mtu = u;
790         }
791
792         if (routes) {
793                 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
794                                 &lease->static_route_allocated, routes);
795                 if (r < 0)
796                     return r;
797         }
798
799         *ret = lease;
800         lease = NULL;
801
802         return 0;
803 }
804
805 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
806         uint32_t address;
807
808         assert(lease);
809         assert(lease->address != INADDR_ANY);
810
811         address = be32toh(lease->address);
812
813         /* fall back to the default subnet masks based on address class */
814
815         if ((address >> 31) == 0x0)
816                 /* class A, leading bits: 0 */
817                 lease->subnet_mask = htobe32(0xff000000);
818         else if ((address >> 30) == 0x2)
819                 /* class B, leading bits 10 */
820                 lease->subnet_mask = htobe32(0xffff0000);
821         else if ((address >> 29) == 0x6)
822                 /* class C, leading bits 110 */
823                 lease->subnet_mask = htobe32(0xffffff00);
824         else
825                 /* class D or E, no default mask. give up */
826                 return -ERANGE;
827
828         return 0;
829 }