]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/dhcpd.c
Fix compilation errors introduced in the last set of checkins.
[thirdparty/dhcp.git] / server / dhcpd.c
1 /* dhcpd.c
2
3 DHCP Server Daemon. */
4
5 /*
6 * Copyright (c) 1996-2000 Internet Software Consortium.
7 * Use is subject to license terms which appear in the file named
8 * ISC-LICENSE that should have accompanied this file when you
9 * received it. If a file named ISC-LICENSE did not accompany this
10 * file, or you are not sure the one you have is correct, you may
11 * obtain an applicable copy of the license at:
12 *
13 * http://www.isc.org/isc-license-1.0.html.
14 *
15 * This file is part of the ISC DHCP distribution. The documentation
16 * associated with this file is listed in the file DOCUMENTATION,
17 * included in the top-level directory of this release.
18 *
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
21 */
22
23 #ifndef lint
24 static char ocopyright[] =
25 "$Id: dhcpd.c,v 1.81 2000/01/26 14:56:18 mellon Exp $ Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
26 #endif
27
28 static char copyright[] =
29 "Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
30 static char arr [] = "All rights reserved.";
31 static char message [] = "Internet Software Consortium DHCP Server";
32 static char contrib [] = "\nPlease contribute if you find this software useful.";
33 static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html\n";
34
35 #include "dhcpd.h"
36 #include "version.h"
37
38 static void usage PROTO ((void));
39
40 TIME cur_time;
41 struct group root_group;
42
43 struct iaddr server_identifier;
44 int server_identifier_matched;
45
46 u_int16_t local_port;
47 u_int16_t remote_port;
48
49 struct in_addr limited_broadcast;
50
51 const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
52 const char *path_dhcpd_db = _PATH_DHCPD_DB;
53 const char *path_dhcpd_pid = _PATH_DHCPD_PID;
54
55 int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
56
57 int main (argc, argv, envp)
58 int argc;
59 char **argv, **envp;
60 {
61 int i, status;
62 struct servent *ent;
63 char *s;
64 int cftest = 0;
65 int lftest = 0;
66 #ifndef DEBUG
67 int pidfilewritten = 0;
68 int pid;
69 char pbuf [20];
70 int daemon = 1;
71 #endif
72 int quiet = 0;
73 char *server = (char *)0;
74 isc_result_t result;
75 omapi_object_t *listener;
76 unsigned seed;
77 struct interface_info *ip;
78 struct data_string fname;
79 struct option_cache *oc;
80 struct option_state *options = (struct option_state *)0;;
81
82 /* Initially, log errors to stderr as well as to syslogd. */
83 #ifdef SYSLOG_4_2
84 openlog ("dhcpd", LOG_NDELAY);
85 log_priority = DHCPD_LOG_FACILITY;
86 #else
87 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
88 #endif
89
90 for (i = 1; i < argc; i++) {
91 if (!strcmp (argv [i], "-p")) {
92 if (++i == argc)
93 usage ();
94 for (s = argv [i]; *s; s++)
95 if (!isdigit (*s))
96 log_fatal ("%s: not a valid UDP port",
97 argv [i]);
98 status = atoi (argv [i]);
99 if (status < 1 || status > 65535)
100 log_fatal ("%s: not a valid UDP port",
101 argv [i]);
102 local_port = htons (status);
103 log_debug ("binding to user-specified port %d",
104 ntohs (local_port));
105 } else if (!strcmp (argv [i], "-f")) {
106 #ifndef DEBUG
107 daemon = 0;
108 #endif
109 } else if (!strcmp (argv [i], "-d")) {
110 #ifndef DEBUG
111 daemon = 0;
112 #endif
113 log_perror = -1;
114 } else if (!strcmp (argv [i], "-s")) {
115 if (++i == argc)
116 usage ();
117 server = argv [i];
118 } else if (!strcmp (argv [i], "-cf")) {
119 if (++i == argc)
120 usage ();
121 path_dhcpd_conf = argv [i];
122 } else if (!strcmp (argv [i], "-lf")) {
123 if (++i == argc)
124 usage ();
125 path_dhcpd_db = argv [i];
126 } else if (!strcmp (argv [i], "-pf")) {
127 if (++i == argc)
128 usage ();
129 path_dhcpd_pid = argv [i];
130 } else if (!strcmp (argv [i], "-t")) {
131 /* test configurations only */
132 #ifndef DEBUG
133 daemon = 0;
134 #endif
135 cftest = 1;
136 log_perror = -1;
137 } else if (!strcmp (argv [i], "-T")) {
138 /* test configurations and lease file only */
139 #ifndef DEBUG
140 daemon = 0;
141 #endif
142 cftest = 1;
143 lftest = 1;
144 log_perror = -1;
145 } else if (!strcmp (argv [i], "-q")) {
146 quiet = 1;
147 quiet_interface_discovery = 1;
148 } else if (argv [i][0] == '-') {
149 usage ();
150 } else {
151 struct interface_info *tmp =
152 ((struct interface_info *)
153 dmalloc (sizeof *tmp, MDL));
154 if (!tmp)
155 log_fatal ("Insufficient memory to %s %s",
156 "record interface", argv [i]);
157 memset (tmp, 0, sizeof *tmp);
158 strcpy (tmp -> name, argv [i]);
159 tmp -> next = interfaces;
160 tmp -> flags = INTERFACE_REQUESTED;
161 interfaces = tmp;
162 }
163 }
164
165 if (!quiet) {
166 log_info ("%s %s", message, DHCP_VERSION);
167 log_info (copyright);
168 log_info (arr);
169 log_info (contrib);
170 log_info (url);
171 } else
172 quiet = 0;
173
174 /* Default to the DHCP/BOOTP port. */
175 if (!local_port)
176 {
177 ent = getservbyname ("dhcp", "udp");
178 if (!ent)
179 local_port = htons (67);
180 else
181 local_port = ent -> s_port;
182 #ifndef __CYGWIN32__ /* XXX */
183 endservent ();
184 #endif
185 }
186
187 remote_port = htons (ntohs (local_port) + 1);
188
189 if (server) {
190 if (!inet_aton (server, &limited_broadcast)) {
191 struct hostent *he;
192 he = gethostbyname (server);
193 if (he) {
194 memcpy (&limited_broadcast,
195 he -> h_addr_list [0],
196 sizeof limited_broadcast);
197 } else
198 limited_broadcast.s_addr = INADDR_BROADCAST;
199 }
200 } else {
201 limited_broadcast.s_addr = INADDR_BROADCAST;
202 }
203
204 /* Get the current time... */
205 GET_TIME (&cur_time);
206
207 /* Initialize DNS support... */
208 #if 0
209 dns_startup ();
210 #endif
211
212 /* Set up the client classification system. */
213 classification_setup ();
214
215 /* Initialize the omapi system. */
216 result = omapi_init ();
217 if (result != ISC_R_SUCCESS)
218 log_fatal ("Can't initialize OMAPI: %s\n",
219 isc_result_totext (result));
220
221 /* Set up the OMAPI wrappers for various server database internal
222 objects. */
223 dhcp_db_objects_setup ();
224
225 /* Read the dhcpd.conf file... */
226 if (readconf () != ISC_R_SUCCESS)
227 log_fatal ("Configuration file errors encountered -- exiting");
228
229 /* test option should cause an early exit */
230 if (cftest && !lftest)
231 exit(0);
232
233 /* Now try to get the lease file name. */
234 option_state_allocate (&options, MDL);
235
236 execute_statements_in_scope ((struct packet *)0,
237 (struct lease *)0,
238 (struct option_state *)0,
239 options, &global_scope,
240 &root_group,
241 (struct group *)0);
242 memset (&fname, 0, sizeof fname);
243 oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
244 if (oc &&
245 evaluate_option_cache (&fname, (struct packet *)0,
246 (struct lease *)0, options,
247 (struct option_state *)0,
248 &global_scope, oc, MDL)) {
249 s = dmalloc (fname.len + 1, MDL);
250 if (!s)
251 log_fatal ("no memory for lease db filename.");
252 memcpy (s, fname.data, fname.len);
253 s [fname.len] = 0;
254 data_string_forget (&fname, MDL);
255 path_dhcpd_db = s;
256 }
257
258 oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
259 if (oc &&
260 evaluate_option_cache (&fname, (struct packet *)0,
261 (struct lease *)0, options,
262 (struct option_state *)0,
263 &global_scope, oc, MDL)) {
264 s = dmalloc (fname.len + 1, MDL);
265 if (!s)
266 log_fatal ("no memory for lease db filename.");
267 memcpy (s, fname.data, fname.len);
268 s [fname.len] = 0;
269 data_string_forget (&fname, MDL);
270 path_dhcpd_pid = s;
271 }
272
273 /* Don't need the options anymore. */
274 option_state_dereference (&options, MDL);
275
276 /* Start up the database... */
277 db_startup (lftest);
278
279 if (lftest)
280 exit (0);
281
282 /* Discover all the network interfaces and initialize them. */
283 discover_interfaces (DISCOVER_SERVER);
284
285 /* Make up a seed for the random number generator from current
286 time plus the sum of the last four bytes of each
287 interface's hardware address interpreted as an integer.
288 Not much entropy, but we're booting, so we're not likely to
289 find anything better. */
290 seed = 0;
291 for (ip = interfaces; ip; ip = ip -> next) {
292 int junk;
293 memcpy (&junk,
294 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
295 sizeof seed], sizeof seed);
296 seed += junk;
297 }
298 srandom (seed + cur_time);
299
300 /* Initialize icmp support... */
301 icmp_startup (1, lease_pinged);
302
303 /* Start up a listener for the object management API protocol. */
304 listener = (omapi_object_t *)0;
305 result = omapi_generic_new (&listener, MDL);
306 if (result != ISC_R_SUCCESS)
307 log_fatal ("Can't allocate new generic object: %s\n",
308 isc_result_totext (result));
309 result = omapi_protocol_listen (listener,
310 OMAPI_PROTOCOL_PORT, 1);
311 if (result != ISC_R_SUCCESS)
312 log_fatal ("Can't start OMAPI protocol: %s",
313 isc_result_totext (result));
314
315 #ifndef DEBUG
316 if (daemon) {
317 /* First part of becoming a daemon... */
318 if ((pid = fork ()) < 0)
319 log_fatal ("Can't fork daemon: %m");
320 else if (pid)
321 exit (0);
322 }
323
324 /* Read previous pid file. */
325 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
326 status = read (i, pbuf, (sizeof pbuf) - 1);
327 close (i);
328 pbuf [status] = 0;
329 pid = atoi (pbuf);
330
331 /* If the previous server process is not still running,
332 write a new pid file immediately. */
333 if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
334 unlink (path_dhcpd_pid);
335 if ((i = open (path_dhcpd_pid,
336 O_WRONLY | O_CREAT, 0640)) >= 0) {
337 sprintf (pbuf, "%d\n", (int)getpid ());
338 write (i, pbuf, strlen (pbuf));
339 close (i);
340 pidfilewritten = 1;
341 }
342 } else
343 log_fatal ("There's already a DHCP server running.\n");
344 }
345
346 /* If we were requested to log to stdout on the command line,
347 keep doing so; otherwise, stop. */
348 if (log_perror == -1)
349 log_perror = 1;
350 else
351 log_perror = 0;
352
353 if (daemon) {
354 /* Become session leader and get pid... */
355 close (0);
356 close (1);
357 close (2);
358 pid = setsid ();
359 }
360
361 /* If we didn't write the pid file earlier because we found a
362 process running the logged pid, but we made it to here,
363 meaning nothing is listening on the bootp port, then write
364 the pid file out - what's in it now is bogus anyway. */
365 if (!pidfilewritten) {
366 unlink (path_dhcpd_pid);
367 if ((i = open (path_dhcpd_pid,
368 O_WRONLY | O_CREAT, 0640)) >= 0) {
369 sprintf (pbuf, "%d\n", (int)getpid ());
370 write (i, pbuf, strlen (pbuf));
371 close (i);
372 pidfilewritten = 1;
373 }
374 }
375 #endif /* !DEBUG */
376
377 /* Set up the bootp packet handler... */
378 bootp_packet_handler = do_packet;
379
380 /* Receive packets and dispatch them... */
381 dispatch ();
382
383 /* Not reached */
384 return 0;
385 }
386
387 /* Print usage message. */
388
389 static void usage ()
390 {
391 log_info (message);
392 log_info (copyright);
393 log_info (arr);
394
395 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f] [-cf config-file]%s",
396 "\n [-lf lease-file] [if0 [...ifN]]");
397 }
398
399 void lease_pinged (from, packet, length)
400 struct iaddr from;
401 u_int8_t *packet;
402 int length;
403 {
404 struct lease *lp;
405
406 /* Don't try to look up a pinged lease if we aren't trying to
407 ping one - otherwise somebody could easily make us churn by
408 just forging repeated ICMP EchoReply packets for us to look
409 up. */
410 if (!outstanding_pings)
411 return;
412
413 lp = find_lease_by_ip_addr (from);
414
415 if (!lp) {
416 log_info ("unexpected ICMP Echo Reply from %s", piaddr (from));
417 return;
418 }
419
420 if (!lp -> state) {
421 log_error ("ICMP Echo Reply for %s arrived late or is spurious.\n",
422 piaddr (from));
423 return;
424 }
425
426 if (lp -> ends > cur_time) {
427 log_error ("ICMP Echo reply while lease %s valid\n",
428 piaddr (from));
429 }
430
431 /* At this point it looks like we pinged a lease and got a
432 response, which shouldn't have happened. */
433 data_string_forget (&lp -> state -> parameter_request_list, MDL);
434 free_lease_state (lp -> state, MDL);
435 lp -> state = (struct lease_state *)0;
436
437 abandon_lease (lp, "pinged before offer");
438 cancel_timeout (lease_ping_timeout, lp);
439 --outstanding_pings;
440 }
441
442 void lease_ping_timeout (vlp)
443 void *vlp;
444 {
445 struct lease *lp = vlp;
446
447 --outstanding_pings;
448 dhcp_reply (lp);
449 }