blob: 1ef85697e7fc5338b1836c66b1507ac15b295a89 [file] [log] [blame]
San Mehatffd68722010-01-20 09:56:15 -08001/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DHCP
20
21#define BOOTREQUEST 1
22#define BOOTREPLY 2
23#define DHCP_COOKIE 0x63825363
24
25/* The Linux in-kernel DHCP client silently ignores any packet
26 smaller than this. Sigh........... */
27#define MIN_PACKETSZ 300
28
29#define OPTION_PAD 0
30#define OPTION_NETMASK 1
31#define OPTION_ROUTER 3
32#define OPTION_DNSSERVER 6
33#define OPTION_HOSTNAME 12
34#define OPTION_DOMAINNAME 15
35#define OPTION_BROADCAST 28
36#define OPTION_VENDOR_CLASS_OPT 43
37#define OPTION_REQUESTED_IP 50
38#define OPTION_LEASE_TIME 51
39#define OPTION_OVERLOAD 52
40#define OPTION_MESSAGE_TYPE 53
41#define OPTION_SERVER_IDENTIFIER 54
42#define OPTION_REQUESTED_OPTIONS 55
43#define OPTION_MESSAGE 56
44#define OPTION_MAXMESSAGE 57
45#define OPTION_T1 58
46#define OPTION_T2 59
47#define OPTION_VENDOR_ID 60
48#define OPTION_CLIENT_ID 61
49#define OPTION_SNAME 66
50#define OPTION_FILENAME 67
51#define OPTION_USER_CLASS 77
52#define OPTION_CLIENT_FQDN 81
53#define OPTION_AGENT_ID 82
54#define OPTION_ARCH 93
55#define OPTION_PXE_UUID 97
56#define OPTION_SUBNET_SELECT 118
57#define OPTION_END 255
58
59#define SUBOPT_CIRCUIT_ID 1
60#define SUBOPT_REMOTE_ID 2
61#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
62#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
63#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
64
65#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
66#define SUBOPT_PXE_DISCOVERY 6
67#define SUBOPT_PXE_SERVERS 8
68#define SUBOPT_PXE_MENU 9
69#define SUBOPT_PXE_MENU_PROMPT 10
70
71#define DHCPDISCOVER 1
72#define DHCPOFFER 2
73#define DHCPREQUEST 3
74#define DHCPDECLINE 4
75#define DHCPACK 5
76#define DHCPNAK 6
77#define DHCPRELEASE 7
78#define DHCPINFORM 8
79
80#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
81#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
82#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
83
84static int sanitise(unsigned char *opt, char *buf);
85static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
86static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
87static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
88static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
89 int opt, char *string, int null_term);
90static struct in_addr option_addr(unsigned char *opt);
91static struct in_addr option_addr_arr(unsigned char *opt, int offset);
92static unsigned int option_uint(unsigned char *opt, int i, int size);
93static void log_packet(char *type, void *addr, unsigned char *ext_mac,
94 int mac_len, char *interface, char *string, u32 xid);
95static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
96static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
97static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
98 unsigned char *agent_id, unsigned char *real_end);
99static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
100static void do_options(struct dhcp_context *context,
101 struct dhcp_packet *mess,
102 unsigned char *real_end,
103 unsigned char *req_options,
104 char *hostname,
105 char *domain, char *config_domain,
106 struct dhcp_netid *netid,
107 struct in_addr subnet_addr,
108 unsigned char fqdn_flags,
109 int null_term, int pxearch,
110 unsigned char *uuid);
111
112
113static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
114static void do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
115static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
116static int prune_vendor_opts(struct dhcp_netid *netid);
117static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid);
118struct dhcp_boot *find_boot(struct dhcp_netid *netid);
119
120
121size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
122 size_t sz, time_t now, int unicast_dest, int *is_inform)
123{
124 unsigned char *opt, *clid = NULL;
125 struct dhcp_lease *ltmp, *lease = NULL;
126 struct dhcp_vendor *vendor;
127 struct dhcp_mac *mac;
128 struct dhcp_netid_list *id_list;
129 int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
130 struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
131 unsigned char *end = (unsigned char *)(mess + 1);
132 unsigned char *real_end = (unsigned char *)(mess + 1);
133 char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
134 int hostname_auth = 0, borken_opt = 0;
135 unsigned char *req_options = NULL;
136 char *message = NULL;
137 unsigned int time;
138 struct dhcp_config *config;
139 struct dhcp_netid *netid;
140 struct in_addr subnet_addr, fallback, override;
141 unsigned short fuzz = 0;
142 unsigned int mess_type = 0;
143 unsigned char fqdn_flags = 0;
144 unsigned char *agent_id = NULL, *uuid = NULL;
145 unsigned char *emac = NULL;
146 int emac_len = 0;
147 struct dhcp_netid known_id, iface_id;
148 struct dhcp_opt *o;
149 unsigned char pxe_uuid[17];
150
151 subnet_addr.s_addr = override.s_addr = 0;
152
153 /* set tag with name == interface */
154 iface_id.net = iface_name;
155 iface_id.next = NULL;
156 netid = &iface_id;
157
158 if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
159 return 0;
160
161 if (mess->htype == 0 && mess->hlen != 0)
162 return 0;
163
164 /* check for DHCP rather than BOOTP */
165 if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
166 {
167 mess_type = option_uint(opt, 0, 1);
168
169 /* only insist on a cookie for DHCP. */
170 if (*((u32 *)&mess->options) != htonl(DHCP_COOKIE))
171 return 0;
172
173 /* two things to note here: expand_buf may move the packet,
174 so reassign mess from daemon->packet. Also, the size
175 sent includes the IP and UDP headers, hence the magic "-28" */
176 if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
177 {
178 size_t size = (size_t)option_uint(opt, 0, 2) - 28;
179
180 if (size > DHCP_PACKET_MAX)
181 size = DHCP_PACKET_MAX;
182 else if (size < sizeof(struct dhcp_packet))
183 size = sizeof(struct dhcp_packet);
184
185 if (expand_buf(&daemon->dhcp_packet, size))
186 {
187 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
188 real_end = end = ((unsigned char *)mess) + size;
189 }
190 }
191
192 /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
193 it can affect the context-determination code. */
194 if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
195 mess->ciaddr.s_addr = 0;
196
197 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
198 {
199 /* Any agent-id needs to be copied back out, verbatim, as the last option
200 in the packet. Here, we shift it to the very end of the buffer, if it doesn't
201 get overwritten, then it will be shuffled back at the end of processing.
202 Note that the incoming options must not be overwritten here, so there has to
203 be enough free space at the end of the packet to copy the option. */
204 unsigned char *sopt;
205 unsigned int total = option_len(opt) + 2;
206 unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
207 if (last_opt && last_opt < end - total)
208 {
209 end -= total;
210 agent_id = end;
211 memcpy(agent_id, opt, total);
212 }
213
214 /* look for RFC3527 Link selection sub-option */
215 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
216 subnet_addr = option_addr(sopt);
217
218 /* look for RFC5107 server-identifier-override */
219 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
220 override = option_addr(sopt);
221
222 /* if a circuit-id or remote-is option is provided, exact-match to options. */
223 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
224 {
225 int search;
226
227 if (vendor->match_type == MATCH_CIRCUIT)
228 search = SUBOPT_CIRCUIT_ID;
229 else if (vendor->match_type == MATCH_REMOTE)
230 search = SUBOPT_REMOTE_ID;
231 else if (vendor->match_type == MATCH_SUBSCRIBER)
232 search = SUBOPT_SUBSCR_ID;
233 else
234 continue;
235
236 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
237 vendor->len == option_len(sopt) &&
238 memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
239 {
240 vendor->netid.next = netid;
241 netid = &vendor->netid;
242 break;
243 }
244 }
245 }
246
247 /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
248 if (subnet_addr.s_addr == 0 && (opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
249 subnet_addr = option_addr(opt);
250
251 /* If there is no client identifier option, use the hardware address */
252 if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
253 {
254 clid_len = option_len(opt);
255 clid = option_ptr(opt, 0);
256 }
257
258 /* do we have a lease in store? */
259 lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
260
261 /* If this request is missing a clid, but we've seen one before,
262 use it again for option matching etc. */
263 if (lease && !clid && lease->clid)
264 {
265 clid_len = lease->clid_len;
266 clid = lease->clid;
267 }
268
269 /* find mac to use for logging and hashing */
270 emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
271 }
272
273 for (mac = daemon->dhcp_macs; mac; mac = mac->next)
274 if (mac->hwaddr_len == mess->hlen &&
275 (mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
276 memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
277 {
278 mac->netid.next = netid;
279 netid = &mac->netid;
280 }
281
282 /* Determine network for this packet. Our caller will have already linked all the
283 contexts which match the addresses of the receiving interface but if the
284 machine has an address already, or came via a relay, or we have a subnet selector,
285 we search again. If we don't have have a giaddr or explicit subnet selector,
286 use the ciaddr. This is necessary because a machine which got a lease via a
287 relay won't use the relay to renew. If matching a ciaddr fails but we have a context
288 from the physical network, continue using that to allow correct DHCPNAK generation later. */
289 if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
290 {
291 struct dhcp_context *context_tmp, *context_new = NULL;
292 struct in_addr addr;
293 int force = 0;
294
295 if (subnet_addr.s_addr)
296 {
297 addr = subnet_addr;
298 force = 1;
299 }
300 else if (mess->giaddr.s_addr)
301 {
302 addr = mess->giaddr;
303 force = 1;
304 }
305 else
306 {
307 /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
308 addr = mess->ciaddr;
309 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
310 if (context_tmp->netmask.s_addr &&
311 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
312 is_same_net(addr, context_tmp->end, context_tmp->netmask))
313 {
314 context_new = context;
315 break;
316 }
317 }
318
319 if (!context_new)
320 for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
321 if (context_tmp->netmask.s_addr &&
322 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
323 is_same_net(addr, context_tmp->end, context_tmp->netmask))
324 {
325 context_tmp->current = context_new;
326 context_new = context_tmp;
327 }
328
329 if (context_new || force)
330 context = context_new;
331
332 }
333
334 if (!context)
335 {
Robert Greenwaltb452a632010-02-24 17:42:07 -0800336// my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
337// subnet_addr.s_addr ? _("with subnet selector") : _("via"),
338// subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
San Mehatffd68722010-01-20 09:56:15 -0800339 return 0;
340 }
341
342 /* keep _a_ local address available. */
343 fallback = context->local;
344
345 if (daemon->options & OPT_LOG_OPTS)
346 {
347 struct dhcp_context *context_tmp;
348 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
349 {
350 strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
351 if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
352 my_syslog(MS_DHCP | LOG_INFO, _("%u Available DHCP subnet: %s/%s"),
353 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
354 else
355 my_syslog(MS_DHCP | LOG_INFO, _("%u Available DHCP range: %s -- %s"),
356 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
357 }
358 }
359
360 mess->op = BOOTREPLY;
361
362 config = find_config(daemon->dhcp_conf, context, clid, clid_len,
363 mess->chaddr, mess->hlen, mess->htype, NULL);
364
365 /* set "known" tag for known hosts */
366 if (config)
367 {
368 known_id.net = "known";
369 known_id.next = netid;
370 netid = &known_id;
371 }
372
373 if (mess_type == 0)
374 {
375 /* BOOTP request */
376 struct dhcp_netid id, bootp_id;
377 struct in_addr *logaddr = NULL;
378
379 /* must have a MAC addr for bootp */
380 if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
381 return 0;
382
383 if (have_config(config, CONFIG_DISABLE))
384 message = _("disabled");
385
386 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
387
388 if (have_config(config, CONFIG_NAME))
389 {
390 hostname = config->hostname;
391 domain = config->domain;
392 }
393
394 if (have_config(config, CONFIG_NETID))
395 {
396 config->netid.next = netid;
397 netid = &config->netid;
398 }
399
400 /* Match incoming filename field as a netid. */
401 if (mess->file[0])
402 {
403 memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
404 daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
405 id.net = (char *)daemon->dhcp_buff2;
406 id.next = netid;
407 netid = &id;
408 }
409
410 /* Add "bootp" as a tag to allow different options, address ranges etc
411 for BOOTP clients */
412 bootp_id.net = "bootp";
413 bootp_id.next = netid;
414 netid = &bootp_id;
415
416 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
417 if (match_netid(id_list->list, netid, 0))
418 message = _("ignored");
419
420 if (!message)
421 {
422 int nailed = 0;
423
424 if (have_config(config, CONFIG_ADDR))
425 {
426 nailed = 1;
427 logaddr = &config->addr;
428 mess->yiaddr = config->addr;
429 if ((lease = lease_find_by_addr(config->addr)) &&
430 (lease->hwaddr_len != mess->hlen ||
431 lease->hwaddr_type != mess->htype ||
432 memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
433 message = _("address in use");
434 }
435 else
436 {
437 if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
438 !address_available(context, lease->addr, netid))
439 {
440 if (lease)
441 {
442 /* lease exists, wrong network. */
443 lease_prune(lease, now);
444 lease = NULL;
445 }
446 if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, netid, now))
447 message = _("no address available");
448 }
449 else
450 mess->yiaddr = lease->addr;
451 }
452
453 if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
454 message = _("wrong network");
455 else if (context->netid.net)
456 {
457 context->netid.next = netid;
458 netid = &context->netid;
459 }
460
461 if (!message && !nailed)
462 {
463 for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
464 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
465 break;
466 if (!id_list)
467 message = _("no address configured");
468 }
469
470 if (!message &&
471 !lease &&
472 (!(lease = lease_allocate(mess->yiaddr))))
473 message = _("no leases left");
474
475 if (!message)
476 {
477 logaddr = &mess->yiaddr;
478
479 lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
480 if (hostname)
481 lease_set_hostname(lease, hostname, 1);
482 /* infinite lease unless nailed in dhcp-host line. */
483 lease_set_expires(lease,
484 have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
485 now);
486 lease_set_interface(lease, int_index);
487
488 clear_packet(mess, end);
489 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
490 domain, netid, subnet_addr, 0, 0, 0, NULL);
491 }
492 }
493
494 log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
495
496 return message ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
497 }
498
499 if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
500 {
501 /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
502 int len = option_len(opt);
503 char *pq = daemon->dhcp_buff;
504 unsigned char *pp, *op = option_ptr(opt, 0);
505
506 fqdn_flags = *op;
507 len -= 3;
508 op += 3;
509 pp = op;
510
511 /* Always force update, since the client has no way to do it itself. */
512 if (!(fqdn_flags & 0x01))
513 fqdn_flags |= 0x02;
514
515 fqdn_flags &= ~0x08;
516 fqdn_flags |= 0x01;
517
518 if (fqdn_flags & 0x04)
519 while (*op != 0 && ((op + (*op) + 1) - pp) < len)
520 {
521 memcpy(pq, op+1, *op);
522 pq += *op;
523 op += (*op)+1;
524 *(pq++) = '.';
525 }
526 else
527 {
528 memcpy(pq, op, len);
529 if (len > 0 && op[len-1] == 0)
530 borken_opt = 1;
531 pq += len + 1;
532 }
533
534 if (pq != daemon->dhcp_buff)
535 pq--;
536
537 *pq = 0;
538
539 if (legal_hostname(daemon->dhcp_buff))
540 offer_hostname = client_hostname = daemon->dhcp_buff;
541 }
542 else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
543 {
544 int len = option_len(opt);
545 memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
546 /* Microsoft clients are broken, and need zero-terminated strings
547 in options. We detect this state here, and do the same in
548 any options we send */
549 if (len > 0 && daemon->dhcp_buff[len-1] == 0)
550 borken_opt = 1;
551 else
552 daemon->dhcp_buff[len] = 0;
553 if (legal_hostname(daemon->dhcp_buff))
554 client_hostname = daemon->dhcp_buff;
555 }
556
557 if (client_hostname && daemon->options & OPT_LOG_OPTS)
558 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
559
560 if (have_config(config, CONFIG_NAME))
561 {
562 hostname = config->hostname;
563 domain = config->domain;
564 hostname_auth = 1;
565 /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
566 if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
567 offer_hostname = hostname;
568 }
569 else if (client_hostname)
570 {
571 domain = strip_hostname(client_hostname);
572
573 if (strlen(client_hostname) != 0)
574 {
575 hostname = client_hostname;
576 if (!config)
577 {
578 /* Search again now we have a hostname.
579 Only accept configs without CLID and HWADDR here, (they won't match)
580 to avoid impersonation by name. */
581 struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
582 mess->chaddr, mess->hlen,
583 mess->htype, hostname);
584 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
585 {
586 config = new;
587 /* set "known" tag for known hosts */
588 known_id.net = "known";
589 known_id.next = netid;
590 netid = &known_id;
591 }
592 }
593 }
594 }
595
596 if (have_config(config, CONFIG_NETID))
597 {
598 config->netid.next = netid;
599 netid = &config->netid;
600 }
601
602 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
603 Otherwise assume the option is an array, and look for a matching element.
604 If no data given, existance of the option is enough. */
605 for (o = daemon->dhcp_match; o; o = o->next)
606 {
607 int i, matched = 0;
608
609 if (!(opt = option_find(mess, sz, o->opt, 1)) ||
610 o->len > option_len(opt))
611 continue;
612
613 if (o->len == 0)
614 matched = 1;
615 else if (o->flags & DHOPT_HEX)
616 {
617 if (memcmp_masked(o->val, option_ptr(opt, 0), o->len, o->u.wildcard_mask))
618 matched = 1;
619 }
620 else
621 for (i = 0; i <= (option_len(opt) - o->len); )
622 {
623 if (memcmp(o->val, option_ptr(opt, i), o->len) == 0)
624 {
625 matched = 1;
626 break;
627 }
628
629 if (o->flags & DHOPT_STRING)
630 i++;
631 else
632 i += o->len;
633 }
634
635 if (matched)
636 {
637 o->netid->next = netid;
638 netid = o->netid;
639 }
640 }
641
642 /* user-class options are, according to RFC3004, supposed to contain
643 a set of counted strings. Here we check that this is so (by seeing
644 if the counts are consistent with the overall option length) and if
645 so zero the counts so that we don't get spurious matches between
646 the vendor string and the counts. If the lengths don't add up, we
647 assume that the option is a single string and non RFC3004 compliant
648 and just do the substring match. dhclient provides these broken options.
649 The code, later, which sends user-class data to the lease-change script
650 relies on the transformation done here.
651 */
652
653 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
654 {
655 unsigned char *ucp = option_ptr(opt, 0);
656 int tmp, j;
657 for (j = 0; j < option_len(opt); j += ucp[j] + 1);
658 if (j == option_len(opt))
659 for (j = 0; j < option_len(opt); j = tmp)
660 {
661 tmp = j + ucp[j] + 1;
662 ucp[j] = 0;
663 }
664 }
665
666 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
667 {
668 int mopt;
669
670 if (vendor->match_type == MATCH_VENDOR)
671 mopt = OPTION_VENDOR_ID;
672 else if (vendor->match_type == MATCH_USER)
673 mopt = OPTION_USER_CLASS;
674 else
675 continue;
676
677 if ((opt = option_find(mess, sz, mopt, 1)))
678 {
679 int i;
680 for (i = 0; i <= (option_len(opt) - vendor->len); i++)
681 if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
682 {
683 vendor->netid.next = netid;
684 netid = &vendor->netid;
685 break;
686 }
687 }
688 }
689
690 /* mark vendor-encapsulated options which match the client-supplied vendor class */
691 match_vendor_opts(option_find(mess, sz, OPTION_VENDOR_ID, 1), daemon->dhcp_opts);
692
693 if (daemon->options & OPT_LOG_OPTS)
694 {
695 if (sanitise(option_find(mess, sz, OPTION_VENDOR_ID, 1), daemon->namebuff))
696 my_syslog(MS_DHCP | LOG_INFO, _("%u Vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
697 if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
698 my_syslog(MS_DHCP | LOG_INFO, _("%u User class: %s"), ntohl(mess->xid), daemon->namebuff);
699 }
700
701 /* if all the netids in the ignore list are present, ignore this client */
702 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
703 if (match_netid(id_list->list, netid, 0))
704 ignore = 1;
705
706 /* Can have setting to ignore the client ID for a particular MAC address or hostname */
707 if (have_config(config, CONFIG_NOCLID))
708 clid = NULL;
709
710 /* Check if client is PXE client. */
711 if (daemon->enable_pxe &&
712 (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
713 strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
714 {
715 if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
716 {
717 memcpy(pxe_uuid, option_ptr(opt, 0), 17);
718 uuid = pxe_uuid;
719 }
720
721 /* Check if this is really a PXE bootserver request, and handle specially if so. */
722 if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
723 (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
724 (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
725 {
726 struct pxe_service *service;
727 int type = option_uint(opt, 0, 2);
728 int layer = option_uint(opt, 2, 2);
729 unsigned char save71[4];
730 struct dhcp_opt opt71;
731
732 if (ignore)
733 return 0;
734
735 if (layer & 0x8000)
736 {
737 my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
738 return 0;
739 }
740
741 memcpy(save71, option_ptr(opt, 0), 4);
742
743 for (service = daemon->pxe_services; service; service = service->next)
744 if (service->type == type)
745 break;
746
747 if (!service || !service->basename)
748 return 0;
749
750 clear_packet(mess, end);
751
752 mess->yiaddr = mess->ciaddr;
753 mess->ciaddr.s_addr = 0;
754 if (service->server.s_addr != 0)
755 mess->siaddr = service->server;
756 else
757 mess->siaddr = context->local;
758
759 snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
760 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
761 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
762 pxe_misc(mess, end, uuid);
763
764 prune_vendor_opts(netid);
765 opt71.val = save71;
766 opt71.opt = SUBOPT_PXE_BOOT_ITEM;
767 opt71.len = 4;
768 opt71.flags = DHOPT_VENDOR_MATCH;
769 opt71.netid = NULL;
770 opt71.next = daemon->dhcp_opts;
771 do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
772
773 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
774 return dhcp_packet_size(mess, netid, agent_id, real_end);
775 }
776
777 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
778 {
779 pxearch = option_uint(opt, 0, 2);
780
781 /* proxy DHCP here. The DHCPREQUEST stuff is for gPXE */
782 if ((mess_type == DHCPDISCOVER || mess_type == DHCPREQUEST) &&
783 (context->flags & CONTEXT_PROXY))
784 {
785 struct dhcp_boot *boot = find_boot(netid);
786
787 mess->yiaddr.s_addr = 0;
788 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
789 {
790 mess->ciaddr.s_addr = 0;
791 mess->flags |= htons(0x8000); /* broadcast */
792 }
793
794 clear_packet(mess, end);
795
796 /* Provide the bootfile here, for gPXE, and in case we have no menu items
797 and set discovery_control = 8 */
798 if (boot)
799 {
800 if (boot->next_server.s_addr)
801 mess->siaddr = boot->next_server;
802
803 if (boot->file)
804 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
805 }
806
807 option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
808 mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
809 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
810 pxe_misc(mess, end, uuid);
811 prune_vendor_opts(netid);
812 do_encap_opts(pxe_opts(pxearch, netid), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
813
814 log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy" : "proxy-ignored", mess->xid);
815 return ignore ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
816 }
817 }
818 }
819
820 /* if we're just a proxy server, go no further */
821 if (context->flags & CONTEXT_PROXY)
822 return 0;
823
824 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
825 {
826 req_options = (unsigned char *)daemon->dhcp_buff2;
827 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
828 req_options[option_len(opt)] = OPTION_END;
829 }
830
831 switch (mess_type)
832 {
833 case DHCPDECLINE:
834 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
835 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
836 return 0;
837
838 /* sanitise any message. Paranoid? Moi? */
839 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
840
841 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
842 return 0;
843
844 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff, mess->xid);
845
846 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
847 lease_prune(lease, now);
848
849 if (have_config(config, CONFIG_ADDR) &&
850 config->addr.s_addr == option_addr(opt).s_addr)
851 {
852 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
853 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
854 inet_ntoa(config->addr), daemon->dhcp_buff);
855 config->flags |= CONFIG_DECLINED;
856 config->decline_time = now;
857 }
858 else
859 /* make sure this host gets a different address next time. */
860 for (; context; context = context->current)
861 context->addr_epoch++;
862
863 return 0;
864
865 case DHCPRELEASE:
866 if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
867 !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
868 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
869 return 0;
870
871 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
872 lease_prune(lease, now);
873 else
874 message = _("unknown lease");
875
876 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
877
878 return 0;
879
880 case DHCPDISCOVER:
881 if (ignore || have_config(config, CONFIG_DISABLE))
882 {
883 message = _("ignored");
884 opt = NULL;
885 }
886 else
887 {
888 struct in_addr addr, conf;
889
890 addr.s_addr = conf.s_addr = 0;
891
892 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
893 addr = option_addr(opt);
894
895 if (have_config(config, CONFIG_ADDR))
896 {
897 char *addrs = inet_ntoa(config->addr);
898
899 if ((ltmp = lease_find_by_addr(config->addr)) &&
900 ltmp != lease &&
901 !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
902 {
903 int len;
904 unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
905 ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
906 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
907 addrs, print_mac(daemon->namebuff, mac, len));
908 }
909 else
910 {
911 struct dhcp_context *tmp;
912 for (tmp = context; tmp; tmp = tmp->current)
913 if (context->router.s_addr == config->addr.s_addr)
914 break;
915 if (tmp)
916 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
917 else if (have_config(config, CONFIG_DECLINED) &&
918 difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
919 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
920 else
921 conf = config->addr;
922 }
923 }
924
925 if (conf.s_addr)
926 mess->yiaddr = conf;
927 else if (lease &&
928 address_available(context, lease->addr, netid) &&
929 !config_find_by_address(daemon->dhcp_conf, lease->addr))
930 mess->yiaddr = lease->addr;
931 else if (opt && address_available(context, addr, netid) && !lease_find_by_addr(addr) &&
932 !config_find_by_address(daemon->dhcp_conf, addr))
933 mess->yiaddr = addr;
934 else if (emac_len == 0)
935 message = _("no unique-id");
936 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, netid, now))
937 message = _("no address available");
938 }
939
940 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message, mess->xid);
941
942 if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
943 return 0;
944
945 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
946
947 if (context->netid.net)
948 {
949 context->netid.next = netid;
950 netid = &context->netid;
951 }
952
953 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
954 clear_packet(mess, end);
955 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
956 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
957 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
958 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
959 if (time != 0xffffffff)
960 {
961 option_put(mess, end, OPTION_T1, 4, (time/2));
962 option_put(mess, end, OPTION_T2, 4, (time*7)/8);
963 }
964 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
965 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
966
967 return dhcp_packet_size(mess, netid, agent_id, real_end);
968
969 case DHCPREQUEST:
970 if (ignore || have_config(config, CONFIG_DISABLE))
971 return 0;
972 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
973 {
974 /* SELECTING or INIT_REBOOT */
975 mess->yiaddr = option_addr(opt);
976
977 /* send vendor and user class info for new or recreated lease */
978 do_classes = 1;
979
980 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
981 {
982 /* SELECTING */
983 selecting = 1;
984
985 if (override.s_addr != 0)
986 {
987 if (option_addr(opt).s_addr != override.s_addr)
988 return 0;
989 }
990 else
991 {
992 for (; context; context = context->current)
993 if (context->local.s_addr == option_addr(opt).s_addr)
994 break;
995
996 if (!context)
997 {
998 /* In auth mode, a REQUEST sent to the wrong server
999 should be faulted, so that the client establishes
1000 communication with us, otherwise, silently ignore. */
1001 if (!(daemon->options & OPT_AUTHORITATIVE))
1002 return 0;
1003 message = _("wrong server-ID");
1004 }
1005 }
1006
1007 /* If a lease exists for this host and another address, squash it. */
1008 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1009 {
1010 lease_prune(lease, now);
1011 lease = NULL;
1012 }
1013 }
1014 else
1015 {
1016 /* INIT-REBOOT */
1017 if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
1018 return 0;
1019
1020 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1021 {
1022 message = _("wrong address");
1023 /* avoid loops when client brain-dead */
1024 lease_prune(lease, now);
1025 lease = NULL;
1026 }
1027 }
1028 }
1029 else
1030 {
1031 /* RENEWING or REBINDING */
1032 /* Check existing lease for this address.
1033 We allow it to be missing if dhcp-authoritative mode
1034 as long as we can allocate the lease now - checked below.
1035 This makes for a smooth recovery from a lost lease DB */
1036 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
1037 (!lease && !(daemon->options & OPT_AUTHORITATIVE)))
1038 {
1039 message = _("lease not found");
1040 /* ensure we broadcast NAK */
1041 unicast_dest = 0;
1042 }
1043 /* desynchronise renewals */
1044 fuzz = rand16();
1045 mess->yiaddr = mess->ciaddr;
1046 }
1047
1048 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
1049
1050 if (!message)
1051 {
1052 struct dhcp_config *addr_config;
1053 struct dhcp_context *tmp = NULL;
1054
1055 if (have_config(config, CONFIG_ADDR))
1056 for (tmp = context; tmp; tmp = tmp->current)
1057 if (context->router.s_addr == config->addr.s_addr)
1058 break;
1059
1060 if (!(context = narrow_context(context, mess->yiaddr, netid)))
1061 {
1062 /* If a machine moves networks whilst it has a lease, we catch that here. */
1063 message = _("wrong network");
1064 /* ensure we broadcast NAK */
1065 unicast_dest = 0;
1066 }
1067
1068 /* Check for renewal of a lease which is outside the allowed range. */
1069 else if (!address_available(context, mess->yiaddr, netid) &&
1070 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
1071 message = _("address not available");
1072
1073 /* Check if a new static address has been configured. Be very sure that
1074 when the client does DISCOVER, it will get the static address, otherwise
1075 an endless protocol loop will ensue. */
1076 else if (!tmp && !selecting &&
1077 have_config(config, CONFIG_ADDR) &&
1078 (!have_config(config, CONFIG_DECLINED) ||
1079 difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
1080 config->addr.s_addr != mess->yiaddr.s_addr &&
1081 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
1082 message = _("static lease available");
1083
1084 /* Check to see if the address is reserved as a static address for another host */
1085 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
1086 message = _("address reserved");
1087
1088 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1089 {
1090 /* If a host is configured with more than one MAC address, it's OK to 'nix
1091 a lease from one of it's MACs to give the address to another. */
1092 if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1093 {
1094 my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
1095 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
1096 inet_ntoa(ltmp->addr));
1097 lease = ltmp;
1098 }
1099 else
1100 message = _("address in use");
1101 }
1102
1103 if (!message)
1104 {
1105 if (emac_len == 0)
1106 message = _("no unique-id");
1107
1108 else if (!lease)
1109 {
1110 if ((lease = lease_allocate(mess->yiaddr)))
1111 do_classes = 1;
1112 else
1113 message = _("no leases left");
1114 }
1115 }
1116 }
1117
1118 if (message)
1119 {
1120 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
1121
1122 mess->yiaddr.s_addr = 0;
1123 clear_packet(mess, end);
1124 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
1125 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1126 option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
1127 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
1128 a distant subnet which unicast a REQ to us won't work. */
1129 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
1130 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1131 {
1132 mess->flags |= htons(0x8000); /* broadcast */
1133 mess->ciaddr.s_addr = 0;
1134 }
1135 }
1136 else
1137 {
1138 if (do_classes)
1139 {
1140 if (mess->giaddr.s_addr)
1141 lease->giaddr = mess->giaddr;
1142
1143 lease->changed = 1;
1144 /* copy user-class and vendor class into new lease, for the script */
1145 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1146 {
1147 int len = option_len(opt);
1148 unsigned char *ucp = option_ptr(opt, 0);
1149 /* If the user-class option started as counted strings, the first byte will be zero. */
1150 if (len != 0 && ucp[0] == 0)
1151 ucp++, len--;
1152 free(lease->userclass);
1153 if ((lease->userclass = whine_malloc(len+1)))
1154 {
1155 memcpy(lease->userclass, ucp, len);
1156 lease->userclass[len] = 0;
1157 lease->userclass_len = len+1;
1158 }
1159 }
1160 if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
1161 {
1162 int len = option_len(opt);
1163 unsigned char *ucp = option_ptr(opt, 0);
1164 free(lease->vendorclass);
1165 if ((lease->vendorclass = whine_malloc(len+1)))
1166 {
1167 memcpy(lease->vendorclass, ucp, len);
1168 lease->vendorclass[len] = 0;
1169 lease->vendorclass_len = len+1;
1170 }
1171 }
1172 if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
1173 {
1174 int len = option_len(opt);
1175 unsigned char *ucp = option_ptr(opt, 0);
1176 free(lease->supplied_hostname);
1177 if ((lease->supplied_hostname = whine_malloc(len+1)))
1178 {
1179 memcpy(lease->supplied_hostname, ucp, len);
1180 lease->supplied_hostname[len] = 0;
1181 lease->supplied_hostname_len = len+1;
1182 }
1183 }
1184 }
1185
1186 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1187 {
1188 hostname = client_hostname;
1189 hostname_auth = 1;
1190 }
1191
1192 if (context->netid.net)
1193 {
1194 context->netid.next = netid;
1195 netid = &context->netid;
1196 }
1197
1198 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1199 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
1200
1201 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1202 if (!hostname_auth)
1203 {
1204 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1205 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
1206 break;
1207 if (id_list)
1208 hostname = NULL;
1209 }
1210 if (hostname)
1211 lease_set_hostname(lease, hostname, hostname_auth);
1212
1213 lease_set_expires(lease, time, now);
1214 lease_set_interface(lease, int_index);
1215
1216 if (override.s_addr != 0)
1217 lease->override = override;
1218 else
1219 override = lease->override;
1220
1221 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
1222
1223 clear_packet(mess, end);
1224 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1225 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1226 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1227 if (time != 0xffffffff)
1228 {
1229 while (fuzz > (time/16))
1230 fuzz = fuzz/2;
1231 option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
1232 option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
1233 }
1234 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
1235 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1236 }
1237
1238 return dhcp_packet_size(mess, netid, agent_id, real_end);
1239
1240 case DHCPINFORM:
1241 if (ignore || have_config(config, CONFIG_DISABLE))
1242 message = _("ignored");
1243
1244 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
1245
1246 if (message || mess->ciaddr.s_addr == 0)
1247 return 0;
1248
1249 /* For DHCPINFORM only, cope without a valid context */
1250 context = narrow_context(context, mess->ciaddr, netid);
1251
1252 /* Find a least based on IP address if we didn't
1253 get one from MAC address/client-d */
1254 if (!lease &&
1255 (lease = lease_find_by_addr(mess->ciaddr)) &&
1256 lease->hostname)
1257 hostname = lease->hostname;
1258
1259 if (!hostname)
1260 hostname = host_from_dns(mess->ciaddr);
1261
1262 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
1263
1264 if (context && context->netid.net)
1265 {
1266 context->netid.next = netid;
1267 netid = &context->netid;
1268 }
1269
1270 if (lease)
1271 {
1272 if (override.s_addr != 0)
1273 lease->override = override;
1274 else
1275 override = lease->override;
1276 }
1277
1278 clear_packet(mess, end);
1279 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1280 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1281
1282 if (lease)
1283 {
1284 if (lease->expires == 0)
1285 time = 0xffffffff;
1286 else
1287 time = (unsigned int)difftime(lease->expires, now);
1288 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1289 lease_set_interface(lease, int_index);
1290 }
1291
1292 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
1293 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1294
1295 *is_inform = 1; /* handle reply differently */
1296 return dhcp_packet_size(mess, netid, agent_id, real_end);
1297 }
1298
1299 return 0;
1300}
1301
1302/* find a good value to use as MAC address for logging and address-allocation hashing.
1303 This is normally just the chaddr field from the DHCP packet,
1304 but eg Firewire will have hlen == 0 and use the client-id instead.
1305 This could be anything, but will normally be EUI64 for Firewire.
1306 We assume that if the first byte of the client-id equals the htype byte
1307 then the client-id is using the usual encoding and use the rest of the
1308 client-id: if not we can use the whole client-id. This should give
1309 sane MAC address logs. */
1310unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
1311 int clid_len, unsigned char *clid, int *len_out)
1312{
1313 if (hwlen == 0 && clid && clid_len > 3)
1314 {
1315 if (clid[0] == hwtype)
1316 {
1317 *len_out = clid_len - 1 ;
1318 return clid + 1;
1319 }
1320
1321#if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1322 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1323 {
1324 *len_out = clid_len - 1 ;
1325 return clid + 1;
1326 }
1327#endif
1328
1329 *len_out = clid_len;
1330 return clid;
1331 }
1332
1333 *len_out = hwlen;
1334 return hwaddr;
1335}
1336
1337static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
1338{
1339 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1340
1341 if (opt)
1342 {
1343 unsigned int req_time = option_uint(opt, 0, 4);
1344 if (req_time < 120 )
1345 req_time = 120; /* sanity */
1346 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1347 time = req_time;
1348 }
1349
1350 return time;
1351}
1352
1353static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1354{
1355 if (override.s_addr != 0)
1356 return override;
1357 else if (context)
1358 return context->local;
1359 else
1360 return fallback;
1361}
1362
1363static int sanitise(unsigned char *opt, char *buf)
1364{
1365 char *p;
1366 int i;
1367
1368 *buf = 0;
1369
1370 if (!opt)
1371 return 0;
1372
1373 p = option_ptr(opt, 0);
1374
1375 for (i = option_len(opt); i > 0; i--)
1376 {
1377 char c = *p++;
1378 if (isprint((int)c))
1379 *buf++ = c;
1380 }
1381 *buf = 0; /* add terminator */
1382
1383 return 1;
1384}
1385
1386static void log_packet(char *type, void *addr, unsigned char *ext_mac,
1387 int mac_len, char *interface, char *string, u32 xid)
1388{
1389 struct in_addr a;
1390
1391 /* addr may be misaligned */
1392 if (addr)
1393 memcpy(&a, addr, sizeof(a));
1394
1395 print_mac(daemon->namebuff, ext_mac, mac_len);
1396
1397 if(daemon->options & OPT_LOG_OPTS)
1398 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
1399 ntohl(xid),
1400 type,
1401 interface,
1402 addr ? inet_ntoa(a) : "",
1403 addr ? " " : "",
1404 daemon->namebuff,
1405 string ? string : "");
1406 else
1407 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s",
1408 type,
1409 interface,
1410 addr ? inet_ntoa(a) : "",
1411 addr ? " " : "",
1412 daemon->namebuff,
1413 string ? string : "");
1414}
1415
1416static void log_options(unsigned char *start, u32 xid)
1417{
1418 while (*start != OPTION_END)
1419 {
1420 int is_ip, is_name, i;
1421 char *text = option_string(start[0], &is_ip, &is_name);
1422 unsigned char trunc = option_len(start);
1423
1424 if (is_ip)
1425 for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
1426 {
1427 if (i != 0)
1428 strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
1429 strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
1430 }
1431 else if (!is_name || !sanitise(start, daemon->namebuff))
1432 {
1433 if (trunc > 13)
1434 trunc = 13;
1435 print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
1436 }
1437
1438 my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
1439 ntohl(xid), option_len(start), start[0],
1440 text ? ":" : "", text ? text : "",
1441 trunc == 0 ? "" : " ",
1442 trunc == 0 ? "" : daemon->namebuff,
1443 trunc == option_len(start) ? "" : "...");
1444 start += start[1] + 2;
1445 }
1446}
1447
1448static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1449{
1450 while (1)
1451 {
1452 if (p > end)
1453 return NULL;
1454 else if (*p == OPTION_END)
1455 return opt == OPTION_END ? p : NULL;
1456 else if (*p == OPTION_PAD)
1457 p++;
1458 else
1459 {
1460 int opt_len;
1461 if (p > end - 2)
1462 return NULL; /* malformed packet */
1463 opt_len = option_len(p);
1464 if (p > end - (2 + opt_len))
1465 return NULL; /* malformed packet */
1466 if (*p == opt && opt_len >= minsize)
1467 return p;
1468 p += opt_len + 2;
1469 }
1470 }
1471}
1472
1473static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1474{
1475 unsigned char *ret, *overload;
1476
1477 /* skip over DHCP cookie; */
1478 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
1479 return ret;
1480
1481 /* look for overload option. */
1482 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
1483 return NULL;
1484
1485 /* Can we look in filename area ? */
1486 if ((overload[2] & 1) &&
1487 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
1488 return ret;
1489
1490 /* finally try sname area */
1491 if ((overload[2] & 2) &&
1492 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
1493 return ret;
1494
1495 return NULL;
1496}
1497
1498static struct in_addr option_addr_arr(unsigned char *opt, int offset)
1499{
1500 /* this worries about unaligned data in the option. */
1501 /* struct in_addr is network byte order */
1502 struct in_addr ret;
1503
1504 memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
1505
1506 return ret;
1507}
1508
1509static struct in_addr option_addr(unsigned char *opt)
1510{
1511 return option_addr_arr(opt, 0);
1512}
1513
1514static unsigned int option_uint(unsigned char *opt, int offset, int size)
1515{
1516 /* this worries about unaligned data and byte order */
1517 unsigned int ret = 0;
1518 int i;
1519 unsigned char *p = option_ptr(opt, offset);
1520
1521 for (i = 0; i < size; i++)
1522 ret = (ret << 8) | *p++;
1523
1524 return ret;
1525}
1526
1527static unsigned char *dhcp_skip_opts(unsigned char *start)
1528{
1529 while (*start != 0)
1530 start += start[1] + 2;
1531 return start;
1532}
1533
1534/* only for use when building packet: doesn't check for bad data. */
1535static unsigned char *find_overload(struct dhcp_packet *mess)
1536{
1537 unsigned char *p = &mess->options[0] + sizeof(u32);
1538
1539 while (*p != 0)
1540 {
1541 if (*p == OPTION_OVERLOAD)
1542 return p;
1543 p += p[1] + 2;
1544 }
1545 return NULL;
1546}
1547
1548static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
1549 unsigned char *agent_id, unsigned char *real_end)
1550{
1551 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1552 unsigned char *overload;
1553 size_t ret;
1554 struct dhcp_netid_list *id_list;
1555 struct dhcp_netid *n;
1556
1557 /* move agent_id back down to the end of the packet */
1558 if (agent_id)
1559 {
1560 memmove(p, agent_id, real_end - agent_id);
1561 p += real_end - agent_id;
1562 memset(p, 0, real_end - p); /* in case of overlap */
1563 }
1564
1565 /* We do logging too */
1566 if (netid && (daemon->options & OPT_LOG_OPTS))
1567 {
1568 char *s = daemon->namebuff;
1569 for (*s = 0; netid; netid = netid->next)
1570 {
1571 /* kill dupes. */
1572 for (n = netid->next; n; n = n->next)
1573 if (strcmp(netid->net, n->net) == 0)
1574 break;
1575
1576 if (!n)
1577 {
1578 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
1579 if (netid->next)
1580 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
1581 }
1582 }
1583 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
1584 }
1585
1586 /* add END options to the regions. */
1587 overload = find_overload(mess);
1588
1589 if (overload && (option_uint(overload, 0, 1) & 1))
1590 {
1591 *dhcp_skip_opts(mess->file) = OPTION_END;
1592 if (daemon->options & OPT_LOG_OPTS)
1593 log_options(mess->file, mess->xid);
1594 }
1595 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
1596 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
1597
1598 if (overload && (option_uint(overload, 0, 1) & 2))
1599 {
1600 *dhcp_skip_opts(mess->sname) = OPTION_END;
1601 if (daemon->options & OPT_LOG_OPTS)
1602 log_options(mess->sname, mess->xid);
1603 }
1604 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
1605 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
1606
1607
1608 *p++ = OPTION_END;
1609
1610 if (daemon->options & OPT_LOG_OPTS)
1611 {
1612 if (mess->siaddr.s_addr != 0)
1613 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
1614
1615 log_options(&mess->options[0] + sizeof(u32), mess->xid);
1616 }
1617
1618 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
1619 if (match_netid(id_list->list, netid, 0))
1620 mess->flags |= htons(0x8000); /* force broadcast */
1621
1622 ret = (size_t)(p - (unsigned char *)mess);
1623
1624 if (ret < MIN_PACKETSZ)
1625 ret = MIN_PACKETSZ;
1626
1627 return ret;
1628}
1629
1630static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
1631{
1632 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1633
1634 if (p + len + 3 >= end)
1635 /* not enough space in options area, try and use overload, if poss */
1636 {
1637 unsigned char *overload;
1638
1639 if (!(overload = find_overload(mess)) &&
1640 (mess->file[0] == 0 || mess->sname[0] == 0))
1641 {
1642 /* attempt to overload fname and sname areas, we've reserved space for the
1643 overflow option previuously. */
1644 overload = p;
1645 *(p++) = OPTION_OVERLOAD;
1646 *(p++) = 1;
1647 }
1648
1649 p = NULL;
1650
1651 /* using filename field ? */
1652 if (overload)
1653 {
1654 if (mess->file[0] == 0)
1655 overload[2] |= 1;
1656
1657 if (overload[2] & 1)
1658 {
1659 p = dhcp_skip_opts(mess->file);
1660 if (p + len + 3 >= mess->file + sizeof(mess->file))
1661 p = NULL;
1662 }
1663
1664 if (!p)
1665 {
1666 /* try to bring sname into play (it may be already) */
1667 if (mess->sname[0] == 0)
1668 overload[2] |= 2;
1669
1670 if (overload[2] & 2)
1671 {
1672 p = dhcp_skip_opts(mess->sname);
1673 if (p + len + 3 >= mess->sname + sizeof(mess->file))
1674 p = NULL;
1675 }
1676 }
1677 }
1678
1679 if (!p)
1680 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1681 }
1682
1683 if (p)
1684 {
1685 *(p++) = opt;
1686 *(p++) = len;
1687 }
1688
1689 return p;
1690}
1691
1692static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
1693{
1694 int i;
1695 unsigned char *p = free_space(mess, end, opt, len);
1696
1697 if (p)
1698 for (i = 0; i < len; i++)
1699 *(p++) = val >> (8 * (len - (i + 1)));
1700}
1701
1702static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1703 char *string, int null_term)
1704{
1705 unsigned char *p;
1706 size_t len = strlen(string);
1707
1708 if (null_term && len != 255)
1709 len++;
1710
1711 if ((p = free_space(mess, end, opt, len)))
1712 memcpy(p, string, len);
1713}
1714
1715/* return length, note this only does the data part */
1716static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
1717{
1718 int len = opt->len;
1719
1720 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1721 len++;
1722
1723 if (p && len != 0)
1724 {
1725 if (context && (opt->flags & DHOPT_ADDR))
1726 {
1727 int j;
1728 struct in_addr *a = (struct in_addr *)opt->val;
1729 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
1730 {
1731 /* zero means "self" (but not in vendorclass options.) */
1732 if (a->s_addr == 0)
1733 memcpy(p, &context->local, INADDRSZ);
1734 else
1735 memcpy(p, a, INADDRSZ);
1736 p += INADDRSZ;
1737 }
1738 }
1739 else
1740 memcpy(p, opt->val, len);
1741 }
1742 return len;
1743}
1744
1745static int in_list(unsigned char *list, int opt)
1746{
1747 int i;
1748
1749 /* If no requested options, send everything, not nothing. */
1750 if (!list)
1751 return 1;
1752
1753 for (i = 0; list[i] != OPTION_END; i++)
1754 if (opt == list[i])
1755 return 1;
1756
1757 return 0;
1758}
1759
1760static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
1761{
1762 struct dhcp_opt *tmp;
1763 for (tmp = opts; tmp; tmp = tmp->next)
1764 if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)))
1765 if (match_netid(tmp->netid, netid, netid ? 0 : 1))
1766 return tmp;
1767
1768 return netid ? option_find2(NULL, opts, opt) : NULL;
1769}
1770
1771/* mark vendor-encapsulated options which match the client-supplied or
1772 config-supplied vendor class */
1773static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1774{
1775 for (; dopt; dopt = dopt->next)
1776 {
1777 dopt->flags &= ~DHOPT_VENDOR_MATCH;
1778 if (opt && (dopt->flags & DHOPT_VENDOR))
1779 {
1780 int i, len = 0;
1781 if (dopt->u.vendor_class)
1782 len = strlen((char *)dopt->u.vendor_class);
1783 for (i = 0; i <= (option_len(opt) - len); i++)
1784 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
1785 {
1786 dopt->flags |= DHOPT_VENDOR_MATCH;
1787 break;
1788 }
1789 }
1790 }
1791}
1792
1793static void do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1794 struct dhcp_packet *mess, unsigned char *end, int null_term)
1795{
1796 int len, enc_len;
1797 struct dhcp_opt *start;
1798 unsigned char *p;
1799
1800 /* find size in advance */
1801 for (enc_len = 0, start = opt; opt; opt = opt->next)
1802 if (opt->flags & flag)
1803 {
1804 int new = do_opt(opt, NULL, NULL, null_term) + 2;
1805 if (enc_len + new <= 255)
1806 enc_len += new;
1807 else
1808 {
1809 p = free_space(mess, end, encap, enc_len);
1810 for (; start && start != opt; start = start->next)
1811 if (p && (start->flags & flag))
1812 {
1813 len = do_opt(start, p + 2, NULL, null_term);
1814 *(p++) = start->opt;
1815 *(p++) = len;
1816 p += len;
1817 }
1818 enc_len = new;
1819 start = opt;
1820 }
1821 }
1822
1823 if (enc_len != 0 &&
1824 (p = free_space(mess, end, encap, enc_len + 1)))
1825 {
1826 for (; start; start = start->next)
1827 if (start->flags & flag)
1828 {
1829 len = do_opt(start, p + 2, NULL, null_term);
1830 *(p++) = start->opt;
1831 *(p++) = len;
1832 p += len;
1833 }
1834 *p = OPTION_END;
1835 }
1836}
1837
1838static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
1839{
1840 unsigned char *p;
1841
1842 option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
1843 if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
1844 memcpy(p, uuid, 17);
1845}
1846
1847static int prune_vendor_opts(struct dhcp_netid *netid)
1848{
1849 int force = 0;
1850 struct dhcp_opt *opt;
1851
1852 /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
1853 for (opt = daemon->dhcp_opts; opt; opt = opt->next)
1854 if (opt->flags & DHOPT_VENDOR_MATCH)
1855 {
1856 if (!match_netid(opt->netid, netid, 1))
1857 opt->flags &= ~DHOPT_VENDOR_MATCH;
1858 else if (opt->flags & DHOPT_FORCE)
1859 force = 1;
1860 }
1861 return force;
1862}
1863
1864static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
1865{
1866#define NUM_OPTS 4
1867
1868 unsigned char *p, *q;
1869 struct pxe_service *service;
1870 static struct dhcp_opt *o, *ret;
1871 int i, j = NUM_OPTS - 1;
1872
1873 /* We pass back references to these, hence they are declared static */
1874 static unsigned char discovery_control;
1875 static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
1876 static struct dhcp_opt *fake_opts = NULL;
1877
1878 /* We are found by broadcast, so disable multicast. It gets switched on again
1879 if we point to other servers and don't give a unicast address. Note that
1880 we don't provide our own address for services we are the boot server for because unicast
1881 discovery is to port 4011 and we don't listen there. If you are using proxy DHCP
1882 and DHCP relays, the relay will need to forward to the proxy too. */
1883 discovery_control = 2;
1884
1885 ret = daemon->dhcp_opts;
1886
1887 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
1888 return ret;
1889
1890 for (i = 0; i < NUM_OPTS; i++)
1891 {
1892 fake_opts[i].flags = DHOPT_VENDOR_MATCH;
1893 fake_opts[i].netid = NULL;
1894 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
1895 }
1896
1897 /* create the data for the PXE_MENU and PXE_SERVERS options. */
1898 p = (unsigned char *)daemon->dhcp_buff;
1899 q = (unsigned char *)daemon->dhcp_buff2;
1900
1901 for (i = 0, service = daemon->pxe_services; service; service = service->next)
1902 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
1903 {
1904 size_t len = strlen(service->menu);
1905 /* opt 43 max size is 255. encapsulated option has type and length
1906 bytes, so its max size is 253. */
1907 if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
1908 {
1909 *(p++) = service->type >> 8;
1910 *(p++) = service->type;
1911 *(p++) = len;
1912 memcpy(p, service->menu, len);
1913 p += len;
1914 i++;
1915 }
1916 else
1917 {
1918 toobig:
1919 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
1920 return daemon->dhcp_opts;
1921 }
1922
1923 if (!service->basename)
1924 {
1925 if (service->server.s_addr != 0)
1926 {
1927 if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
1928 goto toobig;
1929
1930 /* Boot service with known address - give it */
1931 *(q++) = service->type >> 8;
1932 *(q++) = service->type;
1933 *(q++) = 1;
1934 /* dest misaligned */
1935 memcpy(q, &service->server.s_addr, INADDRSZ);
1936 q += INADDRSZ;
1937 }
1938 else if (service->type != 0)
1939 /* We're not supplying a server, so let the client multicast.
1940 type zero is "local boot" so no need for M/C on that. */
1941 discovery_control = 0;
1942 }
1943 }
1944
1945 /* if no prompt, wait forever if there's a choice */
1946 fake_prompt[0] = (i > 1) ? 255 : 0;
1947
1948 if (i == 0)
1949 discovery_control = 8; /* no menu - just use use mess->filename */
1950 else
1951 {
1952 ret = &fake_opts[j--];
1953 ret->len = p - (unsigned char *)daemon->dhcp_buff;
1954 ret->val = (unsigned char *)daemon->dhcp_buff;
1955 ret->opt = SUBOPT_PXE_MENU;
1956
1957 if (q - (unsigned char *)daemon->dhcp_buff2 != 0)
1958 {
1959 ret = &fake_opts[j--];
1960 ret->len = q - (unsigned char *)daemon->dhcp_buff2;
1961 ret->val = (unsigned char *)daemon->dhcp_buff2;
1962 ret->opt = SUBOPT_PXE_SERVERS;
1963 }
1964 }
1965
1966 for (o = daemon->dhcp_opts; o; o = o->next)
1967 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
1968 break;
1969
1970 if (!o)
1971 {
1972 ret = &fake_opts[j--];
1973 ret->len = sizeof(fake_prompt);
1974 ret->val = fake_prompt;
1975 ret->opt = SUBOPT_PXE_MENU_PROMPT;
1976 }
1977
1978 if (discovery_control != 0)
1979 {
1980 ret = &fake_opts[j--];
1981 ret->len = 1;
1982 ret->opt = SUBOPT_PXE_DISCOVERY;
1983 ret->val= &discovery_control;
1984 }
1985
1986 return ret;
1987}
1988
1989static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
1990{
1991 memset(mess->sname, 0, sizeof(mess->sname));
1992 memset(mess->file, 0, sizeof(mess->file));
1993 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
1994 mess->siaddr.s_addr = 0;
1995}
1996
1997struct dhcp_boot *find_boot(struct dhcp_netid *netid)
1998{
1999 struct dhcp_boot *boot;
2000
2001 /* decide which dhcp-boot option we're using */
2002 for (boot = daemon->boot_config; boot; boot = boot->next)
2003 if (match_netid(boot->netid, netid, 0))
2004 break;
2005 if (!boot)
2006 /* No match, look for one without a netid */
2007 for (boot = daemon->boot_config; boot; boot = boot->next)
2008 if (match_netid(boot->netid, netid, 1))
2009 break;
2010
2011 return boot;
2012}
2013
2014static void do_options(struct dhcp_context *context,
2015 struct dhcp_packet *mess,
2016 unsigned char *end,
2017 unsigned char *req_options,
2018 char *hostname,
2019 char *domain, char *config_domain,
2020 struct dhcp_netid *netid,
2021 struct in_addr subnet_addr,
2022 unsigned char fqdn_flags,
2023 int null_term, int pxe_arch,
2024 unsigned char *uuid)
2025{
2026 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2027 struct dhcp_boot *boot;
2028 unsigned char *p;
2029 int i, len, force_encap = 0;
2030 unsigned char f0 = 0, s0 = 0;
2031 int done_file = 0, done_server = 0;
2032
2033 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
2034 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
2035
2036 /* logging */
2037 if ((daemon->options & OPT_LOG_OPTS) && req_options)
2038 {
2039 char *q = daemon->namebuff;
2040 for (i = 0; req_options[i] != OPTION_END; i++)
2041 {
2042 char *s = option_string(req_options[i], NULL, NULL);
2043 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
2044 "%d%s%s%s",
2045 req_options[i],
2046 s ? ":" : "",
2047 s ? s : "",
2048 req_options[i+1] == OPTION_END ? "" : ", ");
2049 if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2050 {
2051 q = daemon->namebuff;
2052 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
2053 }
2054 }
2055 }
2056
2057 if (context)
2058 mess->siaddr = context->local;
2059
2060 /* See if we can send the boot stuff as options.
2061 To do this we need a requested option list, BOOTP
2062 and very old DHCP clients won't have this, we also
2063 provide an manual option to disable it.
2064 Some PXE ROMs have bugs (surprise!) and need zero-terminated
2065 names, so we always send those. */
2066 if ((boot = find_boot(netid)))
2067 {
2068 if (boot->sname)
2069 {
2070 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2071 req_options &&
2072 in_list(req_options, OPTION_SNAME))
2073 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
2074 else
2075 strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
2076 }
2077
2078 if (boot->file)
2079 {
2080 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2081 req_options &&
2082 in_list(req_options, OPTION_FILENAME))
2083 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2084 else
2085 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
2086 }
2087
2088 if (boot->next_server.s_addr)
2089 mess->siaddr = boot->next_server;
2090 }
2091 else
2092 /* Use the values of the relevant options if no dhcp-boot given and
2093 they're not explicitly asked for as options. OPTION_END is used
2094 as an internal way to specify siaddr without using dhcp-boot, for use in
2095 dhcp-optsfile. */
2096 {
2097 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && mess->file[0] == 0 &&
2098 (opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
2099 {
2100 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2101 done_file = 1;
2102 }
2103
2104 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
2105 (opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
2106 {
2107 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2108 done_server = 1;
2109 }
2110
2111 if ((opt = option_find2(netid, config_opts, OPTION_END)))
2112 mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
2113 }
2114
2115 /* We don't want to do option-overload for BOOTP, so make the file and sname
2116 fields look like they are in use, even when they aren't. This gets restored
2117 at the end of this function. */
2118
2119 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2120 {
2121 f0 = mess->file[0];
2122 mess->file[0] = 1;
2123 s0 = mess->sname[0];
2124 mess->sname[0] = 1;
2125 }
2126
2127 /* At this point, if mess->sname or mess->file are zeroed, they are available
2128 for option overload, reserve space for the overload option. */
2129 if (mess->file[0] == 0 || mess->sname[0] == 0)
2130 end -= 3;
2131
2132 /* rfc3011 says this doesn't need to be in the requested options list. */
2133 if (subnet_addr.s_addr)
2134 option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
2135
2136 /* replies to DHCPINFORM may not have a valid context */
2137 if (context)
2138 {
2139 if (!option_find2(netid, config_opts, OPTION_NETMASK))
2140 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
2141
2142 /* May not have a "guessed" broadcast address if we got no packets via a relay
2143 from this net yet (ie just unicast renewals after a restart */
2144 if (context->broadcast.s_addr &&
2145 !option_find2(netid, config_opts, OPTION_BROADCAST))
2146 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2147
2148 /* Same comments as broadcast apply, and also may not be able to get a sensible
2149 default when using subnet select. User must configure by steam in that case. */
2150 if (context->router.s_addr &&
2151 in_list(req_options, OPTION_ROUTER) &&
2152 !option_find2(netid, config_opts, OPTION_ROUTER))
2153 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2154
2155 if (in_list(req_options, OPTION_DNSSERVER) &&
2156 !option_find2(netid, config_opts, OPTION_DNSSERVER))
2157 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2158 }
2159
2160 if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
2161 !option_find2(netid, config_opts, OPTION_DOMAINNAME))
2162 option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
2163
2164 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
2165 if (hostname)
2166 {
2167 if (in_list(req_options, OPTION_HOSTNAME) &&
2168 !option_find2(netid, config_opts, OPTION_HOSTNAME))
2169 option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
2170
2171 if (fqdn_flags != 0)
2172 {
2173 len = strlen(hostname) + 3;
2174
2175 if (fqdn_flags & 0x04)
2176 len += 2;
2177 else if (null_term)
2178 len++;
2179
2180 if (domain)
2181 len += strlen(domain) + 1;
2182
2183 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
2184 {
2185 *(p++) = fqdn_flags;
2186 *(p++) = 255;
2187 *(p++) = 255;
2188
2189 if (fqdn_flags & 0x04)
2190 {
2191 p = do_rfc1035_name(p, hostname);
2192 if (domain)
2193 p = do_rfc1035_name(p, domain);
2194 *p++ = 0;
2195 }
2196 else
2197 {
2198 memcpy(p, hostname, strlen(hostname));
2199 p += strlen(hostname);
2200 if (domain)
2201 {
2202 *(p++) = '.';
2203 memcpy(p, domain, strlen(domain));
2204 p += strlen(domain);
2205 }
2206 if (null_term)
2207 *(p++) = 0;
2208 }
2209 }
2210 }
2211 }
2212
2213 for (opt = config_opts; opt; opt = opt->next)
2214 {
2215 int optno = opt->opt;
2216
2217 /* was it asked for, or are we sending it anyway? */
2218 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
2219 continue;
2220
2221 /* prohibit some used-internally options */
2222 if (optno == OPTION_CLIENT_FQDN ||
2223 optno == OPTION_MAXMESSAGE ||
2224 optno == OPTION_OVERLOAD ||
2225 optno == OPTION_PAD ||
2226 optno == OPTION_END)
2227 continue;
2228
2229 if (optno == OPTION_SNAME && done_server)
2230 continue;
2231
2232 if (optno == OPTION_FILENAME && done_file)
2233 continue;
2234
2235 /* netids match and not encapsulated? */
2236 if (opt != option_find2(netid, config_opts, optno))
2237 continue;
2238
2239 /* For the options we have default values on
2240 dhc-option=<optionno> means "don't include this option"
2241 not "include a zero-length option" */
2242 if (opt->len == 0 &&
2243 (optno == OPTION_NETMASK ||
2244 optno == OPTION_BROADCAST ||
2245 optno == OPTION_ROUTER ||
2246 optno == OPTION_DNSSERVER ||
2247 optno == OPTION_DOMAINNAME ||
2248 optno == OPTION_HOSTNAME))
2249 continue;
2250
2251 /* vendor-class comes from elsewhere for PXE */
2252 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2253 continue;
2254
2255 /* always force null-term for filename and servername - buggy PXE again. */
2256 len = do_opt(opt, NULL, context,
2257 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2258
2259 if ((p = free_space(mess, end, optno, len)))
2260 {
2261 do_opt(opt, p, context,
2262 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2263
2264 /* If we send a vendor-id, revisit which vendor-ops we consider
2265 it appropriate to send. */
2266 if (optno == OPTION_VENDOR_ID)
2267 match_vendor_opts(p - 2, config_opts);
2268 }
2269 }
2270
2271 /* Now send options to be encapsulated in arbitrary options,
2272 eg dhcp-option=encap:172,17,.......
2273 The may be more that one "outer" to do, so group
2274 all the options which match each outer in turn. */
2275 for (opt = config_opts; opt; opt = opt->next)
2276 opt->flags &= ~DHOPT_ENCAP_DONE;
2277
2278 for (opt = config_opts; opt; opt = opt->next)
2279 if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE)
2280 {
2281 struct dhcp_opt *o;
2282 int found = 0;
2283
2284 for (o = config_opts; o; o = o->next)
2285 {
2286 o->flags &= ~DHOPT_ENCAP_MATCH;
2287 if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
2288 {
2289 o->flags |= DHOPT_ENCAP_DONE;
2290 if (match_netid(o->netid, netid, 1) &&
2291 (o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap)))
2292 {
2293 o->flags |= DHOPT_ENCAP_MATCH;
2294 found = 1;
2295 }
2296 }
2297 }
2298
2299 if (found)
2300 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
2301 }
2302
2303 /* Must precede pxe_opts, since it overwrites req_options */
2304 force_encap = prune_vendor_opts(netid);
2305 if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
2306 force_encap = 1;
2307
2308 if (pxe_arch != -1)
2309 {
2310 pxe_misc(mess, end, uuid);
2311 config_opts = pxe_opts(pxe_arch, netid);
2312 }
2313
2314 if (force_encap)
2315 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term);
2316
2317 /* restore BOOTP anti-overload hack */
2318 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2319 {
2320 mess->file[0] = f0;
2321 mess->sname[0] = s0;
2322 }
2323}
2324
2325#endif