Tomato 1.28
[tomato.git] / release / src / router / dnsmasq / src / rfc2131.c
blob2802ca1edf9840dabea94852af8c059870c24589
1 /* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
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.
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.
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/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_DHCP
21 #define BOOTREQUEST 1
22 #define BOOTREPLY 2
23 #define DHCP_COOKIE 0x63825363
25 /* The Linux in-kernel DHCP client silently ignores any packet
26 smaller than this. Sigh........... */
27 #define MIN_PACKETSZ 300
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_VENDOR_IDENT 124
58 #define OPTION_VENDOR_IDENT_OPT 125
59 #define OPTION_END 255
61 #define SUBOPT_CIRCUIT_ID 1
62 #define SUBOPT_REMOTE_ID 2
63 #define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
64 #define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
65 #define SUBOPT_SERVER_OR 11 /* RFC 5107 */
67 #define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
68 #define SUBOPT_PXE_DISCOVERY 6
69 #define SUBOPT_PXE_SERVERS 8
70 #define SUBOPT_PXE_MENU 9
71 #define SUBOPT_PXE_MENU_PROMPT 10
73 #define DHCPDISCOVER 1
74 #define DHCPOFFER 2
75 #define DHCPREQUEST 3
76 #define DHCPDECLINE 4
77 #define DHCPACK 5
78 #define DHCPNAK 6
79 #define DHCPRELEASE 7
80 #define DHCPINFORM 8
82 #define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
84 #define have_config(config, mask) ((config) && ((config)->flags & (mask)))
85 #define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
86 #define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
88 #ifdef HAVE_SCRIPT
89 static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
90 static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
91 #endif
92 static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
93 static int sanitise(unsigned char *opt, char *buf);
94 static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
95 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
96 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
97 static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
98 int opt, char *string, int null_term);
99 static struct in_addr option_addr(unsigned char *opt);
100 static struct in_addr option_addr_arr(unsigned char *opt, int offset);
101 static unsigned int option_uint(unsigned char *opt, int i, int size);
102 static void log_packet(char *type, void *addr, unsigned char *ext_mac,
103 int mac_len, char *interface, char *string, u32 xid);
104 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
105 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
106 static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
107 unsigned char *agent_id, unsigned char *real_end);
108 static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
109 static void do_options(struct dhcp_context *context,
110 struct dhcp_packet *mess,
111 unsigned char *real_end,
112 unsigned char *req_options,
113 char *hostname,
114 char *domain, char *config_domain,
115 struct dhcp_netid *netid,
116 struct in_addr subnet_addr,
117 unsigned char fqdn_flags,
118 int null_term, int pxearch,
119 unsigned char *uuid,
120 int vendor_class_len);
123 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
124 static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
125 static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
126 static int prune_vendor_opts(struct dhcp_netid *netid);
127 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local);
128 struct dhcp_boot *find_boot(struct dhcp_netid *netid);
131 size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
132 size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
134 unsigned char *opt, *clid = NULL;
135 struct dhcp_lease *ltmp, *lease = NULL;
136 struct dhcp_vendor *vendor;
137 struct dhcp_mac *mac;
138 struct dhcp_netid_list *id_list;
139 int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
140 struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
141 unsigned char *end = (unsigned char *)(mess + 1);
142 unsigned char *real_end = (unsigned char *)(mess + 1);
143 char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
144 int hostname_auth = 0, borken_opt = 0;
145 unsigned char *req_options = NULL;
146 char *message = NULL;
147 unsigned int time;
148 struct dhcp_config *config;
149 struct dhcp_netid *netid, *tagif_netid;
150 struct in_addr subnet_addr, fallback, override;
151 unsigned short fuzz = 0;
152 unsigned int mess_type = 0;
153 unsigned char fqdn_flags = 0;
154 unsigned char *agent_id = NULL, *uuid = NULL;
155 unsigned char *emac = NULL;
156 int vendor_class_len = 0, emac_len = 0;
157 struct dhcp_netid known_id, iface_id, cpewan_id;
158 struct dhcp_opt *o;
159 unsigned char pxe_uuid[17];
160 unsigned char *oui = NULL, *serial = NULL, *class = NULL;
162 subnet_addr.s_addr = override.s_addr = 0;
164 /* set tag with name == interface */
165 iface_id.net = iface_name;
166 iface_id.next = NULL;
167 netid = &iface_id;
169 if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
170 return 0;
172 if (mess->htype == 0 && mess->hlen != 0)
173 return 0;
175 /* check for DHCP rather than BOOTP */
176 if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
178 u32 cookie = htonl(DHCP_COOKIE);
180 /* only insist on a cookie for DHCP. */
181 if (memcmp(mess->options, &cookie, sizeof(u32)) != 0)
182 return 0;
184 mess_type = option_uint(opt, 0, 1);
186 /* two things to note here: expand_buf may move the packet,
187 so reassign mess from daemon->packet. Also, the size
188 sent includes the IP and UDP headers, hence the magic "-28" */
189 if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
191 size_t size = (size_t)option_uint(opt, 0, 2) - 28;
193 if (size > DHCP_PACKET_MAX)
194 size = DHCP_PACKET_MAX;
195 else if (size < sizeof(struct dhcp_packet))
196 size = sizeof(struct dhcp_packet);
198 if (expand_buf(&daemon->dhcp_packet, size))
200 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
201 real_end = end = ((unsigned char *)mess) + size;
205 /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
206 it can affect the context-determination code. */
207 if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
208 mess->ciaddr.s_addr = 0;
210 /* search for device identity from CPEWAN devices, we pass this through to the script */
211 if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
213 unsigned int elen, offset, len = option_len(opt);
215 for (offset = 0; offset < (len - 5); offset += elen + 5)
217 elen = option_uint(opt, offset + 4 , 1);
218 if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
220 unsigned char *x = option_ptr(opt, offset + 5);
221 unsigned char *y = option_ptr(opt, offset + elen + 5);
222 oui = option_find1(x, y, 1, 1);
223 serial = option_find1(x, y, 2, 1);
224 class = option_find1(x, y, 3, 1);
226 /* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
227 the gateway id back. Note that the device class is optional */
228 if (oui && serial)
230 cpewan_id.net = "cpewan-id";
231 cpewan_id.next = netid;
232 netid = &cpewan_id;
234 break;
239 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
241 /* Any agent-id needs to be copied back out, verbatim, as the last option
242 in the packet. Here, we shift it to the very end of the buffer, if it doesn't
243 get overwritten, then it will be shuffled back at the end of processing.
244 Note that the incoming options must not be overwritten here, so there has to
245 be enough free space at the end of the packet to copy the option. */
246 unsigned char *sopt;
247 unsigned int total = option_len(opt) + 2;
248 unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
249 if (last_opt && last_opt < end - total)
251 end -= total;
252 agent_id = end;
253 memcpy(agent_id, opt, total);
256 /* look for RFC3527 Link selection sub-option */
257 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
258 subnet_addr = option_addr(sopt);
260 /* look for RFC5107 server-identifier-override */
261 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
262 override = option_addr(sopt);
264 /* if a circuit-id or remote-is option is provided, exact-match to options. */
265 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
267 int search;
269 if (vendor->match_type == MATCH_CIRCUIT)
270 search = SUBOPT_CIRCUIT_ID;
271 else if (vendor->match_type == MATCH_REMOTE)
272 search = SUBOPT_REMOTE_ID;
273 else if (vendor->match_type == MATCH_SUBSCRIBER)
274 search = SUBOPT_SUBSCR_ID;
275 else
276 continue;
278 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
279 vendor->len == option_len(sopt) &&
280 memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
282 vendor->netid.next = netid;
283 netid = &vendor->netid;
288 /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
289 if (subnet_addr.s_addr == 0 && (opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
290 subnet_addr = option_addr(opt);
292 /* If there is no client identifier option, use the hardware address */
293 if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
295 clid_len = option_len(opt);
296 clid = option_ptr(opt, 0);
299 /* do we have a lease in store? */
300 lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
302 /* If this request is missing a clid, but we've seen one before,
303 use it again for option matching etc. */
304 if (lease && !clid && lease->clid)
306 clid_len = lease->clid_len;
307 clid = lease->clid;
310 /* find mac to use for logging and hashing */
311 emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
314 for (mac = daemon->dhcp_macs; mac; mac = mac->next)
315 if (mac->hwaddr_len == mess->hlen &&
316 (mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
317 memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
319 mac->netid.next = netid;
320 netid = &mac->netid;
323 /* Determine network for this packet. Our caller will have already linked all the
324 contexts which match the addresses of the receiving interface but if the
325 machine has an address already, or came via a relay, or we have a subnet selector,
326 we search again. If we don't have have a giaddr or explicit subnet selector,
327 use the ciaddr. This is necessary because a machine which got a lease via a
328 relay won't use the relay to renew. If matching a ciaddr fails but we have a context
329 from the physical network, continue using that to allow correct DHCPNAK generation later. */
330 if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
332 struct dhcp_context *context_tmp, *context_new = NULL;
333 struct in_addr addr;
334 int force = 0;
336 if (subnet_addr.s_addr)
338 addr = subnet_addr;
339 force = 1;
341 else if (mess->giaddr.s_addr)
343 addr = mess->giaddr;
344 force = 1;
346 else
348 /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
349 addr = mess->ciaddr;
350 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
351 if (context_tmp->netmask.s_addr &&
352 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
353 is_same_net(addr, context_tmp->end, context_tmp->netmask))
355 context_new = context;
356 break;
360 if (!context_new)
361 for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
362 if (context_tmp->netmask.s_addr &&
363 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
364 is_same_net(addr, context_tmp->end, context_tmp->netmask))
366 context_tmp->current = context_new;
367 context_new = context_tmp;
370 if (context_new || force)
371 context = context_new;
375 if (!context)
377 my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
378 subnet_addr.s_addr ? _("with subnet selector") : _("via"),
379 subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
380 return 0;
383 /* keep _a_ local address available. */
384 fallback = context->local;
386 if (daemon->options & OPT_LOG_OPTS)
388 struct dhcp_context *context_tmp;
389 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
391 strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
392 if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
393 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
394 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
395 else
396 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
397 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
401 mess->op = BOOTREPLY;
403 config = find_config(daemon->dhcp_conf, context, clid, clid_len,
404 mess->chaddr, mess->hlen, mess->htype, NULL);
406 /* set "known" tag for known hosts */
407 if (config)
409 known_id.net = "known";
410 known_id.next = netid;
411 netid = &known_id;
414 if (mess_type == 0 && !pxe)
416 /* BOOTP request */
417 struct dhcp_netid id, bootp_id;
418 struct in_addr *logaddr = NULL;
420 /* must have a MAC addr for bootp */
421 if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
422 return 0;
424 if (have_config(config, CONFIG_DISABLE))
425 message = _("disabled");
427 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
429 if (have_config(config, CONFIG_NAME))
431 hostname = config->hostname;
432 domain = config->domain;
435 if (config)
437 struct dhcp_netid_list *list;
439 for (list = config->netid; list; list = list->next)
441 list->list->next = netid;
442 netid = list->list;
446 /* Match incoming filename field as a netid. */
447 if (mess->file[0])
449 memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
450 daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
451 id.net = (char *)daemon->dhcp_buff2;
452 id.next = netid;
453 netid = &id;
456 /* Add "bootp" as a tag to allow different options, address ranges etc
457 for BOOTP clients */
458 bootp_id.net = "bootp";
459 bootp_id.next = netid;
460 netid = &bootp_id;
462 tagif_netid = run_tag_if(netid);
464 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
465 if (match_netid(id_list->list, tagif_netid, 0))
466 message = _("ignored");
468 if (!message)
470 int nailed = 0;
472 if (have_config(config, CONFIG_ADDR))
474 nailed = 1;
475 logaddr = &config->addr;
476 mess->yiaddr = config->addr;
477 if ((lease = lease_find_by_addr(config->addr)) &&
478 (lease->hwaddr_len != mess->hlen ||
479 lease->hwaddr_type != mess->htype ||
480 memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
481 message = _("address in use");
483 else
485 if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
486 !address_available(context, lease->addr, tagif_netid))
488 if (lease)
490 /* lease exists, wrong network. */
491 lease_prune(lease, now);
492 lease = NULL;
494 if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))
495 message = _("no address available");
497 else
498 mess->yiaddr = lease->addr;
501 if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
502 message = _("wrong network");
503 else if (context->netid.net)
505 context->netid.next = netid;
506 netid = &context->netid;
507 tagif_netid = run_tag_if(netid);
510 if (!message && !nailed)
512 for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
513 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
514 break;
515 if (!id_list)
516 message = _("no address configured");
519 if (!message &&
520 !lease &&
521 (!(lease = lease_allocate(mess->yiaddr))))
522 message = _("no leases left");
524 if (!message)
526 logaddr = &mess->yiaddr;
528 lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
529 if (hostname)
530 lease_set_hostname(lease, hostname, 1);
531 /* infinite lease unless nailed in dhcp-host line. */
532 lease_set_expires(lease,
533 have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
534 now);
535 lease_set_interface(lease, int_index);
537 clear_packet(mess, end);
538 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
539 domain, tagif_netid, subnet_addr, 0, 0, 0, NULL, 0);
543 log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
545 return message ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
548 if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
550 /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
551 int len = option_len(opt);
552 char *pq = daemon->dhcp_buff;
553 unsigned char *pp, *op = option_ptr(opt, 0);
555 fqdn_flags = *op;
556 len -= 3;
557 op += 3;
558 pp = op;
560 /* Always force update, since the client has no way to do it itself. */
561 if (!(fqdn_flags & 0x01))
562 fqdn_flags |= 0x02;
564 fqdn_flags &= ~0x08;
565 fqdn_flags |= 0x01;
567 if (fqdn_flags & 0x04)
568 while (*op != 0 && ((op + (*op) + 1) - pp) < len)
570 memcpy(pq, op+1, *op);
571 pq += *op;
572 op += (*op)+1;
573 *(pq++) = '.';
575 else
577 memcpy(pq, op, len);
578 if (len > 0 && op[len-1] == 0)
579 borken_opt = 1;
580 pq += len + 1;
583 if (pq != daemon->dhcp_buff)
584 pq--;
586 *pq = 0;
588 if (legal_hostname(daemon->dhcp_buff))
589 offer_hostname = client_hostname = daemon->dhcp_buff;
591 else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
593 int len = option_len(opt);
594 memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
595 /* Microsoft clients are broken, and need zero-terminated strings
596 in options. We detect this state here, and do the same in
597 any options we send */
598 if (len > 0 && daemon->dhcp_buff[len-1] == 0)
599 borken_opt = 1;
600 else
601 daemon->dhcp_buff[len] = 0;
602 if (legal_hostname(daemon->dhcp_buff))
603 client_hostname = daemon->dhcp_buff;
606 if (client_hostname && daemon->options & OPT_LOG_OPTS)
607 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
609 if (have_config(config, CONFIG_NAME))
611 hostname = config->hostname;
612 domain = config->domain;
613 hostname_auth = 1;
614 /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
615 if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
616 offer_hostname = hostname;
618 else if (client_hostname)
620 domain = strip_hostname(client_hostname);
622 if (strlen(client_hostname) != 0)
624 hostname = client_hostname;
625 if (!config)
627 /* Search again now we have a hostname.
628 Only accept configs without CLID and HWADDR here, (they won't match)
629 to avoid impersonation by name. */
630 struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
631 mess->chaddr, mess->hlen,
632 mess->htype, hostname);
633 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
635 config = new;
636 /* set "known" tag for known hosts */
637 known_id.net = "known";
638 known_id.next = netid;
639 netid = &known_id;
645 if (config)
647 struct dhcp_netid_list *list;
649 for (list = config->netid; list; list = list->next)
651 list->list->next = netid;
652 netid = list->list;
656 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
657 Otherwise assume the option is an array, and look for a matching element.
658 If no data given, existance of the option is enough. This code handles
659 rfc3925 V-I classes too. */
660 for (o = daemon->dhcp_match; o; o = o->next)
662 unsigned int len, elen, match = 0;
663 size_t offset, o2;
665 if (o->flags & DHOPT_RFC3925)
667 if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
668 continue;
670 for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
672 len = option_uint(opt, offset + 4 , 1);
673 /* Need to take care that bad data can't run us off the end of the packet */
674 if ((offset + len + 5 <= (option_len(opt))) &&
675 (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
676 for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
678 elen = option_uint(opt, o2, 1);
679 if ((o2 + elen + 1 <= option_len(opt)) &&
680 (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
681 break;
683 if (match)
684 break;
687 else
689 if (!(opt = option_find(mess, sz, o->opt, 1)))
690 continue;
692 match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
695 if (match)
697 o->netid->next = netid;
698 netid = o->netid;
702 /* user-class options are, according to RFC3004, supposed to contain
703 a set of counted strings. Here we check that this is so (by seeing
704 if the counts are consistent with the overall option length) and if
705 so zero the counts so that we don't get spurious matches between
706 the vendor string and the counts. If the lengths don't add up, we
707 assume that the option is a single string and non RFC3004 compliant
708 and just do the substring match. dhclient provides these broken options.
709 The code, later, which sends user-class data to the lease-change script
710 relies on the transformation done here.
713 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
715 unsigned char *ucp = option_ptr(opt, 0);
716 int tmp, j;
717 for (j = 0; j < option_len(opt); j += ucp[j] + 1);
718 if (j == option_len(opt))
719 for (j = 0; j < option_len(opt); j = tmp)
721 tmp = j + ucp[j] + 1;
722 ucp[j] = 0;
726 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
728 int mopt;
730 if (vendor->match_type == MATCH_VENDOR)
731 mopt = OPTION_VENDOR_ID;
732 else if (vendor->match_type == MATCH_USER)
733 mopt = OPTION_USER_CLASS;
734 else
735 continue;
737 if ((opt = option_find(mess, sz, mopt, 1)))
739 int i;
740 for (i = 0; i <= (option_len(opt) - vendor->len); i++)
741 if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
743 vendor->netid.next = netid;
744 netid = &vendor->netid;
745 break;
750 /* mark vendor-encapsulated options which match the client-supplied vendor class,
751 save client-supplied vendor class */
752 if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
754 memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
755 vendor_class_len = option_len(opt);
757 match_vendor_opts(opt, daemon->dhcp_opts);
759 if (daemon->options & OPT_LOG_OPTS)
761 if (sanitise(opt, daemon->namebuff))
762 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
763 if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
764 my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
767 tagif_netid = run_tag_if(netid);
769 /* if all the netids in the ignore list are present, ignore this client */
770 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
771 if (match_netid(id_list->list, tagif_netid, 0))
772 ignore = 1;
774 /* If configured, we can override the server-id to be the address of the relay,
775 so that all traffic goes via the relay and can pick up agent-id info. This can be
776 configured for all relays, or by address. */
777 if (daemon->override && mess->giaddr.s_addr != 0 && override.s_addr == 0)
779 if (!daemon->override_relays)
780 override = mess->giaddr;
781 else
783 struct addr_list *l;
784 for (l = daemon->override_relays; l; l = l->next)
785 if (l->addr.s_addr == mess->giaddr.s_addr)
786 break;
787 if (l)
788 override = mess->giaddr;
792 /* Can have setting to ignore the client ID for a particular MAC address or hostname */
793 if (have_config(config, CONFIG_NOCLID))
794 clid = NULL;
796 /* Check if client is PXE client. */
797 if (daemon->enable_pxe &&
798 (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
799 strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
801 if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
803 memcpy(pxe_uuid, option_ptr(opt, 0), 17);
804 uuid = pxe_uuid;
807 /* Check if this is really a PXE bootserver request, and handle specially if so. */
808 if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
809 (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
810 (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
812 struct pxe_service *service;
813 int type = option_uint(opt, 0, 2);
814 int layer = option_uint(opt, 2, 2);
815 unsigned char save71[4];
816 struct dhcp_opt opt71;
818 if (ignore)
819 return 0;
821 if (layer & 0x8000)
823 my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
824 return 0;
827 memcpy(save71, option_ptr(opt, 0), 4);
829 for (service = daemon->pxe_services; service; service = service->next)
830 if (service->type == type)
831 break;
833 if (!service || !service->basename)
834 return 0;
836 clear_packet(mess, end);
838 mess->yiaddr = mess->ciaddr;
839 mess->ciaddr.s_addr = 0;
840 if (service->server.s_addr != 0)
841 mess->siaddr = service->server;
842 else
843 mess->siaddr = context->local;
845 snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
846 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
847 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
848 pxe_misc(mess, end, uuid);
850 prune_vendor_opts(tagif_netid);
851 opt71.val = save71;
852 opt71.opt = SUBOPT_PXE_BOOT_ITEM;
853 opt71.len = 4;
854 opt71.flags = DHOPT_VENDOR_MATCH;
855 opt71.netid = NULL;
856 opt71.next = daemon->dhcp_opts;
857 do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
859 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
860 return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
863 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
865 pxearch = option_uint(opt, 0, 2);
867 /* proxy DHCP here. */
868 if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
869 (context->flags & CONTEXT_PROXY))
871 struct dhcp_boot *boot = find_boot(tagif_netid);
873 mess->yiaddr.s_addr = 0;
874 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
876 mess->ciaddr.s_addr = 0;
877 mess->flags |= htons(0x8000); /* broadcast */
880 clear_packet(mess, end);
882 /* Provide the bootfile here, for gPXE, and in case we have no menu items
883 and set discovery_control = 8 */
884 if (boot)
886 if (boot->next_server.s_addr)
887 mess->siaddr = boot->next_server;
889 if (boot->file)
890 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
893 option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
894 mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
895 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
896 pxe_misc(mess, end, uuid);
897 prune_vendor_opts(tagif_netid);
898 do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
900 log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
901 return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
906 /* if we're just a proxy server, go no further */
907 if ((context->flags & CONTEXT_PROXY) || pxe)
908 return 0;
910 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
912 req_options = (unsigned char *)daemon->dhcp_buff2;
913 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
914 req_options[option_len(opt)] = OPTION_END;
917 switch (mess_type)
919 case DHCPDECLINE:
920 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
921 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
922 return 0;
924 /* sanitise any message. Paranoid? Moi? */
925 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
927 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
928 return 0;
930 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff, mess->xid);
932 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
933 lease_prune(lease, now);
935 if (have_config(config, CONFIG_ADDR) &&
936 config->addr.s_addr == option_addr(opt).s_addr)
938 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
939 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
940 inet_ntoa(config->addr), daemon->dhcp_buff);
941 config->flags |= CONFIG_DECLINED;
942 config->decline_time = now;
944 else
945 /* make sure this host gets a different address next time. */
946 for (; context; context = context->current)
947 context->addr_epoch++;
949 return 0;
951 case DHCPRELEASE:
952 if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
953 !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
954 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
955 return 0;
957 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
958 lease_prune(lease, now);
959 else
960 message = _("unknown lease");
962 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
964 return 0;
966 case DHCPDISCOVER:
967 if (ignore || have_config(config, CONFIG_DISABLE))
969 message = _("ignored");
970 opt = NULL;
972 else
974 struct in_addr addr, conf;
976 addr.s_addr = conf.s_addr = 0;
978 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
979 addr = option_addr(opt);
981 if (have_config(config, CONFIG_ADDR))
983 char *addrs = inet_ntoa(config->addr);
985 if ((ltmp = lease_find_by_addr(config->addr)) &&
986 ltmp != lease &&
987 !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
989 int len;
990 unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
991 ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
992 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
993 addrs, print_mac(daemon->namebuff, mac, len));
995 else
997 struct dhcp_context *tmp;
998 for (tmp = context; tmp; tmp = tmp->current)
999 if (context->router.s_addr == config->addr.s_addr)
1000 break;
1001 if (tmp)
1002 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
1003 else if (have_config(config, CONFIG_DECLINED) &&
1004 difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
1005 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
1006 else
1007 conf = config->addr;
1011 if (conf.s_addr)
1012 mess->yiaddr = conf;
1013 else if (lease &&
1014 address_available(context, lease->addr, tagif_netid) &&
1015 !config_find_by_address(daemon->dhcp_conf, lease->addr))
1016 mess->yiaddr = lease->addr;
1017 else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
1018 !config_find_by_address(daemon->dhcp_conf, addr))
1019 mess->yiaddr = addr;
1020 else if (emac_len == 0)
1021 message = _("no unique-id");
1022 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))
1023 message = _("no address available");
1026 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message, mess->xid);
1028 if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
1029 return 0;
1031 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
1033 if (context->netid.net)
1035 context->netid.next = netid;
1036 netid = &context->netid;
1037 tagif_netid = run_tag_if(netid);
1040 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1041 clear_packet(mess, end);
1042 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
1043 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1044 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1045 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
1046 if (time != 0xffffffff)
1048 option_put(mess, end, OPTION_T1, 4, (time/2));
1049 option_put(mess, end, OPTION_T2, 4, (time*7)/8);
1051 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
1052 domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
1054 return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
1056 case DHCPREQUEST:
1057 if (ignore || have_config(config, CONFIG_DISABLE))
1058 return 0;
1059 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
1061 /* SELECTING or INIT_REBOOT */
1062 mess->yiaddr = option_addr(opt);
1064 /* send vendor and user class info for new or recreated lease */
1065 do_classes = 1;
1067 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
1069 /* SELECTING */
1070 selecting = 1;
1072 if (override.s_addr != 0)
1074 if (option_addr(opt).s_addr != override.s_addr)
1075 return 0;
1077 else
1079 for (; context; context = context->current)
1080 if (context->local.s_addr == option_addr(opt).s_addr)
1081 break;
1083 if (!context)
1085 /* In auth mode, a REQUEST sent to the wrong server
1086 should be faulted, so that the client establishes
1087 communication with us, otherwise, silently ignore. */
1088 if (!(daemon->options & OPT_AUTHORITATIVE))
1089 return 0;
1090 message = _("wrong server-ID");
1094 /* If a lease exists for this host and another address, squash it. */
1095 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1097 lease_prune(lease, now);
1098 lease = NULL;
1101 else
1103 /* INIT-REBOOT */
1104 if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
1105 return 0;
1107 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1108 message = _("wrong address");
1111 else
1113 /* RENEWING or REBINDING */
1114 /* Check existing lease for this address.
1115 We allow it to be missing if dhcp-authoritative mode
1116 as long as we can allocate the lease now - checked below.
1117 This makes for a smooth recovery from a lost lease DB */
1118 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
1119 (!lease && !(daemon->options & OPT_AUTHORITATIVE)))
1121 message = _("lease not found");
1122 /* ensure we broadcast NAK */
1123 unicast_dest = 0;
1126 /* desynchronise renewals */
1127 fuzz = rand16();
1128 mess->yiaddr = mess->ciaddr;
1131 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
1133 if (!message)
1135 struct dhcp_config *addr_config;
1136 struct dhcp_context *tmp = NULL;
1138 if (have_config(config, CONFIG_ADDR))
1139 for (tmp = context; tmp; tmp = tmp->current)
1140 if (context->router.s_addr == config->addr.s_addr)
1141 break;
1143 if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
1145 /* If a machine moves networks whilst it has a lease, we catch that here. */
1146 message = _("wrong network");
1147 /* ensure we broadcast NAK */
1148 unicast_dest = 0;
1151 /* Check for renewal of a lease which is outside the allowed range. */
1152 else if (!address_available(context, mess->yiaddr, tagif_netid) &&
1153 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
1154 message = _("address not available");
1156 /* Check if a new static address has been configured. Be very sure that
1157 when the client does DISCOVER, it will get the static address, otherwise
1158 an endless protocol loop will ensue. */
1159 else if (!tmp && !selecting &&
1160 have_config(config, CONFIG_ADDR) &&
1161 (!have_config(config, CONFIG_DECLINED) ||
1162 difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
1163 config->addr.s_addr != mess->yiaddr.s_addr &&
1164 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
1165 message = _("static lease available");
1167 /* Check to see if the address is reserved as a static address for another host */
1168 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
1169 message = _("address reserved");
1171 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1173 /* If a host is configured with more than one MAC address, it's OK to 'nix
1174 a lease from one of it's MACs to give the address to another. */
1175 if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1177 my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
1178 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
1179 inet_ntoa(ltmp->addr));
1180 lease = ltmp;
1182 else
1183 message = _("address in use");
1186 if (!message)
1188 if (emac_len == 0)
1189 message = _("no unique-id");
1191 else if (!lease)
1193 if ((lease = lease_allocate(mess->yiaddr)))
1194 do_classes = 1;
1195 else
1196 message = _("no leases left");
1201 if (message)
1203 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
1205 mess->yiaddr.s_addr = 0;
1206 clear_packet(mess, end);
1207 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
1208 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1209 option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
1210 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
1211 a distant subnet which unicast a REQ to us won't work. */
1212 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
1213 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1215 mess->flags |= htons(0x8000); /* broadcast */
1216 mess->ciaddr.s_addr = 0;
1219 else
1221 if (context->netid.net)
1223 context->netid.next = netid;
1224 netid = &context->netid;
1225 tagif_netid = run_tag_if(netid);
1228 #ifdef HAVE_SCRIPT
1229 if (do_classes && daemon->lease_change_command)
1231 struct dhcp_netid *n;
1233 if (mess->giaddr.s_addr)
1234 lease->giaddr = mess->giaddr;
1236 lease->changed = 1;
1237 free(lease->extradata);
1238 lease->extradata_size = lease->extradata_len = 0;
1240 add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
1241 add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
1242 add_extradata_opt(lease, oui);
1243 add_extradata_opt(lease, serial);
1244 add_extradata_opt(lease, class);
1246 /* space-concat tag set */
1247 if (!tagif_netid)
1248 add_extradata_opt(lease, NULL);
1249 else
1250 for (n = tagif_netid; n; n = n->next)
1251 add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1253 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1255 int len = option_len(opt);
1256 unsigned char *ucp = option_ptr(opt, 0);
1257 /* If the user-class option started as counted strings, the first byte will be zero. */
1258 if (len != 0 && ucp[0] == 0)
1259 ucp++, len--;
1260 add_extradata_data(lease, ucp, len, 0);
1263 #endif
1265 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1267 domain = get_domain(mess->yiaddr);
1268 hostname = client_hostname;
1269 hostname_auth = 1;
1272 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1273 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
1275 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1276 if (!hostname_auth)
1278 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1279 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1280 break;
1281 if (id_list)
1282 hostname = NULL;
1285 /* Last ditch, if configured, generate hostname from mac address */
1286 if (!hostname && emac_len != 0)
1288 for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
1289 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1290 break;
1291 if (id_list)
1293 int i;
1295 hostname = daemon->dhcp_buff;
1296 /* buffer is 256 bytes, 3 bytes per octet */
1297 for (i = 0; (i < emac_len) && (i < 80); i++)
1298 hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
1299 hostname = daemon->dhcp_buff;
1303 if (hostname)
1304 lease_set_hostname(lease, hostname, hostname_auth);
1306 lease_set_expires(lease, time, now);
1307 lease_set_interface(lease, int_index);
1309 if (override.s_addr != 0)
1310 lease->override = override;
1311 else
1312 override = lease->override;
1314 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
1316 clear_packet(mess, end);
1317 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1318 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1319 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1320 if (time != 0xffffffff)
1322 while (fuzz > (time/16))
1323 fuzz = fuzz/2;
1324 option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
1325 option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
1327 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
1328 domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
1331 return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
1333 case DHCPINFORM:
1334 if (ignore || have_config(config, CONFIG_DISABLE))
1335 message = _("ignored");
1337 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
1339 if (message || mess->ciaddr.s_addr == 0)
1340 return 0;
1342 /* For DHCPINFORM only, cope without a valid context */
1343 context = narrow_context(context, mess->ciaddr, tagif_netid);
1345 /* Find a least based on IP address if we didn't
1346 get one from MAC address/client-d */
1347 if (!lease &&
1348 (lease = lease_find_by_addr(mess->ciaddr)) &&
1349 lease->hostname)
1350 hostname = lease->hostname;
1352 if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
1353 domain = get_domain(mess->ciaddr);
1355 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
1357 if (context && context->netid.net)
1359 context->netid.next = netid;
1360 netid = &context->netid;
1361 tagif_netid = run_tag_if(netid);
1364 if (lease)
1366 if (override.s_addr != 0)
1367 lease->override = override;
1368 else
1369 override = lease->override;
1372 clear_packet(mess, end);
1373 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1374 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1376 if (lease)
1378 if (lease->expires == 0)
1379 time = 0xffffffff;
1380 else
1381 time = (unsigned int)difftime(lease->expires, now);
1382 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1383 lease_set_interface(lease, int_index);
1386 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
1387 domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
1389 *is_inform = 1; /* handle reply differently */
1390 return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
1393 return 0;
1396 static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
1398 int i;
1400 if (o->len > len)
1401 return 0;
1403 if (o->len == 0)
1404 return 1;
1406 if (o->flags & DHOPT_HEX)
1408 if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
1409 return 1;
1411 else
1412 for (i = 0; i <= (len - o->len); )
1414 if (memcmp(o->val, p + i, o->len) == 0)
1415 return 1;
1417 if (o->flags & DHOPT_STRING)
1418 i++;
1419 else
1420 i += o->len;
1423 return 0;
1427 /* find a good value to use as MAC address for logging and address-allocation hashing.
1428 This is normally just the chaddr field from the DHCP packet,
1429 but eg Firewire will have hlen == 0 and use the client-id instead.
1430 This could be anything, but will normally be EUI64 for Firewire.
1431 We assume that if the first byte of the client-id equals the htype byte
1432 then the client-id is using the usual encoding and use the rest of the
1433 client-id: if not we can use the whole client-id. This should give
1434 sane MAC address logs. */
1435 unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
1436 int clid_len, unsigned char *clid, int *len_out)
1438 if (hwlen == 0 && clid && clid_len > 3)
1440 if (clid[0] == hwtype)
1442 *len_out = clid_len - 1 ;
1443 return clid + 1;
1446 #if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1447 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1449 *len_out = clid_len - 1 ;
1450 return clid + 1;
1452 #endif
1454 *len_out = clid_len;
1455 return clid;
1458 *len_out = hwlen;
1459 return hwaddr;
1462 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
1464 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1466 if (opt)
1468 unsigned int req_time = option_uint(opt, 0, 4);
1469 if (req_time < 120 )
1470 req_time = 120; /* sanity */
1471 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1472 time = req_time;
1475 return time;
1478 static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1480 if (override.s_addr != 0)
1481 return override;
1482 else if (context)
1483 return context->local;
1484 else
1485 return fallback;
1488 static int sanitise(unsigned char *opt, char *buf)
1490 char *p;
1491 int i;
1493 *buf = 0;
1495 if (!opt)
1496 return 0;
1498 p = option_ptr(opt, 0);
1500 for (i = option_len(opt); i > 0; i--)
1502 char c = *p++;
1503 if (isprint((int)c))
1504 *buf++ = c;
1506 *buf = 0; /* add terminator */
1508 return 1;
1511 #ifdef HAVE_SCRIPT
1512 static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim)
1514 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1516 size_t newsz = lease->extradata_len + len + 100;
1517 unsigned char *new = whine_malloc(newsz);
1519 if (!new)
1520 return;
1522 if (lease->extradata)
1524 memcpy(new, lease->extradata, lease->extradata_len);
1525 free(lease->extradata);
1528 lease->extradata = new;
1529 lease->extradata_size = newsz;
1532 if (len != 0)
1533 memcpy(lease->extradata + lease->extradata_len, data, len);
1534 lease->extradata[lease->extradata_len + len] = delim;
1535 lease->extradata_len += len + 1;
1538 static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
1540 if (!opt)
1541 add_extradata_data(lease, NULL, 0, 0);
1542 else
1544 size_t i, len = option_len(opt);
1545 unsigned char *ucp = option_ptr(opt, 0);
1547 /* check for embeded NULLs */
1548 for (i = 0; i < len; i++)
1549 if (ucp[i] == 0)
1551 len = i;
1552 break;
1555 add_extradata_data(lease, ucp, len, 0);
1558 #endif
1560 static void log_packet(char *type, void *addr, unsigned char *ext_mac,
1561 int mac_len, char *interface, char *string, u32 xid)
1563 struct in_addr a;
1565 /* addr may be misaligned */
1566 if (addr)
1567 memcpy(&a, addr, sizeof(a));
1569 print_mac(daemon->namebuff, ext_mac, mac_len);
1571 if(daemon->options & OPT_LOG_OPTS)
1572 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
1573 ntohl(xid),
1574 type,
1575 interface,
1576 addr ? inet_ntoa(a) : "",
1577 addr ? " " : "",
1578 daemon->namebuff,
1579 string ? string : "");
1580 else
1581 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s",
1582 type,
1583 interface,
1584 addr ? inet_ntoa(a) : "",
1585 addr ? " " : "",
1586 daemon->namebuff,
1587 string ? string : "");
1590 static void log_options(unsigned char *start, u32 xid)
1592 while (*start != OPTION_END)
1594 int is_ip, is_name, i;
1595 char *text = option_string(start[0], &is_ip, &is_name);
1596 unsigned char trunc = option_len(start);
1598 if (is_ip)
1599 for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
1601 if (i != 0)
1602 strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
1603 strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
1605 else if (!is_name || !sanitise(start, daemon->namebuff))
1607 if (trunc > 13)
1608 trunc = 13;
1609 print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
1612 my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
1613 ntohl(xid), option_len(start), start[0],
1614 text ? ":" : "", text ? text : "",
1615 trunc == 0 ? "" : " ",
1616 trunc == 0 ? "" : daemon->namebuff,
1617 trunc == option_len(start) ? "" : "...");
1618 start += start[1] + 2;
1622 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1624 while (1)
1626 if (p > end)
1627 return NULL;
1628 else if (*p == OPTION_END)
1629 return opt == OPTION_END ? p : NULL;
1630 else if (*p == OPTION_PAD)
1631 p++;
1632 else
1634 int opt_len;
1635 if (p > end - 2)
1636 return NULL; /* malformed packet */
1637 opt_len = option_len(p);
1638 if (p > end - (2 + opt_len))
1639 return NULL; /* malformed packet */
1640 if (*p == opt && opt_len >= minsize)
1641 return p;
1642 p += opt_len + 2;
1647 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1649 unsigned char *ret, *overload;
1651 /* skip over DHCP cookie; */
1652 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
1653 return ret;
1655 /* look for overload option. */
1656 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
1657 return NULL;
1659 /* Can we look in filename area ? */
1660 if ((overload[2] & 1) &&
1661 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
1662 return ret;
1664 /* finally try sname area */
1665 if ((overload[2] & 2) &&
1666 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
1667 return ret;
1669 return NULL;
1672 static struct in_addr option_addr_arr(unsigned char *opt, int offset)
1674 /* this worries about unaligned data in the option. */
1675 /* struct in_addr is network byte order */
1676 struct in_addr ret;
1678 memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
1680 return ret;
1683 static struct in_addr option_addr(unsigned char *opt)
1685 return option_addr_arr(opt, 0);
1688 static unsigned int option_uint(unsigned char *opt, int offset, int size)
1690 /* this worries about unaligned data and byte order */
1691 unsigned int ret = 0;
1692 int i;
1693 unsigned char *p = option_ptr(opt, offset);
1695 for (i = 0; i < size; i++)
1696 ret = (ret << 8) | *p++;
1698 return ret;
1701 static unsigned char *dhcp_skip_opts(unsigned char *start)
1703 while (*start != 0)
1704 start += start[1] + 2;
1705 return start;
1708 /* only for use when building packet: doesn't check for bad data. */
1709 static unsigned char *find_overload(struct dhcp_packet *mess)
1711 unsigned char *p = &mess->options[0] + sizeof(u32);
1713 while (*p != 0)
1715 if (*p == OPTION_OVERLOAD)
1716 return p;
1717 p += p[1] + 2;
1719 return NULL;
1722 static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
1723 unsigned char *agent_id, unsigned char *real_end)
1725 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1726 unsigned char *overload;
1727 size_t ret;
1728 struct dhcp_netid_list *id_list;
1729 struct dhcp_netid *n;
1731 /* move agent_id back down to the end of the packet */
1732 if (agent_id)
1734 memmove(p, agent_id, real_end - agent_id);
1735 p += real_end - agent_id;
1736 memset(p, 0, real_end - p); /* in case of overlap */
1739 /* We do logging too */
1740 if (netid && (daemon->options & OPT_LOG_OPTS))
1742 char *s = daemon->namebuff;
1743 for (*s = 0; netid; netid = netid->next)
1745 /* kill dupes. */
1746 for (n = netid->next; n; n = n->next)
1747 if (strcmp(netid->net, n->net) == 0)
1748 break;
1750 if (!n)
1752 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
1753 if (netid->next)
1754 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
1757 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
1760 /* add END options to the regions. */
1761 overload = find_overload(mess);
1763 if (overload && (option_uint(overload, 0, 1) & 1))
1765 *dhcp_skip_opts(mess->file) = OPTION_END;
1766 if (daemon->options & OPT_LOG_OPTS)
1767 log_options(mess->file, mess->xid);
1769 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
1770 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
1772 if (overload && (option_uint(overload, 0, 1) & 2))
1774 *dhcp_skip_opts(mess->sname) = OPTION_END;
1775 if (daemon->options & OPT_LOG_OPTS)
1776 log_options(mess->sname, mess->xid);
1778 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
1779 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
1782 *p++ = OPTION_END;
1784 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
1785 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
1786 break;
1787 if (id_list)
1788 mess->flags |= htons(0x8000); /* force broadcast */
1790 if (daemon->options & OPT_LOG_OPTS)
1792 if (mess->siaddr.s_addr != 0)
1793 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
1795 if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
1796 my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
1798 log_options(&mess->options[0] + sizeof(u32), mess->xid);
1801 ret = (size_t)(p - (unsigned char *)mess);
1803 if (ret < MIN_PACKETSZ)
1804 ret = MIN_PACKETSZ;
1806 return ret;
1809 static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
1811 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1813 if (p + len + 3 >= end)
1814 /* not enough space in options area, try and use overload, if poss */
1816 unsigned char *overload;
1818 if (!(overload = find_overload(mess)) &&
1819 (mess->file[0] == 0 || mess->sname[0] == 0))
1821 /* attempt to overload fname and sname areas, we've reserved space for the
1822 overflow option previuously. */
1823 overload = p;
1824 *(p++) = OPTION_OVERLOAD;
1825 *(p++) = 1;
1828 p = NULL;
1830 /* using filename field ? */
1831 if (overload)
1833 if (mess->file[0] == 0)
1834 overload[2] |= 1;
1836 if (overload[2] & 1)
1838 p = dhcp_skip_opts(mess->file);
1839 if (p + len + 3 >= mess->file + sizeof(mess->file))
1840 p = NULL;
1843 if (!p)
1845 /* try to bring sname into play (it may be already) */
1846 if (mess->sname[0] == 0)
1847 overload[2] |= 2;
1849 if (overload[2] & 2)
1851 p = dhcp_skip_opts(mess->sname);
1852 if (p + len + 3 >= mess->sname + sizeof(mess->file))
1853 p = NULL;
1858 if (!p)
1859 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1862 if (p)
1864 *(p++) = opt;
1865 *(p++) = len;
1868 return p;
1871 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
1873 int i;
1874 unsigned char *p = free_space(mess, end, opt, len);
1876 if (p)
1877 for (i = 0; i < len; i++)
1878 *(p++) = val >> (8 * (len - (i + 1)));
1881 static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1882 char *string, int null_term)
1884 unsigned char *p;
1885 size_t len = strlen(string);
1887 if (null_term && len != 255)
1888 len++;
1890 if ((p = free_space(mess, end, opt, len)))
1891 memcpy(p, string, len);
1894 /* return length, note this only does the data part */
1895 static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
1897 int len = opt->len;
1899 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1900 len++;
1902 if (p && len != 0)
1904 if (context && (opt->flags & DHOPT_ADDR))
1906 int j;
1907 struct in_addr *a = (struct in_addr *)opt->val;
1908 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
1910 /* zero means "self" (but not in vendorclass options.) */
1911 if (a->s_addr == 0)
1912 memcpy(p, &context->local, INADDRSZ);
1913 else
1914 memcpy(p, a, INADDRSZ);
1915 p += INADDRSZ;
1918 else
1919 memcpy(p, opt->val, len);
1921 return len;
1924 static int in_list(unsigned char *list, int opt)
1926 int i;
1928 /* If no requested options, send everything, not nothing. */
1929 if (!list)
1930 return 1;
1932 for (i = 0; list[i] != OPTION_END; i++)
1933 if (opt == list[i])
1934 return 1;
1936 return 0;
1939 static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
1941 struct dhcp_opt *tmp;
1942 for (tmp = opts; tmp; tmp = tmp->next)
1943 if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
1944 if (match_netid(tmp->netid, netid, 0))
1945 return tmp;
1947 /* No match, look for one without a netid */
1948 for (tmp = opts; tmp; tmp = tmp->next)
1949 if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
1950 if (match_netid(tmp->netid, netid, 1))
1951 return tmp;
1953 return NULL;
1956 /* mark vendor-encapsulated options which match the client-supplied or
1957 config-supplied vendor class */
1958 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1960 for (; dopt; dopt = dopt->next)
1962 dopt->flags &= ~DHOPT_VENDOR_MATCH;
1963 if (opt && (dopt->flags & DHOPT_VENDOR))
1965 int i, len = 0;
1966 if (dopt->u.vendor_class)
1967 len = strlen((char *)dopt->u.vendor_class);
1968 for (i = 0; i <= (option_len(opt) - len); i++)
1969 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
1971 dopt->flags |= DHOPT_VENDOR_MATCH;
1972 break;
1978 static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1979 struct dhcp_packet *mess, unsigned char *end, int null_term)
1981 int len, enc_len, ret = 0;
1982 struct dhcp_opt *start;
1983 unsigned char *p;
1985 /* find size in advance */
1986 for (enc_len = 0, start = opt; opt; opt = opt->next)
1987 if (opt->flags & flag)
1989 int new = do_opt(opt, NULL, NULL, null_term) + 2;
1990 ret = 1;
1991 if (enc_len + new <= 255)
1992 enc_len += new;
1993 else
1995 p = free_space(mess, end, encap, enc_len);
1996 for (; start && start != opt; start = start->next)
1997 if (p && (start->flags & flag))
1999 len = do_opt(start, p + 2, NULL, null_term);
2000 *(p++) = start->opt;
2001 *(p++) = len;
2002 p += len;
2004 enc_len = new;
2005 start = opt;
2009 if (enc_len != 0 &&
2010 (p = free_space(mess, end, encap, enc_len + 1)))
2012 for (; start; start = start->next)
2013 if (start->flags & flag)
2015 len = do_opt(start, p + 2, NULL, null_term);
2016 *(p++) = start->opt;
2017 *(p++) = len;
2018 p += len;
2020 *p = OPTION_END;
2023 return ret;
2026 static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
2028 unsigned char *p;
2030 option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
2031 if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
2032 memcpy(p, uuid, 17);
2035 static int prune_vendor_opts(struct dhcp_netid *netid)
2037 int force = 0;
2038 struct dhcp_opt *opt;
2040 /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
2041 for (opt = daemon->dhcp_opts; opt; opt = opt->next)
2042 if (opt->flags & DHOPT_VENDOR_MATCH)
2044 if (!match_netid(opt->netid, netid, 1))
2045 opt->flags &= ~DHOPT_VENDOR_MATCH;
2046 else if (opt->flags & DHOPT_FORCE)
2047 force = 1;
2049 return force;
2052 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local)
2054 #define NUM_OPTS 4
2056 unsigned char *p, *q;
2057 struct pxe_service *service;
2058 static struct dhcp_opt *o, *ret;
2059 int i, j = NUM_OPTS - 1;
2060 struct in_addr boot_server;
2062 /* We pass back references to these, hence they are declared static */
2063 static unsigned char discovery_control;
2064 static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
2065 static struct dhcp_opt *fake_opts = NULL;
2067 /* Disable multicast, since we don't support it, and broadcast
2068 unless we need it */
2069 discovery_control = 3;
2071 ret = daemon->dhcp_opts;
2073 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
2074 return ret;
2076 for (i = 0; i < NUM_OPTS; i++)
2078 fake_opts[i].flags = DHOPT_VENDOR_MATCH;
2079 fake_opts[i].netid = NULL;
2080 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
2083 /* create the data for the PXE_MENU and PXE_SERVERS options. */
2084 p = (unsigned char *)daemon->dhcp_buff;
2085 q = (unsigned char *)daemon->dhcp_buff3;
2087 for (i = 0, service = daemon->pxe_services; service; service = service->next)
2088 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
2090 size_t len = strlen(service->menu);
2091 /* opt 43 max size is 255. encapsulated option has type and length
2092 bytes, so its max size is 253. */
2093 if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
2095 *(p++) = service->type >> 8;
2096 *(p++) = service->type;
2097 *(p++) = len;
2098 memcpy(p, service->menu, len);
2099 p += len;
2100 i++;
2102 else
2104 toobig:
2105 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
2106 return daemon->dhcp_opts;
2109 boot_server = service->basename ? local : service->server;
2111 if (boot_server.s_addr != 0)
2113 if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
2114 goto toobig;
2116 /* Boot service with known address - give it */
2117 *(q++) = service->type >> 8;
2118 *(q++) = service->type;
2119 *(q++) = 1;
2120 /* dest misaligned */
2121 memcpy(q, &boot_server.s_addr, INADDRSZ);
2122 q += INADDRSZ;
2124 else if (service->type != 0)
2125 /* We don't know the server for a service type, so we'll
2126 allow the client to broadcast for it */
2127 discovery_control = 2;
2130 /* if no prompt, wait forever if there's a choice */
2131 fake_prompt[0] = (i > 1) ? 255 : 0;
2133 if (i == 0)
2134 discovery_control = 8; /* no menu - just use use mess->filename */
2135 else
2137 ret = &fake_opts[j--];
2138 ret->len = p - (unsigned char *)daemon->dhcp_buff;
2139 ret->val = (unsigned char *)daemon->dhcp_buff;
2140 ret->opt = SUBOPT_PXE_MENU;
2142 if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
2144 ret = &fake_opts[j--];
2145 ret->len = q - (unsigned char *)daemon->dhcp_buff3;
2146 ret->val = (unsigned char *)daemon->dhcp_buff3;
2147 ret->opt = SUBOPT_PXE_SERVERS;
2151 for (o = daemon->dhcp_opts; o; o = o->next)
2152 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
2153 break;
2155 if (!o)
2157 ret = &fake_opts[j--];
2158 ret->len = sizeof(fake_prompt);
2159 ret->val = fake_prompt;
2160 ret->opt = SUBOPT_PXE_MENU_PROMPT;
2163 ret = &fake_opts[j--];
2164 ret->len = 1;
2165 ret->opt = SUBOPT_PXE_DISCOVERY;
2166 ret->val= &discovery_control;
2168 return ret;
2171 static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
2173 memset(mess->sname, 0, sizeof(mess->sname));
2174 memset(mess->file, 0, sizeof(mess->file));
2175 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
2176 mess->siaddr.s_addr = 0;
2179 struct dhcp_boot *find_boot(struct dhcp_netid *netid)
2181 struct dhcp_boot *boot;
2183 /* decide which dhcp-boot option we're using */
2184 for (boot = daemon->boot_config; boot; boot = boot->next)
2185 if (match_netid(boot->netid, netid, 0))
2186 break;
2187 if (!boot)
2188 /* No match, look for one without a netid */
2189 for (boot = daemon->boot_config; boot; boot = boot->next)
2190 if (match_netid(boot->netid, netid, 1))
2191 break;
2193 return boot;
2196 static void do_options(struct dhcp_context *context,
2197 struct dhcp_packet *mess,
2198 unsigned char *end,
2199 unsigned char *req_options,
2200 char *hostname,
2201 char *domain, char *config_domain,
2202 struct dhcp_netid *netid,
2203 struct in_addr subnet_addr,
2204 unsigned char fqdn_flags,
2205 int null_term, int pxe_arch,
2206 unsigned char *uuid,
2207 int vendor_class_len)
2209 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2210 struct dhcp_boot *boot;
2211 unsigned char *p;
2212 int i, len, force_encap = 0;
2213 unsigned char f0 = 0, s0 = 0;
2214 int done_file = 0, done_server = 0;
2215 int done_vendor_class = 0;
2217 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
2218 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
2220 /* logging */
2221 if ((daemon->options & OPT_LOG_OPTS) && req_options)
2223 char *q = daemon->namebuff;
2224 for (i = 0; req_options[i] != OPTION_END; i++)
2226 char *s = option_string(req_options[i], NULL, NULL);
2227 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
2228 "%d%s%s%s",
2229 req_options[i],
2230 s ? ":" : "",
2231 s ? s : "",
2232 req_options[i+1] == OPTION_END ? "" : ", ");
2233 if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2235 q = daemon->namebuff;
2236 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
2241 if (context)
2242 mess->siaddr = context->local;
2244 /* See if we can send the boot stuff as options.
2245 To do this we need a requested option list, BOOTP
2246 and very old DHCP clients won't have this, we also
2247 provide an manual option to disable it.
2248 Some PXE ROMs have bugs (surprise!) and need zero-terminated
2249 names, so we always send those. */
2250 if ((boot = find_boot(netid)))
2252 if (boot->sname)
2254 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2255 req_options &&
2256 in_list(req_options, OPTION_SNAME))
2257 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
2258 else
2259 strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
2262 if (boot->file)
2264 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2265 req_options &&
2266 in_list(req_options, OPTION_FILENAME))
2267 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2268 else
2269 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
2272 if (boot->next_server.s_addr)
2273 mess->siaddr = boot->next_server;
2275 else
2276 /* Use the values of the relevant options if no dhcp-boot given and
2277 they're not explicitly asked for as options. OPTION_END is used
2278 as an internal way to specify siaddr without using dhcp-boot, for use in
2279 dhcp-optsfile. */
2281 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
2282 (opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
2284 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2285 done_file = 1;
2288 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
2289 (opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
2291 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2292 done_server = 1;
2295 if ((opt = option_find2(netid, config_opts, OPTION_END)))
2296 mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
2299 /* We don't want to do option-overload for BOOTP, so make the file and sname
2300 fields look like they are in use, even when they aren't. This gets restored
2301 at the end of this function. */
2303 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2305 f0 = mess->file[0];
2306 mess->file[0] = 1;
2307 s0 = mess->sname[0];
2308 mess->sname[0] = 1;
2311 /* At this point, if mess->sname or mess->file are zeroed, they are available
2312 for option overload, reserve space for the overload option. */
2313 if (mess->file[0] == 0 || mess->sname[0] == 0)
2314 end -= 3;
2316 /* rfc3011 says this doesn't need to be in the requested options list. */
2317 if (subnet_addr.s_addr)
2318 option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
2320 /* replies to DHCPINFORM may not have a valid context */
2321 if (context)
2323 if (!option_find2(netid, config_opts, OPTION_NETMASK))
2324 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
2326 /* May not have a "guessed" broadcast address if we got no packets via a relay
2327 from this net yet (ie just unicast renewals after a restart */
2328 if (context->broadcast.s_addr &&
2329 !option_find2(netid, config_opts, OPTION_BROADCAST))
2330 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2332 /* Same comments as broadcast apply, and also may not be able to get a sensible
2333 default when using subnet select. User must configure by steam in that case. */
2334 if (context->router.s_addr &&
2335 in_list(req_options, OPTION_ROUTER) &&
2336 !option_find2(netid, config_opts, OPTION_ROUTER))
2337 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2339 if (in_list(req_options, OPTION_DNSSERVER) &&
2340 !option_find2(netid, config_opts, OPTION_DNSSERVER))
2341 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2344 if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
2345 !option_find2(netid, config_opts, OPTION_DOMAINNAME))
2346 option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
2348 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
2349 if (hostname)
2351 if (in_list(req_options, OPTION_HOSTNAME) &&
2352 !option_find2(netid, config_opts, OPTION_HOSTNAME))
2353 option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
2355 if (fqdn_flags != 0)
2357 len = strlen(hostname) + 3;
2359 if (fqdn_flags & 0x04)
2360 len += 2;
2361 else if (null_term)
2362 len++;
2364 if (domain)
2365 len += strlen(domain) + 1;
2367 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
2369 *(p++) = fqdn_flags;
2370 *(p++) = 255;
2371 *(p++) = 255;
2373 if (fqdn_flags & 0x04)
2375 p = do_rfc1035_name(p, hostname);
2376 if (domain)
2377 p = do_rfc1035_name(p, domain);
2378 *p++ = 0;
2380 else
2382 memcpy(p, hostname, strlen(hostname));
2383 p += strlen(hostname);
2384 if (domain)
2386 *(p++) = '.';
2387 memcpy(p, domain, strlen(domain));
2388 p += strlen(domain);
2390 if (null_term)
2391 *(p++) = 0;
2397 for (opt = config_opts; opt; opt = opt->next)
2399 int optno = opt->opt;
2401 /* was it asked for, or are we sending it anyway? */
2402 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
2403 continue;
2405 /* prohibit some used-internally options */
2406 if (optno == OPTION_CLIENT_FQDN ||
2407 optno == OPTION_MAXMESSAGE ||
2408 optno == OPTION_OVERLOAD ||
2409 optno == OPTION_PAD ||
2410 optno == OPTION_END)
2411 continue;
2413 if (optno == OPTION_SNAME && done_server)
2414 continue;
2416 if (optno == OPTION_FILENAME && done_file)
2417 continue;
2419 /* netids match and not encapsulated? */
2420 if (opt != option_find2(netid, config_opts, optno))
2421 continue;
2423 /* For the options we have default values on
2424 dhc-option=<optionno> means "don't include this option"
2425 not "include a zero-length option" */
2426 if (opt->len == 0 &&
2427 (optno == OPTION_NETMASK ||
2428 optno == OPTION_BROADCAST ||
2429 optno == OPTION_ROUTER ||
2430 optno == OPTION_DNSSERVER ||
2431 optno == OPTION_DOMAINNAME ||
2432 optno == OPTION_HOSTNAME))
2433 continue;
2435 /* vendor-class comes from elsewhere for PXE */
2436 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2437 continue;
2439 /* always force null-term for filename and servername - buggy PXE again. */
2440 len = do_opt(opt, NULL, context,
2441 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2443 if ((p = free_space(mess, end, optno, len)))
2445 do_opt(opt, p, context,
2446 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2448 /* If we send a vendor-id, revisit which vendor-ops we consider
2449 it appropriate to send. */
2450 if (optno == OPTION_VENDOR_ID)
2452 match_vendor_opts(p - 2, config_opts);
2453 done_vendor_class = 1;
2458 /* Now send options to be encapsulated in arbitrary options,
2459 eg dhcp-option=encap:172,17,.......
2460 Also hand vendor-identifying vendor-encapsulated options,
2461 dhcp-option = rfc3925-encap:13,17,.......
2462 The may be more that one "outer" to do, so group
2463 all the options which match each outer in turn. */
2464 for (opt = config_opts; opt; opt = opt->next)
2465 opt->flags &= ~DHOPT_ENCAP_DONE;
2467 for (opt = config_opts; opt; opt = opt->next)
2469 int flags;
2471 if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
2473 int found = 0;
2474 struct dhcp_opt *o;
2476 if (opt->flags & DHOPT_ENCAP_DONE)
2477 continue;
2479 for (len = 0, o = config_opts; o; o = o->next)
2481 int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
2483 o->flags &= ~DHOPT_ENCAP_MATCH;
2485 if (!(o->flags & flags) || opt->u.encap != o->u.encap)
2486 continue;
2488 o->flags |= DHOPT_ENCAP_DONE;
2489 if (match_netid(o->netid, netid, 1) &&
2490 ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
2492 o->flags |= DHOPT_ENCAP_MATCH;
2493 found = 1;
2494 len += do_opt(o, NULL, NULL, 0) + 2;
2498 if (found)
2500 if (flags & DHOPT_ENCAPSULATE)
2501 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
2502 else if (len > 250)
2503 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
2504 else if ((p = free_space(mess, end, OPTION_VENDOR_IDENT_OPT, len + 5)))
2506 int swap_ent = htonl(opt->u.encap);
2507 memcpy(p, &swap_ent, 4);
2508 p += 4;
2509 *(p++) = len;
2510 for (o = config_opts; o; o = o->next)
2511 if (o->flags & DHOPT_ENCAP_MATCH)
2513 len = do_opt(o, p + 2, NULL, 0);
2514 *(p++) = o->opt;
2515 *(p++) = len;
2516 p += len;
2523 force_encap = prune_vendor_opts(netid);
2525 if (context && pxe_arch != -1)
2527 pxe_misc(mess, end, uuid);
2528 config_opts = pxe_opts(pxe_arch, netid, context->local);
2531 if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
2532 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term) &&
2533 pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
2534 (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
2535 /* If we send vendor encapsulated options, and haven't already sent option 60,
2536 echo back the value we got from the client. */
2537 memcpy(p, daemon->dhcp_buff3, vendor_class_len);
2539 /* restore BOOTP anti-overload hack */
2540 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2542 mess->file[0] = f0;
2543 mess->sname[0] = s0;
2547 #endif