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