Merge branch 'tomato-ND-usbmod-mix' into tomato-ND-USBmod
[tomato.git] / release / src / router / dnsmasq / src / rfc2131.c
blobc7b4671f59d37dbd94d6857ffec6536036513bd3
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 = _("disabled");
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 (canonicalise(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 (canonicalise(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 ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
712 strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
714 if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
716 memcpy(pxe_uuid, option_ptr(opt, 0), 17);
717 uuid = pxe_uuid;
720 /* Check if this is really a PXE bootserver request, and handle specially if so. */
721 if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
722 (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
723 (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
725 struct pxe_service *service;
726 int type = option_uint(opt, 0, 2);
727 int layer = option_uint(opt, 2, 2);
728 unsigned char save71[4];
729 struct dhcp_opt opt71;
731 if (layer & 0x8000)
733 my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
734 return 0;
737 memcpy(save71, option_ptr(opt, 0), 4);
739 for (service = daemon->pxe_services; service; service = service->next)
740 if (service->type == type)
741 break;
743 if (!service || !service->basename)
744 return 0;
746 clear_packet(mess, end);
748 mess->yiaddr = mess->ciaddr;
749 mess->ciaddr.s_addr = 0;
750 if (service->server.s_addr != 0)
751 mess->siaddr = service->server;
752 else
753 mess->siaddr = context->local;
755 snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
756 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
757 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
758 pxe_misc(mess, end, uuid);
760 prune_vendor_opts(netid);
761 opt71.val = save71;
762 opt71.opt = SUBOPT_PXE_BOOT_ITEM;
763 opt71.len = 4;
764 opt71.flags = DHOPT_VENDOR_MATCH;
765 opt71.netid = NULL;
766 opt71.next = daemon->dhcp_opts;
767 do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
769 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
770 return dhcp_packet_size(mess, netid, agent_id, real_end);
773 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
775 pxearch = option_uint(opt, 0, 2);
777 /* proxy DHCP here. The DHCPREQUEST stuff is for gPXE */
778 if ((mess_type == DHCPDISCOVER || mess_type == DHCPREQUEST) &&
779 (context->flags & CONTEXT_PROXY))
781 struct dhcp_boot *boot = find_boot(netid);
783 mess->yiaddr.s_addr = 0;
784 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
786 mess->ciaddr.s_addr = 0;
787 mess->flags |= htons(0x8000); /* broadcast */
790 clear_packet(mess, end);
792 /* Provide the bootfile here, for gPXE, and in case we have no menu items
793 and set discovery_control = 8 */
794 if (boot)
796 if (boot->next_server.s_addr)
797 mess->siaddr = boot->next_server;
799 if (boot->file)
800 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
803 option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
804 mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
805 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
806 pxe_misc(mess, end, uuid);
807 prune_vendor_opts(netid);
808 do_encap_opts(pxe_opts(pxearch, netid), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
810 log_packet("PXE", NULL, emac, emac_len, iface_name, "proxy", mess->xid);
811 return dhcp_packet_size(mess, netid, agent_id, real_end);
816 /* if we're just a proxy server, go no further */
817 if (context->flags & CONTEXT_PROXY)
818 return 0;
820 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
822 req_options = (unsigned char *)daemon->dhcp_buff2;
823 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
824 req_options[option_len(opt)] = OPTION_END;
827 switch (mess_type)
829 case DHCPDECLINE:
830 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
831 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
832 return 0;
834 /* sanitise any message. Paranoid? Moi? */
835 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
837 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
838 return 0;
840 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff, mess->xid);
842 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
843 lease_prune(lease, now);
845 if (have_config(config, CONFIG_ADDR) &&
846 config->addr.s_addr == option_addr(opt).s_addr)
848 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
849 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
850 inet_ntoa(config->addr), daemon->dhcp_buff);
851 config->flags |= CONFIG_DECLINED;
852 config->decline_time = now;
854 else
855 /* make sure this host gets a different address next time. */
856 for (; context; context = context->current)
857 context->addr_epoch++;
859 return 0;
861 case DHCPRELEASE:
862 if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
863 !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
864 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
865 return 0;
867 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
868 lease_prune(lease, now);
869 else
870 message = _("unknown lease");
872 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
874 return 0;
876 case DHCPDISCOVER:
877 if (ignore || have_config(config, CONFIG_DISABLE))
879 message = _("ignored");
880 opt = NULL;
882 else
884 struct in_addr addr, conf;
886 addr.s_addr = conf.s_addr = 0;
888 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
889 addr = option_addr(opt);
891 if (have_config(config, CONFIG_ADDR))
893 char *addrs = inet_ntoa(config->addr);
895 if ((ltmp = lease_find_by_addr(config->addr)) &&
896 ltmp != lease &&
897 !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
899 int len;
900 unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
901 ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
902 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
903 addrs, print_mac(daemon->namebuff, mac, len));
905 else
907 struct dhcp_context *tmp;
908 for (tmp = context; tmp; tmp = tmp->current)
909 if (context->router.s_addr == config->addr.s_addr)
910 break;
911 if (tmp)
912 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
913 else if (have_config(config, CONFIG_DECLINED) &&
914 difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
915 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
916 else
917 conf = config->addr;
921 if (conf.s_addr)
922 mess->yiaddr = conf;
923 else if (lease &&
924 address_available(context, lease->addr, netid) &&
925 !config_find_by_address(daemon->dhcp_conf, lease->addr))
926 mess->yiaddr = lease->addr;
927 else if (opt && address_available(context, addr, netid) && !lease_find_by_addr(addr) &&
928 !config_find_by_address(daemon->dhcp_conf, addr))
929 mess->yiaddr = addr;
930 else if (emac_len == 0)
931 message = _("no unique-id");
932 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, netid, now))
933 message = _("no address available");
936 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message, mess->xid);
938 if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
939 return 0;
941 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
943 if (context->netid.net)
945 context->netid.next = netid;
946 netid = &context->netid;
949 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
950 clear_packet(mess, end);
951 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
952 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
953 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
954 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
955 if (time != 0xffffffff)
957 option_put(mess, end, OPTION_T1, 4, (time/2));
958 option_put(mess, end, OPTION_T2, 4, (time*7)/8);
960 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
961 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
963 return dhcp_packet_size(mess, netid, agent_id, real_end);
965 case DHCPREQUEST:
966 if (ignore || have_config(config, CONFIG_DISABLE))
967 return 0;
968 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
970 /* SELECTING or INIT_REBOOT */
971 mess->yiaddr = option_addr(opt);
973 /* send vendor and user class info for new or recreated lease */
974 do_classes = 1;
976 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
978 /* SELECTING */
979 selecting = 1;
981 if (override.s_addr != 0)
983 if (option_addr(opt).s_addr != override.s_addr)
984 return 0;
986 else
988 for (; context; context = context->current)
989 if (context->local.s_addr == option_addr(opt).s_addr)
990 break;
992 if (!context)
994 /* In auth mode, a REQUEST sent to the wrong server
995 should be faulted, so that the client establishes
996 communication with us, otherwise, silently ignore. */
997 if (!(daemon->options & OPT_AUTHORITATIVE))
998 return 0;
999 message = _("wrong server-ID");
1003 /* If a lease exists for this host and another address, squash it. */
1004 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1006 lease_prune(lease, now);
1007 lease = NULL;
1010 else
1012 /* INIT-REBOOT */
1013 if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
1014 return 0;
1016 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1018 message = _("wrong address");
1019 /* avoid loops when client brain-dead */
1020 lease_prune(lease, now);
1021 lease = NULL;
1025 else
1027 /* RENEWING or REBINDING */
1028 /* Check existing lease for this address.
1029 We allow it to be missing if dhcp-authoritative mode
1030 as long as we can allocate the lease now - checked below.
1031 This makes for a smooth recovery from a lost lease DB */
1032 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
1033 (!lease && !(daemon->options & OPT_AUTHORITATIVE)))
1035 message = _("lease not found");
1036 /* ensure we broadcast NAK */
1037 unicast_dest = 0;
1039 /* desynchronise renewals */
1040 fuzz = rand16();
1041 mess->yiaddr = mess->ciaddr;
1044 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
1046 if (!message)
1048 struct dhcp_config *addr_config;
1049 struct dhcp_context *tmp = NULL;
1051 if (have_config(config, CONFIG_ADDR))
1052 for (tmp = context; tmp; tmp = tmp->current)
1053 if (context->router.s_addr == config->addr.s_addr)
1054 break;
1056 if (!(context = narrow_context(context, mess->yiaddr, netid)))
1058 /* If a machine moves networks whilst it has a lease, we catch that here. */
1059 message = _("wrong network");
1060 /* ensure we broadcast NAK */
1061 unicast_dest = 0;
1064 /* Check for renewal of a lease which is outside the allowed range. */
1065 else if (!address_available(context, mess->yiaddr, netid) &&
1066 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
1067 message = _("address not available");
1069 /* Check if a new static address has been configured. Be very sure that
1070 when the client does DISCOVER, it will get the static address, otherwise
1071 an endless protocol loop will ensue. */
1072 else if (!tmp && !selecting &&
1073 have_config(config, CONFIG_ADDR) &&
1074 (!have_config(config, CONFIG_DECLINED) ||
1075 difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
1076 config->addr.s_addr != mess->yiaddr.s_addr &&
1077 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
1078 message = _("static lease available");
1080 /* Check to see if the address is reserved as a static address for another host */
1081 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
1082 message = _("address reserved");
1084 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1086 /* If a host is configured with more than one MAC address, it's OK to 'nix
1087 a lease from one of it's MACs to give the address to another. */
1088 if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1090 my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
1091 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
1092 inet_ntoa(ltmp->addr));
1093 lease = ltmp;
1095 else
1096 message = _("address in use");
1099 if (!message)
1101 if (emac_len == 0)
1102 message = _("no unique-id");
1104 else if (!lease)
1106 if ((lease = lease_allocate(mess->yiaddr)))
1107 do_classes = 1;
1108 else
1109 message = _("no leases left");
1114 if (message)
1116 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
1118 mess->yiaddr.s_addr = 0;
1119 clear_packet(mess, end);
1120 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
1121 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1122 option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
1123 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
1124 a distant subnet which unicast a REQ to us won't work. */
1125 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
1126 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1128 mess->flags |= htons(0x8000); /* broadcast */
1129 mess->ciaddr.s_addr = 0;
1132 else
1134 if (do_classes)
1136 lease->changed = 1;
1137 /* copy user-class and vendor class into new lease, for the script */
1138 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1140 int len = option_len(opt);
1141 unsigned char *ucp = option_ptr(opt, 0);
1142 /* If the user-class option started as counted strings, the first byte will be zero. */
1143 if (len != 0 && ucp[0] == 0)
1144 ucp++, len--;
1145 free(lease->userclass);
1146 if ((lease->userclass = whine_malloc(len+1)))
1148 memcpy(lease->userclass, ucp, len);
1149 lease->userclass[len] = 0;
1150 lease->userclass_len = len+1;
1153 if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
1155 int len = option_len(opt);
1156 unsigned char *ucp = option_ptr(opt, 0);
1157 free(lease->vendorclass);
1158 if ((lease->vendorclass = whine_malloc(len+1)))
1160 memcpy(lease->vendorclass, ucp, len);
1161 lease->vendorclass[len] = 0;
1162 lease->vendorclass_len = len+1;
1167 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1169 hostname = client_hostname;
1170 hostname_auth = 1;
1173 if (context->netid.net)
1175 context->netid.next = netid;
1176 netid = &context->netid;
1179 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1180 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
1182 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1183 if (!hostname_auth)
1185 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1186 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
1187 break;
1188 if (id_list)
1189 hostname = NULL;
1191 if (hostname)
1192 lease_set_hostname(lease, hostname, hostname_auth);
1194 lease_set_expires(lease, time, now);
1195 lease_set_interface(lease, int_index);
1197 if (override.s_addr != 0)
1198 lease->override = override;
1199 else
1200 override = lease->override;
1202 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
1204 clear_packet(mess, end);
1205 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1206 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1207 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1208 if (time != 0xffffffff)
1210 while (fuzz > (time/16))
1211 fuzz = fuzz/2;
1212 option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
1213 option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
1215 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
1216 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1219 return dhcp_packet_size(mess, netid, agent_id, real_end);
1221 case DHCPINFORM:
1222 if (ignore || have_config(config, CONFIG_DISABLE))
1223 message = _("ignored");
1225 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
1227 if (message || mess->ciaddr.s_addr == 0)
1228 return 0;
1230 /* For DHCPINFORM only, cope without a valid context */
1231 context = narrow_context(context, mess->ciaddr, netid);
1233 /* Find a least based on IP address if we didn't
1234 get one from MAC address/client-d */
1235 if (!lease &&
1236 (lease = lease_find_by_addr(mess->ciaddr)) &&
1237 lease->hostname)
1238 hostname = lease->hostname;
1240 if (!hostname)
1241 hostname = host_from_dns(mess->ciaddr);
1243 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
1245 if (context && context->netid.net)
1247 context->netid.next = netid;
1248 netid = &context->netid;
1251 if (lease)
1253 if (override.s_addr != 0)
1254 lease->override = override;
1255 else
1256 override = lease->override;
1259 clear_packet(mess, end);
1260 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1261 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1263 if (lease)
1265 if (lease->expires == 0)
1266 time = 0xffffffff;
1267 else
1268 time = (unsigned int)difftime(lease->expires, now);
1269 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1270 lease_set_interface(lease, int_index);
1273 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
1274 domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid);
1276 *is_inform = 1; /* handle reply differently */
1277 return dhcp_packet_size(mess, netid, agent_id, real_end);
1280 return 0;
1283 /* find a good value to use as MAC address for logging and address-allocation hashing.
1284 This is normally just the chaddr field from the DHCP packet,
1285 but eg Firewire will have hlen == 0 and use the client-id instead.
1286 This could be anything, but will normally be EUI64 for Firewire.
1287 We assume that if the first byte of the client-id equals the htype byte
1288 then the client-id is using the usual encoding and use the rest of the
1289 client-id: if not we can use the whole client-id. This should give
1290 sane MAC address logs. */
1291 unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
1292 int clid_len, unsigned char *clid, int *len_out)
1294 if (hwlen == 0 && clid && clid_len > 3)
1296 if (clid[0] == hwtype)
1298 *len_out = clid_len - 1 ;
1299 return clid + 1;
1302 #if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1303 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1305 *len_out = clid_len - 1 ;
1306 return clid + 1;
1308 #endif
1310 *len_out = clid_len;
1311 return clid;
1314 *len_out = hwlen;
1315 return hwaddr;
1318 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
1320 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1322 if (opt)
1324 unsigned int req_time = option_uint(opt, 0, 4);
1325 if (req_time < 120 )
1326 req_time = 120; /* sanity */
1327 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1328 time = req_time;
1331 return time;
1334 static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1336 if (override.s_addr != 0)
1337 return override;
1338 else if (context)
1339 return context->local;
1340 else
1341 return fallback;
1344 static int sanitise(unsigned char *opt, char *buf)
1346 char *p;
1347 int i;
1349 *buf = 0;
1351 if (!opt)
1352 return 0;
1354 p = option_ptr(opt, 0);
1356 for (i = option_len(opt); i > 0; i--)
1358 char c = *p++;
1359 if (isprint((int)c))
1360 *buf++ = c;
1362 *buf = 0; /* add terminator */
1364 return 1;
1367 static void log_packet(char *type, void *addr, unsigned char *ext_mac,
1368 int mac_len, char *interface, char *string, u32 xid)
1370 /* !!TB - reduce excessive logging for DHCP packets */
1371 if ((type) && !(daemon->options & OPT_LOG_OPTS))
1372 return;
1374 struct in_addr a;
1376 /* addr may be misaligned */
1377 if (addr)
1378 memcpy(&a, addr, sizeof(a));
1380 print_mac(daemon->namebuff, ext_mac, mac_len);
1382 if(daemon->options & OPT_LOG_OPTS)
1383 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
1384 ntohl(xid),
1385 type,
1386 interface,
1387 addr ? inet_ntoa(a) : "",
1388 addr ? " " : "",
1389 daemon->namebuff,
1390 string ? string : "");
1391 else
1392 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s",
1393 type,
1394 interface,
1395 addr ? inet_ntoa(a) : "",
1396 addr ? " " : "",
1397 daemon->namebuff,
1398 string ? string : "");
1401 static void log_options(unsigned char *start, u32 xid)
1403 while (*start != OPTION_END)
1405 int is_ip, is_name, i;
1406 char *text = option_string(start[0], &is_ip, &is_name);
1407 unsigned char trunc = option_len(start);
1409 if (is_ip)
1410 for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
1412 if (i != 0)
1413 strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
1414 strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
1416 else if (!is_name || !sanitise(start, daemon->namebuff))
1418 if (trunc > 13)
1419 trunc = 13;
1420 print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
1423 my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
1424 ntohl(xid), option_len(start), start[0],
1425 text ? ":" : "", text ? text : "",
1426 trunc == 0 ? "" : " ",
1427 trunc == 0 ? "" : daemon->namebuff,
1428 trunc == option_len(start) ? "" : "...");
1429 start += start[1] + 2;
1433 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1435 while (1)
1437 if (p > end)
1438 return NULL;
1439 else if (*p == OPTION_END)
1440 return opt == OPTION_END ? p : NULL;
1441 else if (*p == OPTION_PAD)
1442 p++;
1443 else
1445 int opt_len;
1446 if (p > end - 2)
1447 return NULL; /* malformed packet */
1448 opt_len = option_len(p);
1449 if (p > end - (2 + opt_len))
1450 return NULL; /* malformed packet */
1451 if (*p == opt && opt_len >= minsize)
1452 return p;
1453 p += opt_len + 2;
1458 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1460 unsigned char *ret, *overload;
1462 /* skip over DHCP cookie; */
1463 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
1464 return ret;
1466 /* look for overload option. */
1467 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
1468 return NULL;
1470 /* Can we look in filename area ? */
1471 if ((overload[2] & 1) &&
1472 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
1473 return ret;
1475 /* finally try sname area */
1476 if ((overload[2] & 2) &&
1477 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
1478 return ret;
1480 return NULL;
1483 static struct in_addr option_addr_arr(unsigned char *opt, int offset)
1485 /* this worries about unaligned data in the option. */
1486 /* struct in_addr is network byte order */
1487 struct in_addr ret;
1489 memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
1491 return ret;
1494 static struct in_addr option_addr(unsigned char *opt)
1496 return option_addr_arr(opt, 0);
1499 static unsigned int option_uint(unsigned char *opt, int offset, int size)
1501 /* this worries about unaligned data and byte order */
1502 unsigned int ret = 0;
1503 int i;
1504 unsigned char *p = option_ptr(opt, offset);
1506 for (i = 0; i < size; i++)
1507 ret = (ret << 8) | *p++;
1509 return ret;
1512 static unsigned char *dhcp_skip_opts(unsigned char *start)
1514 while (*start != 0)
1515 start += start[1] + 2;
1516 return start;
1519 /* only for use when building packet: doesn't check for bad data. */
1520 static unsigned char *find_overload(struct dhcp_packet *mess)
1522 unsigned char *p = &mess->options[0] + sizeof(u32);
1524 while (*p != 0)
1526 if (*p == OPTION_OVERLOAD)
1527 return p;
1528 p += p[1] + 2;
1530 return NULL;
1533 static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
1534 unsigned char *agent_id, unsigned char *real_end)
1536 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1537 unsigned char *overload;
1538 size_t ret;
1539 struct dhcp_netid_list *id_list;
1540 struct dhcp_netid *n;
1542 /* move agent_id back down to the end of the packet */
1543 if (agent_id)
1545 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1546 memmove(p, agent_id, real_end - agent_id);
1547 p += real_end - agent_id;
1548 memset(p, 0, real_end - p); /* in case of overlap */
1551 /* We do logging too */
1552 if (netid && (daemon->options & OPT_LOG_OPTS))
1554 char *p = daemon->namebuff;
1555 *p = 0;
1556 for (; netid; netid = netid->next)
1558 /* kill dupes. */
1559 for (n = netid->next; n; n = n->next)
1560 if (strcmp(netid->net, n->net) == 0)
1561 break;
1563 if (!n)
1565 strncat (p, netid->net, MAXDNAME);
1566 if (netid->next)
1567 strncat (p, ", ", MAXDNAME);
1570 p[MAXDNAME - 1] = 0;
1571 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), p);
1574 /* add END options to the regions. */
1575 overload = find_overload(mess);
1577 if (overload && (option_uint(overload, 0, 1) & 1))
1579 *dhcp_skip_opts(mess->file) = OPTION_END;
1580 if (daemon->options & OPT_LOG_OPTS)
1581 log_options(mess->file, mess->xid);
1583 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
1584 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
1586 if (overload && (option_uint(overload, 0, 1) & 2))
1588 *dhcp_skip_opts(mess->sname) = OPTION_END;
1589 if (daemon->options & OPT_LOG_OPTS)
1590 log_options(mess->sname, mess->xid);
1592 else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
1593 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
1596 *p++ = OPTION_END;
1598 if (daemon->options & OPT_LOG_OPTS)
1600 if (mess->siaddr.s_addr != 0)
1601 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
1603 log_options(&mess->options[0] + sizeof(u32), mess->xid);
1606 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
1607 if (match_netid(id_list->list, netid, 0))
1608 mess->flags |= htons(0x8000); /* force broadcast */
1610 ret = (size_t)(p - (unsigned char *)mess);
1612 if (ret < MIN_PACKETSZ)
1613 ret = MIN_PACKETSZ;
1615 return ret;
1618 static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
1620 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1622 if (p + len + 3 >= end)
1623 /* not enough space in options area, try and use overload, if poss */
1625 unsigned char *overload;
1627 if (!(overload = find_overload(mess)) &&
1628 (mess->file[0] == 0 || mess->sname[0] == 0))
1630 /* attempt to overload fname and sname areas, we've reserved space for the
1631 overflow option previuously. */
1632 overload = p;
1633 *(p++) = OPTION_OVERLOAD;
1634 *(p++) = 1;
1637 p = NULL;
1639 /* using filename field ? */
1640 if (overload)
1642 if (mess->file[0] == 0)
1643 overload[2] |= 1;
1645 if (overload[2] & 1)
1647 p = dhcp_skip_opts(mess->file);
1648 if (p + len + 3 >= mess->file + sizeof(mess->file))
1649 p = NULL;
1652 if (!p)
1654 /* try to bring sname into play (it may be already) */
1655 if (mess->sname[0] == 0)
1656 overload[2] |= 2;
1658 if (overload[2] & 2)
1660 p = dhcp_skip_opts(mess->sname);
1661 if (p + len + 3 >= mess->sname + sizeof(mess->file))
1662 p = NULL;
1667 if (!p)
1668 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1671 if (p)
1673 *(p++) = opt;
1674 *(p++) = len;
1677 return p;
1680 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
1682 int i;
1683 unsigned char *p = free_space(mess, end, opt, len);
1685 if (p)
1686 for (i = 0; i < len; i++)
1687 *(p++) = val >> (8 * (len - (i + 1)));
1690 static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1691 char *string, int null_term)
1693 unsigned char *p;
1694 size_t len = strlen(string);
1696 if (null_term && len != 255)
1697 len++;
1699 if ((p = free_space(mess, end, opt, len)))
1700 memcpy(p, string, len);
1703 /* return length, note this only does the data part */
1704 static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
1706 int len = opt->len;
1708 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1709 len++;
1711 if (p && len != 0)
1713 if (context && (opt->flags & DHOPT_ADDR))
1715 int j;
1716 struct in_addr *a = (struct in_addr *)opt->val;
1717 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
1719 /* zero means "self" (but not in vendorclass options.) */
1720 if (a->s_addr == 0)
1721 memcpy(p, &context->local, INADDRSZ);
1722 else
1723 memcpy(p, a, INADDRSZ);
1724 p += INADDRSZ;
1727 else
1728 memcpy(p, opt->val, len);
1730 return len;
1733 static int in_list(unsigned char *list, int opt)
1735 int i;
1737 /* If no requested options, send everything, not nothing. */
1738 if (!list)
1739 return 1;
1741 for (i = 0; list[i] != OPTION_END; i++)
1742 if (opt == list[i])
1743 return 1;
1745 return 0;
1748 static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
1750 struct dhcp_opt *tmp;
1751 for (tmp = opts; tmp; tmp = tmp->next)
1752 if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)))
1753 if (match_netid(tmp->netid, netid, netid ? 0 : 1))
1754 return tmp;
1756 return netid ? option_find2(NULL, opts, opt) : NULL;
1759 /* mark vendor-encapsulated options which match the client-supplied or
1760 config-supplied vendor class */
1761 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1763 for (; dopt; dopt = dopt->next)
1765 dopt->flags &= ~DHOPT_VENDOR_MATCH;
1766 if (opt && (dopt->flags & DHOPT_VENDOR))
1768 int i, len = 0;
1769 if (dopt->u.vendor_class)
1770 len = strlen((char *)dopt->u.vendor_class);
1771 for (i = 0; i <= (option_len(opt) - len); i++)
1772 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
1774 dopt->flags |= DHOPT_VENDOR_MATCH;
1775 break;
1781 static void do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1782 struct dhcp_packet *mess, unsigned char *end, int null_term)
1784 int len, enc_len;
1785 struct dhcp_opt *start;
1786 unsigned char *p;
1788 /* find size in advance */
1789 for (enc_len = 0, start = opt; opt; opt = opt->next)
1790 if (opt->flags & flag)
1792 int new = do_opt(opt, NULL, NULL, null_term) + 2;
1793 if (enc_len + new <= 255)
1794 enc_len += new;
1795 else
1797 p = free_space(mess, end, encap, enc_len);
1798 for (; start && start != opt; start = start->next)
1799 if (p && (start->flags & flag))
1801 len = do_opt(start, p + 2, NULL, null_term);
1802 *(p++) = start->opt;
1803 *(p++) = len;
1804 p += len;
1806 enc_len = new;
1807 start = opt;
1811 if (enc_len != 0 &&
1812 (p = free_space(mess, end, encap, enc_len + 1)))
1814 for (; start; start = start->next)
1815 if (start->flags & flag)
1817 len = do_opt(start, p + 2, NULL, null_term);
1818 *(p++) = start->opt;
1819 *(p++) = len;
1820 p += len;
1822 *p = OPTION_END;
1826 static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
1828 unsigned char *p;
1830 option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
1831 if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
1832 memcpy(p, uuid, 17);
1835 static int prune_vendor_opts(struct dhcp_netid *netid)
1837 int force = 0;
1838 struct dhcp_opt *opt;
1840 /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
1841 for (opt = daemon->dhcp_opts; opt; opt = opt->next)
1842 if (opt->flags & DHOPT_VENDOR_MATCH)
1844 if (!match_netid(opt->netid, netid, 1))
1845 opt->flags &= ~DHOPT_VENDOR_MATCH;
1846 else if (opt->flags & DHOPT_FORCE)
1847 force = 1;
1849 return force;
1852 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
1854 #define NUM_OPTS 4
1856 unsigned char *p, *q;
1857 struct pxe_service *service;
1858 static struct dhcp_opt *o, *ret;
1859 int i, j = NUM_OPTS - 1;
1861 /* We pass back references to these, hence they are declared static */
1862 static unsigned char discovery_control;
1863 static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
1864 static struct dhcp_opt *fake_opts = NULL;
1866 /* We are found by broadcast, so disable multicast. It gets switched on again
1867 if we point to other servers and don't give a unicast address. Note that
1868 we don't provide our own address for services we are the boot server for because unicast
1869 discovery is to port 4011 and we don't listen there. If you are using proxy DHCP
1870 and DHCP relays, the relay will need to forward to the proxy too. */
1871 discovery_control = 2;
1873 ret = daemon->dhcp_opts;
1875 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
1876 return ret;
1878 for (i = 0; i < NUM_OPTS; i++)
1880 fake_opts[i].flags = DHOPT_VENDOR_MATCH;
1881 fake_opts[i].netid = NULL;
1882 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
1885 /* create the data for the PXE_MENU and PXE_SERVERS options. */
1886 p = (unsigned char *)daemon->dhcp_buff;
1887 q = (unsigned char *)daemon->dhcp_buff2;
1889 for (i = 0, service = daemon->pxe_services; service; service = service->next)
1890 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
1892 size_t len = strlen(service->menu);
1893 /* opt 43 max size is 255. encapsulated option has type and length
1894 bytes, so its max size is 253. */
1895 if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
1897 *(p++) = service->type >> 8;
1898 *(p++) = service->type;
1899 *(p++) = len;
1900 memcpy(p, service->menu, len);
1901 p += len;
1902 i++;
1904 else
1906 toobig:
1907 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
1908 return daemon->dhcp_opts;
1911 if (!service->basename)
1913 if (service->server.s_addr != 0)
1915 if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
1916 goto toobig;
1918 /* Boot service with known address - give it */
1919 *(q++) = service->type >> 8;
1920 *(q++) = service->type;
1921 *(q++) = 1;
1922 /* dest misaligned */
1923 memcpy(q, &service->server.s_addr, INADDRSZ);
1924 q += INADDRSZ;
1926 else if (service->type != 0)
1927 /* We're not supplying a server, so let the client multicast.
1928 type zero is "local boot" so no need for M/C on that. */
1929 discovery_control = 0;
1933 /* if no prompt, wait forever if there's a choice */
1934 fake_prompt[0] = (i > 1) ? 255 : 0;
1936 if (i == 0)
1937 discovery_control = 8; /* no menu - just use use mess->filename */
1938 else
1940 ret = &fake_opts[j--];
1941 ret->len = p - (unsigned char *)daemon->dhcp_buff;
1942 ret->val = (unsigned char *)daemon->dhcp_buff;
1943 ret->opt = SUBOPT_PXE_MENU;
1945 if (q - (unsigned char *)daemon->dhcp_buff2 != 0)
1947 ret = &fake_opts[j--];
1948 ret->len = q - (unsigned char *)daemon->dhcp_buff2;
1949 ret->val = (unsigned char *)daemon->dhcp_buff2;
1950 ret->opt = SUBOPT_PXE_SERVERS;
1954 for (o = daemon->dhcp_opts; o; o = o->next)
1955 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
1956 break;
1958 if (!o)
1960 ret = &fake_opts[j--];
1961 ret->len = sizeof(fake_prompt);
1962 ret->val = fake_prompt;
1963 ret->opt = SUBOPT_PXE_MENU_PROMPT;
1966 if (discovery_control != 0)
1968 ret = &fake_opts[j--];
1969 ret->len = 1;
1970 ret->opt = SUBOPT_PXE_DISCOVERY;
1971 ret->val= &discovery_control;
1974 return ret;
1977 static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
1979 memset(mess->sname, 0, sizeof(mess->sname));
1980 memset(mess->file, 0, sizeof(mess->file));
1981 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
1982 mess->siaddr.s_addr = 0;
1985 struct dhcp_boot *find_boot(struct dhcp_netid *netid)
1987 struct dhcp_boot *boot;
1989 /* decide which dhcp-boot option we're using */
1990 for (boot = daemon->boot_config; boot; boot = boot->next)
1991 if (match_netid(boot->netid, netid, 0))
1992 break;
1993 if (!boot)
1994 /* No match, look for one without a netid */
1995 for (boot = daemon->boot_config; boot; boot = boot->next)
1996 if (match_netid(boot->netid, netid, 1))
1997 break;
1999 return boot;
2002 static void do_options(struct dhcp_context *context,
2003 struct dhcp_packet *mess,
2004 unsigned char *end,
2005 unsigned char *req_options,
2006 char *hostname,
2007 char *domain, char *config_domain,
2008 struct dhcp_netid *netid,
2009 struct in_addr subnet_addr,
2010 unsigned char fqdn_flags,
2011 int null_term, int pxe_arch,
2012 unsigned char *uuid)
2014 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2015 struct dhcp_boot *boot;
2016 unsigned char *p;
2017 int i, len, force_encap = 0;
2018 unsigned char f0 = 0, s0 = 0;
2019 int done_file = 0, done_server = 0;
2021 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
2022 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
2024 /* logging */
2025 if ((daemon->options & OPT_LOG_OPTS) && req_options)
2027 char *q = daemon->namebuff;
2028 for (i = 0; req_options[i] != OPTION_END; i++)
2030 char *s = option_string(req_options[i], NULL, NULL);
2031 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
2032 "%d%s%s%s",
2033 req_options[i],
2034 s ? ":" : "",
2035 s ? s : "",
2036 req_options[i+1] == OPTION_END ? "" : ", ");
2037 if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2039 q = daemon->namebuff;
2040 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
2045 if (context)
2046 mess->siaddr = context->local;
2048 /* See if we can send the boot stuff as options.
2049 To do this we need a requested option list, BOOTP
2050 and very old DHCP clients won't have this, we also
2051 provide an manual option to disable it.
2052 Some PXE ROMs have bugs (surprise!) and need zero-terminated
2053 names, so we always send those. */
2054 if ((boot = find_boot(netid)))
2056 if (boot->sname)
2058 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2059 req_options &&
2060 in_list(req_options, OPTION_SNAME))
2061 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
2062 else
2063 strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
2066 if (boot->file)
2068 if (!(daemon->options & OPT_NO_OVERRIDE) &&
2069 req_options &&
2070 in_list(req_options, OPTION_FILENAME))
2071 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2072 else
2073 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
2076 if (boot->next_server.s_addr)
2077 mess->siaddr = boot->next_server;
2079 else
2080 /* Use the values of the relevant options if no dhcp-boot given and
2081 they're not explicitly asked for as options. */
2083 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && mess->file[0] == 0 &&
2084 (opt = option_find2(netid, config_opts, OPTION_FILENAME)))
2086 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2087 done_file = 1;
2090 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
2091 (opt = option_find2(netid, config_opts, OPTION_SNAME)))
2093 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2094 done_server = 1;
2098 /* We don't want to do option-overload for BOOTP, so make the file and sname
2099 fields look like they are in use, even when they aren't. This gets restored
2100 at the end of this function. */
2102 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2104 f0 = mess->file[0];
2105 mess->file[0] = 1;
2106 s0 = mess->sname[0];
2107 mess->sname[0] = 1;
2110 /* At this point, if mess->sname or mess->file are zeroed, they are available
2111 for option overload, reserve space for the overload option. */
2112 if (mess->file[0] == 0 || mess->sname[0] == 0)
2113 end -= 3;
2115 /* rfc3011 says this doesn't need to be in the requested options list. */
2116 if (subnet_addr.s_addr)
2117 option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
2119 /* replies to DHCPINFORM may not have a valid context */
2120 if (context)
2122 if (!option_find2(netid, config_opts, OPTION_NETMASK))
2123 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
2125 /* May not have a "guessed" broadcast address if we got no packets via a relay
2126 from this net yet (ie just unicast renewals after a restart */
2127 if (context->broadcast.s_addr &&
2128 !option_find2(netid, config_opts, OPTION_BROADCAST))
2129 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2131 /* Same comments as broadcast apply, and also may not be able to get a sensible
2132 default when using subnet select. User must configure by steam in that case. */
2133 if (context->router.s_addr &&
2134 in_list(req_options, OPTION_ROUTER) &&
2135 !option_find2(netid, config_opts, OPTION_ROUTER))
2136 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2138 if (in_list(req_options, OPTION_DNSSERVER) &&
2139 !option_find2(netid, config_opts, OPTION_DNSSERVER))
2140 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2143 if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
2144 !option_find2(netid, config_opts, OPTION_DOMAINNAME))
2145 option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
2147 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
2148 if (hostname)
2150 if (in_list(req_options, OPTION_HOSTNAME) &&
2151 !option_find2(netid, config_opts, OPTION_HOSTNAME))
2152 option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
2154 if (fqdn_flags != 0)
2156 len = strlen(hostname) + 3;
2158 if (fqdn_flags & 0x04)
2159 len += 2;
2160 else if (null_term)
2161 len++;
2163 if (domain)
2164 len += strlen(domain) + 1;
2166 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
2168 *(p++) = fqdn_flags;
2169 *(p++) = 255;
2170 *(p++) = 255;
2172 if (fqdn_flags & 0x04)
2174 p = do_rfc1035_name(p, hostname);
2175 if (domain)
2176 p = do_rfc1035_name(p, domain);
2177 *p++ = 0;
2179 else
2181 memcpy(p, hostname, strlen(hostname));
2182 p += strlen(hostname);
2183 if (domain)
2185 *(p++) = '.';
2186 memcpy(p, domain, strlen(domain));
2187 p += strlen(domain);
2189 if (null_term)
2190 *(p++) = 0;
2196 for (opt = config_opts; opt; opt = opt->next)
2198 int optno = opt->opt;
2200 /* was it asked for, or are we sending it anyway? */
2201 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
2202 continue;
2204 /* prohibit some used-internally options */
2205 if (optno == OPTION_CLIENT_FQDN ||
2206 optno == OPTION_MAXMESSAGE ||
2207 optno == OPTION_OVERLOAD ||
2208 optno == OPTION_PAD ||
2209 optno == OPTION_END)
2210 continue;
2212 if (optno == OPTION_SNAME && done_server)
2213 continue;
2215 if (optno == OPTION_FILENAME && done_file)
2216 continue;
2218 /* netids match and not encapsulated? */
2219 if (opt != option_find2(netid, config_opts, optno))
2220 continue;
2222 /* For the options we have default values on
2223 dhc-option=<optionno> means "don't include this option"
2224 not "include a zero-length option" */
2225 if (opt->len == 0 &&
2226 (optno == OPTION_NETMASK ||
2227 optno == OPTION_BROADCAST ||
2228 optno == OPTION_ROUTER ||
2229 optno == OPTION_DNSSERVER ||
2230 optno == OPTION_DOMAINNAME ||
2231 optno == OPTION_HOSTNAME))
2232 continue;
2234 /* vendor-class comes from elsewhere for PXE */
2235 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2236 continue;
2238 /* always force null-term for filename and servername - buggy PXE again. */
2239 len = do_opt(opt, NULL, context,
2240 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2242 if ((p = free_space(mess, end, optno, len)))
2244 do_opt(opt, p, context,
2245 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2247 /* If we send a vendor-id, revisit which vendor-ops we consider
2248 it appropriate to send. */
2249 if (optno == OPTION_VENDOR_ID)
2250 match_vendor_opts(p - 2, config_opts);
2254 /* Now send options to be encapsulated in arbitrary options,
2255 eg dhcp-option=encap:172,17,.......
2256 The may be more that one "outer" to do, so group
2257 all the options which match each outer in turn. */
2258 for (opt = config_opts; opt; opt = opt->next)
2259 opt->flags &= ~DHOPT_ENCAP_DONE;
2261 for (opt = config_opts; opt; opt = opt->next)
2262 if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE)
2264 struct dhcp_opt *o;
2265 int found = 0;
2267 for (o = config_opts; o; o = o->next)
2269 o->flags &= ~DHOPT_ENCAP_MATCH;
2270 if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
2272 o->flags |= DHOPT_ENCAP_DONE;
2273 if (match_netid(o->netid, netid, 1) &&
2274 (o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap)))
2276 o->flags |= DHOPT_ENCAP_MATCH;
2277 found = 1;
2282 if (found)
2283 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
2286 /* Must precede pxe_opts, since it overwrites req_options */
2287 force_encap = prune_vendor_opts(netid);
2288 if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
2289 force_encap = 1;
2291 if (pxe_arch != -1)
2293 pxe_misc(mess, end, uuid);
2294 config_opts = pxe_opts(pxe_arch, netid);
2297 if (force_encap)
2298 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term);
2300 /* restore BOOTP anti-overload hack */
2301 if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
2303 mess->file[0] = f0;
2304 mess->sname[0] = s0;
2308 #endif