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:
13 * http://www.isc.org/isc-license-1.0.html.
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.
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
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.";
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";
38 static void usage
PROTO ((void));
41 struct group root_group
;
43 struct iaddr server_identifier
;
44 int server_identifier_matched
;
47 u_int16_t remote_port
;
49 struct in_addr limited_broadcast
;
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
;
55 int dhcp_max_agent_option_packet_length
= DHCP_MTU_MAX
;
57 int main (argc
, argv
, envp
)
67 int pidfilewritten
= 0;
73 char *server
= (char *)0;
75 omapi_object_t
*listener
;
77 struct interface_info
*ip
;
78 struct data_string fname
;
79 struct option_cache
*oc
;
80 struct option_state
*options
= (struct option_state
*)0;;
82 /* Initially, log errors to stderr as well as to syslogd. */
84 openlog ("dhcpd", LOG_NDELAY
);
85 log_priority
= DHCPD_LOG_FACILITY
;
87 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
90 for (i
= 1; i
< argc
; i
++) {
91 if (!strcmp (argv
[i
], "-p")) {
94 for (s
= argv
[i
]; *s
; s
++)
96 log_fatal ("%s: not a valid UDP port",
98 status
= atoi (argv
[i
]);
99 if (status
< 1 || status
> 65535)
100 log_fatal ("%s: not a valid UDP port",
102 local_port
= htons (status
);
103 log_debug ("binding to user-specified port %d",
105 } else if (!strcmp (argv
[i
], "-f")) {
109 } else if (!strcmp (argv
[i
], "-d")) {
114 } else if (!strcmp (argv
[i
], "-s")) {
118 } else if (!strcmp (argv
[i
], "-cf")) {
121 path_dhcpd_conf
= argv
[i
];
122 } else if (!strcmp (argv
[i
], "-lf")) {
125 path_dhcpd_db
= argv
[i
];
126 } else if (!strcmp (argv
[i
], "-pf")) {
129 path_dhcpd_pid
= argv
[i
];
130 } else if (!strcmp (argv
[i
], "-t")) {
131 /* test configurations only */
137 } else if (!strcmp (argv
[i
], "-T")) {
138 /* test configurations and lease file only */
145 } else if (!strcmp (argv
[i
], "-q")) {
147 quiet_interface_discovery
= 1;
148 } else if (argv
[i
][0] == '-') {
151 struct interface_info
*tmp
=
152 ((struct interface_info
*)
153 dmalloc (sizeof *tmp
, MDL
));
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
;
166 log_info ("%s %s", message
, DHCP_VERSION
);
167 log_info (copyright
);
174 /* Default to the DHCP/BOOTP port. */
177 ent
= getservbyname ("dhcp", "udp");
179 local_port
= htons (67);
181 local_port
= ent
-> s_port
;
182 #ifndef __CYGWIN32__ /* XXX */
187 remote_port
= htons (ntohs (local_port
) + 1);
190 if (!inet_aton (server
, &limited_broadcast
)) {
192 he
= gethostbyname (server
);
194 memcpy (&limited_broadcast
,
195 he
-> h_addr_list
[0],
196 sizeof limited_broadcast
);
198 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
201 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
204 /* Get the current time... */
205 GET_TIME (&cur_time
);
207 /* Initialize DNS support... */
212 /* Set up the client classification system. */
213 classification_setup ();
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
));
221 /* Set up the OMAPI wrappers for various server database internal
223 dhcp_db_objects_setup ();
225 /* Read the dhcpd.conf file... */
226 if (readconf () != ISC_R_SUCCESS
)
227 log_fatal ("Configuration file errors encountered -- exiting");
229 /* test option should cause an early exit */
230 if (cftest
&& !lftest
)
233 /* Now try to get the lease file name. */
234 option_state_allocate (&options
, MDL
);
236 execute_statements_in_scope ((struct packet
*)0,
238 (struct option_state
*)0,
239 options
, &global_scope
,
242 memset (&fname
, 0, sizeof fname
);
243 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
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
);
251 log_fatal ("no memory for lease db filename.");
252 memcpy (s
, fname
.data
, fname
.len
);
254 data_string_forget (&fname
, MDL
);
258 oc
= lookup_option (&server_universe
, options
, SV_PID_FILE_NAME
);
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
);
266 log_fatal ("no memory for lease db filename.");
267 memcpy (s
, fname
.data
, fname
.len
);
269 data_string_forget (&fname
, MDL
);
273 /* Don't need the options anymore. */
274 option_state_dereference (&options
, MDL
);
276 /* Start up the database... */
282 /* Discover all the network interfaces and initialize them. */
283 discover_interfaces (DISCOVER_SERVER
);
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. */
291 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
294 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
295 sizeof seed
], sizeof seed
);
298 srandom (seed
+ cur_time
);
300 /* Initialize icmp support... */
301 icmp_startup (1, lease_pinged
);
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
));
317 /* First part of becoming a daemon... */
318 if ((pid
= fork ()) < 0)
319 log_fatal ("Can't fork daemon: %m");
324 /* Read previous pid file. */
325 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
326 status
= read (i
, pbuf
, (sizeof pbuf
) - 1);
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
));
343 log_fatal ("There's already a DHCP server running.\n");
346 /* If we were requested to log to stdout on the command line,
347 keep doing so; otherwise, stop. */
348 if (log_perror
== -1)
354 /* Become session leader and get pid... */
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
));
377 /* Set up the bootp packet handler... */
378 bootp_packet_handler
= do_packet
;
380 /* Receive packets and dispatch them... */
387 /* Print usage message. */
392 log_info (copyright
);
395 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f] [-cf config-file]%s",
396 "\n [-lf lease-file] [if0 [...ifN]]");
399 void lease_pinged (from
, packet
, length
)
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
410 if (!outstanding_pings
)
413 lp
= find_lease_by_ip_addr (from
);
416 log_info ("unexpected ICMP Echo Reply from %s", piaddr (from
));
421 log_error ("ICMP Echo Reply for %s arrived late or is spurious.\n",
426 if (lp
-> ends
> cur_time
) {
427 log_error ("ICMP Echo reply while lease %s valid\n",
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;
437 abandon_lease (lp
, "pinged before offer");
438 cancel_timeout (lease_ping_timeout
, lp
);
442 void lease_ping_timeout (vlp
)
445 struct lease
*lp
= vlp
;