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