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, NULL);
1893 if (domain) p = do_rfc1035_name(p, domain, NULL);
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