2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #define REQUEST (1 << 0)
41 #define UINT8 (1 << 1)
42 #define UINT16 (1 << 2)
43 #define SINT16 (1 << 3)
44 #define UINT32 (1 << 4)
45 #define SINT32 (1 << 5)
47 #define STRING (1 << 7)
49 #define ARRAY (1 << 9)
50 #define RFC3361 (1 << 10)
51 #define RFC3397 (1 << 11)
52 #define RFC3442 (1 << 12)
54 #define IPV4R IPV4 | REQUEST
56 #define DAD "Duplicate address detected"
58 /* Our aggregate option buffer.
59 * We ONLY use this when options are split, which for most purposes is
60 * practically never. See RFC3396 for details. */
61 static uint8_t *opt_buffer
;
69 static const struct dhcp_opt
const dhcp_opts
[] = {
70 { 1, IPV4
| REQUEST
, "subnet_mask" },
71 /* RFC 3442 states that the CSR has to come before all other
72 * routes. For completeness, we also specify static routes,
74 { 121, RFC3442
, "classless_static_routes" },
75 { 249, RFC3442
, "ms_classless_static_routes" },
76 { 33, IPV4
| ARRAY
| REQUEST
, "static_routes" },
77 { 3, IPV4
| ARRAY
| REQUEST
, "routers" },
78 { 2, UINT32
, "time_offset" },
79 { 4, IPV4
| ARRAY
, "time_servers" },
80 { 5, IPV4
| ARRAY
, "ien116_name_servers" },
81 { 6, IPV4
| ARRAY
, "domain_name_servers" },
82 { 7, IPV4
| ARRAY
, "log_servers" },
83 { 8, IPV4
| ARRAY
, "cookie_servers" },
84 { 9, IPV4
| ARRAY
, "lpr_servers" },
85 { 10, IPV4
| ARRAY
, "impress_servers" },
86 { 11, IPV4
| ARRAY
, "resource_location_servers" },
87 { 12, STRING
, "host_name" },
88 { 13, UINT16
, "boot_size" },
89 { 14, STRING
, "merit_dump" },
90 { 15, STRING
, "domain_name" },
91 { 16, IPV4
, "swap_server" },
92 { 17, STRING
, "root_path" },
93 { 18, STRING
, "extensions_path" },
94 { 19, UINT8
, "ip_forwarding" },
95 { 20, UINT8
, "non_local_source_routing" },
96 { 21, IPV4
| ARRAY
, "policy_filter" },
97 { 22, SINT16
, "max_dgram_reassembly" },
98 { 23, UINT16
, "default_ip_ttl" },
99 { 24, UINT32
, "path_mtu_aging_timeout" },
100 { 25, UINT16
| ARRAY
, "path_mtu_plateau_table" },
101 { 26, UINT16
, "interface_mtu" },
102 { 27, UINT8
, "all_subnets_local" },
103 { 28, IPV4
| REQUEST
, "broadcast_address" },
104 { 29, UINT8
, "perform_mask_discovery" },
105 { 30, UINT8
, "mask_supplier" },
106 { 31, UINT8
, "router_discovery" },
107 { 32, IPV4
, "router_solicitation_address" },
108 { 34, UINT8
, "trailer_encapsulation" },
109 { 35, UINT32
, "arp_cache_timeout" },
110 { 36, UINT16
, "ieee802_3_encapsulation" },
111 { 37, UINT8
, "default_tcp_ttl" },
112 { 38, UINT32
, "tcp_keepalive_interval" },
113 { 39, UINT8
, "tcp_keepalive_garbage" },
114 { 40, STRING
, "nis_domain" },
115 { 41, IPV4
| ARRAY
, "nis_servers" },
116 { 42, IPV4
| ARRAY
, "ntp_servers" },
117 { 43, STRING
, "vendor_encapsulated_options" },
118 { 44, IPV4
| ARRAY
, "netbios_name_servers" },
119 { 45, IPV4
, "netbios_dd_server" },
120 { 46, UINT8
, "netbios_node_type" },
121 { 47, STRING
, "netbios_scope" },
122 { 48, IPV4
| ARRAY
, "font_servers" },
123 { 49, IPV4
| ARRAY
, "x_display_manager" },
124 { 50, IPV4
, "dhcp_requested_address" },
125 { 51, UINT32
| REQUEST
, "dhcp_lease_time" },
126 { 52, UINT8
, "dhcp_option_overload" },
127 { 53, UINT8
, "dhcp_message_type" },
128 { 54, IPV4
, "dhcp_server_identifier" },
129 { 55, UINT8
| ARRAY
, "dhcp_parameter_request_list" },
130 { 56, STRING
, "dhcp_message" },
131 { 57, UINT16
, "dhcp_max_message_size" },
132 { 58, UINT32
| REQUEST
, "dhcp_renewal_time" },
133 { 59, UINT32
| REQUEST
, "dhcp_rebinding_time" },
134 { 64, STRING
, "nisplus_domain" },
135 { 65, IPV4
| ARRAY
, "nisplus_servers" },
136 { 66, STRING
, "tftp_server_name" },
137 { 67, STRING
, "bootfile_name" },
138 { 68, IPV4
| ARRAY
, "mobile_ip_home_agent" },
139 { 69, IPV4
| ARRAY
, "smtp_server" },
140 { 70, IPV4
| ARRAY
, "pop_server" },
141 { 71, IPV4
| ARRAY
, "nntp_server" },
142 { 72, IPV4
| ARRAY
, "www_server" },
143 { 73, IPV4
| ARRAY
, "finger_server" },
144 { 74, IPV4
| ARRAY
, "irc_server" },
145 { 75, IPV4
| ARRAY
, "streettalk_server" },
146 { 76, IPV4
| ARRAY
, "streettalk_directory_assistance_server" },
147 { 77, STRING
, "user_class" },
148 { 81, STRING
| RFC3397
, "fqdn_name" },
149 { 85, IPV4
| ARRAY
, "nds_servers" },
150 { 86, STRING
, "nds_tree_name" },
151 { 87, STRING
, "nds_context" },
152 { 88, STRING
| RFC3397
, "bcms_controller_names" },
153 { 89, IPV4
| ARRAY
, "bcms_controller_address" },
154 { 91, UINT32
, "client_last_transaction_time" },
155 { 92, IPV4
| ARRAY
, "associated_ip" },
156 { 98, STRING
, "uap_servers" },
157 { 112, IPV4
| ARRAY
, "netinfo_server_address" },
158 { 113, STRING
, "netinfo_server_tag" },
159 { 114, STRING
, "default_url" },
160 { 118, IPV4
, "subnet_selection" },
161 { 119, STRING
| RFC3397
, "domain_search" },
165 static const char *if_params
[] = {
177 static const char *dhcp_params
[] = {
190 const struct dhcp_opt
*opt
;
193 for (p
= if_params
; *p
; p
++)
194 printf(" - %s\n", *p
);
196 for (p
= dhcp_params
; *p
; p
++)
199 for (opt
= dhcp_opts
; opt
->option
; opt
++)
201 printf("%03d %s\n", opt
->option
, opt
->var
);
204 int make_option_mask(uint8_t *mask
, const char *opts
, int add
)
206 char *token
, *o
, *p
, *t
;
207 const struct dhcp_opt
*opt
;
210 o
= p
= xstrdup(opts
);
211 while ((token
= strsep(&p
, ", "))) {
214 for (opt
= dhcp_opts
; opt
->option
; opt
++) {
218 if (strcmp(opt
->var
, token
) == 0)
222 n
= strtol(token
, &t
, 0);
223 if (errno
== 0 && !*t
)
224 if (opt
->option
== n
)
228 if (add
== 2 && !(opt
->type
& IPV4
)) {
233 if (add
== 1 || add
== 2)
234 add_option_mask(mask
,
237 del_option_mask(mask
,
253 valid_length(uint8_t option
, int dl
, int *type
)
255 const struct dhcp_opt
*opt
;
261 for (opt
= dhcp_opts
; opt
->option
; opt
++) {
262 if (opt
->option
!= option
)
268 if (opt
->type
== 0 ||
269 opt
->type
& STRING
||
274 if (opt
->type
& UINT32
|| opt
->type
& IPV4
)
275 sz
= sizeof(uint32_t);
276 if (opt
->type
& UINT16
)
277 sz
= sizeof(uint16_t);
278 if (opt
->type
& UINT8
)
279 sz
= sizeof(uint8_t);
280 if (opt
->type
& IPV4
|| opt
->type
& ARRAY
)
282 return (dl
== sz
? 0 : -1);
285 /* unknown option, so let it pass */
291 free_option_buffer(void)
297 #define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
298 static const uint8_t *
299 get_option(const struct dhcp_message
*dhcp
, uint8_t opt
, int *len
, int *type
)
301 const uint8_t *p
= dhcp
->options
;
302 const uint8_t *e
= p
+ sizeof(dhcp
->options
);
307 const uint8_t *op
= NULL
;
315 opt_buffer
= xmalloc(sizeof(*dhcp
));
317 atexit(free_option_buffer
);
334 /* bit 1 set means parse boot file */
337 e
= p
+ sizeof(dhcp
->bootfile
);
338 } else if (overl
& 2) {
339 /* bit 2 set means parse server name */
341 p
= dhcp
->servername
;
342 e
= p
+ sizeof(dhcp
->servername
);
346 case DHO_OPTIONSOVERLOADED
:
347 /* Ensure we only get this option once */
357 if (valid_length(opt
, bl
, type
) == -1) {
365 return (const uint8_t *)&opt_buffer
;
374 get_option_addr(struct in_addr
*a
, const struct dhcp_message
*dhcp
,
377 const uint8_t *p
= get_option_raw(dhcp
, option
);
381 memcpy(&a
->s_addr
, p
, sizeof(a
->s_addr
));
386 get_option_uint32(uint32_t *i
, const struct dhcp_message
*dhcp
, uint8_t option
)
388 const uint8_t *p
= get_option_raw(dhcp
, option
);
393 memcpy(&d
, p
, sizeof(d
));
399 get_option_uint16(uint16_t *i
, const struct dhcp_message
*dhcp
, uint8_t option
)
401 const uint8_t *p
= get_option_raw(dhcp
, option
);
406 memcpy(&d
, p
, sizeof(d
));
412 get_option_uint8(uint8_t *i
, const struct dhcp_message
*dhcp
, uint8_t option
)
414 const uint8_t *p
= get_option_raw(dhcp
, option
);
423 /* Decode an RFC3397 DNS search order option into a space
424 * seperated string. Returns length of string (including
425 * terminating zero) or zero on error. out may be NULL
426 * to just determine output length. */
428 decode_rfc3397(char *out
, ssize_t len
, int pl
, const uint8_t *p
)
430 const uint8_t *r
, *q
= p
;
431 int count
= 0, l
, hops
;
437 /* We check we are inside our length again incase
438 * the data is NOT terminated correctly. */
439 while ((l
= *q
++) && q
- p
< pl
) {
441 if (ltype
== 0x80 || ltype
== 0x40)
443 else if (ltype
== 0xc0) { /* pointer */
446 /* save source of first jump. */
456 /* straightforward name segment, add with '.' */
459 if ((ssize_t
)l
+ 1 > len
) {
472 /* change last dot to space */
479 /* change last space to zero terminator */
487 decode_rfc3442(char *out
, ssize_t len
, int pl
, const uint8_t *p
)
490 ssize_t b
, bytes
= 0, ocets
;
495 /* Minimum is 5 -first is CIDR and a router length of 4 */
508 ocets
= (cidr
+ 7) / 8;
511 bytes
+= ((4 * 4) * 2) + 4;
514 if ((((4 * 4) * 2) + 4) > len
) {
522 /* If we have ocets then we have a destination and netmask */
525 memcpy(&addr
.s_addr
, p
, ocets
);
526 b
= snprintf(o
, len
, "%s/%d", inet_ntoa(addr
), cidr
);
529 b
= snprintf(o
, len
, "0.0.0.0/0");
533 /* Finally, snag the router */
534 memcpy(&addr
.s_addr
, p
, 4);
536 b
= snprintf(o
, len
, " %s", inet_ntoa(addr
));
547 decode_rfc3442_rt(int dl
, const uint8_t *data
)
549 const uint8_t *p
= data
;
553 struct rt
*routes
= NULL
;
554 struct rt
*rt
= NULL
;
556 /* Minimum is 5 -first is CIDR and a router length of 4 */
570 rt
->next
= xzalloc(sizeof(*rt
));
573 routes
= rt
= xzalloc(sizeof(*routes
));
577 ocets
= (cidr
+ 7) / 8;
578 /* If we have ocets then we have a destination and netmask */
580 memcpy(&rt
->dest
.s_addr
, p
, ocets
);
582 rt
->net
.s_addr
= htonl(~0U << (32 - cidr
));
585 /* Finally, snag the router */
586 memcpy(&rt
->gate
.s_addr
, p
, 4);
593 decode_rfc3361(int dl
, const uint8_t *data
)
610 if ((l
= decode_rfc3397(NULL
, 0, dl
, data
)) > 0) {
612 decode_rfc3397(sip
, l
, dl
, data
);
616 if (dl
== 0 || dl
% 4 != 0) {
620 addr
.s_addr
= INADDR_BROADCAST
;
621 l
= ((dl
/ sizeof(addr
.s_addr
)) * ((4 * 4) + 1)) + 1;
622 sip
= p
= xmalloc(l
);
624 memcpy(&addr
.s_addr
, data
, sizeof(addr
.s_addr
));
625 data
+= sizeof(addr
.s_addr
);
626 p
+= snprintf(p
, l
- (p
- sip
), "%s ", inet_ntoa(addr
));
627 l
-= sizeof(addr
.s_addr
);
640 get_option_string(const struct dhcp_message
*dhcp
, uint8_t option
)
647 p
= get_option(dhcp
, option
, &len
, &type
);
648 if (!p
|| *p
== '\0')
651 if (type
& RFC3397
) {
652 type
= decode_rfc3397(NULL
, 0, len
, p
);
657 s
= xmalloc(sizeof(char) * type
);
658 decode_rfc3397(s
, type
, len
, p
);
663 return decode_rfc3361(len
, p
);
665 s
= xmalloc(sizeof(char) * (len
+ 1));
671 /* This calculates the netmask that we should use for static routes.
672 * This IS different from the calculation used to calculate the netmask
673 * for an interface address. */
675 route_netmask(uint32_t ip_in
)
677 /* used to be unsigned long - check if error */
678 uint32_t p
= ntohl(ip_in
);
700 /* We need to obey routing options.
701 * If we have a CSR then we only use that.
702 * Otherwise we add static routes and then routers. */
704 get_option_routes(const struct dhcp_message
*dhcp
,
705 const char *ifname
, int *opts
)
709 struct rt
*routes
= NULL
;
710 struct rt
*route
= NULL
;
713 /* If we have CSR's then we MUST use these only */
714 p
= get_option(dhcp
, DHO_CSR
, &len
, NULL
);
715 /* Check for crappy MS option */
717 p
= get_option(dhcp
, DHO_MSCSR
, &len
, NULL
);
719 routes
= decode_rfc3442_rt(len
, p
);
720 if (routes
&& !(*opts
& DHCPCD_CSR_WARNED
)) {
722 "%s: using Classless Static Routes (RFC3442)",
724 *opts
|= DHCPCD_CSR_WARNED
;
729 /* OK, get our static routes first. */
730 p
= get_option(dhcp
, DHO_STATICROUTE
, &len
, NULL
);
735 route
->next
= xmalloc(sizeof(*route
));
738 routes
= route
= xmalloc(sizeof(*routes
));
740 memcpy(&route
->dest
.s_addr
, p
, 4);
742 memcpy(&route
->gate
.s_addr
, p
, 4);
744 route
->net
.s_addr
= route_netmask(route
->dest
.s_addr
);
748 /* Now grab our routers */
749 p
= get_option(dhcp
, DHO_ROUTER
, &len
, NULL
);
754 route
->next
= xzalloc(sizeof(*route
));
757 routes
= route
= xzalloc(sizeof(*route
));
758 memcpy(&route
->gate
.s_addr
, p
, 4);
767 encode_rfc1035(const char *src
, uint8_t *dst
)
774 for (; *src
; src
++) {
778 /* Skip the trailing . */
786 *p
++ = (uint8_t)*src
;
793 #define PUTADDR(_type, _val) \
797 memcpy(p, &_val.s_addr, 4); \
802 dhcp_message_add_addr(struct dhcp_message
*dhcp
,
803 uint8_t type
, struct in_addr addr
)
809 while (*p
!= DHO_END
) {
814 len
= p
- (uint8_t *)dhcp
;
815 if (len
+ 6 > sizeof(*dhcp
)) {
826 make_message(struct dhcp_message
**message
,
827 const struct interface
*iface
,
830 struct dhcp_message
*dhcp
;
832 uint8_t *n_params
= NULL
;
833 time_t up
= uptime() - iface
->start_uptime
;
838 const struct dhcp_opt
*opt
;
839 const struct if_options
*ifo
= iface
->state
->options
;
840 const struct dhcp_lease
*lease
= &iface
->state
->lease
;
842 dhcp
= xzalloc(sizeof (*dhcp
));
846 if ((type
== DHCP_INFORM
||
847 type
== DHCP_RELEASE
||
848 type
== DHCP_REQUEST
) &&
849 !IN_LINKLOCAL(ntohl(iface
->addr
.s_addr
)))
851 dhcp
->ciaddr
= iface
->addr
.s_addr
;
852 /* In-case we haven't actually configured the address yet */
853 if (type
== DHCP_INFORM
&& iface
->addr
.s_addr
== 0)
854 dhcp
->ciaddr
= lease
->addr
.s_addr
;
855 /* Zero the address if we're currently on a different subnet */
856 if (type
== DHCP_REQUEST
&&
857 iface
->net
.s_addr
!= lease
->net
.s_addr
)
861 dhcp
->op
= DHCP_BOOTREQUEST
;
862 dhcp
->hwtype
= iface
->family
;
863 switch (iface
->family
) {
866 dhcp
->hwlen
= ETHER_ADDR_LEN
;
867 memcpy(&dhcp
->chaddr
, &iface
->hwaddr
, ETHER_ADDR_LEN
);
869 case ARPHRD_IEEE1394
:
870 case ARPHRD_INFINIBAND
:
872 if (dhcp
->ciaddr
== 0 &&
873 type
!= DHCP_DECLINE
&& type
!= DHCP_RELEASE
)
874 dhcp
->flags
= htons(BROADCAST_FLAG
);
878 if (type
!= DHCP_DECLINE
&& type
!= DHCP_RELEASE
) {
879 if (up
< 0 || up
> (time_t)UINT16_MAX
)
880 dhcp
->secs
= htons((uint16_t)UINT16_MAX
);
882 dhcp
->secs
= htons(up
);
884 dhcp
->xid
= iface
->state
->xid
;
885 dhcp
->cookie
= htonl(MAGIC_COOKIE
);
887 *p
++ = DHO_MESSAGETYPE
;
891 if (iface
->clientid
) {
893 memcpy(p
, iface
->clientid
, iface
->clientid
[0] + 1);
894 p
+= iface
->clientid
[0] + 1;
897 if (lease
->addr
.s_addr
&& !IN_LINKLOCAL(htonl(lease
->addr
.s_addr
))) {
898 if (type
== DHCP_DECLINE
||
899 type
== DHCP_DISCOVER
||
900 (type
== DHCP_REQUEST
&&
901 lease
->addr
.s_addr
!= iface
->addr
.s_addr
))
903 PUTADDR(DHO_IPADDRESS
, lease
->addr
);
904 if (lease
->server
.s_addr
)
905 PUTADDR(DHO_SERVERID
, lease
->server
);
908 if (type
== DHCP_RELEASE
) {
909 if (lease
->server
.s_addr
)
910 PUTADDR(DHO_SERVERID
, lease
->server
);
914 if (type
== DHCP_DECLINE
) {
922 if (type
== DHCP_DISCOVER
||
923 type
== DHCP_INFORM
||
924 type
== DHCP_REQUEST
)
926 *p
++ = DHO_MAXMESSAGESIZE
;
928 sz
= get_mtu(iface
->name
);
930 if (set_mtu(iface
->name
, MTU_MIN
) == 0)
937 if (ifo
->userclass
[0]) {
938 *p
++ = DHO_USERCLASS
;
939 memcpy(p
, ifo
->userclass
, ifo
->userclass
[0] + 1);
940 p
+= ifo
->userclass
[0] + 1;
943 if (ifo
->vendorclassid
[0]) {
944 *p
++ = DHO_VENDORCLASSID
;
945 memcpy(p
, ifo
->vendorclassid
,
946 ifo
->vendorclassid
[0] + 1);
947 p
+= ifo
->vendorclassid
[0] + 1;
951 if (type
!= DHCP_INFORM
) {
952 if (ifo
->leasetime
!= 0) {
953 *p
++ = DHO_LEASETIME
;
955 ul
= htonl(ifo
->leasetime
);
961 /* Regardless of RFC2132, we should always send a hostname
962 * upto the first dot (the short hostname) as otherwise
963 * confuses some DHCP servers when updating DNS.
964 * The FQDN option should be used if a FQDN is required. */
965 if (ifo
->options
& DHCPCD_HOSTNAME
&& ifo
->hostname
[0]) {
967 hp
= strchr(ifo
->hostname
, '.');
969 len
= hp
- ifo
->hostname
;
971 len
= strlen(ifo
->hostname
);
973 memcpy(p
, ifo
->hostname
, len
);
976 if (ifo
->fqdn
!= FQDN_DISABLE
&& ifo
->hostname
[0]) {
977 /* IETF DHC-FQDN option (81), RFC4702 */
983 * S: 1 => Client requests Server to update
984 * a RR in DNS as well as PTR
985 * O: 1 => Server indicates to client that
986 * DNS has been updated
987 * E: 1 => Name data is DNS format
988 * N: 1 => Client requests Server to not
991 *p
++ = (ifo
->fqdn
& 0x09) | 0x04;
992 *p
++ = 0; /* from server for PTR RR */
993 *p
++ = 0; /* from server for A RR if S=1 */
994 ul
= encode_rfc1035(ifo
->hostname
, p
);
999 /* vendor is already encoded correctly, so just add it */
1000 if (ifo
->vendor
[0]) {
1002 memcpy(p
, ifo
->vendor
, ifo
->vendor
[0] + 1);
1003 p
+= ifo
->vendor
[0] + 1;
1006 *p
++ = DHO_PARAMETERREQUESTLIST
;
1009 for (opt
= dhcp_opts
; opt
->option
; opt
++) {
1010 if (!(opt
->type
& REQUEST
||
1011 has_option_mask(ifo
->requestmask
, opt
->option
)))
1013 if (type
== DHCP_INFORM
&&
1014 (opt
->option
== DHO_RENEWALTIME
||
1015 opt
->option
== DHO_REBINDTIME
))
1019 *n_params
= p
- n_params
- 1;
1023 #ifdef BOOTP_MESSAGE_LENTH_MIN
1024 /* Some crappy DHCP servers think they have to obey the BOOTP minimum
1026 * They are wrong, but we should still cater for them. */
1027 while (p
- m
< BOOTP_MESSAGE_LENTH_MIN
)
1036 write_lease(const struct interface
*iface
, const struct dhcp_message
*dhcp
)
1039 ssize_t bytes
= sizeof(*dhcp
);
1040 const uint8_t *p
= dhcp
->options
;
1041 const uint8_t *e
= p
+ sizeof(dhcp
->options
);
1045 /* We don't write BOOTP leases */
1046 if (is_bootp(dhcp
)) {
1047 unlink(iface
->leasefile
);
1051 syslog(LOG_DEBUG
, "%s: writing lease `%s'",
1052 iface
->name
, iface
->leasefile
);
1054 fd
= open(iface
->leasefile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0400);
1056 syslog(LOG_ERR
, "%s: open: %m", iface
->name
);
1060 /* Only write as much as we need */
1064 bytes
= p
- (const uint8_t *)dhcp
;
1073 bytes
= write(fd
, dhcp
, bytes
);
1078 struct dhcp_message
*
1079 read_lease(const struct interface
*iface
)
1082 struct dhcp_message
*dhcp
;
1085 fd
= open(iface
->leasefile
, O_RDONLY
);
1087 if (errno
!= ENOENT
)
1088 syslog(LOG_ERR
, "%s: open `%s': %m",
1089 iface
->name
, iface
->leasefile
);
1092 syslog(LOG_DEBUG
, "%s: reading lease `%s'",
1093 iface
->name
, iface
->leasefile
);
1094 dhcp
= xmalloc(sizeof(*dhcp
));
1095 memset(dhcp
, 0, sizeof(*dhcp
));
1096 bytes
= read(fd
, dhcp
, sizeof(*dhcp
));
1106 print_string(char *s
, ssize_t len
, int dl
, const uint8_t *data
)
1109 const uint8_t *e
, *p
;
1117 /* If rest is all NULL, skip it. */
1118 for (p
= data
; p
< e
; p
++)
1124 if (!isascii(c
) || !isprint(c
)) {
1130 r
= snprintf(s
, len
, "\\%03o", c
);
1139 case '"': /* FALLTHROUGH */
1140 case '\'': /* FALLTHROUGH */
1141 case '$': /* FALLTHROUGH */
1142 case '`': /* FALLTHROUGH */
1170 print_option(char *s
, ssize_t len
, int type
, int dl
, const uint8_t *data
)
1172 const uint8_t *e
, *t
;
1177 struct in_addr addr
;
1182 if (type
& RFC3397
) {
1183 l
= decode_rfc3397(NULL
, 0, dl
, data
);
1187 decode_rfc3397(tmp
, l
, dl
, data
);
1188 l
= print_string(s
, len
, l
- 1, (uint8_t *)tmp
);
1194 return decode_rfc3442(s
, len
, dl
, data
);
1196 if (type
& STRING
) {
1197 /* Some DHCP servers return NULL strings */
1200 return print_string(s
, len
, dl
, data
);
1206 else if (type
& UINT16
) {
1209 } else if (type
& SINT16
) {
1212 } else if (type
& UINT32
) {
1215 } else if (type
& SINT32
) {
1218 } else if (type
& IPV4
) {
1225 return (l
+ 1) * dl
;
1237 l
= snprintf(s
, len
, "%d", *data
);
1239 } else if (type
& UINT16
) {
1240 memcpy(&u16
, data
, sizeof(u16
));
1242 l
= snprintf(s
, len
, "%d", u16
);
1243 data
+= sizeof(u16
);
1244 } else if (type
& SINT16
) {
1245 memcpy(&s16
, data
, sizeof(s16
));
1247 l
= snprintf(s
, len
, "%d", s16
);
1248 data
+= sizeof(s16
);
1249 } else if (type
& UINT32
) {
1250 memcpy(&u32
, data
, sizeof(u32
));
1252 l
= snprintf(s
, len
, "%d", u32
);
1253 data
+= sizeof(u32
);
1254 } else if (type
& SINT32
) {
1255 memcpy(&s32
, data
, sizeof(s32
));
1257 l
= snprintf(s
, len
, "%d", s32
);
1258 data
+= sizeof(s32
);
1259 } else if (type
& IPV4
) {
1260 memcpy(&addr
.s_addr
, data
, sizeof(addr
.s_addr
));
1261 l
= snprintf(s
, len
, "%s", inet_ntoa(addr
));
1262 data
+= sizeof(addr
.s_addr
);
1274 setvar(char ***e
, const char *prefix
, const char *var
, const char *value
)
1276 size_t len
= strlen(prefix
) + strlen(var
) + strlen(value
) + 4;
1279 snprintf(**e
, len
, "%s_%s=%s", prefix
, var
, value
);
1284 configure_env(char **env
, const char *prefix
, const struct dhcp_message
*dhcp
,
1285 const struct if_options
*ifo
)
1290 struct in_addr addr
;
1294 const struct dhcp_opt
*opt
;
1300 get_option_uint8(&overl
, dhcp
, DHO_OPTIONSOVERLOADED
);
1303 for (opt
= dhcp_opts
; opt
->option
; opt
++) {
1306 if (has_option_mask(ifo
->nomask
, opt
->option
))
1308 if (get_option_raw(dhcp
, opt
->option
))
1311 if (dhcp
->yiaddr
|| dhcp
->ciaddr
)
1313 if (*dhcp
->bootfile
&& !(overl
& 1))
1315 if (*dhcp
->servername
&& !(overl
& 2))
1321 if (dhcp
->yiaddr
|| dhcp
->ciaddr
) {
1322 /* Set some useful variables that we derive from the DHCP
1323 * message but are not necessarily in the options */
1324 addr
.s_addr
= dhcp
->yiaddr
? dhcp
->yiaddr
: dhcp
->ciaddr
;
1325 setvar(&ep
, prefix
, "ip_address", inet_ntoa(addr
));
1326 if (get_option_addr(&net
, dhcp
, DHO_SUBNETMASK
) == -1) {
1327 net
.s_addr
= get_netmask(addr
.s_addr
);
1328 setvar(&ep
, prefix
, "subnet_mask", inet_ntoa(net
));
1330 i
= inet_ntocidr(net
);
1331 snprintf(cidr
, sizeof(cidr
), "%d", inet_ntocidr(net
));
1332 setvar(&ep
, prefix
, "subnet_cidr", cidr
);
1333 if (get_option_addr(&brd
, dhcp
, DHO_BROADCAST
) == -1) {
1334 brd
.s_addr
= addr
.s_addr
| ~net
.s_addr
;
1335 setvar(&ep
, prefix
, "broadcast_address", inet_ntoa(brd
));
1337 addr
.s_addr
= dhcp
->yiaddr
& net
.s_addr
;
1338 setvar(&ep
, prefix
, "network_number", inet_ntoa(addr
));
1341 if (*dhcp
->bootfile
&& !(overl
& 1))
1342 setvar(&ep
, prefix
, "filename", (const char *)dhcp
->bootfile
);
1343 if (*dhcp
->servername
&& !(overl
& 2))
1344 setvar(&ep
, prefix
, "server_name", (const char *)dhcp
->servername
);
1346 for (opt
= dhcp_opts
; opt
->option
; opt
++) {
1349 if (has_option_mask(ifo
->nomask
, opt
->option
))
1352 p
= get_option(dhcp
, opt
->option
, &pl
, NULL
);
1355 /* We only want the FQDN name */
1356 if (opt
->option
== DHO_FQDN
) {
1360 len
= print_option(NULL
, 0, opt
->type
, pl
, p
);
1363 e
= strlen(prefix
) + strlen(opt
->var
) + len
+ 4;
1364 v
= val
= *ep
++ = xmalloc(e
);
1365 v
+= snprintf(val
, e
, "%s_%s=", prefix
, opt
->var
);
1367 print_option(v
, len
, opt
->type
, pl
, p
);
1374 get_lease(struct dhcp_lease
*lease
, const struct dhcp_message
*dhcp
)
1378 /* BOOTP does not set yiaddr for replies when ciaddr is set. */
1380 lease
->addr
.s_addr
= dhcp
->yiaddr
;
1382 lease
->addr
.s_addr
= dhcp
->ciaddr
;
1383 if (get_option_addr(&lease
->net
, dhcp
, DHO_SUBNETMASK
) == -1)
1384 lease
->net
.s_addr
= get_netmask(lease
->addr
.s_addr
);
1385 if (get_option_addr(&lease
->brd
, dhcp
, DHO_BROADCAST
) == -1)
1386 lease
->brd
.s_addr
= lease
->addr
.s_addr
| ~lease
->net
.s_addr
;
1387 if (get_option_uint32(&lease
->leasetime
, dhcp
, DHO_LEASETIME
) == 0) {
1388 /* Ensure that we can use the lease */
1389 get_monotonic(&now
);
1390 if (now
.tv_sec
+ (time_t)lease
->leasetime
< now
.tv_sec
)
1391 lease
->leasetime
= ~0U; /* Infinite lease */
1393 lease
->leasetime
= ~0U; /* Default to infinite lease */
1394 if (get_option_uint32(&lease
->renewaltime
, dhcp
, DHO_RENEWALTIME
) != 0)
1395 lease
->renewaltime
= 0;
1396 if (get_option_uint32(&lease
->rebindtime
, dhcp
, DHO_REBINDTIME
) != 0)
1397 lease
->rebindtime
= 0;
1398 if (get_option_addr(&lease
->server
, dhcp
, DHO_SERVERID
) != 0)
1399 lease
->server
.s_addr
= INADDR_ANY
;