Revert "Reduce excessive logging for DHCP packets"
[tomato.git] / release / src / router / dnsmasq / src / rfc2131.c
blob1ec1bcf45ab666f6dbbf2ff851fb2c69905f46c6
1 /* dnsmasq is Copyright (c) 2000-2009 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_END 255
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 */
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
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
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)]))
84 static int sanitise(unsigned char *opt, char *buf);
85 static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
86 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
87 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
88 static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
89 int opt, char *string, int null_term);
90 static struct in_addr option_addr(unsigned char *opt);
91 static struct in_addr option_addr_arr(unsigned char *opt, int offset);
92 static unsigned int option_uint(unsigned char *opt, int i, int size);
93 static void log_packet(char *type, void *addr, unsigned char *ext_mac,
94 int mac_len, char *interface, char *string, u32 xid);
95 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
96 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
97 static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
98 unsigned char *agent_id, unsigned char *real_end);
99 static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
100 static 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);
113 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
114 static void do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
115 static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
116 static int prune_vendor_opts(struct dhcp_netid *netid);
117 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid);
118 struct dhcp_boot *find_boot(struct dhcp_netid *netid);
121 size_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)
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];
151 subnet_addr.s_addr = override.s_addr = 0;
153 /* set tag with name == interface */
154 iface_id.net = iface_name;
155 iface_id.next = NULL;
156 netid = &iface_id;
158 if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
159 return 0;
161 if (mess->htype == 0 && mess->hlen != 0)
162 return 0;
164 /* check for DHCP rather than BOOTP */
165 if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
167 mess_type = option_uint(opt, 0, 1);
169 /* only insist on a cookie for DHCP. */
170 if (*((u32 *)&mess->options) != htonl(DHCP_COOKIE))
171 return 0;
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)))
178 size_t size = (size_t)option_uint(opt, 0, 2) - 28;
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);
185 if (expand_buf(&daemon->dhcp_packet, size))
187 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
188 real_end = end = ((unsigned char *)mess) + size;
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;
197 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
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)
209 end -= total;
210 agent_id = end;
211 memcpy(agent_id, opt, total);
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);
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);
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)
225 int search;
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;
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)
240 vendor->netid.next = netid;
241 netid = &vendor->netid;
242 break;
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);
251 /* If there is no client identifier option, use the hardware address */
252 if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
254 clid_len = option_len(opt);
255 clid = option_ptr(opt, 0);
258 /* do we have a lease in store? */
259 lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
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)
265 clid_len = lease->clid_len;
266 clid = lease->clid;
269 /* find mac to use for logging and hashing */
270 emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
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))
278 mac->netid.next = netid;
279 netid = &mac->netid;
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)
291 struct dhcp_context *context_tmp, *context_new = NULL;
292 struct in_addr addr;
293 int force = 0;
295 if (subnet_addr.s_addr)
297 addr = subnet_addr;
298 force = 1;
300 else if (mess->giaddr.s_addr)
302 addr = mess->giaddr;
303 force = 1;
305 else
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))
314 context_new = context;
315 break;
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))
325 context_tmp->current = context_new;
326 context_new = context_tmp;
329 if (context_new || force)
330 context = context_new;
334 if (!context)
336 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));
339 return 0;
342 /* keep _a_ local address available. */
343 fallback = context->local;
345 if (daemon->options & OPT_LOG_OPTS)
347 struct dhcp_context *context_tmp;
348 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
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));
360 mess->op = BOOTREPLY;
362 config = find_config(daemon->dhcp_conf, context, clid, clid_len,
363 mess->chaddr, mess->hlen, mess->htype, NULL);
365 /* set "known" tag for known hosts */
366 if (config)
368 known_id.net = "known";
369 known_id.next = netid;
370 netid = &known_id;
373 if (mess_type == 0)
375 /* BOOTP request */
376 struct dhcp_netid id, bootp_id;
377 struct in_addr *logaddr = NULL;
379 /* must have a MAC addr for bootp */
380 if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
381 return 0;
383 if (have_config(config, CONFIG_DISABLE))
384 message = _("disabled");
386 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
388 if (have_config(config, CONFIG_NAME))
390 hostname = config->hostname;
391 domain = config->domain;
394 if (have_config(config, CONFIG_NETID))
396 config->netid.next = netid;
397 netid = &config->netid;
400 /* Match incoming filename field as a netid. */
401 if (mess->file[0])
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;
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;
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");
420 if (!message)
422 int nailed = 0;
424 if (have_config(config, CONFIG_ADDR))
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");
435 else
437 if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
438 !address_available(context, lease->addr, netid))
440 if (lease)
442 /* lease exists, wrong network. */
443 lease_prune(lease, now);
444 lease = NULL;
446 if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, netid, now))
447 message = _("no address available");
449 else
450 mess->yiaddr = lease->addr;
453 if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
454 message = _("wrong network");
455 else if (context->netid.net)
457 context->netid.next = netid;
458 netid = &context->netid;
461 if (!message && !nailed)
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");
470 if (!message &&
471 !lease &&
472 (!(lease = lease_allocate(mess->yiaddr))))
473 message = _("no leases left");
475 if (!message)
477 logaddr = &mess->yiaddr;
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);
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);
494 log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
496 return message ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
499 if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
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);
506 fqdn_flags = *op;
507 len -= 3;
508 op += 3;
509 pp = op;
511 /* Always force update, since the client has no way to do it itself. */
512 if (!(fqdn_flags & 0x01))
513 fqdn_flags |= 0x02;
515 fqdn_flags &= ~0x08;
516 fqdn_flags |= 0x01;
518 if (fqdn_flags & 0x04)
519 while (*op != 0 && ((op + (*op) + 1) - pp) < len)
521 memcpy(pq, op+1, *op);
522 pq += *op;
523 op += (*op)+1;
524 *(pq++) = '.';
526 else
528 memcpy(pq, op, len);
529 if (len > 0 && op[len-1] == 0)
530 borken_opt = 1;
531 pq += len + 1;
534 if (pq != daemon->dhcp_buff)
535 pq--;
537 *pq = 0;
539 if (legal_hostname(daemon->dhcp_buff))
540 offer_hostname = client_hostname = daemon->dhcp_buff;
542 else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
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;
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);
560 if (have_config(config, CONFIG_NAME))
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;
569 else if (client_hostname)
571 domain = strip_hostname(client_hostname);
573 if (strlen(client_hostname) != 0)
575 hostname = client_hostname;
576 if (!config)
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)
586 config = new;
587 /* set "known" tag for known hosts */
588 known_id.net = "known";
589 known_id.next = netid;
590 netid = &known_id;
596 if (have_config(config, CONFIG_NETID))
598 config->netid.next = netid;
599 netid = &config->netid;
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)
607 int i, matched = 0;
609 if (!(opt = option_find(mess, sz, o->opt, 1)) ||
610 o->len > option_len(opt))
611 continue;
613 if (o->len == 0)
614 matched = 1;
615 else if (o->flags & DHOPT_HEX)
617 if (memcmp_masked(o->val, option_ptr(opt, 0), o->len, o->u.wildcard_mask))
618 matched = 1;
620 else
621 for (i = 0; i <= (option_len(opt) - o->len); )
623 if (memcmp(o->val, option_ptr(opt, i), o->len) == 0)
625 matched = 1;
626 break;
629 if (o->flags & DHOPT_STRING)
630 i++;
631 else
632 i += o->len;
635 if (matched)
637 o->netid->next = netid;
638 netid = o->netid;
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.
653 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
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)
661 tmp = j + ucp[j] + 1;
662 ucp[j] = 0;
666 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
668 int mopt;
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;
677 if ((opt = option_find(mess, sz, mopt, 1)))
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)
683 vendor->netid.next = netid;
684 netid = &vendor->netid;
685 break;
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);
693 if (daemon->options & OPT_LOG_OPTS)
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);
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;
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;
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)
715 if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
717 memcpy(pxe_uuid, option_ptr(opt, 0), 17);
718 uuid = pxe_uuid;
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)))
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;
732 if (ignore)
733 return 0;
735 if (layer & 0x8000)
737 my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
738 return 0;
741 memcpy(save71, option_ptr(opt, 0), 4);
743 for (service = daemon->pxe_services; service; service = service->next)
744 if (service->type == type)
745 break;
747 if (!service || !service->basename)
748 return 0;
750 clear_packet(mess, end);
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;
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);
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);
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);
777 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
779 pxearch = option_uint(opt, 0, 2);
781 /* proxy DHCP here. The DHCPREQUEST stuff is for gPXE */
782 if ((mess_type == DHCPDISCOVER || mess_type == DHCPREQUEST) &&
783 (context->flags & CONTEXT_PROXY))
785 struct dhcp_boot *boot = find_boot(netid);
787 mess->yiaddr.s_addr = 0;
788 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
790 mess->ciaddr.s_addr = 0;
791 mess->flags |= htons(0x8000); /* broadcast */
794 clear_packet(mess, end);
796 /* Provide the bootfile here, for gPXE, and in case we have no menu items
797 and set discovery_control = 8 */
798 if (boot)
800 if (boot->next_server.s_addr)
801 mess->siaddr = boot->next_server;
803 if (boot->file)
804 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
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);
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);
820 /* if we're just a proxy server, go no further */
821 if (context->flags & CONTEXT_PROXY)
822 return 0;
824 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
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;
831 switch (mess_type)
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;
838 /* sanitise any message. Paranoid? Moi? */
839 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
841 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
842 return 0;
844 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff, mess->xid);
846 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
847 lease_prune(lease, now);
849 if (have_config(config, CONFIG_ADDR) &&
850 config->addr.s_addr == option_addr(opt).s_addr)
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;
858 else
859 /* make sure this host gets a different address next time. */
860 for (; context; context = context->current)
861 context->addr_epoch++;
863 return 0;
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;
871 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
872 lease_prune(lease, now);
873 else
874 message = _("unknown lease");
876 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
878 return 0;
880 case DHCPDISCOVER:
881 if (ignore || have_config(config, CONFIG_DISABLE))
883 message = _("ignored");
884 opt = NULL;
886 else
888 struct in_addr addr, conf;
890 addr.s_addr = conf.s_addr = 0;
892 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
893 addr = option_addr(opt);
895 if (have_config(config, CONFIG_ADDR))
897 char *addrs = inet_ntoa(config->addr);
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))
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));
909 else
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;
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");
940 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message, mess->xid);
942 if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
943 return 0;
945 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
947 if (context->netid.net)
949 context->netid.next = netid;
950 netid = &context->netid;
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)
961 option_put(mess, end, OPTION_T1, 4, (time/2));
962 option_put(mess, end, OPTION_T2, 4, (time*7)/8);
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);
967 return dhcp_packet_size(mess, netid, agent_id, real_end);
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)))
974 /* SELECTING or INIT_REBOOT */
975 mess->yiaddr = option_addr(opt);
977 /* send vendor and user class info for new or recreated lease */
978 do_classes = 1;
980 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
982 /* SELECTING */
983 selecting = 1;
985 if (override.s_addr != 0)
987 if (option_addr(opt).s_addr != override.s_addr)
988 return 0;
990 else
992 for (; context; context = context->current)
993 if (context->local.s_addr == option_addr(opt).s_addr)
994 break;
996 if (!context)
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");
1007 /* If a lease exists for this host and another address, squash it. */
1008 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1010 lease_prune(lease, now);
1011 lease = NULL;
1014 else
1016 /* INIT-REBOOT */
1017 if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
1018 return 0;
1020 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1022 message = _("wrong address");
1023 /* avoid loops when client brain-dead */
1024 lease_prune(lease, now);
1025 lease = NULL;
1029 else
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)))
1039 message = _("lease not found");
1040 /* ensure we broadcast NAK */
1041 unicast_dest = 0;
1043 /* desynchronise renewals */
1044 fuzz = rand16();
1045 mess->yiaddr = mess->ciaddr;
1048 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
1050 if (!message)
1052 struct dhcp_config *addr_config;
1053 struct dhcp_context *tmp = NULL;
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;
1060 if (!(context = narrow_context(context, mess->yiaddr, netid)))
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;
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");
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");
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");
1088 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
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))
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;
1099 else
1100 message = _("address in use");
1103 if (!message)
1105 if (emac_len == 0)
1106 message = _("no unique-id");
1108 else if (!lease)
1110 if ((lease = lease_allocate(mess->yiaddr)))
1111 do_classes = 1;
1112 else
1113 message = _("no leases left");
1118 if (message)
1120 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
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))
1132 mess->flags |= htons(0x8000); /* broadcast */
1133 mess->ciaddr.s_addr = 0;
1136 else
1138 if (do_classes)
1140 if (mess->giaddr.s_addr)
1141 lease->giaddr = mess->giaddr;
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)))
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)))
1155 memcpy(lease->userclass, ucp, len);
1156 lease->userclass[len] = 0;
1157 lease->userclass_len = len+1;
1160 if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
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)))
1167 memcpy(lease->vendorclass, ucp, len);
1168 lease->vendorclass[len] = 0;
1169 lease->vendorclass_len = len+1;
1172 if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
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)))
1179 memcpy(lease->supplied_hostname, ucp, len);
1180 lease->supplied_hostname[len] = 0;
1181 lease->supplied_hostname_len = len+1;
1186 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1188 hostname = client_hostname;
1189 hostname_auth = 1;
1192 if (context->netid.net)
1194 context->netid.next = netid;
1195 netid = &context->netid;
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);
1201 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1202 if (!hostname_auth)
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;
1210 if (hostname)
1211 lease_set_hostname(lease, hostname, hostname_auth);
1213 lease_set_expires(lease, time, now);
1214 lease_set_interface(lease, int_index);
1216 if (override.s_addr != 0)
1217 lease->override = override;
1218 else
1219 override = lease->override;
1221 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
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)
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);
1234 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
1235 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1238 return dhcp_packet_size(mess, netid, agent_id, real_end);
1240 case DHCPINFORM:
1241 if (ignore || have_config(config, CONFIG_DISABLE))
1242 message = _("ignored");
1244 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
1246 if (message || mess->ciaddr.s_addr == 0)
1247 return 0;
1249 /* For DHCPINFORM only, cope without a valid context */
1250 context = narrow_context(context, mess->ciaddr, netid);
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;
1259 if (!hostname)
1260 hostname = host_from_dns(mess->ciaddr);
1262 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
1264 if (context && context->netid.net)
1266 context->netid.next = netid;
1267 netid = &context->netid;
1270 if (lease)
1272 if (override.s_addr != 0)
1273 lease->override = override;
1274 else
1275 override = lease->override;
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));
1282 if (lease)
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);
1292 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
1293 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1295 *is_inform = 1; /* handle reply differently */
1296 return dhcp_packet_size(mess, netid, agent_id, real_end);
1299 return 0;
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. */
1310 unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
1311 int clid_len, unsigned char *clid, int *len_out)
1313 if (hwlen == 0 && clid && clid_len > 3)
1315 if (clid[0] == hwtype)
1317 *len_out = clid_len - 1 ;
1318 return clid + 1;
1321 #if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1322 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1324 *len_out = clid_len - 1 ;
1325 return clid + 1;
1327 #endif
1329 *len_out = clid_len;
1330 return clid;
1333 *len_out = hwlen;
1334 return hwaddr;
1337 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
1339 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1341 if (opt)
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;
1350 return time;
1353 static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1355 if (override.s_addr != 0)
1356 return override;
1357 else if (context)
1358 return context->local;
1359 else
1360 return fallback;
1363 static int sanitise(unsigned char *opt, char *buf)
1365 char *p;
1366 int i;
1368 *buf = 0;
1370 if (!opt)
1371 return 0;
1373 p = option_ptr(opt, 0);
1375 for (i = option_len(opt); i > 0; i--)
1377 char c = *p++;
1378 if (isprint((int)c))
1379 *buf++ = c;
1381 *buf = 0; /* add terminator */
1383 return 1;
1386 static void log_packet(char *type, void *addr, unsigned char *ext_mac,
1387 int mac_len, char *interface, char *string, u32 xid)
1389 struct in_addr a;
1391 /* addr may be misaligned */
1392 if (addr)
1393 memcpy(&a, addr, sizeof(a));
1395 print_mac(daemon->namebuff, ext_mac, mac_len);
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 : "");
1416 static void log_options(unsigned char *start, u32 xid)
1418 while (*start != OPTION_END)
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);
1424 if (is_ip)
1425 for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
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));
1431 else if (!is_name || !sanitise(start, daemon->namebuff))
1433 if (trunc > 13)
1434 trunc = 13;
1435 print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
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;
1448 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1450 while (1)
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
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;
1473 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1475 unsigned char *ret, *overload;
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;
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;
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;
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;
1495 return NULL;
1498 static struct in_addr option_addr_arr(unsigned char *opt, int offset)
1500 /* this worries about unaligned data in the option. */
1501 /* struct in_addr is network byte order */
1502 struct in_addr ret;
1504 memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
1506 return ret;
1509 static struct in_addr option_addr(unsigned char *opt)
1511 return option_addr_arr(opt, 0);
1514 static unsigned int option_uint(unsigned char *opt, int offset, int size)
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);
1521 for (i = 0; i < size; i++)
1522 ret = (ret << 8) | *p++;
1524 return ret;
1527 static unsigned char *dhcp_skip_opts(unsigned char *start)
1529 while (*start != 0)
1530 start += start[1] + 2;
1531 return start;
1534 /* only for use when building packet: doesn't check for bad data. */
1535 static unsigned char *find_overload(struct dhcp_packet *mess)
1537 unsigned char *p = &mess->options[0] + sizeof(u32);
1539 while (*p != 0)
1541 if (*p == OPTION_OVERLOAD)
1542 return p;
1543 p += p[1] + 2;
1545 return NULL;
1548 static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
1549 unsigned char *agent_id, unsigned char *real_end)
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;
1557 /* move agent_id back down to the end of the packet */
1558 if (agent_id)
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 */
1565 /* We do logging too */
1566 if (netid && (daemon->options & OPT_LOG_OPTS))
1568 char *s = daemon->namebuff;
1569 for (*s = 0; netid; netid = netid->next)
1571 /* kill dupes. */
1572 for (n = netid->next; n; n = n->next)
1573 if (strcmp(netid->net, n->net) == 0)
1574 break;
1576 if (!n)
1578 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
1579 if (netid->next)
1580 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
1583 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
1586 /* add END options to the regions. */
1587 overload = find_overload(mess);
1589 if (overload && (option_uint(overload, 0, 1) & 1))
1591 *dhcp_skip_opts(mess->file) = OPTION_END;
1592 if (daemon->options & OPT_LOG_OPTS)
1593 log_options(mess->file, mess->xid);
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);
1598 if (overload && (option_uint(overload, 0, 1) & 2))
1600 *dhcp_skip_opts(mess->sname) = OPTION_END;
1601 if (daemon->options & OPT_LOG_OPTS)
1602 log_options(mess->sname, mess->xid);
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);
1608 *p++ = OPTION_END;
1610 if (daemon->options & OPT_LOG_OPTS)
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));
1615 log_options(&mess->options[0] + sizeof(u32), mess->xid);
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 */
1622 ret = (size_t)(p - (unsigned char *)mess);
1624 if (ret < MIN_PACKETSZ)
1625 ret = MIN_PACKETSZ;
1627 return ret;
1630 static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
1632 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1634 if (p + len + 3 >= end)
1635 /* not enough space in options area, try and use overload, if poss */
1637 unsigned char *overload;
1639 if (!(overload = find_overload(mess)) &&
1640 (mess->file[0] == 0 || mess->sname[0] == 0))
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;
1649 p = NULL;
1651 /* using filename field ? */
1652 if (overload)
1654 if (mess->file[0] == 0)
1655 overload[2] |= 1;
1657 if (overload[2] & 1)
1659 p = dhcp_skip_opts(mess->file);
1660 if (p + len + 3 >= mess->file + sizeof(mess->file))
1661 p = NULL;
1664 if (!p)
1666 /* try to bring sname into play (it may be already) */
1667 if (mess->sname[0] == 0)
1668 overload[2] |= 2;
1670 if (overload[2] & 2)
1672 p = dhcp_skip_opts(mess->sname);
1673 if (p + len + 3 >= mess->sname + sizeof(mess->file))
1674 p = NULL;
1679 if (!p)
1680 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1683 if (p)
1685 *(p++) = opt;
1686 *(p++) = len;
1689 return p;
1692 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
1694 int i;
1695 unsigned char *p = free_space(mess, end, opt, len);
1697 if (p)
1698 for (i = 0; i < len; i++)
1699 *(p++) = val >> (8 * (len - (i + 1)));
1702 static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1703 char *string, int null_term)
1705 unsigned char *p;
1706 size_t len = strlen(string);
1708 if (null_term && len != 255)
1709 len++;
1711 if ((p = free_space(mess, end, opt, len)))
1712 memcpy(p, string, len);
1715 /* return length, note this only does the data part */
1716 static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
1718 int len = opt->len;
1720 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1721 len++;
1723 if (p && len != 0)
1725 if (context && (opt->flags & DHOPT_ADDR))
1727 int j;
1728 struct in_addr *a = (struct in_addr *)opt->val;
1729 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
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;
1739 else
1740 memcpy(p, opt->val, len);
1742 return len;
1745 static int in_list(unsigned char *list, int opt)
1747 int i;
1749 /* If no requested options, send everything, not nothing. */
1750 if (!list)
1751 return 1;
1753 for (i = 0; list[i] != OPTION_END; i++)
1754 if (opt == list[i])
1755 return 1;
1757 return 0;
1760 static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
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;
1768 return netid ? option_find2(NULL, opts, opt) : NULL;
1771 /* mark vendor-encapsulated options which match the client-supplied or
1772 config-supplied vendor class */
1773 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1775 for (; dopt; dopt = dopt->next)
1777 dopt->flags &= ~DHOPT_VENDOR_MATCH;
1778 if (opt && (dopt->flags & DHOPT_VENDOR))
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)
1786 dopt->flags |= DHOPT_VENDOR_MATCH;
1787 break;
1793 static void do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1794 struct dhcp_packet *mess, unsigned char *end, int null_term)
1796 int len, enc_len;
1797 struct dhcp_opt *start;
1798 unsigned char *p;
1800 /* find size in advance */
1801 for (enc_len = 0, start = opt; opt; opt = opt->next)
1802 if (opt->flags & flag)
1804 int new = do_opt(opt, NULL, NULL, null_term) + 2;
1805 if (enc_len + new <= 255)
1806 enc_len += new;
1807 else
1809 p = free_space(mess, end, encap, enc_len);
1810 for (; start && start != opt; start = start->next)
1811 if (p && (start->flags & flag))
1813 len = do_opt(start, p + 2, NULL, null_term);
1814 *(p++) = start->opt;
1815 *(p++) = len;
1816 p += len;
1818 enc_len = new;
1819 start = opt;
1823 if (enc_len != 0 &&
1824 (p = free_space(mess, end, encap, enc_len + 1)))
1826 for (; start; start = start->next)
1827 if (start->flags & flag)
1829 len = do_opt(start, p + 2, NULL, null_term);
1830 *(p++) = start->opt;
1831 *(p++) = len;
1832 p += len;
1834 *p = OPTION_END;
1838 static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
1840 unsigned char *p;
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);
1847 static int prune_vendor_opts(struct dhcp_netid *netid)
1849 int force = 0;
1850 struct dhcp_opt *opt;
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)
1856 if (!match_netid(opt->netid, netid, 1))
1857 opt->flags &= ~DHOPT_VENDOR_MATCH;
1858 else if (opt->flags & DHOPT_FORCE)
1859 force = 1;
1861 return force;
1864 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
1866 #define NUM_OPTS 4
1868 unsigned char *p, *q;
1869 struct pxe_service *service;
1870 static struct dhcp_opt *o, *ret;
1871 int i, j = NUM_OPTS - 1;
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;
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;
1885 ret = daemon->dhcp_opts;
1887 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
1888 return ret;
1890 for (i = 0; i < NUM_OPTS; i++)
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];
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;
1901 for (i = 0, service = daemon->pxe_services; service; service = service->next)
1902 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
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)
1909 *(p++) = service->type >> 8;
1910 *(p++) = service->type;
1911 *(p++) = len;
1912 memcpy(p, service->menu, len);
1913 p += len;
1914 i++;
1916 else
1918 toobig:
1919 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
1920 return daemon->dhcp_opts;
1923 if (!service->basename)
1925 if (service->server.s_addr != 0)
1927 if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
1928 goto toobig;
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;
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;
1945 /* if no prompt, wait forever if there's a choice */
1946 fake_prompt[0] = (i > 1) ? 255 : 0;
1948 if (i == 0)
1949 discovery_control = 8; /* no menu - just use use mess->filename */
1950 else
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;
1957 if (q - (unsigned char *)daemon->dhcp_buff2 != 0)
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;
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;
1970 if (!o)
1972 ret = &fake_opts[j--];
1973 ret->len = sizeof(fake_prompt);
1974 ret->val = fake_prompt;
1975 ret->opt = SUBOPT_PXE_MENU_PROMPT;
1978 if (discovery_control != 0)
1980 ret = &fake_opts[j--];
1981 ret->len = 1;
1982 ret->opt = SUBOPT_PXE_DISCOVERY;
1983 ret->val= &discovery_control;
1986 return ret;
1989 static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
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;
1997 struct dhcp_boot *find_boot(struct dhcp_netid *netid)
1999 struct dhcp_boot *boot;
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;
2011 return boot;
2014 static 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)
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;
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);
2036 /* logging */
2037 if ((daemon->options & OPT_LOG_OPTS) && req_options)
2039 char *q = daemon->namebuff;
2040 for (i = 0; req_options[i] != OPTION_END; i++)
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)
2051 q = daemon->namebuff;
2052 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
2057 if (context)
2058 mess->siaddr = context->local;
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)))
2068 if (boot->sname)
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);
2078 if (boot->file)
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);
2088 if (boot->next_server.s_addr)
2089 mess->siaddr = boot->next_server;
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. */
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))
2100 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2101 done_file = 1;
2104 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
2105 (opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
2107 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2108 done_server = 1;
2111 if ((opt = option_find2(netid, config_opts, OPTION_END)))
2112 mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
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. */
2119 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2121 f0 = mess->file[0];
2122 mess->file[0] = 1;
2123 s0 = mess->sname[0];
2124 mess->sname[0] = 1;
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;
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));
2136 /* replies to DHCPINFORM may not have a valid context */
2137 if (context)
2139 if (!option_find2(netid, config_opts, OPTION_NETMASK))
2140 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
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));
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));
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));
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);
2164 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
2165 if (hostname)
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);
2171 if (fqdn_flags != 0)
2173 len = strlen(hostname) + 3;
2175 if (fqdn_flags & 0x04)
2176 len += 2;
2177 else if (null_term)
2178 len++;
2180 if (domain)
2181 len += strlen(domain) + 1;
2183 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
2185 *(p++) = fqdn_flags;
2186 *(p++) = 255;
2187 *(p++) = 255;
2189 if (fqdn_flags & 0x04)
2191 p = do_rfc1035_name(p, hostname);
2192 if (domain)
2193 p = do_rfc1035_name(p, domain);
2194 *p++ = 0;
2196 else
2198 memcpy(p, hostname, strlen(hostname));
2199 p += strlen(hostname);
2200 if (domain)
2202 *(p++) = '.';
2203 memcpy(p, domain, strlen(domain));
2204 p += strlen(domain);
2206 if (null_term)
2207 *(p++) = 0;
2213 for (opt = config_opts; opt; opt = opt->next)
2215 int optno = opt->opt;
2217 /* was it asked for, or are we sending it anyway? */
2218 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
2219 continue;
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;
2229 if (optno == OPTION_SNAME && done_server)
2230 continue;
2232 if (optno == OPTION_FILENAME && done_file)
2233 continue;
2235 /* netids match and not encapsulated? */
2236 if (opt != option_find2(netid, config_opts, optno))
2237 continue;
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;
2251 /* vendor-class comes from elsewhere for PXE */
2252 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2253 continue;
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);
2259 if ((p = free_space(mess, end, optno, len)))
2261 do_opt(opt, p, context,
2262 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
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);
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;
2278 for (opt = config_opts; opt; opt = opt->next)
2279 if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE)
2281 struct dhcp_opt *o;
2282 int found = 0;
2284 for (o = config_opts; o; o = o->next)
2286 o->flags &= ~DHOPT_ENCAP_MATCH;
2287 if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
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)))
2293 o->flags |= DHOPT_ENCAP_MATCH;
2294 found = 1;
2299 if (found)
2300 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
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;
2308 if (pxe_arch != -1)
2310 pxe_misc(mess, end, uuid);
2311 config_opts = pxe_opts(pxe_arch, netid);
2314 if (force_encap)
2315 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term);
2317 /* restore BOOTP anti-overload hack */
2318 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2320 mess->file[0] = f0;
2321 mess->sname[0] = s0;
2325 #endif