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