]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/dhcpd.c
66f8b7727c0046db8817804defde2e3aa8c4de71
[thirdparty/dhcp.git] / server / dhcpd.c
1 /* dhcpd.c
2
3 DHCP Server Daemon. */
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998, 1999
7 * The Internet Software Consortium. All rights reserved.
8 *
9 * Redistribution and use of this source file, source files derived in whole
10 * or in part from this source file, and binary files derived in whole or in
11 * part from this source file, with or without modification, are permitted
12 * provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * This copyright notice must appear directly below any initial commentary
17 * describing the file, and may not be preceded by any other copyright
18 * notice.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of The Internet Software Consortium (hereafter
23 * referred to as "the ISC") nor the names of its contributors may be
24 * used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 * 4. This software is a part of the ISC DHCP Distribution. Redistributions
27 * of this source file or binary files derived from this source file
28 * MUST include all documentation accompanying the ISC release from
29 * which such redistributions are derived of this source file, specifically
30 * the following files (listed relative to the top of the ISC DHCP
31 * distribution directory tree):
32 *
33 * README
34 * common/dhcp-contrib.5
35 * common/dhcp-options.5
36 * server/dhcpd.8
37 * server/dhcpd.conf.5
38 * server/dhcpd.leases.5
39 * client/dhclient.8
40 * client/dhclient.conf.5
41 * client/dhclient-script.8
42 * client/dhclient.leases.5
43 * relay/dhcrelay.8
44 *
45 * Absence of these files from a distribution you receive does not excuse
46 * you from this requirement - if the distribution you receive does not
47 * contain these files, you must get them from the ISC and include them
48 * in any redistribution of this source file or any derivative work based
49 * wholly or in part on this source file. It is permissible in a binary
50 * redistribution derived from this source file to include formatted
51 * versions of the manual pages mentioned above, and also to add to or
52 * correct the manual pages and README file mentioned above so long as the
53 * sections labeled CONTRIBUTIONS in these documents are unchanged except
54 * with respect to formatting, so long as the order in which the
55 * CONTRIBUTIONS section appears in these documents is not changed, and
56 * so long as the dhcp-contrib.5 manual page is unchanged except with
57 * respect to formatting. It is also permissible to redistribute this
58 * source file, source files derived wholly or in part from this source
59 * file, and binaries derived wholly or in part from this source file
60 * accompanied by the aforementioned manual pages translated into another
61 * language. In this case, the CONTRIBUTIONS section and the
62 * dhcp-contrib.5 section may either be left in their original language
63 * or translated into the new language with such care and diligence as
64 * is required to preserve the original meaning.
65 * 5. If, in addition to the documentation mentioned in section 4, this
66 * source file, a source file derived wholly or in part from this source
67 * file, or a binary file derived wholly or in part from this source file
68 * is redistributed with additional printed or electronic documentation,
69 * then that documentation must refer to the dhcp-contrib.5 manual page
70 * in as conspicuous a way as the aforementioned documentation refers to
71 * it, and the dhcp-contrib.5 manual page must be converted into the same
72 * format and be made easily accessible to any recipient of such
73 * redistributions.
74 *
75 * THIS SOFTWARE IS PROVIDED BY THE ISC AND CONTRIBUTORS ``AS IS'' AND ANY
76 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
77 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
78 * DISCLAIMED. IN NO EVENT SHALL THE ISC OR CONTRIBUTORS BE LIABLE FOR ANY
79 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
80 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
81 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
82 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
84 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85 * SUCH DAMAGE.
86 *
87 * This software has been written for the ISC by Ted Lemon <mellon@isc.org>
88 * in cooperation with Vixie Enterprises and Internet Engines, Inc. To
89 * learn more about the ISC, see ``http://www.vix.com/isc''. Development
90 * of this software is funded through contributions and support contracts.
91 * Please see the dhcp-contrib manual page that accompanies this file for
92 * information on how you can contribute.
93 */
94
95 #ifndef lint
96 static char ocopyright[] =
97 "$Id: dhcpd.c,v 1.58 1999/03/16 00:56:36 mellon Exp $ Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
98 #endif
99
100 static char copyright[] =
101 "Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
102 static char arr [] = "All rights reserved.";
103 static char message [] = "Internet Software Consortium DHCP Server V3.0-alpha 980315";
104 static char contrib [] = "\nPlease contribute if you find this software useful.";
105 static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html\n";
106
107 #include "dhcpd.h"
108
109 static void usage PROTO ((void));
110
111 TIME cur_time;
112 struct group root_group;
113
114 struct iaddr server_identifier;
115 int server_identifier_matched;
116
117 u_int16_t local_port;
118 u_int16_t remote_port;
119
120 int log_priority;
121 #ifdef DEBUG
122 int log_perror = -1;
123 #else
124 int log_perror = 1;
125 #endif
126
127 char *path_dhcpd_conf = _PATH_DHCPD_CONF;
128 char *path_dhcpd_db = _PATH_DHCPD_DB;
129 char *path_dhcpd_pid = _PATH_DHCPD_PID;
130
131 int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
132
133 int main (argc, argv, envp)
134 int argc;
135 char **argv, **envp;
136 {
137 int i, status;
138 struct servent *ent;
139 char *s;
140 int cftest = 0;
141 #ifndef DEBUG
142 int pidfilewritten = 0;
143 int pid;
144 char pbuf [20];
145 int daemon = 1;
146 #endif
147 int quiet = 0;
148
149 /* Initially, log errors to stderr as well as to syslogd. */
150 #ifdef SYSLOG_4_2
151 openlog ("dhcpd", LOG_NDELAY);
152 log_priority = DHCPD_LOG_FACILITY;
153 #else
154 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
155 #endif
156
157 #ifndef DEBUG
158 #ifndef SYSLOG_4_2
159 #ifndef __CYGWIN32__ /* XXX */
160 setlogmask (LOG_UPTO (LOG_INFO));
161 #endif
162 #endif
163 #endif
164
165 for (i = 1; i < argc; i++) {
166 if (!strcmp (argv [i], "-p")) {
167 if (++i == argc)
168 usage ();
169 for (s = argv [i]; *s; s++)
170 if (!isdigit (*s))
171 log_fatal ("%s: not a valid UDP port",
172 argv [i]);
173 status = atoi (argv [i]);
174 if (status < 1 || status > 65535)
175 log_fatal ("%s: not a valid UDP port",
176 argv [i]);
177 local_port = htons (status);
178 log_debug ("binding to user-specified port %d",
179 ntohs (local_port));
180 } else if (!strcmp (argv [i], "-f")) {
181 #ifndef DEBUG
182 daemon = 0;
183 #endif
184 } else if (!strcmp (argv [i], "-d")) {
185 #ifndef DEBUG
186 daemon = 0;
187 #endif
188 log_perror = -1;
189 } else if (!strcmp (argv [i], "-cf")) {
190 if (++i == argc)
191 usage ();
192 path_dhcpd_conf = argv [i];
193 } else if (!strcmp (argv [i], "-lf")) {
194 if (++i == argc)
195 usage ();
196 path_dhcpd_db = argv [i];
197 } else if (!strcmp (argv [i], "-pf")) {
198 if (++i == argc)
199 usage ();
200 path_dhcpd_pid = argv [i];
201 } else if (!strcmp (argv [i], "-t")) {
202 /* test configurations only */
203 #ifndef DEBUG
204 daemon = 0;
205 #endif
206 cftest = 1;
207 log_perror = -1;
208 } else if (!strcmp (argv [i], "-q")) {
209 quiet = 1;
210 quiet_interface_discovery = 1;
211 } else if (argv [i][0] == '-') {
212 usage ();
213 } else {
214 struct interface_info *tmp =
215 ((struct interface_info *)
216 dmalloc (sizeof *tmp, "get_interface_list"));
217 if (!tmp)
218 log_fatal ("Insufficient memory to %s %s",
219 "record interface", argv [i]);
220 memset (tmp, 0, sizeof *tmp);
221 strcpy (tmp -> name, argv [i]);
222 tmp -> next = interfaces;
223 tmp -> flags = INTERFACE_REQUESTED;
224 interfaces = tmp;
225 }
226 }
227
228 if (!quiet) {
229 log_info (message);
230 log_info (copyright);
231 log_info (arr);
232 log_info (contrib);
233 log_info (url);
234 }
235
236 /* Default to the DHCP/BOOTP port. */
237 if (!local_port)
238 {
239 ent = getservbyname ("dhcp", "udp");
240 if (!ent)
241 local_port = htons (67);
242 else
243 local_port = ent -> s_port;
244 #ifndef __CYGWIN32__ /* XXX */
245 endservent ();
246 #endif
247 }
248
249 remote_port = htons (ntohs (local_port) + 1);
250
251 /* Get the current time... */
252 GET_TIME (&cur_time);
253
254 /* Initialize DNS support... */
255 #if 0
256 dns_startup ();
257 #endif
258
259 /* Start the interactive client listener. */
260 interact_startup ();
261
262 /* Set up the client classification system. */
263 classification_setup ();
264
265 /* Read the dhcpd.conf file... */
266 if (!readconf ())
267 log_fatal ("Configuration file errors encountered -- exiting");
268
269 /* test option should cause an early exit */
270 if (cftest)
271 exit(0);
272
273 /* Start up the database... */
274 db_startup ();
275
276 /* Discover all the network interfaces and initialize them. */
277 discover_interfaces (DISCOVER_SERVER);
278
279 /* Initialize icmp support... */
280 icmp_startup (1, lease_pinged);
281
282 #ifndef DEBUG
283 if (daemon) {
284 /* First part of becoming a daemon... */
285 if ((pid = fork ()) < 0)
286 log_fatal ("Can't fork daemon: %m");
287 else if (pid)
288 exit (0);
289 }
290
291 /* Read previous pid file. */
292 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
293 status = read (i, pbuf, (sizeof pbuf) - 1);
294 close (i);
295 pbuf [status] = 0;
296 pid = atoi (pbuf);
297
298 /* If the previous server process is not still running,
299 write a new pid file immediately. */
300 if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
301 unlink (path_dhcpd_pid);
302 if ((i = open (path_dhcpd_pid,
303 O_WRONLY | O_CREAT, 0640)) >= 0) {
304 sprintf (pbuf, "%d\n", (int)getpid ());
305 write (i, pbuf, strlen (pbuf));
306 close (i);
307 pidfilewritten = 1;
308 }
309 } else
310 log_fatal ("There's already a DHCP server running.\n");
311 }
312
313 /* If we were requested to log to stdout on the command line,
314 keep doing so; otherwise, stop. */
315 if (log_perror == -1)
316 log_perror = 1;
317 else
318 log_perror = 0;
319
320 if (daemon) {
321 /* Become session leader and get pid... */
322 close (0);
323 close (1);
324 close (2);
325 pid = setsid ();
326 }
327
328 /* If we didn't write the pid file earlier because we found a
329 process running the logged pid, but we made it to here,
330 meaning nothing is listening on the bootp port, then write
331 the pid file out - what's in it now is bogus anyway. */
332 if (!pidfilewritten) {
333 unlink (path_dhcpd_pid);
334 if ((i = open (path_dhcpd_pid,
335 O_WRONLY | O_CREAT, 0640)) >= 0) {
336 sprintf (pbuf, "%d\n", (int)getpid ());
337 write (i, pbuf, strlen (pbuf));
338 close (i);
339 pidfilewritten = 1;
340 }
341 }
342 #endif /* !DEBUG */
343
344 /* Set up the bootp packet handler... */
345 bootp_packet_handler = do_packet;
346
347 /* Receive packets and dispatch them... */
348 dispatch ();
349
350 /* Not reached */
351 return 0;
352 }
353
354 /* Print usage message. */
355
356 static void usage ()
357 {
358 log_info (message);
359 log_info (copyright);
360 log_info (arr);
361
362 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f] [-cf config-file]%s",
363 "\n [-lf lease-file] [if0 [...ifN]]");
364 }
365
366 void cleanup ()
367 {
368 }
369
370 void lease_pinged (from, packet, length)
371 struct iaddr from;
372 u_int8_t *packet;
373 int length;
374 {
375 struct lease *lp;
376
377 /* Don't try to look up a pinged lease if we aren't trying to
378 ping one - otherwise somebody could easily make us churn by
379 just forging repeated ICMP EchoReply packets for us to look
380 up. */
381 if (!outstanding_pings)
382 return;
383
384 lp = find_lease_by_ip_addr (from);
385
386 if (!lp) {
387 log_info ("unexpected ICMP Echo Reply from %s", piaddr (from));
388 return;
389 }
390
391 if (!lp -> state) {
392 log_error ("ICMP Echo Reply for %s arrived late or is spurious.\n",
393 piaddr (from));
394 return;
395 }
396
397 if (lp -> ends > cur_time) {
398 log_error ("ICMP Echo reply arrived while lease %s was valid.\n",
399 piaddr (from));
400 }
401
402 /* At this point it looks like we pinged a lease and got a
403 response, which shouldn't have happened. */
404 data_string_forget (&lp -> state -> parameter_request_list,
405 "lease_pinged");
406 free_lease_state (lp -> state, "lease_pinged");
407 lp -> state = (struct lease_state *)0;
408
409 abandon_lease (lp, "pinged before offer");
410 cancel_timeout (lease_ping_timeout, lp);
411 --outstanding_pings;
412 }
413
414 void lease_ping_timeout (vlp)
415 void *vlp;
416 {
417 struct lease *lp = vlp;
418
419 --outstanding_pings;
420 dhcp_reply (lp);
421 }