1 /* vi: set sw=4 ts=4: */
3 * DHCP server config and lease file manipulation
5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
7 * Licensed under GPLv2, see file LICENSE in this source tree.
9 #include <netinet/ether.h>
14 /* on these functions, make sure your datatype matches */
15 static int FAST_FUNC
read_str(const char *line
, void *arg
)
20 *dest
= xstrdup(line
);
24 static int FAST_FUNC
read_u32(const char *line
, void *arg
)
26 *(uint32_t*)arg
= bb_strtou32(line
, NULL
, 10);
30 static int FAST_FUNC
read_staticlease(const char *const_line
, void *arg
)
35 struct ether_addr mac_bytes
; /* it's "struct { uint8_t mac[6]; }" */
39 line
= (char *) const_line
;
40 mac_string
= strtok_r(line
, " \t", &line
);
41 if (!mac_string
|| !ether_aton_r(mac_string
, &mac_bytes
))
45 ip_string
= strtok_r(NULL
, " \t", &line
);
46 if (!ip_string
|| !udhcp_str2nip(ip_string
, &nip
))
49 add_static_lease(arg
, (uint8_t*) &mac_bytes
, nip
);
51 log_static_leases(arg
);
57 struct config_keyword
{
59 int (*handler
)(const char *line
, void *var
) FAST_FUNC
;
64 #define OFS(field) offsetof(struct server_config_t, field)
66 static const struct config_keyword keywords
[] = {
67 /* keyword handler variable address default */
68 {"start" , udhcp_str2nip
, OFS(start_ip
), "192.168.0.20"},
69 {"end" , udhcp_str2nip
, OFS(end_ip
), "192.168.0.254"},
70 {"interface" , read_str
, OFS(interface
), "eth0"},
71 /* Avoid "max_leases value not sane" warning by setting default
72 * to default_end_ip - default_start_ip + 1: */
73 {"max_leases" , read_u32
, OFS(max_leases
), "235"},
74 {"auto_time" , read_u32
, OFS(auto_time
), "7200"},
75 {"decline_time" , read_u32
, OFS(decline_time
), "3600"},
76 {"conflict_time", read_u32
, OFS(conflict_time
), "3600"},
77 {"offer_time" , read_u32
, OFS(offer_time
), "60"},
78 {"min_lease" , read_u32
, OFS(min_lease_sec
), "60"},
79 {"lease_file" , read_str
, OFS(lease_file
), LEASES_FILE
},
80 {"pidfile" , read_str
, OFS(pidfile
), "/var/run/udhcpd.pid"},
81 {"siaddr" , udhcp_str2nip
, OFS(siaddr_nip
), "0.0.0.0"},
82 /* keywords with no defaults must be last! */
83 {"option" , udhcp_str2optset
, OFS(options
), ""},
84 {"opt" , udhcp_str2optset
, OFS(options
), ""},
85 {"notify_file" , read_str
, OFS(notify_file
), NULL
},
86 {"sname" , read_str
, OFS(sname
), NULL
},
87 {"boot_file" , read_str
, OFS(boot_file
), NULL
},
88 {"static_lease" , read_staticlease
, OFS(static_leases
), ""},
90 enum { KWS_WITH_DEFAULTS
= ARRAY_SIZE(keywords
) - 6 };
92 void FAST_FUNC
read_config(const char *file
)
95 const struct config_keyword
*k
;
99 for (i
= 0; i
< KWS_WITH_DEFAULTS
; i
++)
100 keywords
[i
].handler(keywords
[i
].def
, (char*)&server_config
+ keywords
[i
].ofs
);
102 parser
= config_open(file
);
103 while (config_read(parser
, token
, 2, 2, "# \t", PARSE_NORMAL
)) {
104 for (k
= keywords
, i
= 0; i
< ARRAY_SIZE(keywords
); k
++, i
++) {
105 if (strcasecmp(token
[0], k
->keyword
) == 0) {
106 if (!k
->handler(token
[1], (char*)&server_config
+ k
->ofs
)) {
107 bb_error_msg("can't parse line %u in %s",
108 parser
->lineno
, file
);
109 /* reset back to the default value */
110 k
->handler(k
->def
, (char*)&server_config
+ k
->ofs
);
116 config_close(parser
);
118 server_config
.start_ip
= ntohl(server_config
.start_ip
);
119 server_config
.end_ip
= ntohl(server_config
.end_ip
);
122 void FAST_FUNC
write_leases(void)
129 fd
= open_or_warn(server_config
.lease_file
, O_WRONLY
|O_CREAT
|O_TRUNC
);
133 curr
= written_at
= time(NULL
);
135 written_at
= SWAP_BE64(written_at
);
136 full_write(fd
, &written_at
, sizeof(written_at
));
138 for (i
= 0; i
< server_config
.max_leases
; i
++) {
139 leasetime_t tmp_time
;
141 if (g_leases
[i
].lease_nip
== 0)
144 /* Screw with the time in the struct, for easier writing */
145 tmp_time
= g_leases
[i
].expires
;
147 g_leases
[i
].expires
-= curr
;
148 if ((signed_leasetime_t
) g_leases
[i
].expires
< 0)
149 g_leases
[i
].expires
= 0;
150 g_leases
[i
].expires
= htonl(g_leases
[i
].expires
);
152 /* No error check. If the file gets truncated,
153 * we lose some leases on restart. Oh well. */
154 full_write(fd
, &g_leases
[i
], sizeof(g_leases
[i
]));
156 /* Then restore it when done */
157 g_leases
[i
].expires
= tmp_time
;
161 if (server_config
.notify_file
) {
163 argv
[0] = server_config
.notify_file
;
164 argv
[1] = server_config
.lease_file
;
166 spawn_and_wait(argv
);
170 void FAST_FUNC
read_leases(const char *file
)
172 struct dyn_lease lease
;
173 int64_t written_at
, time_passed
;
175 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
179 fd
= open_or_warn(file
, O_RDONLY
);
183 if (full_read(fd
, &written_at
, sizeof(written_at
)) != sizeof(written_at
))
185 written_at
= SWAP_BE64(written_at
);
187 time_passed
= time(NULL
) - written_at
;
188 /* Strange written_at, or lease file from old version of udhcpd
189 * which had no "written_at" field? */
190 if ((uint64_t)time_passed
> 12 * 60 * 60)
193 while (full_read(fd
, &lease
, sizeof(lease
)) == sizeof(lease
)) {
194 uint32_t y
= ntohl(lease
.lease_nip
);
195 if (y
>= server_config
.start_ip
&& y
<= server_config
.end_ip
) {
196 signed_leasetime_t expires
= ntohl(lease
.expires
) - (signed_leasetime_t
)time_passed
;
200 /* We keep expired leases: add_lease() will add
201 * a lease with 0 seconds remaining.
202 * Fewer IP address changes this way for mass reboot scenario.
206 /* Check if there is a different static lease for this IP or MAC */
207 static_nip
= get_static_nip_by_mac(server_config
.static_leases
, lease
.lease_mac
);
209 /* NB: we do not add lease even if static_nip == lease.lease_nip.
213 if (is_nip_reserved(server_config
.static_leases
, lease
.lease_nip
))
216 /* NB: add_lease takes "relative time", IOW,
217 * lease duration, not lease deadline. */
218 if (add_lease(lease
.lease_mac
, lease
.lease_nip
,
220 lease
.hostname
, sizeof(lease
.hostname
)
223 bb_error_msg("too many leases while loading %s", file
);
226 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
231 log1("read %d leases", i
);