]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/rfc2131.c
Use correct DHCP context for PXE-proxy server-id.
[people/ms/dnsmasq.git] / src / rfc2131.c
CommitLineData
aff33962 1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
9e4abcb5
SK
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
824af85b
SK
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
9e4abcb5
SK
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.
824af85b 12
73a08a24
SK
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/>.
9e4abcb5
SK
15*/
16
9e4abcb5
SK
17#include "dnsmasq.h"
18
7622fc06
SK
19#ifdef HAVE_DHCP
20
5e9e0efb 21#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
1a6bca81 22#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
0a852541 23
316e2730 24#ifdef HAVE_SCRIPT
316e2730
SK
25static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
26#endif
572b41eb 27
f2621c7f 28static int sanitise(unsigned char *opt, char *buf);
73a08a24 29static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
824af85b 30static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
1b7ecd11
SK
31static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
32static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
33 int opt, char *string, int null_term);
9e4abcb5 34static struct in_addr option_addr(unsigned char *opt);
7622fc06
SK
35static unsigned int option_uint(unsigned char *opt, int i, int size);
36static void log_packet(char *type, void *addr, unsigned char *ext_mac,
8c0b73d3 37 int mac_len, char *interface, char *string, char *err, u32 xid);
cdeda28f 38static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
5e9e0efb 39static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
7de060b0 40static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
7622fc06 41static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
aa63a21c 42static int in_list(unsigned char *list, int opt);
1b7ecd11
SK
43static void do_options(struct dhcp_context *context,
44 struct dhcp_packet *mess,
45 unsigned char *real_end,
46 unsigned char *req_options,
9009d746 47 char *hostname,
70c5e3e0 48 char *config_domain,
1b7ecd11 49 struct dhcp_netid *netid,
7de060b0 50 struct in_addr subnet_addr,
1b7ecd11 51 unsigned char fqdn_flags,
7622fc06 52 int null_term, int pxearch,
8ef5ada2 53 unsigned char *uuid,
7de060b0 54 int vendor_class_len,
ca85a282
SK
55 time_t now,
56 unsigned int lease_time,
57 unsigned short fuzz);
7622fc06 58
9009d746 59
6b01084f 60static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
8ef5ada2 61static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
7622fc06
SK
62static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
63static int prune_vendor_opts(struct dhcp_netid *netid);
751d6f4a 64static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
7622fc06
SK
65struct dhcp_boot *find_boot(struct dhcp_netid *netid);
66
67
824af85b 68size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
7de060b0 69 size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
9e4abcb5 70{
26128d27 71 unsigned char *opt, *clid = NULL;
0a852541 72 struct dhcp_lease *ltmp, *lease = NULL;
a222641c 73 struct dhcp_vendor *vendor;
cdeda28f 74 struct dhcp_mac *mac;
26128d27 75 struct dhcp_netid_list *id_list;
7622fc06 76 int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
824af85b 77 struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
1b7ecd11 78 unsigned char *end = (unsigned char *)(mess + 1);
7622fc06 79 unsigned char *real_end = (unsigned char *)(mess + 1);
9009d746 80 char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
cdeda28f 81 int hostname_auth = 0, borken_opt = 0;
3d8df260 82 unsigned char *req_options = NULL;
44a2a316 83 char *message = NULL;
59353a6b 84 unsigned int time;
9e4abcb5 85 struct dhcp_config *config;
8ef5ada2 86 struct dhcp_netid *netid, *tagif_netid;
7de060b0 87 struct in_addr subnet_addr, override;
a84fa1d0 88 unsigned short fuzz = 0;
3be34541 89 unsigned int mess_type = 0;
3d8df260 90 unsigned char fqdn_flags = 0;
7622fc06 91 unsigned char *agent_id = NULL, *uuid = NULL;
1b7ecd11 92 unsigned char *emac = NULL;
8ef5ada2 93 int vendor_class_len = 0, emac_len = 0;
316e2730 94 struct dhcp_netid known_id, iface_id, cpewan_id;
73a08a24 95 struct dhcp_opt *o;
7622fc06 96 unsigned char pxe_uuid[17];
99e8891f
VG
97 unsigned char *oui = NULL, *serial = NULL;
98#ifdef HAVE_SCRIPT
99 unsigned char *class = NULL;
100#endif
3be34541 101
1a6bca81 102 subnet_addr.s_addr = override.s_addr = 0;
9009d746
SK
103
104 /* set tag with name == interface */
105 iface_id.net = iface_name;
106 iface_id.next = NULL;
107 netid = &iface_id;
849a8357 108
5e9e0efb 109 if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
33820b7e 110 return 0;
cdeda28f 111
5e9e0efb 112 if (mess->htype == 0 && mess->hlen != 0)
cdeda28f 113 return 0;
5e9e0efb 114
3be34541 115 /* check for DHCP rather than BOOTP */
bb01cb96 116 if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
3be34541 117 {
8ef5ada2
SK
118 u32 cookie = htonl(DHCP_COOKIE);
119
3be34541 120 /* only insist on a cookie for DHCP. */
8ef5ada2 121 if (memcmp(mess->options, &cookie, sizeof(u32)) != 0)
3be34541 122 return 0;
8ef5ada2
SK
123
124 mess_type = option_uint(opt, 0, 1);
125
5e9e0efb
SK
126 /* two things to note here: expand_buf may move the packet,
127 so reassign mess from daemon->packet. Also, the size
128 sent includes the IP and UDP headers, hence the magic "-28" */
129 if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
130 {
7622fc06 131 size_t size = (size_t)option_uint(opt, 0, 2) - 28;
5e9e0efb
SK
132
133 if (size > DHCP_PACKET_MAX)
134 size = DHCP_PACKET_MAX;
135 else if (size < sizeof(struct dhcp_packet))
136 size = sizeof(struct dhcp_packet);
137
138 if (expand_buf(&daemon->dhcp_packet, size))
139 {
824af85b 140 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
7622fc06 141 real_end = end = ((unsigned char *)mess) + size;
5e9e0efb
SK
142 }
143 }
144
3be34541
SK
145 /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
146 it can affect the context-determination code. */
bb01cb96 147 if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
3be34541 148 mess->ciaddr.s_addr = 0;
44a2a316 149
316e2730
SK
150 /* search for device identity from CPEWAN devices, we pass this through to the script */
151 if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
152 {
153 unsigned int elen, offset, len = option_len(opt);
154
155 for (offset = 0; offset < (len - 5); offset += elen + 5)
156 {
157 elen = option_uint(opt, offset + 4 , 1);
158 if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
159 {
160 unsigned char *x = option_ptr(opt, offset + 5);
161 unsigned char *y = option_ptr(opt, offset + elen + 5);
162 oui = option_find1(x, y, 1, 1);
163 serial = option_find1(x, y, 2, 1);
99e8891f
VG
164#ifdef HAVE_SCRIPT
165 class = option_find1(x, y, 3, 1);
166#endif
316e2730
SK
167 /* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
168 the gateway id back. Note that the device class is optional */
169 if (oui && serial)
170 {
171 cpewan_id.net = "cpewan-id";
172 cpewan_id.next = netid;
173 netid = &cpewan_id;
174 }
175 break;
176 }
177 }
178 }
179
5e9e0efb
SK
180 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
181 {
182 /* Any agent-id needs to be copied back out, verbatim, as the last option
183 in the packet. Here, we shift it to the very end of the buffer, if it doesn't
184 get overwritten, then it will be shuffled back at the end of processing.
185 Note that the incoming options must not be overwritten here, so there has to
186 be enough free space at the end of the packet to copy the option. */
f2621c7f 187 unsigned char *sopt;
5e9e0efb
SK
188 unsigned int total = option_len(opt) + 2;
189 unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
190 if (last_opt && last_opt < end - total)
191 {
7622fc06
SK
192 end -= total;
193 agent_id = end;
5e9e0efb
SK
194 memcpy(agent_id, opt, total);
195 }
196
197 /* look for RFC3527 Link selection sub-option */
1a6bca81 198 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
f2621c7f 199 subnet_addr = option_addr(sopt);
1a6bca81
SK
200
201 /* look for RFC5107 server-identifier-override */
202 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
203 override = option_addr(sopt);
f2621c7f
SK
204
205 /* if a circuit-id or remote-is option is provided, exact-match to options. */
206 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
207 {
208 int search;
209
210 if (vendor->match_type == MATCH_CIRCUIT)
211 search = SUBOPT_CIRCUIT_ID;
212 else if (vendor->match_type == MATCH_REMOTE)
213 search = SUBOPT_REMOTE_ID;
214 else if (vendor->match_type == MATCH_SUBSCRIBER)
215 search = SUBOPT_SUBSCR_ID;
216 else
217 continue;
218
1a6bca81 219 if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
f2621c7f 220 vendor->len == option_len(sopt) &&
1a6bca81 221 memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
f2621c7f
SK
222 {
223 vendor->netid.next = netid;
224 netid = &vendor->netid;
f2621c7f
SK
225 }
226 }
5e9e0efb 227 }
f2621c7f 228
5e9e0efb
SK
229 /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
230 if (subnet_addr.s_addr == 0 && (opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
3be34541 231 subnet_addr = option_addr(opt);
26128d27
SK
232
233 /* If there is no client identifier option, use the hardware address */
bb01cb96 234 if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
26128d27 235 {
26128d27 236 clid_len = option_len(opt);
1a6bca81 237 clid = option_ptr(opt, 0);
26128d27 238 }
1b7ecd11 239
0a852541 240 /* do we have a lease in store? */
5e9e0efb 241 lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
0a852541
SK
242
243 /* If this request is missing a clid, but we've seen one before,
244 use it again for option matching etc. */
245 if (lease && !clid && lease->clid)
246 {
247 clid_len = lease->clid_len;
248 clid = lease->clid;
249 }
1b7ecd11
SK
250
251 /* find mac to use for logging and hashing */
252 emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
44a2a316 253 }
3be34541 254
cdeda28f
SK
255 for (mac = daemon->dhcp_macs; mac; mac = mac->next)
256 if (mac->hwaddr_len == mess->hlen &&
5e9e0efb
SK
257 (mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
258 memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
cdeda28f 259 {
5e9e0efb
SK
260 mac->netid.next = netid;
261 netid = &mac->netid;
cdeda28f 262 }
3d8df260 263
0a852541
SK
264 /* Determine network for this packet. Our caller will have already linked all the
265 contexts which match the addresses of the receiving interface but if the
266 machine has an address already, or came via a relay, or we have a subnet selector,
267 we search again. If we don't have have a giaddr or explicit subnet selector,
268 use the ciaddr. This is necessary because a machine which got a lease via a
3d8df260
SK
269 relay won't use the relay to renew. If matching a ciaddr fails but we have a context
270 from the physical network, continue using that to allow correct DHCPNAK generation later. */
0a852541
SK
271 if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
272 {
3d8df260 273 struct dhcp_context *context_tmp, *context_new = NULL;
1697269c 274 struct in_addr addr;
3d8df260
SK
275 int force = 0;
276
277 if (subnet_addr.s_addr)
278 {
279 addr = subnet_addr;
280 force = 1;
281 }
282 else if (mess->giaddr.s_addr)
283 {
284 addr = mess->giaddr;
285 force = 1;
286 }
1697269c
SK
287 else
288 {
289 /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
290 addr = mess->ciaddr;
291 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
292 if (context_tmp->netmask.s_addr &&
293 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
294 is_same_net(addr, context_tmp->end, context_tmp->netmask))
295 {
296 context_new = context;
297 break;
298 }
299 }
300
301 if (!context_new)
302 for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
7de060b0
SK
303 {
304 struct in_addr netmask = context_tmp->netmask;
305
306 /* guess the netmask for relayed networks */
307 if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
308 {
309 if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
310 netmask.s_addr = htonl(0xff000000);
311 else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
312 netmask.s_addr = htonl(0xffff0000);
313 else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
314 netmask.s_addr = htonl(0xffffff00);
315 }
316
317 /* This section fills in context mainly when a client which is on a remote (relayed)
318 network renews a lease without using the relay, after dnsmasq has restarted. */
319 if (netmask.s_addr != 0 &&
320 is_same_net(addr, context_tmp->start, netmask) &&
321 is_same_net(addr, context_tmp->end, netmask))
322 {
323 context_tmp->netmask = netmask;
324 if (context_tmp->local.s_addr == 0)
325 context_tmp->local = fallback;
326 if (context_tmp->router.s_addr == 0)
327 context_tmp->router = mess->giaddr;
328
329 /* fill in missing broadcast addresses for relayed ranges */
330 if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
331 context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
332
333 context_tmp->current = context_new;
334 context_new = context_tmp;
335 }
336 }
0a852541 337
3d8df260 338 if (context_new || force)
7de060b0 339 context = context_new;
0a852541 340 }
3be34541
SK
341
342 if (!context)
343 {
7622fc06 344 my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
f2621c7f
SK
345 subnet_addr.s_addr ? _("with subnet selector") : _("via"),
346 subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
3be34541
SK
347 return 0;
348 }
f2621c7f 349
28866e95 350 if (option_bool(OPT_LOG_OPTS))
f2621c7f
SK
351 {
352 struct dhcp_context *context_tmp;
f2621c7f
SK
353 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
354 {
355 strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
7622fc06 356 if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
8ef5ada2 357 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
7622fc06 358 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
f2621c7f 359 else
8ef5ada2 360 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
7622fc06 361 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
f2621c7f
SK
362 }
363 }
86e92f99
SK
364
365 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
366 Otherwise assume the option is an array, and look for a matching element.
367 If no data given, existance of the option is enough. This code handles
368 rfc3925 V-I classes too. */
369 for (o = daemon->dhcp_match; o; o = o->next)
370 {
371 unsigned int len, elen, match = 0;
372 size_t offset, o2;
373
374 if (o->flags & DHOPT_RFC3925)
375 {
376 if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
377 continue;
378
379 for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
380 {
381 len = option_uint(opt, offset + 4 , 1);
382 /* Need to take care that bad data can't run us off the end of the packet */
383 if ((offset + len + 5 <= (option_len(opt))) &&
384 (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
385 for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
386 {
387 elen = option_uint(opt, o2, 1);
388 if ((o2 + elen + 1 <= option_len(opt)) &&
389 (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
390 break;
391 }
392 if (match)
393 break;
394 }
395 }
396 else
397 {
398 if (!(opt = option_find(mess, sz, o->opt, 1)))
399 continue;
400
401 match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
402 }
403
404 if (match)
405 {
406 o->netid->next = netid;
407 netid = o->netid;
408 }
409 }
410
411 /* user-class options are, according to RFC3004, supposed to contain
412 a set of counted strings. Here we check that this is so (by seeing
413 if the counts are consistent with the overall option length) and if
414 so zero the counts so that we don't get spurious matches between
415 the vendor string and the counts. If the lengths don't add up, we
416 assume that the option is a single string and non RFC3004 compliant
417 and just do the substring match. dhclient provides these broken options.
418 The code, later, which sends user-class data to the lease-change script
419 relies on the transformation done here.
420 */
421
422 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
423 {
424 unsigned char *ucp = option_ptr(opt, 0);
425 int tmp, j;
426 for (j = 0; j < option_len(opt); j += ucp[j] + 1);
427 if (j == option_len(opt))
428 for (j = 0; j < option_len(opt); j = tmp)
429 {
430 tmp = j + ucp[j] + 1;
431 ucp[j] = 0;
432 }
433 }
434
435 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
436 {
437 int mopt;
438
439 if (vendor->match_type == MATCH_VENDOR)
440 mopt = OPTION_VENDOR_ID;
441 else if (vendor->match_type == MATCH_USER)
442 mopt = OPTION_USER_CLASS;
443 else
444 continue;
445
446 if ((opt = option_find(mess, sz, mopt, 1)))
447 {
448 int i;
449 for (i = 0; i <= (option_len(opt) - vendor->len); i++)
450 if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
451 {
452 vendor->netid.next = netid;
453 netid = &vendor->netid;
454 break;
455 }
456 }
457 }
458
459 /* mark vendor-encapsulated options which match the client-supplied vendor class,
460 save client-supplied vendor class */
461 if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
462 {
463 memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
464 vendor_class_len = option_len(opt);
465 }
466 match_vendor_opts(opt, daemon->dhcp_opts);
467
468 if (option_bool(OPT_LOG_OPTS))
469 {
470 if (sanitise(opt, daemon->namebuff))
471 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
472 if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
473 my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
474 }
f2621c7f 475
3be34541 476 mess->op = BOOTREPLY;
5e9e0efb 477
cdeda28f
SK
478 config = find_config(daemon->dhcp_conf, context, clid, clid_len,
479 mess->chaddr, mess->hlen, mess->htype, NULL);
5aabfc78
SK
480
481 /* set "known" tag for known hosts */
482 if (config)
483 {
484 known_id.net = "known";
485 known_id.next = netid;
486 netid = &known_id;
487 }
26128d27 488
316e2730 489 if (mess_type == 0 && !pxe)
3be34541
SK
490 {
491 /* BOOTP request */
6b01084f 492 struct dhcp_netid id, bootp_id;
26128d27 493 struct in_addr *logaddr = NULL;
5e9e0efb
SK
494
495 /* must have a MAC addr for bootp */
7622fc06 496 if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
5e9e0efb 497 return 0;
26128d27 498
26128d27 499 if (have_config(config, CONFIG_DISABLE))
b8187c80 500 message = _("disabled");
26128d27
SK
501
502 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
503
504 if (have_config(config, CONFIG_NAME))
9009d746
SK
505 {
506 hostname = config->hostname;
507 domain = config->domain;
508 }
509
8ef5ada2 510 if (config)
26128d27 511 {
8ef5ada2
SK
512 struct dhcp_netid_list *list;
513
514 for (list = config->netid; list; list = list->next)
515 {
516 list->list->next = netid;
517 netid = list->list;
518 }
26128d27
SK
519 }
520
521 /* Match incoming filename field as a netid. */
522 if (mess->file[0])
523 {
1b7ecd11
SK
524 memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
525 daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
526 id.net = (char *)daemon->dhcp_buff2;
26128d27
SK
527 id.next = netid;
528 netid = &id;
529 }
6b01084f
SK
530
531 /* Add "bootp" as a tag to allow different options, address ranges etc
532 for BOOTP clients */
533 bootp_id.net = "bootp";
534 bootp_id.next = netid;
535 netid = &bootp_id;
26128d27 536
8ef5ada2
SK
537 tagif_netid = run_tag_if(netid);
538
26128d27 539 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
8ef5ada2 540 if (match_netid(id_list->list, tagif_netid, 0))
1f15b81d 541 message = _("ignored");
26128d27 542
3d8df260
SK
543 if (!message)
544 {
9009d746
SK
545 int nailed = 0;
546
3d8df260
SK
547 if (have_config(config, CONFIG_ADDR))
548 {
9009d746 549 nailed = 1;
3d8df260
SK
550 logaddr = &config->addr;
551 mess->yiaddr = config->addr;
552 if ((lease = lease_find_by_addr(config->addr)) &&
cdeda28f 553 (lease->hwaddr_len != mess->hlen ||
5e9e0efb 554 lease->hwaddr_type != mess->htype ||
cdeda28f 555 memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
b8187c80 556 message = _("address in use");
3d8df260 557 }
3d8df260
SK
558 else
559 {
cdeda28f 560 if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
8ef5ada2 561 !address_available(context, lease->addr, tagif_netid))
e17fb629
SK
562 {
563 if (lease)
564 {
565 /* lease exists, wrong network. */
566 lease_prune(lease, now);
567 lease = NULL;
568 }
8ef5ada2 569 if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))
e17fb629
SK
570 message = _("no address available");
571 }
572 else
3d8df260 573 mess->yiaddr = lease->addr;
3d8df260
SK
574 }
575
9009d746
SK
576 if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
577 message = _("wrong network");
578 else if (context->netid.net)
579 {
580 context->netid.next = netid;
7de060b0 581 tagif_netid = run_tag_if(&context->netid);
8ef5ada2 582 }
7de060b0 583
4cb1b320 584 log_tags(tagif_netid, ntohl(mess->xid));
8ef5ada2 585
9009d746
SK
586 if (!message && !nailed)
587 {
588 for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
8ef5ada2 589 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
9009d746
SK
590 break;
591 if (!id_list)
592 message = _("no address configured");
593 }
594
7cebd20f
SK
595 if (!message &&
596 !lease &&
52b92f4d 597 (!(lease = lease4_allocate(mess->yiaddr))))
824af85b 598 message = _("no leases left");
9009d746 599
3d8df260
SK
600 if (!message)
601 {
602 logaddr = &mess->yiaddr;
3d8df260 603
a9ab732e 604 lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now, 1);
3d8df260 605 if (hostname)
70c5e3e0 606 lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
1a6bca81
SK
607 /* infinite lease unless nailed in dhcp-host line. */
608 lease_set_expires(lease,
609 have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
610 now);
353ae4d2 611 lease_set_interface(lease, int_index, now);
3d8df260 612
7622fc06 613 clear_packet(mess, end);
9009d746 614 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
ca85a282 615 netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
3d8df260
SK
616 }
617 }
618
8c0b73d3 619 log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
1b7ecd11 620
7de060b0 621 return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
3be34541 622 }
1b7ecd11 623
3f3adae6 624 if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
9e4abcb5 625 {
3d8df260 626 /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
f6b7dc47 627 int len = option_len(opt);
3d8df260 628 char *pq = daemon->dhcp_buff;
1a6bca81 629 unsigned char *pp, *op = option_ptr(opt, 0);
3d8df260 630
9fed0f71 631 fqdn_flags = *op;
3d8df260
SK
632 len -= 3;
633 op += 3;
634 pp = op;
635
9fed0f71
SK
636 /* NB, the following always sets at least one bit */
637 if (option_bool(OPT_FQDN_UPDATE))
638 {
639 if (fqdn_flags & 0x01)
640 {
641 fqdn_flags |= 0x02; /* set O */
642 fqdn_flags &= ~0x01; /* clear S */
643 }
644 fqdn_flags |= 0x08; /* set N */
645 }
646 else
647 {
648 if (!(fqdn_flags & 0x01))
649 fqdn_flags |= 0x03; /* set S and O */
650 fqdn_flags &= ~0x08; /* clear N */
651 }
3d8df260
SK
652
653 if (fqdn_flags & 0x04)
3f3adae6 654 while (*op != 0 && ((op + (*op)) - pp) < len)
3d8df260
SK
655 {
656 memcpy(pq, op+1, *op);
657 pq += *op;
658 op += (*op)+1;
659 *(pq++) = '.';
660 }
661 else
9e4abcb5 662 {
3d8df260 663 memcpy(pq, op, len);
cdeda28f
SK
664 if (len > 0 && op[len-1] == 0)
665 borken_opt = 1;
3d8df260 666 pq += len + 1;
9e4abcb5 667 }
3d8df260
SK
668
669 if (pq != daemon->dhcp_buff)
670 pq--;
671
672 *pq = 0;
673
1f15b81d 674 if (legal_hostname(daemon->dhcp_buff))
3d8df260
SK
675 offer_hostname = client_hostname = daemon->dhcp_buff;
676 }
677 else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
678 {
679 int len = option_len(opt);
1a6bca81 680 memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
cdeda28f
SK
681 /* Microsoft clients are broken, and need zero-terminated strings
682 in options. We detect this state here, and do the same in
683 any options we send */
684 if (len > 0 && daemon->dhcp_buff[len-1] == 0)
685 borken_opt = 1;
686 else
687 daemon->dhcp_buff[len] = 0;
1f15b81d 688 if (legal_hostname(daemon->dhcp_buff))
3d8df260
SK
689 client_hostname = daemon->dhcp_buff;
690 }
691
28866e95 692 if (client_hostname && option_bool(OPT_LOG_OPTS))
7622fc06
SK
693 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
694
3d8df260
SK
695 if (have_config(config, CONFIG_NAME))
696 {
697 hostname = config->hostname;
9009d746 698 domain = config->domain;
b8187c80 699 hostname_auth = 1;
832af0ba 700 /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
3d8df260 701 if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
832af0ba 702 offer_hostname = hostname;
3d8df260 703 }
5aabfc78 704 else if (client_hostname)
3d8df260 705 {
9009d746 706 domain = strip_hostname(client_hostname);
5aabfc78
SK
707
708 if (strlen(client_hostname) != 0)
709 {
710 hostname = client_hostname;
711 if (!config)
712 {
713 /* Search again now we have a hostname.
714 Only accept configs without CLID and HWADDR here, (they won't match)
715 to avoid impersonation by name. */
716 struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
717 mess->chaddr, mess->hlen,
718 mess->htype, hostname);
9009d746 719 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
824af85b
SK
720 {
721 config = new;
722 /* set "known" tag for known hosts */
723 known_id.net = "known";
724 known_id.next = netid;
725 netid = &known_id;
726 }
5aabfc78
SK
727 }
728 }
9e4abcb5 729 }
a84fa1d0 730
8ef5ada2 731 if (config)
a84fa1d0 732 {
8ef5ada2
SK
733 struct dhcp_netid_list *list;
734
735 for (list = config->netid; list; list = list->next)
736 {
737 list->list->next = netid;
738 netid = list->list;
739 }
a84fa1d0 740 }
36717eee 741
8ef5ada2 742 tagif_netid = run_tag_if(netid);
86e92f99 743
26128d27
SK
744 /* if all the netids in the ignore list are present, ignore this client */
745 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
8ef5ada2 746 if (match_netid(id_list->list, tagif_netid, 0))
26128d27 747 ignore = 1;
8ef5ada2
SK
748
749 /* If configured, we can override the server-id to be the address of the relay,
750 so that all traffic goes via the relay and can pick up agent-id info. This can be
751 configured for all relays, or by address. */
752 if (daemon->override && mess->giaddr.s_addr != 0 && override.s_addr == 0)
753 {
754 if (!daemon->override_relays)
755 override = mess->giaddr;
756 else
757 {
758 struct addr_list *l;
759 for (l = daemon->override_relays; l; l = l->next)
760 if (l->addr.s_addr == mess->giaddr.s_addr)
761 break;
762 if (l)
763 override = mess->giaddr;
764 }
765 }
766
a84fa1d0
SK
767 /* Can have setting to ignore the client ID for a particular MAC address or hostname */
768 if (have_config(config, CONFIG_NOCLID))
0a852541
SK
769 clid = NULL;
770
7622fc06 771 /* Check if client is PXE client. */
1f15b81d
SK
772 if (daemon->enable_pxe &&
773 (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
7622fc06
SK
774 strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
775 {
776 if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
777 {
778 memcpy(pxe_uuid, option_ptr(opt, 0), 17);
779 uuid = pxe_uuid;
780 }
781
782 /* Check if this is really a PXE bootserver request, and handle specially if so. */
783 if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
784 (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
785 (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
786 {
787 struct pxe_service *service;
788 int type = option_uint(opt, 0, 2);
789 int layer = option_uint(opt, 2, 2);
790 unsigned char save71[4];
791 struct dhcp_opt opt71;
792
1f15b81d
SK
793 if (ignore)
794 return 0;
795
7622fc06
SK
796 if (layer & 0x8000)
797 {
798 my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
799 return 0;
800 }
801
802 memcpy(save71, option_ptr(opt, 0), 4);
803
804 for (service = daemon->pxe_services; service; service = service->next)
805 if (service->type == type)
806 break;
807
808 if (!service || !service->basename)
809 return 0;
810
811 clear_packet(mess, end);
812
813 mess->yiaddr = mess->ciaddr;
814 mess->ciaddr.s_addr = 0;
751d6f4a
SK
815 if (service->sname)
816 mess->siaddr = a_record_from_hosts(service->sname, now);
817 else if (service->server.s_addr != 0)
7622fc06
SK
818 mess->siaddr = service->server;
819 else
820 mess->siaddr = context->local;
821
822 snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
823 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
824 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
825 pxe_misc(mess, end, uuid);
826
8ef5ada2 827 prune_vendor_opts(tagif_netid);
7622fc06
SK
828 opt71.val = save71;
829 opt71.opt = SUBOPT_PXE_BOOT_ITEM;
830 opt71.len = 4;
831 opt71.flags = DHOPT_VENDOR_MATCH;
832 opt71.netid = NULL;
833 opt71.next = daemon->dhcp_opts;
834 do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
835
8c0b73d3 836 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
4cb1b320 837 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 838 return dhcp_packet_size(mess, agent_id, real_end);
7622fc06
SK
839 }
840
841 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
842 {
843 pxearch = option_uint(opt, 0, 2);
844
316e2730 845 /* proxy DHCP here. */
28866e95 846 if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
7622fc06 847 {
28866e95 848 struct dhcp_context *tmp;
7622fc06 849
28866e95
SK
850 for (tmp = context; tmp; tmp = tmp->current)
851 if ((tmp->flags & CONTEXT_PROXY) &&
852 match_netid(tmp->filter, tagif_netid, 1))
853 break;
854
855 if (tmp)
7622fc06 856 {
a37cd7aa
SK
857 struct dhcp_boot *boot;
858
859 if (tmp->netid.net)
860 {
861 tmp->netid.next = netid;
862 tagif_netid = run_tag_if(&tmp->netid);
863 }
864
865 boot = find_boot(tagif_netid);
866
28866e95
SK
867 mess->yiaddr.s_addr = 0;
868 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
869 {
870 mess->ciaddr.s_addr = 0;
871 mess->flags |= htons(0x8000); /* broadcast */
872 }
873
874 clear_packet(mess, end);
875
876 /* Provide the bootfile here, for gPXE, and in case we have no menu items
877 and set discovery_control = 8 */
878 if (boot)
879 {
7de060b0 880 if (boot->next_server.s_addr)
28866e95 881 mess->siaddr = boot->next_server;
7de060b0
SK
882 else if (boot->tftp_sname)
883 mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
28866e95
SK
884
885 if (boot->file)
886 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
887 }
7622fc06 888
28866e95
SK
889 option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
890 mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
62018e1f 891 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
28866e95
SK
892 pxe_misc(mess, end, uuid);
893 prune_vendor_opts(tagif_netid);
62018e1f 894 do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
28866e95 895
8c0b73d3 896 log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
4cb1b320 897 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 898 return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
7622fc06 899 }
7622fc06
SK
900 }
901 }
902 }
903
904 /* if we're just a proxy server, go no further */
316e2730 905 if ((context->flags & CONTEXT_PROXY) || pxe)
7622fc06
SK
906 return 0;
907
bb01cb96 908 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
a84fa1d0 909 {
3d8df260 910 req_options = (unsigned char *)daemon->dhcp_buff2;
1a6bca81 911 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
bb01cb96 912 req_options[option_len(opt)] = OPTION_END;
a84fa1d0
SK
913 }
914
3be34541 915 switch (mess_type)
9e4abcb5 916 {
44a2a316 917 case DHCPDECLINE:
bb01cb96 918 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
73a08a24 919 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
44a2a316 920 return 0;
1a6bca81 921
44a2a316 922 /* sanitise any message. Paranoid? Moi? */
f2621c7f 923 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
44a2a316 924
bb01cb96 925 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
44a2a316
SK
926 return 0;
927
8c0b73d3 928 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
44a2a316
SK
929
930 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
931 lease_prune(lease, now);
932
33820b7e 933 if (have_config(config, CONFIG_ADDR) &&
44a2a316 934 config->addr.s_addr == option_addr(opt).s_addr)
9e4abcb5 935 {
849a8357 936 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
7622fc06 937 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
f2621c7f 938 inet_ntoa(config->addr), daemon->dhcp_buff);
849a8357
SK
939 config->flags |= CONFIG_DECLINED;
940 config->decline_time = now;
9e4abcb5 941 }
feba5c1d
SK
942 else
943 /* make sure this host gets a different address next time. */
36717eee
SK
944 for (; context; context = context->current)
945 context->addr_epoch++;
44a2a316
SK
946
947 return 0;
948
949 case DHCPRELEASE:
8ef5ada2 950 if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
1697269c 951 !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
73a08a24 952 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
44a2a316
SK
953 return 0;
954
44a2a316
SK
955 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
956 lease_prune(lease, now);
fd9fa481 957 else
b8187c80 958 message = _("unknown lease");
fd9fa481 959
8c0b73d3 960 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
44a2a316 961
9e4abcb5
SK
962 return 0;
963
964 case DHCPDISCOVER:
5e9e0efb
SK
965 if (ignore || have_config(config, CONFIG_DISABLE))
966 {
cc1a29e2
SK
967 if (option_bool(OPT_QUIET_DHCP))
968 return 0;
b8187c80 969 message = _("ignored");
5e9e0efb
SK
970 opt = NULL;
971 }
972 else
973 {
974 struct in_addr addr, conf;
975
1a6bca81
SK
976 addr.s_addr = conf.s_addr = 0;
977
5e9e0efb
SK
978 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
979 addr = option_addr(opt);
980
5e9e0efb
SK
981 if (have_config(config, CONFIG_ADDR))
982 {
849a8357
SK
983 char *addrs = inet_ntoa(config->addr);
984
9009d746
SK
985 if ((ltmp = lease_find_by_addr(config->addr)) &&
986 ltmp != lease &&
987 !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1b7ecd11
SK
988 {
989 int len;
990 unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
991 ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
7622fc06 992 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
5aabfc78 993 addrs, print_mac(daemon->namebuff, mac, len));
1b7ecd11 994 }
5e9e0efb
SK
995 else
996 {
997 struct dhcp_context *tmp;
998 for (tmp = context; tmp; tmp = tmp->current)
849a8357 999 if (context->router.s_addr == config->addr.s_addr)
5e9e0efb
SK
1000 break;
1001 if (tmp)
7622fc06 1002 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
849a8357
SK
1003 else if (have_config(config, CONFIG_DECLINED) &&
1004 difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
7622fc06 1005 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
5e9e0efb
SK
1006 else
1007 conf = config->addr;
1008 }
1009 }
1010
1011 if (conf.s_addr)
1012 mess->yiaddr = conf;
7622fc06 1013 else if (lease &&
8ef5ada2 1014 address_available(context, lease->addr, tagif_netid) &&
7622fc06 1015 !config_find_by_address(daemon->dhcp_conf, lease->addr))
5e9e0efb 1016 mess->yiaddr = lease->addr;
8ef5ada2 1017 else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
5e9e0efb
SK
1018 !config_find_by_address(daemon->dhcp_conf, addr))
1019 mess->yiaddr = addr;
5aabfc78
SK
1020 else if (emac_len == 0)
1021 message = _("no unique-id");
8ef5ada2 1022 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))
5e9e0efb
SK
1023 message = _("no address available");
1024 }
1025
8c0b73d3 1026 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);
3d8df260 1027
8ef5ada2 1028 if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
33820b7e 1029 return 0;
e17fb629 1030
cdeda28f 1031 if (context->netid.net)
59353a6b
SK
1032 {
1033 context->netid.next = netid;
7de060b0 1034 tagif_netid = run_tag_if(&context->netid);
59353a6b 1035 }
7de060b0 1036
4cb1b320 1037 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 1038
8c0b73d3 1039 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
7de060b0 1040
824af85b 1041 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
7622fc06 1042 clear_packet(mess, end);
1b7ecd11 1043 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
73a08a24 1044 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1045 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
a84fa1d0 1046 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
9009d746 1047 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
ca85a282 1048 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
9e4abcb5 1049
7de060b0 1050 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1051
1052 case DHCPREQUEST:
26128d27
SK
1053 if (ignore || have_config(config, CONFIG_DISABLE))
1054 return 0;
bb01cb96 1055 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
9e4abcb5
SK
1056 {
1057 /* SELECTING or INIT_REBOOT */
44a2a316 1058 mess->yiaddr = option_addr(opt);
9e4abcb5 1059
4011c4e0
SK
1060 /* send vendor and user class info for new or recreated lease */
1061 do_classes = 1;
1062
bb01cb96 1063 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
3be34541
SK
1064 {
1065 /* SELECTING */
832af0ba
SK
1066 selecting = 1;
1067
1a6bca81
SK
1068 if (override.s_addr != 0)
1069 {
1070 if (option_addr(opt).s_addr != override.s_addr)
1071 return 0;
1072 }
9009d746 1073 else
1a6bca81
SK
1074 {
1075 for (; context; context = context->current)
1076 if (context->local.s_addr == option_addr(opt).s_addr)
1077 break;
1078
1079 if (!context)
9009d746 1080 {
7de060b0
SK
1081 /* Handle very strange configs where clients have more than one route to the server.
1082 If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
1083 Have to set override to make sure we echo back the correct server-id */
1084 struct irec *intr;
1085
115ac3e4 1086 enumerate_interfaces(0);
7de060b0
SK
1087
1088 for (intr = daemon->interfaces; intr; intr = intr->next)
1089 if (intr->addr.sa.sa_family == AF_INET &&
1090 intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
1091 intr->tftp_ok)
1092 break;
1093
1094 if (intr)
1095 override = intr->addr.in.sin_addr;
1096 else
1097 {
1098 /* In auth mode, a REQUEST sent to the wrong server
1099 should be faulted, so that the client establishes
1100 communication with us, otherwise, silently ignore. */
1101 if (!option_bool(OPT_AUTHORITATIVE))
1102 return 0;
1103 message = _("wrong server-ID");
1104 }
9009d746 1105 }
1a6bca81 1106 }
e17fb629 1107
3be34541
SK
1108 /* If a lease exists for this host and another address, squash it. */
1109 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1110 {
1111 lease_prune(lease, now);
1112 lease = NULL;
1113 }
3be34541
SK
1114 }
1115 else
9e4abcb5 1116 {
3be34541 1117 /* INIT-REBOOT */
28866e95 1118 if (!lease && !option_bool(OPT_AUTHORITATIVE))
3be34541
SK
1119 return 0;
1120
fd9fa481 1121 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
8ef5ada2 1122 message = _("wrong address");
9e4abcb5 1123 }
44a2a316
SK
1124 }
1125 else
1126 {
1127 /* RENEWING or REBINDING */
cdeda28f
SK
1128 /* Check existing lease for this address.
1129 We allow it to be missing if dhcp-authoritative mode
1130 as long as we can allocate the lease now - checked below.
1131 This makes for a smooth recovery from a lost lease DB */
1132 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
28866e95 1133 (!lease && !option_bool(OPT_AUTHORITATIVE)))
b8187c80 1134 {
28866e95
SK
1135 /* A client rebinding will broadcast the request, so we may see it even
1136 if the lease is held by another server. Just ignore it in that case.
1137 If the request is unicast to us, then somethings wrong, NAK */
1138 if (!unicast_dest)
1139 return 0;
b8187c80
SK
1140 message = _("lease not found");
1141 /* ensure we broadcast NAK */
1142 unicast_dest = 0;
1143 }
8ef5ada2 1144
a84fa1d0
SK
1145 /* desynchronise renewals */
1146 fuzz = rand16();
3be34541 1147 mess->yiaddr = mess->ciaddr;
44a2a316
SK
1148 }
1149
8c0b73d3 1150 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
e17fb629 1151
dfa666f2
SK
1152 if (!message)
1153 {
1154 struct dhcp_config *addr_config;
5e9e0efb
SK
1155 struct dhcp_context *tmp = NULL;
1156
1157 if (have_config(config, CONFIG_ADDR))
1158 for (tmp = context; tmp; tmp = tmp->current)
849a8357 1159 if (context->router.s_addr == config->addr.s_addr)
5e9e0efb 1160 break;
aedef830 1161
8ef5ada2 1162 if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
b8187c80 1163 {
e17fb629 1164 /* If a machine moves networks whilst it has a lease, we catch that here. */
b8187c80
SK
1165 message = _("wrong network");
1166 /* ensure we broadcast NAK */
1167 unicast_dest = 0;
1168 }
1169
fd9fa481 1170 /* Check for renewal of a lease which is outside the allowed range. */
8ef5ada2 1171 else if (!address_available(context, mess->yiaddr, tagif_netid) &&
dfa666f2 1172 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
b8187c80 1173 message = _("address not available");
e17fb629 1174
dfa666f2
SK
1175 /* Check if a new static address has been configured. Be very sure that
1176 when the client does DISCOVER, it will get the static address, otherwise
1177 an endless protocol loop will ensue. */
832af0ba 1178 else if (!tmp && !selecting &&
5e9e0efb 1179 have_config(config, CONFIG_ADDR) &&
849a8357
SK
1180 (!have_config(config, CONFIG_DECLINED) ||
1181 difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
fd9fa481
SK
1182 config->addr.s_addr != mess->yiaddr.s_addr &&
1183 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
b8187c80 1184 message = _("static lease available");
dfa666f2
SK
1185
1186 /* Check to see if the address is reserved as a static address for another host */
3be34541 1187 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
b8187c80 1188 message = _("address reserved");
feba5c1d 1189
9009d746
SK
1190 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1191 {
1192 /* If a host is configured with more than one MAC address, it's OK to 'nix
1193 a lease from one of it's MACs to give the address to another. */
1194 if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1195 {
7622fc06 1196 my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
9009d746
SK
1197 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
1198 inet_ntoa(ltmp->addr));
1199 lease = ltmp;
1200 }
1697269c 1201 else
9009d746
SK
1202 message = _("address in use");
1203 }
1204
1205 if (!message)
1206 {
1207 if (emac_len == 0)
1208 message = _("no unique-id");
1209
1210 else if (!lease)
1211 {
52b92f4d 1212 if ((lease = lease4_allocate(mess->yiaddr)))
9009d746
SK
1213 do_classes = 1;
1214 else
1215 message = _("no leases left");
1216 }
1697269c 1217 }
fd9fa481 1218 }
1697269c 1219
44a2a316
SK
1220 if (message)
1221 {
8c0b73d3 1222 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
44a2a316 1223
1b7ecd11 1224 mess->yiaddr.s_addr = 0;
7622fc06 1225 clear_packet(mess, end);
1b7ecd11 1226 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
73a08a24 1227 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1228 option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
b8187c80
SK
1229 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
1230 a distant subnet which unicast a REQ to us won't work. */
1231 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
1232 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1233 {
1234 mess->flags |= htons(0x8000); /* broadcast */
1235 mess->ciaddr.s_addr = 0;
1236 }
44a2a316 1237 }
fd9fa481 1238 else
44a2a316 1239 {
316e2730
SK
1240 if (context->netid.net)
1241 {
1242 context->netid.next = netid;
7de060b0 1243 tagif_netid = run_tag_if( &context->netid);
316e2730 1244 }
7de060b0 1245
4cb1b320 1246 log_tags(tagif_netid, ntohl(mess->xid));
8ef5ada2 1247
dcffad2a 1248 if (do_classes)
8ef5ada2 1249 {
dcffad2a 1250 /* pick up INIT-REBOOT events. */
4cb1b320 1251 lease->flags |= LEASE_CHANGED;
39bec5ff 1252
dcffad2a
SK
1253#ifdef HAVE_SCRIPT
1254 if (daemon->lease_change_command)
8ef5ada2 1255 {
dcffad2a
SK
1256 struct dhcp_netid *n;
1257
1258 if (mess->giaddr.s_addr)
1259 lease->giaddr = mess->giaddr;
1260
1261 free(lease->extradata);
1262 lease->extradata = NULL;
1263 lease->extradata_size = lease->extradata_len = 0;
1264
1265 add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
1266 add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
1267 add_extradata_opt(lease, oui);
1268 add_extradata_opt(lease, serial);
1269 add_extradata_opt(lease, class);
dd1721c7
SK
1270
1271 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
1272 {
1273 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
1274 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
1275 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
1276 }
1277 else
1278 {
1279 add_extradata_opt(lease, NULL);
1280 add_extradata_opt(lease, NULL);
1281 add_extradata_opt(lease, NULL);
1282 }
1283
dcffad2a
SK
1284 /* space-concat tag set */
1285 if (!tagif_netid)
1286 add_extradata_opt(lease, NULL);
1287 else
1288 for (n = tagif_netid; n; n = n->next)
1289 {
1290 struct dhcp_netid *n1;
1291 /* kill dupes */
1292 for (n1 = n->next; n1; n1 = n1->next)
1293 if (strcmp(n->net, n1->net) == 0)
1294 break;
1295 if (!n1)
1296 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1297 }
1298
1299 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1300 {
1301 int len = option_len(opt);
1302 unsigned char *ucp = option_ptr(opt, 0);
1303 /* If the user-class option started as counted strings, the first byte will be zero. */
1304 if (len != 0 && ucp[0] == 0)
1305 ucp++, len--;
1306 lease_add_extradata(lease, ucp, len, 0);
1307 }
8ef5ada2 1308 }
316e2730 1309#endif
dcffad2a 1310 }
8ef5ada2
SK
1311
1312 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1313 {
1314 domain = get_domain(mess->yiaddr);
b8187c80
SK
1315 hostname = client_hostname;
1316 hostname_auth = 1;
1317 }
8ef5ada2 1318
824af85b 1319 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
a9ab732e 1320 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
8ef5ada2 1321
832af0ba
SK
1322 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1323 if (!hostname_auth)
1324 {
1325 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
8ef5ada2 1326 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
832af0ba
SK
1327 break;
1328 if (id_list)
1329 hostname = NULL;
1330 }
8ef5ada2
SK
1331
1332 /* Last ditch, if configured, generate hostname from mac address */
1333 if (!hostname && emac_len != 0)
1334 {
1335 for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
1336 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1337 break;
1338 if (id_list)
1339 {
1340 int i;
1341
1342 hostname = daemon->dhcp_buff;
1343 /* buffer is 256 bytes, 3 bytes per octet */
1344 for (i = 0; (i < emac_len) && (i < 80); i++)
1345 hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
1346 hostname = daemon->dhcp_buff;
1347 }
1348 }
1349
fd9fa481 1350 if (hostname)
70c5e3e0 1351 lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
832af0ba 1352
5e9e0efb 1353 lease_set_expires(lease, time, now);
353ae4d2 1354 lease_set_interface(lease, int_index, now);
1a6bca81
SK
1355
1356 if (override.s_addr != 0)
1357 lease->override = override;
1358 else
1359 override = lease->override;
1360
8c0b73d3 1361 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
832af0ba 1362
7622fc06 1363 clear_packet(mess, end);
1b7ecd11 1364 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
73a08a24 1365 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1366 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
9009d746 1367 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
ca85a282 1368 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
44a2a316 1369 }
fd9fa481 1370
7de060b0 1371 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1372
1373 case DHCPINFORM:
26128d27 1374 if (ignore || have_config(config, CONFIG_DISABLE))
b8187c80 1375 message = _("ignored");
33820b7e 1376
8c0b73d3 1377 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
a84fa1d0 1378
73a08a24 1379 if (message || mess->ciaddr.s_addr == 0)
a84fa1d0 1380 return 0;
73a08a24
SK
1381
1382 /* For DHCPINFORM only, cope without a valid context */
8ef5ada2 1383 context = narrow_context(context, mess->ciaddr, tagif_netid);
9e4abcb5 1384
5aabfc78
SK
1385 /* Find a least based on IP address if we didn't
1386 get one from MAC address/client-d */
1387 if (!lease &&
1388 (lease = lease_find_by_addr(mess->ciaddr)) &&
1389 lease->hostname)
1390 hostname = lease->hostname;
1391
0f371f9e
SK
1392 if (!hostname)
1393 hostname = host_from_dns(mess->ciaddr);
5aabfc78 1394
73a08a24 1395 if (context && context->netid.net)
59353a6b
SK
1396 {
1397 context->netid.next = netid;
4cb1b320 1398 tagif_netid = run_tag_if(&context->netid);
59353a6b 1399 }
7de060b0 1400
4cb1b320 1401 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 1402
8c0b73d3 1403 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
1a6bca81 1404
3927da46
SK
1405 if (lease)
1406 {
d1a5975f 1407 lease_set_interface(lease, int_index, now);
3927da46
SK
1408 if (override.s_addr != 0)
1409 lease->override = override;
1410 else
1411 override = lease->override;
1412 }
1413
7622fc06 1414 clear_packet(mess, end);
1b7ecd11 1415 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
73a08a24 1416 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
aa63a21c
SK
1417
1418 /* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
1419 we supply a utility which makes DHCPINFORM requests to get this information.
1420 Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
1421 which won't be true for ordinary clients, but will be true for the
1422 dhcp_lease_time utility. */
1423 if (lease && in_list(req_options, OPTION_LEASE_TIME))
1424 {
1425 if (lease->expires == 0)
1426 time = 0xffffffff;
1427 else
1428 time = (unsigned int)difftime(lease->expires, now);
1429 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1430 }
1431
9009d746 1432 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
ca85a282 1433 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
9e4abcb5 1434
5aabfc78 1435 *is_inform = 1; /* handle reply differently */
7de060b0 1436 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1437 }
1438
1439 return 0;
1440}
1441
6b01084f
SK
1442/* find a good value to use as MAC address for logging and address-allocation hashing.
1443 This is normally just the chaddr field from the DHCP packet,
1444 but eg Firewire will have hlen == 0 and use the client-id instead.
1445 This could be anything, but will normally be EUI64 for Firewire.
1446 We assume that if the first byte of the client-id equals the htype byte
1447 then the client-id is using the usual encoding and use the rest of the
1448 client-id: if not we can use the whole client-id. This should give
1449 sane MAC address logs. */
9009d746 1450unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
6b01084f
SK
1451 int clid_len, unsigned char *clid, int *len_out)
1452{
1453 if (hwlen == 0 && clid && clid_len > 3)
1454 {
1455 if (clid[0] == hwtype)
1456 {
1457 *len_out = clid_len - 1 ;
1458 return clid + 1;
1459 }
1460
1461#if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1462 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1463 {
1464 *len_out = clid_len - 1 ;
1465 return clid + 1;
1466 }
1467#endif
1468
1469 *len_out = clid_len;
1470 return clid;
1471 }
1472
1473 *len_out = hwlen;
1474 return hwaddr;
1475}
1476
824af85b 1477static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
9e4abcb5 1478{
5e9e0efb
SK
1479 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1480
1481 if (opt)
1482 {
7622fc06 1483 unsigned int req_time = option_uint(opt, 0, 4);
5e9e0efb
SK
1484 if (req_time < 120 )
1485 req_time = 120; /* sanity */
1486 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1487 time = req_time;
1488 }
3d8df260 1489
5e9e0efb
SK
1490 return time;
1491}
1492
73a08a24 1493static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1a6bca81 1494{
73a08a24 1495 if (override.s_addr != 0)
1a6bca81 1496 return override;
7de060b0 1497 else if (context && context->local.s_addr != 0)
1a6bca81 1498 return context->local;
73a08a24
SK
1499 else
1500 return fallback;
1a6bca81
SK
1501}
1502
f2621c7f
SK
1503static int sanitise(unsigned char *opt, char *buf)
1504{
1505 char *p;
1506 int i;
1507
1508 *buf = 0;
1509
1510 if (!opt)
1511 return 0;
1512
1a6bca81 1513 p = option_ptr(opt, 0);
f2621c7f
SK
1514
1515 for (i = option_len(opt); i > 0; i--)
1516 {
1517 char c = *p++;
824af85b 1518 if (isprint((int)c))
f2621c7f
SK
1519 *buf++ = c;
1520 }
1521 *buf = 0; /* add terminator */
1522
1523 return 1;
1524}
1525
316e2730 1526#ifdef HAVE_SCRIPT
316e2730
SK
1527static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
1528{
1529 if (!opt)
ceae00dd 1530 lease_add_extradata(lease, NULL, 0, 0);
316e2730 1531 else
ceae00dd 1532 lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
316e2730
SK
1533}
1534#endif
1535
5aabfc78 1536static void log_packet(char *type, void *addr, unsigned char *ext_mac,
8c0b73d3 1537 int mac_len, char *interface, char *string, char *err, u32 xid)
5e9e0efb 1538{
1697269c 1539 struct in_addr a;
7622fc06 1540
227ddad9 1541 if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
8c0b73d3
KDB
1542 return;
1543
1697269c
SK
1544 /* addr may be misaligned */
1545 if (addr)
1546 memcpy(&a, addr, sizeof(a));
1547
7622fc06
SK
1548 print_mac(daemon->namebuff, ext_mac, mac_len);
1549
28866e95 1550 if(option_bool(OPT_LOG_OPTS))
8c0b73d3 1551 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
7622fc06
SK
1552 ntohl(xid),
1553 type,
1554 interface,
1555 addr ? inet_ntoa(a) : "",
1556 addr ? " " : "",
1557 daemon->namebuff,
8c0b73d3
KDB
1558 string ? string : "",
1559 err ? err : "");
7622fc06 1560 else
8c0b73d3 1561 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
7622fc06
SK
1562 type,
1563 interface,
1564 addr ? inet_ntoa(a) : "",
1565 addr ? " " : "",
1566 daemon->namebuff,
8c0b73d3
KDB
1567 string ? string : "",
1568 err ? err : "");
f2621c7f
SK
1569}
1570
7622fc06 1571static void log_options(unsigned char *start, u32 xid)
f2621c7f
SK
1572{
1573 while (*start != OPTION_END)
1574 {
4cb1b320 1575 char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
7622fc06 1576
4cb1b320
SK
1577 my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
1578 ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
f2621c7f
SK
1579 start += start[1] + 2;
1580 }
9e4abcb5
SK
1581}
1582
1b7ecd11
SK
1583static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1584{
1a6bca81 1585 while (1)
1b7ecd11 1586 {
1a6bca81
SK
1587 if (p > end)
1588 return NULL;
1589 else if (*p == OPTION_END)
1590 return opt == OPTION_END ? p : NULL;
1b7ecd11
SK
1591 else if (*p == OPTION_PAD)
1592 p++;
1593 else
1594 {
1595 int opt_len;
1a6bca81 1596 if (p > end - 2)
1b7ecd11
SK
1597 return NULL; /* malformed packet */
1598 opt_len = option_len(p);
1a6bca81 1599 if (p > end - (2 + opt_len))
1b7ecd11
SK
1600 return NULL; /* malformed packet */
1601 if (*p == opt && opt_len >= minsize)
1602 return p;
1603 p += opt_len + 2;
1604 }
1605 }
1b7ecd11
SK
1606}
1607
1608static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1609{
1610 unsigned char *ret, *overload;
1611
1612 /* skip over DHCP cookie; */
1613 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
1614 return ret;
1615
1616 /* look for overload option. */
1617 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
1618 return NULL;
1619
1620 /* Can we look in filename area ? */
1621 if ((overload[2] & 1) &&
1622 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
1623 return ret;
1624
1625 /* finally try sname area */
1626 if ((overload[2] & 2) &&
1627 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
1628 return ret;
1629
1630 return NULL;
1631}
1632
4cb1b320 1633static struct in_addr option_addr(unsigned char *opt)
9e4abcb5 1634{
4cb1b320 1635 /* this worries about unaligned data in the option. */
9e4abcb5
SK
1636 /* struct in_addr is network byte order */
1637 struct in_addr ret;
1638
4cb1b320 1639 memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
9e4abcb5
SK
1640
1641 return ret;
1642}
1643
7622fc06 1644static unsigned int option_uint(unsigned char *opt, int offset, int size)
9e4abcb5
SK
1645{
1646 /* this worries about unaligned data and byte order */
44a2a316
SK
1647 unsigned int ret = 0;
1648 int i;
7622fc06 1649 unsigned char *p = option_ptr(opt, offset);
9e4abcb5 1650
44a2a316
SK
1651 for (i = 0; i < size; i++)
1652 ret = (ret << 8) | *p++;
1653
1654 return ret;
9e4abcb5
SK
1655}
1656
1b7ecd11 1657static unsigned char *dhcp_skip_opts(unsigned char *start)
9e4abcb5 1658{
1b7ecd11
SK
1659 while (*start != 0)
1660 start += start[1] + 2;
1661 return start;
1662}
26128d27 1663
1b7ecd11
SK
1664/* only for use when building packet: doesn't check for bad data. */
1665static unsigned char *find_overload(struct dhcp_packet *mess)
1666{
1667 unsigned char *p = &mess->options[0] + sizeof(u32);
26128d27 1668
1b7ecd11 1669 while (*p != 0)
26128d27 1670 {
1b7ecd11
SK
1671 if (*p == OPTION_OVERLOAD)
1672 return p;
1673 p += p[1] + 2;
26128d27 1674 }
1b7ecd11 1675 return NULL;
9e4abcb5
SK
1676}
1677
7de060b0
SK
1678static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
1679{
1680 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1681 unsigned char *overload;
1682 size_t ret;
1683
1684 /* move agent_id back down to the end of the packet */
1685 if (agent_id)
1686 {
1687 memmove(p, agent_id, real_end - agent_id);
1688 p += real_end - agent_id;
1689 memset(p, 0, real_end - p); /* in case of overlap */
1690 }
1691
1b7ecd11 1692 /* add END options to the regions. */
7622fc06
SK
1693 overload = find_overload(mess);
1694
1695 if (overload && (option_uint(overload, 0, 1) & 1))
b8187c80 1696 {
7622fc06 1697 *dhcp_skip_opts(mess->file) = OPTION_END;
28866e95 1698 if (option_bool(OPT_LOG_OPTS))
7622fc06
SK
1699 log_options(mess->file, mess->xid);
1700 }
28866e95 1701 else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
7622fc06
SK
1702 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
1703
1704 if (overload && (option_uint(overload, 0, 1) & 2))
1705 {
1706 *dhcp_skip_opts(mess->sname) = OPTION_END;
28866e95 1707 if (option_bool(OPT_LOG_OPTS))
7622fc06 1708 log_options(mess->sname, mess->xid);
b8187c80 1709 }
28866e95 1710 else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
7622fc06
SK
1711 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
1712
b8187c80 1713
1b7ecd11 1714 *p++ = OPTION_END;
824af85b 1715
28866e95 1716 if (option_bool(OPT_LOG_OPTS))
7622fc06
SK
1717 {
1718 if (mess->siaddr.s_addr != 0)
1719 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
1720
8ef5ada2
SK
1721 if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
1722 my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
1723
7622fc06
SK
1724 log_options(&mess->options[0] + sizeof(u32), mess->xid);
1725 }
1b7ecd11
SK
1726
1727 ret = (size_t)(p - (unsigned char *)mess);
1728
1729 if (ret < MIN_PACKETSZ)
1730 ret = MIN_PACKETSZ;
8ef5ada2 1731
1b7ecd11 1732 return ret;
b8187c80
SK
1733}
1734
1b7ecd11 1735static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
9e4abcb5 1736{
1b7ecd11 1737 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
44a2a316 1738
1b7ecd11
SK
1739 if (p + len + 3 >= end)
1740 /* not enough space in options area, try and use overload, if poss */
1741 {
1742 unsigned char *overload;
1743
1744 if (!(overload = find_overload(mess)) &&
1745 (mess->file[0] == 0 || mess->sname[0] == 0))
1746 {
1747 /* attempt to overload fname and sname areas, we've reserved space for the
1748 overflow option previuously. */
1749 overload = p;
1750 *(p++) = OPTION_OVERLOAD;
1751 *(p++) = 1;
1752 }
1753
1754 p = NULL;
1755
1756 /* using filename field ? */
1757 if (overload)
1758 {
1759 if (mess->file[0] == 0)
1760 overload[2] |= 1;
1761
1762 if (overload[2] & 1)
1763 {
1764 p = dhcp_skip_opts(mess->file);
1765 if (p + len + 3 >= mess->file + sizeof(mess->file))
1766 p = NULL;
1767 }
1768
1769 if (!p)
1770 {
1771 /* try to bring sname into play (it may be already) */
1772 if (mess->sname[0] == 0)
1773 overload[2] |= 2;
1774
1775 if (overload[2] & 2)
1776 {
1777 p = dhcp_skip_opts(mess->sname);
ffa3d7d6 1778 if (p + len + 3 >= mess->sname + sizeof(mess->sname))
1b7ecd11
SK
1779 p = NULL;
1780 }
1781 }
1782 }
1783
1784 if (!p)
7622fc06 1785 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1b7ecd11
SK
1786 }
1787
1788 if (p)
9e4abcb5
SK
1789 {
1790 *(p++) = opt;
a222641c 1791 *(p++) = len;
9e4abcb5 1792 }
1b7ecd11 1793
9e4abcb5
SK
1794 return p;
1795}
1b7ecd11
SK
1796
1797static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
a222641c 1798{
1b7ecd11
SK
1799 int i;
1800 unsigned char *p = free_space(mess, end, opt, len);
a222641c 1801
1b7ecd11
SK
1802 if (p)
1803 for (i = 0; i < len; i++)
1804 *(p++) = val >> (8 * (len - (i + 1)));
a222641c
SK
1805}
1806
1b7ecd11
SK
1807static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1808 char *string, int null_term)
44a2a316 1809{
1b7ecd11 1810 unsigned char *p;
0a852541 1811 size_t len = strlen(string);
3be34541 1812
cdeda28f
SK
1813 if (null_term && len != 255)
1814 len++;
1815
1b7ecd11
SK
1816 if ((p = free_space(mess, end, opt, len)))
1817 memcpy(p, string, len);
44a2a316 1818}
1b7ecd11
SK
1819
1820/* return length, note this only does the data part */
73a08a24 1821static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
9e4abcb5 1822{
1b7ecd11
SK
1823 int len = opt->len;
1824
1825 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1826 len++;
1827
1828 if (p && len != 0)
9e4abcb5 1829 {
73a08a24 1830 if (context && (opt->flags & DHOPT_ADDR))
1b7ecd11
SK
1831 {
1832 int j;
1833 struct in_addr *a = (struct in_addr *)opt->val;
1834 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
1835 {
1836 /* zero means "self" (but not in vendorclass options.) */
1837 if (a->s_addr == 0)
73a08a24 1838 memcpy(p, &context->local, INADDRSZ);
1b7ecd11
SK
1839 else
1840 memcpy(p, a, INADDRSZ);
1841 p += INADDRSZ;
1842 }
9e4abcb5 1843 }
1b7ecd11 1844 else
625ac28c
SK
1845 /* empty string may be extended to "\0" by null_term */
1846 memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
1b7ecd11
SK
1847 }
1848 return len;
9e4abcb5 1849}
7622fc06 1850
9e4abcb5
SK
1851static int in_list(unsigned char *list, int opt)
1852{
1853 int i;
6b01084f
SK
1854
1855 /* If no requested options, send everything, not nothing. */
a84fa1d0
SK
1856 if (!list)
1857 return 1;
1858
9e4abcb5
SK
1859 for (i = 0; list[i] != OPTION_END; i++)
1860 if (opt == list[i])
1861 return 1;
1862
1863 return 0;
1864}
1865
7de060b0 1866static struct dhcp_opt *option_find2(int opt)
9e4abcb5 1867{
7de060b0
SK
1868 struct dhcp_opt *opts;
1869
1870 for (opts = daemon->dhcp_opts; opts; opts = opts->next)
1871 if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
1872 return opts;
1873
8ef5ada2 1874 return NULL;
9e4abcb5
SK
1875}
1876
6b01084f
SK
1877/* mark vendor-encapsulated options which match the client-supplied or
1878 config-supplied vendor class */
1879static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1880{
1881 for (; dopt; dopt = dopt->next)
1882 {
7622fc06 1883 dopt->flags &= ~DHOPT_VENDOR_MATCH;
73a08a24 1884 if (opt && (dopt->flags & DHOPT_VENDOR))
6b01084f
SK
1885 {
1886 int i, len = 0;
73a08a24
SK
1887 if (dopt->u.vendor_class)
1888 len = strlen((char *)dopt->u.vendor_class);
6b01084f 1889 for (i = 0; i <= (option_len(opt) - len); i++)
73a08a24 1890 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
6b01084f 1891 {
7622fc06 1892 dopt->flags |= DHOPT_VENDOR_MATCH;
6b01084f
SK
1893 break;
1894 }
1895 }
1896 }
1897}
1898
8ef5ada2
SK
1899static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1900 struct dhcp_packet *mess, unsigned char *end, int null_term)
73a08a24 1901{
8ef5ada2 1902 int len, enc_len, ret = 0;
7622fc06 1903 struct dhcp_opt *start;
73a08a24
SK
1904 unsigned char *p;
1905
1906 /* find size in advance */
7622fc06
SK
1907 for (enc_len = 0, start = opt; opt; opt = opt->next)
1908 if (opt->flags & flag)
73a08a24
SK
1909 {
1910 int new = do_opt(opt, NULL, NULL, null_term) + 2;
8ef5ada2 1911 ret = 1;
73a08a24
SK
1912 if (enc_len + new <= 255)
1913 enc_len += new;
1914 else
1915 {
1916 p = free_space(mess, end, encap, enc_len);
1917 for (; start && start != opt; start = start->next)
7622fc06 1918 if (p && (start->flags & flag))
73a08a24
SK
1919 {
1920 len = do_opt(start, p + 2, NULL, null_term);
1921 *(p++) = start->opt;
1922 *(p++) = len;
1923 p += len;
1924 }
1925 enc_len = new;
1926 start = opt;
1927 }
1928 }
1929
1930 if (enc_len != 0 &&
1931 (p = free_space(mess, end, encap, enc_len + 1)))
1932 {
1933 for (; start; start = start->next)
7622fc06 1934 if (start->flags & flag)
73a08a24
SK
1935 {
1936 len = do_opt(start, p + 2, NULL, null_term);
1937 *(p++) = start->opt;
1938 *(p++) = len;
1939 p += len;
1940 }
1941 *p = OPTION_END;
1942 }
8ef5ada2
SK
1943
1944 return ret;
73a08a24
SK
1945}
1946
7622fc06 1947static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
91dccd09 1948{
7622fc06
SK
1949 unsigned char *p;
1950
1951 option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
1952 if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
1953 memcpy(p, uuid, 17);
1954}
1955
1956static int prune_vendor_opts(struct dhcp_netid *netid)
1957{
1958 int force = 0;
1959 struct dhcp_opt *opt;
9e038946 1960
7622fc06
SK
1961 /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
1962 for (opt = daemon->dhcp_opts; opt; opt = opt->next)
1963 if (opt->flags & DHOPT_VENDOR_MATCH)
1964 {
1965 if (!match_netid(opt->netid, netid, 1))
1966 opt->flags &= ~DHOPT_VENDOR_MATCH;
1967 else if (opt->flags & DHOPT_FORCE)
1968 force = 1;
1969 }
1970 return force;
1971}
1972
751d6f4a 1973static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
7622fc06
SK
1974{
1975#define NUM_OPTS 4
1976
1977 unsigned char *p, *q;
1978 struct pxe_service *service;
1979 static struct dhcp_opt *o, *ret;
1980 int i, j = NUM_OPTS - 1;
316e2730 1981 struct in_addr boot_server;
7622fc06
SK
1982
1983 /* We pass back references to these, hence they are declared static */
1984 static unsigned char discovery_control;
1985 static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
1986 static struct dhcp_opt *fake_opts = NULL;
1987
316e2730
SK
1988 /* Disable multicast, since we don't support it, and broadcast
1989 unless we need it */
1990 discovery_control = 3;
7622fc06
SK
1991
1992 ret = daemon->dhcp_opts;
1993
1994 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
1995 return ret;
1996
1997 for (i = 0; i < NUM_OPTS; i++)
1998 {
1999 fake_opts[i].flags = DHOPT_VENDOR_MATCH;
2000 fake_opts[i].netid = NULL;
2001 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
2002 }
2003
2004 /* create the data for the PXE_MENU and PXE_SERVERS options. */
2005 p = (unsigned char *)daemon->dhcp_buff;
8ef5ada2 2006 q = (unsigned char *)daemon->dhcp_buff3;
7622fc06
SK
2007
2008 for (i = 0, service = daemon->pxe_services; service; service = service->next)
2009 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
2010 {
2011 size_t len = strlen(service->menu);
2012 /* opt 43 max size is 255. encapsulated option has type and length
2013 bytes, so its max size is 253. */
2014 if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
2015 {
2016 *(p++) = service->type >> 8;
2017 *(p++) = service->type;
2018 *(p++) = len;
2019 memcpy(p, service->menu, len);
2020 p += len;
2021 i++;
2022 }
2023 else
2024 {
2025 toobig:
2026 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
2027 return daemon->dhcp_opts;
2028 }
2029
751d6f4a
SK
2030 boot_server = service->basename ? local :
2031 (service->sname ? a_record_from_hosts(service->sname, now) : service->server);
2032
316e2730 2033 if (boot_server.s_addr != 0)
7622fc06 2034 {
8ef5ada2 2035 if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
316e2730
SK
2036 goto toobig;
2037
2038 /* Boot service with known address - give it */
2039 *(q++) = service->type >> 8;
2040 *(q++) = service->type;
2041 *(q++) = 1;
2042 /* dest misaligned */
2043 memcpy(q, &boot_server.s_addr, INADDRSZ);
2044 q += INADDRSZ;
2045 }
2046 else if (service->type != 0)
2047 /* We don't know the server for a service type, so we'll
2048 allow the client to broadcast for it */
2049 discovery_control = 2;
7622fc06
SK
2050 }
2051
2052 /* if no prompt, wait forever if there's a choice */
2053 fake_prompt[0] = (i > 1) ? 255 : 0;
2054
2055 if (i == 0)
2056 discovery_control = 8; /* no menu - just use use mess->filename */
2057 else
2058 {
2059 ret = &fake_opts[j--];
2060 ret->len = p - (unsigned char *)daemon->dhcp_buff;
2061 ret->val = (unsigned char *)daemon->dhcp_buff;
2062 ret->opt = SUBOPT_PXE_MENU;
2063
8ef5ada2 2064 if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
7622fc06
SK
2065 {
2066 ret = &fake_opts[j--];
8ef5ada2
SK
2067 ret->len = q - (unsigned char *)daemon->dhcp_buff3;
2068 ret->val = (unsigned char *)daemon->dhcp_buff3;
7622fc06
SK
2069 ret->opt = SUBOPT_PXE_SERVERS;
2070 }
2071 }
2072
2073 for (o = daemon->dhcp_opts; o; o = o->next)
2074 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
2075 break;
2076
2077 if (!o)
2078 {
2079 ret = &fake_opts[j--];
2080 ret->len = sizeof(fake_prompt);
2081 ret->val = fake_prompt;
2082 ret->opt = SUBOPT_PXE_MENU_PROMPT;
2083 }
2084
316e2730
SK
2085 ret = &fake_opts[j--];
2086 ret->len = 1;
2087 ret->opt = SUBOPT_PXE_DISCOVERY;
2088 ret->val= &discovery_control;
2089
7622fc06
SK
2090 return ret;
2091}
2092
2093static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
2094{
1b7ecd11
SK
2095 memset(mess->sname, 0, sizeof(mess->sname));
2096 memset(mess->file, 0, sizeof(mess->file));
2097 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
2098 mess->siaddr.s_addr = 0;
2099}
cdeda28f 2100
7622fc06
SK
2101struct dhcp_boot *find_boot(struct dhcp_netid *netid)
2102{
2103 struct dhcp_boot *boot;
2104
2105 /* decide which dhcp-boot option we're using */
2106 for (boot = daemon->boot_config; boot; boot = boot->next)
2107 if (match_netid(boot->netid, netid, 0))
2108 break;
2109 if (!boot)
2110 /* No match, look for one without a netid */
2111 for (boot = daemon->boot_config; boot; boot = boot->next)
2112 if (match_netid(boot->netid, netid, 1))
2113 break;
2114
2115 return boot;
9e038946
SK
2116}
2117
1b7ecd11
SK
2118static void do_options(struct dhcp_context *context,
2119 struct dhcp_packet *mess,
7622fc06 2120 unsigned char *end,
1b7ecd11 2121 unsigned char *req_options,
9009d746 2122 char *hostname,
70c5e3e0 2123 char *domain,
1b7ecd11
SK
2124 struct dhcp_netid *netid,
2125 struct in_addr subnet_addr,
2126 unsigned char fqdn_flags,
7622fc06 2127 int null_term, int pxe_arch,
8ef5ada2 2128 unsigned char *uuid,
7de060b0 2129 int vendor_class_len,
ca85a282
SK
2130 time_t now,
2131 unsigned int lease_time,
2132 unsigned short fuzz)
1b7ecd11
SK
2133{
2134 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2135 struct dhcp_boot *boot;
7622fc06 2136 unsigned char *p;
f2621c7f 2137 int i, len, force_encap = 0;
1b7ecd11 2138 unsigned char f0 = 0, s0 = 0;
824af85b 2139 int done_file = 0, done_server = 0;
8ef5ada2 2140 int done_vendor_class = 0;
7de060b0
SK
2141 struct dhcp_netid *tagif;
2142 struct dhcp_netid_list *id_list;
2143
4cb1b320 2144 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
7d2b5c95
SK
2145 if (context)
2146 context->netid.next = NULL;
57f460de 2147 tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
7de060b0 2148
f2621c7f 2149 /* logging */
28866e95 2150 if (option_bool(OPT_LOG_OPTS) && req_options)
f2621c7f
SK
2151 {
2152 char *q = daemon->namebuff;
2153 for (i = 0; req_options[i] != OPTION_END; i++)
2154 {
4cb1b320 2155 char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
824af85b
SK
2156 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
2157 "%d%s%s%s",
2158 req_options[i],
4cb1b320
SK
2159 strlen(s) != 0 ? ":" : "",
2160 s,
824af85b 2161 req_options[i+1] == OPTION_END ? "" : ", ");
f2621c7f
SK
2162 if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2163 {
2164 q = daemon->namebuff;
7622fc06 2165 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
f2621c7f
SK
2166 }
2167 }
2168 }
2169
7de060b0
SK
2170 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
2171 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
2172 break;
2173 if (id_list)
2174 mess->flags |= htons(0x8000); /* force broadcast */
2175
73a08a24
SK
2176 if (context)
2177 mess->siaddr = context->local;
1b7ecd11
SK
2178
2179 /* See if we can send the boot stuff as options.
2180 To do this we need a requested option list, BOOTP
824af85b
SK
2181 and very old DHCP clients won't have this, we also
2182 provide an manual option to disable it.
1b7ecd11 2183 Some PXE ROMs have bugs (surprise!) and need zero-terminated
7622fc06 2184 names, so we always send those. */
7de060b0 2185 if ((boot = find_boot(tagif)))
91dccd09 2186 {
1b7ecd11 2187 if (boot->sname)
824af85b 2188 {
28866e95 2189 if (!option_bool(OPT_NO_OVERRIDE) &&
824af85b
SK
2190 req_options &&
2191 in_list(req_options, OPTION_SNAME))
1b7ecd11 2192 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
91dccd09 2193 else
824af85b 2194 strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
91dccd09 2195 }
1b7ecd11
SK
2196
2197 if (boot->file)
2198 {
28866e95 2199 if (!option_bool(OPT_NO_OVERRIDE) &&
824af85b
SK
2200 req_options &&
2201 in_list(req_options, OPTION_FILENAME))
1b7ecd11
SK
2202 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2203 else
824af85b 2204 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
1b7ecd11
SK
2205 }
2206
7de060b0 2207 if (boot->next_server.s_addr)
1b7ecd11 2208 mess->siaddr = boot->next_server;
7de060b0
SK
2209 else if (boot->tftp_sname)
2210 mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
91dccd09 2211 }
824af85b
SK
2212 else
2213 /* Use the values of the relevant options if no dhcp-boot given and
1f15b81d
SK
2214 they're not explicitly asked for as options. OPTION_END is used
2215 as an internal way to specify siaddr without using dhcp-boot, for use in
2216 dhcp-optsfile. */
824af85b 2217 {
8ef5ada2 2218 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
7de060b0 2219 (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
824af85b
SK
2220 {
2221 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2222 done_file = 1;
2223 }
7622fc06 2224
824af85b 2225 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
7de060b0 2226 (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
824af85b
SK
2227 {
2228 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2229 done_server = 1;
2230 }
1f15b81d 2231
7de060b0 2232 if ((opt = option_find2(OPTION_END)))
1f15b81d 2233 mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
824af85b 2234 }
7622fc06 2235
1b7ecd11
SK
2236 /* We don't want to do option-overload for BOOTP, so make the file and sname
2237 fields look like they are in use, even when they aren't. This gets restored
2238 at the end of this function. */
2239
28866e95 2240 if (!req_options || option_bool(OPT_NO_OVERRIDE))
91dccd09 2241 {
1b7ecd11
SK
2242 f0 = mess->file[0];
2243 mess->file[0] = 1;
2244 s0 = mess->sname[0];
2245 mess->sname[0] = 1;
91dccd09 2246 }
1b7ecd11
SK
2247
2248 /* At this point, if mess->sname or mess->file are zeroed, they are available
2249 for option overload, reserve space for the overload option. */
2250 if (mess->file[0] == 0 || mess->sname[0] == 0)
2251 end -= 3;
91dccd09 2252
3be34541
SK
2253 /* rfc3011 says this doesn't need to be in the requested options list. */
2254 if (subnet_addr.s_addr)
1b7ecd11 2255 option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
ca85a282
SK
2256
2257 if (lease_time != 0xffffffff)
2258 {
2259 unsigned int t1val = lease_time/2;
2260 unsigned int t2val = (lease_time*7)/8;
2261 unsigned int hval;
2262
2263 /* If set by user, sanity check, so not longer than lease. */
2264 if ((opt = option_find2(OPTION_T1)))
2265 {
2266 hval = ntohl(*((unsigned int *)opt->val));
2267 if (hval < lease_time && hval > 2)
2268 t1val = hval;
2269 }
2270
2271 if ((opt = option_find2(OPTION_T2)))
2272 {
2273 hval = ntohl(*((unsigned int *)opt->val));
2274 if (hval < lease_time && hval > 2)
2275 t2val = hval;
2276 }
2277
7c0f2543
SK
2278 /* ensure T1 is still < T2 */
2279 if (t2val <= t1val)
2280 t1val = t2val - 1;
2281
ca85a282
SK
2282 while (fuzz > (t1val/8))
2283 fuzz = fuzz/2;
2284
2285 t1val -= fuzz;
2286 t2val -= fuzz;
2287
ca85a282
SK
2288 option_put(mess, end, OPTION_T1, 4, t1val);
2289 option_put(mess, end, OPTION_T2, 4, t2val);
2290 }
2291
73a08a24
SK
2292 /* replies to DHCPINFORM may not have a valid context */
2293 if (context)
2294 {
7de060b0 2295 if (!option_find2(OPTION_NETMASK))
73a08a24 2296 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
9e4abcb5 2297
73a08a24
SK
2298 /* May not have a "guessed" broadcast address if we got no packets via a relay
2299 from this net yet (ie just unicast renewals after a restart */
2300 if (context->broadcast.s_addr &&
7de060b0 2301 !option_find2(OPTION_BROADCAST))
73a08a24
SK
2302 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2303
2304 /* Same comments as broadcast apply, and also may not be able to get a sensible
2305 default when using subnet select. User must configure by steam in that case. */
2306 if (context->router.s_addr &&
2307 in_list(req_options, OPTION_ROUTER) &&
7de060b0 2308 !option_find2(OPTION_ROUTER))
73a08a24
SK
2309 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2310
a21e27bc
SK
2311 if (daemon->port == NAMESERVER_PORT &&
2312 in_list(req_options, OPTION_DNSSERVER) &&
7de060b0 2313 !option_find2(OPTION_DNSSERVER))
73a08a24
SK
2314 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2315 }
2316
9009d746 2317 if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
7de060b0 2318 !option_find2(OPTION_DOMAINNAME))
9009d746 2319 option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
9e4abcb5 2320
824af85b 2321 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
3d8df260
SK
2322 if (hostname)
2323 {
824af85b 2324 if (in_list(req_options, OPTION_HOSTNAME) &&
7de060b0 2325 !option_find2(OPTION_HOSTNAME))
1b7ecd11 2326 option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
3d8df260
SK
2327
2328 if (fqdn_flags != 0)
2329 {
73a08a24
SK
2330 len = strlen(hostname) + 3;
2331
3d8df260
SK
2332 if (fqdn_flags & 0x04)
2333 len += 2;
cdeda28f
SK
2334 else if (null_term)
2335 len++;
2336
9009d746
SK
2337 if (domain)
2338 len += strlen(domain) + 1;
3f3adae6
RM
2339 else if (fqdn_flags & 0x04)
2340 len--;
2341
1b7ecd11 2342 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
3d8df260 2343 {
2e34ac14 2344 *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
3d8df260
SK
2345 *(p++) = 255;
2346 *(p++) = 255;
2347
2348 if (fqdn_flags & 0x04)
2349 {
2350 p = do_rfc1035_name(p, hostname);
9009d746 2351 if (domain)
3f3adae6
RM
2352 {
2353 p = do_rfc1035_name(p, domain);
2354 *p++ = 0;
2355 }
3d8df260
SK
2356 }
2357 else
2358 {
2359 memcpy(p, hostname, strlen(hostname));
2360 p += strlen(hostname);
9009d746 2361 if (domain)
3d8df260
SK
2362 {
2363 *(p++) = '.';
9009d746
SK
2364 memcpy(p, domain, strlen(domain));
2365 p += strlen(domain);
cdeda28f
SK
2366 }
2367 if (null_term)
2368 *(p++) = 0;
3d8df260
SK
2369 }
2370 }
2371 }
2372 }
2373
6b01084f 2374 for (opt = config_opts; opt; opt = opt->next)
9e4abcb5 2375 {
824af85b
SK
2376 int optno = opt->opt;
2377
7de060b0
SK
2378 /* netids match and not encapsulated? */
2379 if (!(opt->flags & DHOPT_TAGOK))
2380 continue;
2381
6b01084f 2382 /* was it asked for, or are we sending it anyway? */
824af85b 2383 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
6b01084f
SK
2384 continue;
2385
ca85a282 2386 /* prohibit some used-internally options. T1 and T2 already handled. */
824af85b
SK
2387 if (optno == OPTION_CLIENT_FQDN ||
2388 optno == OPTION_MAXMESSAGE ||
2389 optno == OPTION_OVERLOAD ||
2390 optno == OPTION_PAD ||
ca85a282
SK
2391 optno == OPTION_END ||
2392 optno == OPTION_T1 ||
2393 optno == OPTION_T2)
824af85b
SK
2394 continue;
2395
2396 if (optno == OPTION_SNAME && done_server)
2397 continue;
2398
2399 if (optno == OPTION_FILENAME && done_file)
6b01084f
SK
2400 continue;
2401
33820b7e
SK
2402 /* For the options we have default values on
2403 dhc-option=<optionno> means "don't include this option"
2404 not "include a zero-length option" */
2405 if (opt->len == 0 &&
824af85b
SK
2406 (optno == OPTION_NETMASK ||
2407 optno == OPTION_BROADCAST ||
2408 optno == OPTION_ROUTER ||
2409 optno == OPTION_DNSSERVER ||
2410 optno == OPTION_DOMAINNAME ||
2411 optno == OPTION_HOSTNAME))
33820b7e 2412 continue;
7622fc06
SK
2413
2414 /* vendor-class comes from elsewhere for PXE */
2415 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2416 continue;
824af85b 2417
7622fc06 2418 /* always force null-term for filename and servername - buggy PXE again. */
73a08a24 2419 len = do_opt(opt, NULL, context,
824af85b 2420 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
91dccd09 2421
824af85b 2422 if ((p = free_space(mess, end, optno, len)))
6b01084f 2423 {
73a08a24 2424 do_opt(opt, p, context,
824af85b
SK
2425 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2426
6b01084f
SK
2427 /* If we send a vendor-id, revisit which vendor-ops we consider
2428 it appropriate to send. */
824af85b 2429 if (optno == OPTION_VENDOR_ID)
8ef5ada2
SK
2430 {
2431 match_vendor_opts(p - 2, config_opts);
2432 done_vendor_class = 1;
2433 }
6b01084f
SK
2434 }
2435 }
91dccd09 2436
73a08a24
SK
2437 /* Now send options to be encapsulated in arbitrary options,
2438 eg dhcp-option=encap:172,17,.......
4cb1b320
SK
2439 Also handle vendor-identifying vendor-encapsulated options,
2440 dhcp-option = vi-encap:13,17,.......
73a08a24
SK
2441 The may be more that one "outer" to do, so group
2442 all the options which match each outer in turn. */
7622fc06
SK
2443 for (opt = config_opts; opt; opt = opt->next)
2444 opt->flags &= ~DHOPT_ENCAP_DONE;
2445
73a08a24 2446 for (opt = config_opts; opt; opt = opt->next)
316e2730
SK
2447 {
2448 int flags;
2449
2450 if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
2451 {
2452 int found = 0;
2453 struct dhcp_opt *o;
2454
2455 if (opt->flags & DHOPT_ENCAP_DONE)
2456 continue;
2457
2458 for (len = 0, o = config_opts; o; o = o->next)
2459 {
2460 int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
2461
2462 o->flags &= ~DHOPT_ENCAP_MATCH;
2463
2464 if (!(o->flags & flags) || opt->u.encap != o->u.encap)
2465 continue;
2466
2467 o->flags |= DHOPT_ENCAP_DONE;
7de060b0 2468 if (match_netid(o->netid, tagif, 1) &&
316e2730
SK
2469 ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
2470 {
2471 o->flags |= DHOPT_ENCAP_MATCH;
2472 found = 1;
2473 len += do_opt(o, NULL, NULL, 0) + 2;
2474 }
2475 }
2476
2477 if (found)
2478 {
2479 if (flags & DHOPT_ENCAPSULATE)
2480 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
2481 else if (len > 250)
2482 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
2483 else if ((p = free_space(mess, end, OPTION_VENDOR_IDENT_OPT, len + 5)))
2484 {
2485 int swap_ent = htonl(opt->u.encap);
2486 memcpy(p, &swap_ent, 4);
2487 p += 4;
2488 *(p++) = len;
2489 for (o = config_opts; o; o = o->next)
2490 if (o->flags & DHOPT_ENCAP_MATCH)
2491 {
2492 len = do_opt(o, p + 2, NULL, 0);
2493 *(p++) = o->opt;
2494 *(p++) = len;
2495 p += len;
2496 }
2497 }
2498 }
2499 }
2500 }
73a08a24 2501
7de060b0 2502 force_encap = prune_vendor_opts(tagif);
8ef5ada2 2503
316e2730 2504 if (context && pxe_arch != -1)
7622fc06
SK
2505 {
2506 pxe_misc(mess, end, uuid);
751d6f4a 2507 config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
7622fc06 2508 }
9e4abcb5 2509
8ef5ada2
SK
2510 if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
2511 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term) &&
2512 pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
2513 (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
2514 /* If we send vendor encapsulated options, and haven't already sent option 60,
2515 echo back the value we got from the client. */
2516 memcpy(p, daemon->dhcp_buff3, vendor_class_len);
2517
7622fc06 2518 /* restore BOOTP anti-overload hack */
28866e95 2519 if (!req_options || option_bool(OPT_NO_OVERRIDE))
1b7ecd11
SK
2520 {
2521 mess->file[0] = f0;
2522 mess->sname[0] = s0;
2523 }
2524}
9e4abcb5 2525
7622fc06
SK
2526#endif
2527
2528
2529
2530
2531
2532
2533