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