]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/rfc2131.c
Tweak immediately previous patch.
[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
549b1a47
SK
808 for (; context; context = context->current)
809 if (match_netid(context->filter, tagif_netid, 1) &&
810 is_same_net(mess->ciaddr, context->start, context->netmask))
811 break;
7622fc06 812
549b1a47
SK
813 if (!service || !service->basename || !context)
814 return 0;
815
7622fc06
SK
816 clear_packet(mess, end);
817
818 mess->yiaddr = mess->ciaddr;
819 mess->ciaddr.s_addr = 0;
751d6f4a
SK
820 if (service->sname)
821 mess->siaddr = a_record_from_hosts(service->sname, now);
822 else if (service->server.s_addr != 0)
7622fc06
SK
823 mess->siaddr = service->server;
824 else
825 mess->siaddr = context->local;
826
827 snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
828 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
829 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
830 pxe_misc(mess, end, uuid);
831
8ef5ada2 832 prune_vendor_opts(tagif_netid);
7622fc06
SK
833 opt71.val = save71;
834 opt71.opt = SUBOPT_PXE_BOOT_ITEM;
835 opt71.len = 4;
836 opt71.flags = DHOPT_VENDOR_MATCH;
837 opt71.netid = NULL;
838 opt71.next = daemon->dhcp_opts;
839 do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
840
8c0b73d3 841 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
4cb1b320 842 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 843 return dhcp_packet_size(mess, agent_id, real_end);
7622fc06
SK
844 }
845
846 if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
847 {
848 pxearch = option_uint(opt, 0, 2);
849
316e2730 850 /* proxy DHCP here. */
28866e95 851 if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
7622fc06 852 {
28866e95 853 struct dhcp_context *tmp;
7622fc06 854
28866e95
SK
855 for (tmp = context; tmp; tmp = tmp->current)
856 if ((tmp->flags & CONTEXT_PROXY) &&
857 match_netid(tmp->filter, tagif_netid, 1))
858 break;
859
860 if (tmp)
7622fc06 861 {
a37cd7aa
SK
862 struct dhcp_boot *boot;
863
864 if (tmp->netid.net)
865 {
866 tmp->netid.next = netid;
867 tagif_netid = run_tag_if(&tmp->netid);
868 }
869
870 boot = find_boot(tagif_netid);
871
28866e95
SK
872 mess->yiaddr.s_addr = 0;
873 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
874 {
875 mess->ciaddr.s_addr = 0;
876 mess->flags |= htons(0x8000); /* broadcast */
877 }
878
879 clear_packet(mess, end);
880
881 /* Provide the bootfile here, for gPXE, and in case we have no menu items
882 and set discovery_control = 8 */
883 if (boot)
884 {
7de060b0 885 if (boot->next_server.s_addr)
28866e95 886 mess->siaddr = boot->next_server;
7de060b0
SK
887 else if (boot->tftp_sname)
888 mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
28866e95
SK
889
890 if (boot->file)
891 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
892 }
7622fc06 893
28866e95
SK
894 option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
895 mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
62018e1f 896 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
28866e95
SK
897 pxe_misc(mess, end, uuid);
898 prune_vendor_opts(tagif_netid);
62018e1f 899 do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
28866e95 900
8c0b73d3 901 log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
4cb1b320 902 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 903 return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
7622fc06 904 }
7622fc06
SK
905 }
906 }
907 }
908
909 /* if we're just a proxy server, go no further */
316e2730 910 if ((context->flags & CONTEXT_PROXY) || pxe)
7622fc06
SK
911 return 0;
912
bb01cb96 913 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
a84fa1d0 914 {
3d8df260 915 req_options = (unsigned char *)daemon->dhcp_buff2;
1a6bca81 916 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
bb01cb96 917 req_options[option_len(opt)] = OPTION_END;
a84fa1d0
SK
918 }
919
3be34541 920 switch (mess_type)
9e4abcb5 921 {
44a2a316 922 case DHCPDECLINE:
bb01cb96 923 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
73a08a24 924 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
44a2a316 925 return 0;
1a6bca81 926
44a2a316 927 /* sanitise any message. Paranoid? Moi? */
f2621c7f 928 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
44a2a316 929
bb01cb96 930 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
44a2a316
SK
931 return 0;
932
8c0b73d3 933 log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
44a2a316
SK
934
935 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
936 lease_prune(lease, now);
937
33820b7e 938 if (have_config(config, CONFIG_ADDR) &&
44a2a316 939 config->addr.s_addr == option_addr(opt).s_addr)
9e4abcb5 940 {
849a8357 941 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
7622fc06 942 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
f2621c7f 943 inet_ntoa(config->addr), daemon->dhcp_buff);
849a8357
SK
944 config->flags |= CONFIG_DECLINED;
945 config->decline_time = now;
9e4abcb5 946 }
feba5c1d
SK
947 else
948 /* make sure this host gets a different address next time. */
36717eee
SK
949 for (; context; context = context->current)
950 context->addr_epoch++;
44a2a316
SK
951
952 return 0;
953
954 case DHCPRELEASE:
8ef5ada2 955 if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
1697269c 956 !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
73a08a24 957 option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
44a2a316
SK
958 return 0;
959
44a2a316
SK
960 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
961 lease_prune(lease, now);
fd9fa481 962 else
b8187c80 963 message = _("unknown lease");
fd9fa481 964
8c0b73d3 965 log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
44a2a316 966
9e4abcb5
SK
967 return 0;
968
969 case DHCPDISCOVER:
5e9e0efb
SK
970 if (ignore || have_config(config, CONFIG_DISABLE))
971 {
cc1a29e2
SK
972 if (option_bool(OPT_QUIET_DHCP))
973 return 0;
b8187c80 974 message = _("ignored");
5e9e0efb
SK
975 opt = NULL;
976 }
977 else
978 {
979 struct in_addr addr, conf;
980
1a6bca81
SK
981 addr.s_addr = conf.s_addr = 0;
982
5e9e0efb
SK
983 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
984 addr = option_addr(opt);
985
5e9e0efb
SK
986 if (have_config(config, CONFIG_ADDR))
987 {
849a8357
SK
988 char *addrs = inet_ntoa(config->addr);
989
9009d746
SK
990 if ((ltmp = lease_find_by_addr(config->addr)) &&
991 ltmp != lease &&
992 !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1b7ecd11
SK
993 {
994 int len;
995 unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
996 ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
7622fc06 997 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
5aabfc78 998 addrs, print_mac(daemon->namebuff, mac, len));
1b7ecd11 999 }
5e9e0efb
SK
1000 else
1001 {
1002 struct dhcp_context *tmp;
1003 for (tmp = context; tmp; tmp = tmp->current)
849a8357 1004 if (context->router.s_addr == config->addr.s_addr)
5e9e0efb
SK
1005 break;
1006 if (tmp)
7622fc06 1007 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
849a8357
SK
1008 else if (have_config(config, CONFIG_DECLINED) &&
1009 difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
7622fc06 1010 my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
5e9e0efb
SK
1011 else
1012 conf = config->addr;
1013 }
1014 }
1015
1016 if (conf.s_addr)
1017 mess->yiaddr = conf;
7622fc06 1018 else if (lease &&
8ef5ada2 1019 address_available(context, lease->addr, tagif_netid) &&
7622fc06 1020 !config_find_by_address(daemon->dhcp_conf, lease->addr))
5e9e0efb 1021 mess->yiaddr = lease->addr;
8ef5ada2 1022 else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
5e9e0efb
SK
1023 !config_find_by_address(daemon->dhcp_conf, addr))
1024 mess->yiaddr = addr;
5aabfc78
SK
1025 else if (emac_len == 0)
1026 message = _("no unique-id");
8ef5ada2 1027 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))
5e9e0efb
SK
1028 message = _("no address available");
1029 }
1030
8c0b73d3 1031 log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);
3d8df260 1032
8ef5ada2 1033 if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
33820b7e 1034 return 0;
e17fb629 1035
cdeda28f 1036 if (context->netid.net)
59353a6b
SK
1037 {
1038 context->netid.next = netid;
7de060b0 1039 tagif_netid = run_tag_if(&context->netid);
59353a6b 1040 }
7de060b0 1041
4cb1b320 1042 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 1043
8c0b73d3 1044 log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
7de060b0 1045
824af85b 1046 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
7622fc06 1047 clear_packet(mess, end);
1b7ecd11 1048 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
73a08a24 1049 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1050 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
a84fa1d0 1051 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
9009d746 1052 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
ca85a282 1053 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
9e4abcb5 1054
7de060b0 1055 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1056
1057 case DHCPREQUEST:
26128d27
SK
1058 if (ignore || have_config(config, CONFIG_DISABLE))
1059 return 0;
bb01cb96 1060 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
9e4abcb5
SK
1061 {
1062 /* SELECTING or INIT_REBOOT */
44a2a316 1063 mess->yiaddr = option_addr(opt);
9e4abcb5 1064
4011c4e0
SK
1065 /* send vendor and user class info for new or recreated lease */
1066 do_classes = 1;
1067
bb01cb96 1068 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
3be34541
SK
1069 {
1070 /* SELECTING */
832af0ba
SK
1071 selecting = 1;
1072
1a6bca81
SK
1073 if (override.s_addr != 0)
1074 {
1075 if (option_addr(opt).s_addr != override.s_addr)
1076 return 0;
1077 }
9009d746 1078 else
1a6bca81
SK
1079 {
1080 for (; context; context = context->current)
1081 if (context->local.s_addr == option_addr(opt).s_addr)
1082 break;
1083
1084 if (!context)
9009d746 1085 {
7de060b0
SK
1086 /* Handle very strange configs where clients have more than one route to the server.
1087 If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
1088 Have to set override to make sure we echo back the correct server-id */
1089 struct irec *intr;
1090
115ac3e4 1091 enumerate_interfaces(0);
7de060b0
SK
1092
1093 for (intr = daemon->interfaces; intr; intr = intr->next)
1094 if (intr->addr.sa.sa_family == AF_INET &&
1095 intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
1096 intr->tftp_ok)
1097 break;
1098
1099 if (intr)
1100 override = intr->addr.in.sin_addr;
1101 else
1102 {
1103 /* In auth mode, a REQUEST sent to the wrong server
1104 should be faulted, so that the client establishes
1105 communication with us, otherwise, silently ignore. */
1106 if (!option_bool(OPT_AUTHORITATIVE))
1107 return 0;
1108 message = _("wrong server-ID");
1109 }
9009d746 1110 }
1a6bca81 1111 }
e17fb629 1112
3be34541
SK
1113 /* If a lease exists for this host and another address, squash it. */
1114 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1115 {
1116 lease_prune(lease, now);
1117 lease = NULL;
1118 }
3be34541
SK
1119 }
1120 else
9e4abcb5 1121 {
3be34541 1122 /* INIT-REBOOT */
28866e95 1123 if (!lease && !option_bool(OPT_AUTHORITATIVE))
3be34541
SK
1124 return 0;
1125
fd9fa481 1126 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
8ef5ada2 1127 message = _("wrong address");
9e4abcb5 1128 }
44a2a316
SK
1129 }
1130 else
1131 {
1132 /* RENEWING or REBINDING */
cdeda28f
SK
1133 /* Check existing lease for this address.
1134 We allow it to be missing if dhcp-authoritative mode
1135 as long as we can allocate the lease now - checked below.
1136 This makes for a smooth recovery from a lost lease DB */
1137 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
28866e95 1138 (!lease && !option_bool(OPT_AUTHORITATIVE)))
b8187c80 1139 {
28866e95
SK
1140 /* A client rebinding will broadcast the request, so we may see it even
1141 if the lease is held by another server. Just ignore it in that case.
1142 If the request is unicast to us, then somethings wrong, NAK */
1143 if (!unicast_dest)
1144 return 0;
b8187c80
SK
1145 message = _("lease not found");
1146 /* ensure we broadcast NAK */
1147 unicast_dest = 0;
1148 }
8ef5ada2 1149
a84fa1d0
SK
1150 /* desynchronise renewals */
1151 fuzz = rand16();
3be34541 1152 mess->yiaddr = mess->ciaddr;
44a2a316
SK
1153 }
1154
8c0b73d3 1155 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
e17fb629 1156
dfa666f2
SK
1157 if (!message)
1158 {
1159 struct dhcp_config *addr_config;
5e9e0efb
SK
1160 struct dhcp_context *tmp = NULL;
1161
1162 if (have_config(config, CONFIG_ADDR))
1163 for (tmp = context; tmp; tmp = tmp->current)
849a8357 1164 if (context->router.s_addr == config->addr.s_addr)
5e9e0efb 1165 break;
aedef830 1166
8ef5ada2 1167 if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
b8187c80 1168 {
e17fb629 1169 /* If a machine moves networks whilst it has a lease, we catch that here. */
b8187c80
SK
1170 message = _("wrong network");
1171 /* ensure we broadcast NAK */
1172 unicast_dest = 0;
1173 }
1174
fd9fa481 1175 /* Check for renewal of a lease which is outside the allowed range. */
8ef5ada2 1176 else if (!address_available(context, mess->yiaddr, tagif_netid) &&
dfa666f2 1177 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
b8187c80 1178 message = _("address not available");
e17fb629 1179
dfa666f2
SK
1180 /* Check if a new static address has been configured. Be very sure that
1181 when the client does DISCOVER, it will get the static address, otherwise
1182 an endless protocol loop will ensue. */
832af0ba 1183 else if (!tmp && !selecting &&
5e9e0efb 1184 have_config(config, CONFIG_ADDR) &&
849a8357
SK
1185 (!have_config(config, CONFIG_DECLINED) ||
1186 difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
fd9fa481
SK
1187 config->addr.s_addr != mess->yiaddr.s_addr &&
1188 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
b8187c80 1189 message = _("static lease available");
dfa666f2
SK
1190
1191 /* Check to see if the address is reserved as a static address for another host */
3be34541 1192 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
b8187c80 1193 message = _("address reserved");
feba5c1d 1194
9009d746
SK
1195 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1196 {
1197 /* If a host is configured with more than one MAC address, it's OK to 'nix
1198 a lease from one of it's MACs to give the address to another. */
1199 if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1200 {
7622fc06 1201 my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
9009d746
SK
1202 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
1203 inet_ntoa(ltmp->addr));
1204 lease = ltmp;
1205 }
1697269c 1206 else
9009d746
SK
1207 message = _("address in use");
1208 }
1209
1210 if (!message)
1211 {
1212 if (emac_len == 0)
1213 message = _("no unique-id");
1214
1215 else if (!lease)
1216 {
52b92f4d 1217 if ((lease = lease4_allocate(mess->yiaddr)))
9009d746
SK
1218 do_classes = 1;
1219 else
1220 message = _("no leases left");
1221 }
1697269c 1222 }
fd9fa481 1223 }
1697269c 1224
44a2a316
SK
1225 if (message)
1226 {
8c0b73d3 1227 log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
44a2a316 1228
1b7ecd11 1229 mess->yiaddr.s_addr = 0;
7622fc06 1230 clear_packet(mess, end);
1b7ecd11 1231 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
73a08a24 1232 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1233 option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
b8187c80
SK
1234 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
1235 a distant subnet which unicast a REQ to us won't work. */
1236 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
1237 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1238 {
1239 mess->flags |= htons(0x8000); /* broadcast */
1240 mess->ciaddr.s_addr = 0;
1241 }
44a2a316 1242 }
fd9fa481 1243 else
44a2a316 1244 {
316e2730
SK
1245 if (context->netid.net)
1246 {
1247 context->netid.next = netid;
7de060b0 1248 tagif_netid = run_tag_if( &context->netid);
316e2730 1249 }
7de060b0 1250
4cb1b320 1251 log_tags(tagif_netid, ntohl(mess->xid));
8ef5ada2 1252
dcffad2a 1253 if (do_classes)
8ef5ada2 1254 {
dcffad2a 1255 /* pick up INIT-REBOOT events. */
4cb1b320 1256 lease->flags |= LEASE_CHANGED;
39bec5ff 1257
dcffad2a
SK
1258#ifdef HAVE_SCRIPT
1259 if (daemon->lease_change_command)
8ef5ada2 1260 {
dcffad2a
SK
1261 struct dhcp_netid *n;
1262
1263 if (mess->giaddr.s_addr)
1264 lease->giaddr = mess->giaddr;
1265
1266 free(lease->extradata);
1267 lease->extradata = NULL;
1268 lease->extradata_size = lease->extradata_len = 0;
1269
1270 add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
1271 add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
1272 add_extradata_opt(lease, oui);
1273 add_extradata_opt(lease, serial);
1274 add_extradata_opt(lease, class);
dd1721c7
SK
1275
1276 if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
1277 {
1278 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
1279 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
1280 add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
1281 }
1282 else
1283 {
1284 add_extradata_opt(lease, NULL);
1285 add_extradata_opt(lease, NULL);
1286 add_extradata_opt(lease, NULL);
1287 }
1288
dcffad2a
SK
1289 /* space-concat tag set */
1290 if (!tagif_netid)
1291 add_extradata_opt(lease, NULL);
1292 else
1293 for (n = tagif_netid; n; n = n->next)
1294 {
1295 struct dhcp_netid *n1;
1296 /* kill dupes */
1297 for (n1 = n->next; n1; n1 = n1->next)
1298 if (strcmp(n->net, n1->net) == 0)
1299 break;
1300 if (!n1)
1301 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1302 }
1303
1304 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1305 {
1306 int len = option_len(opt);
1307 unsigned char *ucp = option_ptr(opt, 0);
1308 /* If the user-class option started as counted strings, the first byte will be zero. */
1309 if (len != 0 && ucp[0] == 0)
1310 ucp++, len--;
1311 lease_add_extradata(lease, ucp, len, 0);
1312 }
8ef5ada2 1313 }
316e2730 1314#endif
dcffad2a 1315 }
8ef5ada2
SK
1316
1317 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1318 {
1319 domain = get_domain(mess->yiaddr);
b8187c80
SK
1320 hostname = client_hostname;
1321 hostname_auth = 1;
1322 }
8ef5ada2 1323
824af85b 1324 time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
a9ab732e 1325 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
8ef5ada2 1326
832af0ba
SK
1327 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1328 if (!hostname_auth)
1329 {
1330 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
8ef5ada2 1331 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
832af0ba
SK
1332 break;
1333 if (id_list)
1334 hostname = NULL;
1335 }
8ef5ada2
SK
1336
1337 /* Last ditch, if configured, generate hostname from mac address */
1338 if (!hostname && emac_len != 0)
1339 {
1340 for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
1341 if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1342 break;
1343 if (id_list)
1344 {
1345 int i;
1346
1347 hostname = daemon->dhcp_buff;
1348 /* buffer is 256 bytes, 3 bytes per octet */
1349 for (i = 0; (i < emac_len) && (i < 80); i++)
1350 hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
1351 hostname = daemon->dhcp_buff;
1352 }
1353 }
1354
fd9fa481 1355 if (hostname)
70c5e3e0 1356 lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
832af0ba 1357
5e9e0efb 1358 lease_set_expires(lease, time, now);
353ae4d2 1359 lease_set_interface(lease, int_index, now);
1a6bca81
SK
1360
1361 if (override.s_addr != 0)
1362 lease->override = override;
1363 else
1364 override = lease->override;
1365
8c0b73d3 1366 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
832af0ba 1367
7622fc06 1368 clear_packet(mess, end);
1b7ecd11 1369 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
73a08a24 1370 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1b7ecd11 1371 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
9009d746 1372 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
ca85a282 1373 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
44a2a316 1374 }
fd9fa481 1375
7de060b0 1376 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1377
1378 case DHCPINFORM:
26128d27 1379 if (ignore || have_config(config, CONFIG_DISABLE))
b8187c80 1380 message = _("ignored");
33820b7e 1381
8c0b73d3 1382 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
a84fa1d0 1383
73a08a24 1384 if (message || mess->ciaddr.s_addr == 0)
a84fa1d0 1385 return 0;
73a08a24
SK
1386
1387 /* For DHCPINFORM only, cope without a valid context */
8ef5ada2 1388 context = narrow_context(context, mess->ciaddr, tagif_netid);
9e4abcb5 1389
5aabfc78
SK
1390 /* Find a least based on IP address if we didn't
1391 get one from MAC address/client-d */
1392 if (!lease &&
1393 (lease = lease_find_by_addr(mess->ciaddr)) &&
1394 lease->hostname)
1395 hostname = lease->hostname;
1396
0f371f9e
SK
1397 if (!hostname)
1398 hostname = host_from_dns(mess->ciaddr);
5aabfc78 1399
73a08a24 1400 if (context && context->netid.net)
59353a6b
SK
1401 {
1402 context->netid.next = netid;
4cb1b320 1403 tagif_netid = run_tag_if(&context->netid);
59353a6b 1404 }
7de060b0 1405
4cb1b320 1406 log_tags(tagif_netid, ntohl(mess->xid));
7de060b0 1407
8c0b73d3 1408 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
1a6bca81 1409
3927da46
SK
1410 if (lease)
1411 {
d1a5975f 1412 lease_set_interface(lease, int_index, now);
3927da46
SK
1413 if (override.s_addr != 0)
1414 lease->override = override;
1415 else
1416 override = lease->override;
1417 }
1418
7622fc06 1419 clear_packet(mess, end);
1b7ecd11 1420 option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
73a08a24 1421 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
aa63a21c
SK
1422
1423 /* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
1424 we supply a utility which makes DHCPINFORM requests to get this information.
1425 Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
1426 which won't be true for ordinary clients, but will be true for the
1427 dhcp_lease_time utility. */
1428 if (lease && in_list(req_options, OPTION_LEASE_TIME))
1429 {
1430 if (lease->expires == 0)
1431 time = 0xffffffff;
1432 else
1433 time = (unsigned int)difftime(lease->expires, now);
1434 option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1435 }
1436
9009d746 1437 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
ca85a282 1438 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
9e4abcb5 1439
5aabfc78 1440 *is_inform = 1; /* handle reply differently */
7de060b0 1441 return dhcp_packet_size(mess, agent_id, real_end);
9e4abcb5
SK
1442 }
1443
1444 return 0;
1445}
1446
6b01084f
SK
1447/* find a good value to use as MAC address for logging and address-allocation hashing.
1448 This is normally just the chaddr field from the DHCP packet,
1449 but eg Firewire will have hlen == 0 and use the client-id instead.
1450 This could be anything, but will normally be EUI64 for Firewire.
1451 We assume that if the first byte of the client-id equals the htype byte
1452 then the client-id is using the usual encoding and use the rest of the
1453 client-id: if not we can use the whole client-id. This should give
1454 sane MAC address logs. */
9009d746 1455unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
6b01084f
SK
1456 int clid_len, unsigned char *clid, int *len_out)
1457{
1458 if (hwlen == 0 && clid && clid_len > 3)
1459 {
1460 if (clid[0] == hwtype)
1461 {
1462 *len_out = clid_len - 1 ;
1463 return clid + 1;
1464 }
1465
1466#if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1467 if (clid[0] == ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1468 {
1469 *len_out = clid_len - 1 ;
1470 return clid + 1;
1471 }
1472#endif
1473
1474 *len_out = clid_len;
1475 return clid;
1476 }
1477
1478 *len_out = hwlen;
1479 return hwaddr;
1480}
1481
824af85b 1482static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
9e4abcb5 1483{
5e9e0efb
SK
1484 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1485
1486 if (opt)
1487 {
7622fc06 1488 unsigned int req_time = option_uint(opt, 0, 4);
5e9e0efb
SK
1489 if (req_time < 120 )
1490 req_time = 120; /* sanity */
1491 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1492 time = req_time;
1493 }
3d8df260 1494
5e9e0efb
SK
1495 return time;
1496}
1497
73a08a24 1498static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1a6bca81 1499{
73a08a24 1500 if (override.s_addr != 0)
1a6bca81 1501 return override;
7de060b0 1502 else if (context && context->local.s_addr != 0)
1a6bca81 1503 return context->local;
73a08a24
SK
1504 else
1505 return fallback;
1a6bca81
SK
1506}
1507
f2621c7f
SK
1508static int sanitise(unsigned char *opt, char *buf)
1509{
1510 char *p;
1511 int i;
1512
1513 *buf = 0;
1514
1515 if (!opt)
1516 return 0;
1517
1a6bca81 1518 p = option_ptr(opt, 0);
f2621c7f
SK
1519
1520 for (i = option_len(opt); i > 0; i--)
1521 {
1522 char c = *p++;
824af85b 1523 if (isprint((int)c))
f2621c7f
SK
1524 *buf++ = c;
1525 }
1526 *buf = 0; /* add terminator */
1527
1528 return 1;
1529}
1530
316e2730 1531#ifdef HAVE_SCRIPT
316e2730
SK
1532static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
1533{
1534 if (!opt)
ceae00dd 1535 lease_add_extradata(lease, NULL, 0, 0);
316e2730 1536 else
ceae00dd 1537 lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
316e2730
SK
1538}
1539#endif
1540
5aabfc78 1541static void log_packet(char *type, void *addr, unsigned char *ext_mac,
8c0b73d3 1542 int mac_len, char *interface, char *string, char *err, u32 xid)
5e9e0efb 1543{
1697269c 1544 struct in_addr a;
7622fc06 1545
227ddad9 1546 if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
8c0b73d3
KDB
1547 return;
1548
1697269c
SK
1549 /* addr may be misaligned */
1550 if (addr)
1551 memcpy(&a, addr, sizeof(a));
1552
7622fc06
SK
1553 print_mac(daemon->namebuff, ext_mac, mac_len);
1554
28866e95 1555 if(option_bool(OPT_LOG_OPTS))
8c0b73d3 1556 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
7622fc06
SK
1557 ntohl(xid),
1558 type,
1559 interface,
1560 addr ? inet_ntoa(a) : "",
1561 addr ? " " : "",
1562 daemon->namebuff,
8c0b73d3
KDB
1563 string ? string : "",
1564 err ? err : "");
7622fc06 1565 else
8c0b73d3 1566 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
7622fc06
SK
1567 type,
1568 interface,
1569 addr ? inet_ntoa(a) : "",
1570 addr ? " " : "",
1571 daemon->namebuff,
8c0b73d3
KDB
1572 string ? string : "",
1573 err ? err : "");
f2621c7f
SK
1574}
1575
7622fc06 1576static void log_options(unsigned char *start, u32 xid)
f2621c7f
SK
1577{
1578 while (*start != OPTION_END)
1579 {
4cb1b320 1580 char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
7622fc06 1581
4cb1b320
SK
1582 my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
1583 ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
f2621c7f
SK
1584 start += start[1] + 2;
1585 }
9e4abcb5
SK
1586}
1587
1b7ecd11
SK
1588static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1589{
1a6bca81 1590 while (1)
1b7ecd11 1591 {
1a6bca81
SK
1592 if (p > end)
1593 return NULL;
1594 else if (*p == OPTION_END)
1595 return opt == OPTION_END ? p : NULL;
1b7ecd11
SK
1596 else if (*p == OPTION_PAD)
1597 p++;
1598 else
1599 {
1600 int opt_len;
1a6bca81 1601 if (p > end - 2)
1b7ecd11
SK
1602 return NULL; /* malformed packet */
1603 opt_len = option_len(p);
1a6bca81 1604 if (p > end - (2 + opt_len))
1b7ecd11
SK
1605 return NULL; /* malformed packet */
1606 if (*p == opt && opt_len >= minsize)
1607 return p;
1608 p += opt_len + 2;
1609 }
1610 }
1b7ecd11
SK
1611}
1612
1613static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
1614{
1615 unsigned char *ret, *overload;
1616
1617 /* skip over DHCP cookie; */
1618 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
1619 return ret;
1620
1621 /* look for overload option. */
1622 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
1623 return NULL;
1624
1625 /* Can we look in filename area ? */
1626 if ((overload[2] & 1) &&
1627 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
1628 return ret;
1629
1630 /* finally try sname area */
1631 if ((overload[2] & 2) &&
1632 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
1633 return ret;
1634
1635 return NULL;
1636}
1637
4cb1b320 1638static struct in_addr option_addr(unsigned char *opt)
9e4abcb5 1639{
4cb1b320 1640 /* this worries about unaligned data in the option. */
9e4abcb5
SK
1641 /* struct in_addr is network byte order */
1642 struct in_addr ret;
1643
4cb1b320 1644 memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
9e4abcb5
SK
1645
1646 return ret;
1647}
1648
7622fc06 1649static unsigned int option_uint(unsigned char *opt, int offset, int size)
9e4abcb5
SK
1650{
1651 /* this worries about unaligned data and byte order */
44a2a316
SK
1652 unsigned int ret = 0;
1653 int i;
7622fc06 1654 unsigned char *p = option_ptr(opt, offset);
9e4abcb5 1655
44a2a316
SK
1656 for (i = 0; i < size; i++)
1657 ret = (ret << 8) | *p++;
1658
1659 return ret;
9e4abcb5
SK
1660}
1661
1b7ecd11 1662static unsigned char *dhcp_skip_opts(unsigned char *start)
9e4abcb5 1663{
1b7ecd11
SK
1664 while (*start != 0)
1665 start += start[1] + 2;
1666 return start;
1667}
26128d27 1668
1b7ecd11
SK
1669/* only for use when building packet: doesn't check for bad data. */
1670static unsigned char *find_overload(struct dhcp_packet *mess)
1671{
1672 unsigned char *p = &mess->options[0] + sizeof(u32);
26128d27 1673
1b7ecd11 1674 while (*p != 0)
26128d27 1675 {
1b7ecd11
SK
1676 if (*p == OPTION_OVERLOAD)
1677 return p;
1678 p += p[1] + 2;
26128d27 1679 }
1b7ecd11 1680 return NULL;
9e4abcb5
SK
1681}
1682
7de060b0
SK
1683static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
1684{
1685 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
1686 unsigned char *overload;
1687 size_t ret;
1688
1689 /* move agent_id back down to the end of the packet */
1690 if (agent_id)
1691 {
1692 memmove(p, agent_id, real_end - agent_id);
1693 p += real_end - agent_id;
1694 memset(p, 0, real_end - p); /* in case of overlap */
1695 }
1696
1b7ecd11 1697 /* add END options to the regions. */
7622fc06
SK
1698 overload = find_overload(mess);
1699
1700 if (overload && (option_uint(overload, 0, 1) & 1))
b8187c80 1701 {
7622fc06 1702 *dhcp_skip_opts(mess->file) = OPTION_END;
28866e95 1703 if (option_bool(OPT_LOG_OPTS))
7622fc06
SK
1704 log_options(mess->file, mess->xid);
1705 }
28866e95 1706 else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
7622fc06
SK
1707 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
1708
1709 if (overload && (option_uint(overload, 0, 1) & 2))
1710 {
1711 *dhcp_skip_opts(mess->sname) = OPTION_END;
28866e95 1712 if (option_bool(OPT_LOG_OPTS))
7622fc06 1713 log_options(mess->sname, mess->xid);
b8187c80 1714 }
28866e95 1715 else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
7622fc06
SK
1716 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
1717
b8187c80 1718
1b7ecd11 1719 *p++ = OPTION_END;
824af85b 1720
28866e95 1721 if (option_bool(OPT_LOG_OPTS))
7622fc06
SK
1722 {
1723 if (mess->siaddr.s_addr != 0)
1724 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
1725
8ef5ada2
SK
1726 if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
1727 my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
1728
7622fc06
SK
1729 log_options(&mess->options[0] + sizeof(u32), mess->xid);
1730 }
1b7ecd11
SK
1731
1732 ret = (size_t)(p - (unsigned char *)mess);
1733
1734 if (ret < MIN_PACKETSZ)
1735 ret = MIN_PACKETSZ;
8ef5ada2 1736
1b7ecd11 1737 return ret;
b8187c80
SK
1738}
1739
1b7ecd11 1740static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
9e4abcb5 1741{
1b7ecd11 1742 unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
44a2a316 1743
1b7ecd11
SK
1744 if (p + len + 3 >= end)
1745 /* not enough space in options area, try and use overload, if poss */
1746 {
1747 unsigned char *overload;
1748
1749 if (!(overload = find_overload(mess)) &&
1750 (mess->file[0] == 0 || mess->sname[0] == 0))
1751 {
1752 /* attempt to overload fname and sname areas, we've reserved space for the
1753 overflow option previuously. */
1754 overload = p;
1755 *(p++) = OPTION_OVERLOAD;
1756 *(p++) = 1;
1757 }
1758
1759 p = NULL;
1760
1761 /* using filename field ? */
1762 if (overload)
1763 {
1764 if (mess->file[0] == 0)
1765 overload[2] |= 1;
1766
1767 if (overload[2] & 1)
1768 {
1769 p = dhcp_skip_opts(mess->file);
1770 if (p + len + 3 >= mess->file + sizeof(mess->file))
1771 p = NULL;
1772 }
1773
1774 if (!p)
1775 {
1776 /* try to bring sname into play (it may be already) */
1777 if (mess->sname[0] == 0)
1778 overload[2] |= 2;
1779
1780 if (overload[2] & 2)
1781 {
1782 p = dhcp_skip_opts(mess->sname);
ffa3d7d6 1783 if (p + len + 3 >= mess->sname + sizeof(mess->sname))
1b7ecd11
SK
1784 p = NULL;
1785 }
1786 }
1787 }
1788
1789 if (!p)
7622fc06 1790 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
1b7ecd11
SK
1791 }
1792
1793 if (p)
9e4abcb5
SK
1794 {
1795 *(p++) = opt;
a222641c 1796 *(p++) = len;
9e4abcb5 1797 }
1b7ecd11 1798
9e4abcb5
SK
1799 return p;
1800}
1b7ecd11
SK
1801
1802static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
a222641c 1803{
1b7ecd11
SK
1804 int i;
1805 unsigned char *p = free_space(mess, end, opt, len);
a222641c 1806
1b7ecd11
SK
1807 if (p)
1808 for (i = 0; i < len; i++)
1809 *(p++) = val >> (8 * (len - (i + 1)));
a222641c
SK
1810}
1811
1b7ecd11
SK
1812static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
1813 char *string, int null_term)
44a2a316 1814{
1b7ecd11 1815 unsigned char *p;
0a852541 1816 size_t len = strlen(string);
3be34541 1817
cdeda28f
SK
1818 if (null_term && len != 255)
1819 len++;
1820
1b7ecd11
SK
1821 if ((p = free_space(mess, end, opt, len)))
1822 memcpy(p, string, len);
44a2a316 1823}
1b7ecd11
SK
1824
1825/* return length, note this only does the data part */
73a08a24 1826static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
9e4abcb5 1827{
1b7ecd11
SK
1828 int len = opt->len;
1829
1830 if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
1831 len++;
1832
1833 if (p && len != 0)
9e4abcb5 1834 {
73a08a24 1835 if (context && (opt->flags & DHOPT_ADDR))
1b7ecd11
SK
1836 {
1837 int j;
1838 struct in_addr *a = (struct in_addr *)opt->val;
1839 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
1840 {
1841 /* zero means "self" (but not in vendorclass options.) */
1842 if (a->s_addr == 0)
73a08a24 1843 memcpy(p, &context->local, INADDRSZ);
1b7ecd11
SK
1844 else
1845 memcpy(p, a, INADDRSZ);
1846 p += INADDRSZ;
1847 }
9e4abcb5 1848 }
1b7ecd11 1849 else
625ac28c
SK
1850 /* empty string may be extended to "\0" by null_term */
1851 memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
1b7ecd11
SK
1852 }
1853 return len;
9e4abcb5 1854}
7622fc06 1855
9e4abcb5
SK
1856static int in_list(unsigned char *list, int opt)
1857{
1858 int i;
6b01084f
SK
1859
1860 /* If no requested options, send everything, not nothing. */
a84fa1d0
SK
1861 if (!list)
1862 return 1;
1863
9e4abcb5
SK
1864 for (i = 0; list[i] != OPTION_END; i++)
1865 if (opt == list[i])
1866 return 1;
1867
1868 return 0;
1869}
1870
7de060b0 1871static struct dhcp_opt *option_find2(int opt)
9e4abcb5 1872{
7de060b0
SK
1873 struct dhcp_opt *opts;
1874
1875 for (opts = daemon->dhcp_opts; opts; opts = opts->next)
1876 if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
1877 return opts;
1878
8ef5ada2 1879 return NULL;
9e4abcb5
SK
1880}
1881
6b01084f
SK
1882/* mark vendor-encapsulated options which match the client-supplied or
1883 config-supplied vendor class */
1884static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
1885{
1886 for (; dopt; dopt = dopt->next)
1887 {
7622fc06 1888 dopt->flags &= ~DHOPT_VENDOR_MATCH;
73a08a24 1889 if (opt && (dopt->flags & DHOPT_VENDOR))
6b01084f
SK
1890 {
1891 int i, len = 0;
73a08a24
SK
1892 if (dopt->u.vendor_class)
1893 len = strlen((char *)dopt->u.vendor_class);
6b01084f 1894 for (i = 0; i <= (option_len(opt) - len); i++)
73a08a24 1895 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
6b01084f 1896 {
7622fc06 1897 dopt->flags |= DHOPT_VENDOR_MATCH;
6b01084f
SK
1898 break;
1899 }
1900 }
1901 }
1902}
1903
8ef5ada2
SK
1904static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
1905 struct dhcp_packet *mess, unsigned char *end, int null_term)
73a08a24 1906{
8ef5ada2 1907 int len, enc_len, ret = 0;
7622fc06 1908 struct dhcp_opt *start;
73a08a24
SK
1909 unsigned char *p;
1910
1911 /* find size in advance */
7622fc06
SK
1912 for (enc_len = 0, start = opt; opt; opt = opt->next)
1913 if (opt->flags & flag)
73a08a24
SK
1914 {
1915 int new = do_opt(opt, NULL, NULL, null_term) + 2;
8ef5ada2 1916 ret = 1;
73a08a24
SK
1917 if (enc_len + new <= 255)
1918 enc_len += new;
1919 else
1920 {
1921 p = free_space(mess, end, encap, enc_len);
1922 for (; start && start != opt; start = start->next)
7622fc06 1923 if (p && (start->flags & flag))
73a08a24
SK
1924 {
1925 len = do_opt(start, p + 2, NULL, null_term);
1926 *(p++) = start->opt;
1927 *(p++) = len;
1928 p += len;
1929 }
1930 enc_len = new;
1931 start = opt;
1932 }
1933 }
1934
1935 if (enc_len != 0 &&
1936 (p = free_space(mess, end, encap, enc_len + 1)))
1937 {
1938 for (; start; start = start->next)
7622fc06 1939 if (start->flags & flag)
73a08a24
SK
1940 {
1941 len = do_opt(start, p + 2, NULL, null_term);
1942 *(p++) = start->opt;
1943 *(p++) = len;
1944 p += len;
1945 }
1946 *p = OPTION_END;
1947 }
8ef5ada2
SK
1948
1949 return ret;
73a08a24
SK
1950}
1951
7622fc06 1952static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
91dccd09 1953{
7622fc06
SK
1954 unsigned char *p;
1955
1956 option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
1957 if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
1958 memcpy(p, uuid, 17);
1959}
1960
1961static int prune_vendor_opts(struct dhcp_netid *netid)
1962{
1963 int force = 0;
1964 struct dhcp_opt *opt;
9e038946 1965
7622fc06
SK
1966 /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
1967 for (opt = daemon->dhcp_opts; opt; opt = opt->next)
1968 if (opt->flags & DHOPT_VENDOR_MATCH)
1969 {
1970 if (!match_netid(opt->netid, netid, 1))
1971 opt->flags &= ~DHOPT_VENDOR_MATCH;
1972 else if (opt->flags & DHOPT_FORCE)
1973 force = 1;
1974 }
1975 return force;
1976}
1977
751d6f4a 1978static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
7622fc06
SK
1979{
1980#define NUM_OPTS 4
1981
1982 unsigned char *p, *q;
1983 struct pxe_service *service;
1984 static struct dhcp_opt *o, *ret;
1985 int i, j = NUM_OPTS - 1;
316e2730 1986 struct in_addr boot_server;
7622fc06
SK
1987
1988 /* We pass back references to these, hence they are declared static */
1989 static unsigned char discovery_control;
1990 static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
1991 static struct dhcp_opt *fake_opts = NULL;
1992
316e2730
SK
1993 /* Disable multicast, since we don't support it, and broadcast
1994 unless we need it */
1995 discovery_control = 3;
7622fc06
SK
1996
1997 ret = daemon->dhcp_opts;
1998
1999 if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
2000 return ret;
2001
2002 for (i = 0; i < NUM_OPTS; i++)
2003 {
2004 fake_opts[i].flags = DHOPT_VENDOR_MATCH;
2005 fake_opts[i].netid = NULL;
2006 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
2007 }
2008
2009 /* create the data for the PXE_MENU and PXE_SERVERS options. */
2010 p = (unsigned char *)daemon->dhcp_buff;
8ef5ada2 2011 q = (unsigned char *)daemon->dhcp_buff3;
7622fc06
SK
2012
2013 for (i = 0, service = daemon->pxe_services; service; service = service->next)
2014 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
2015 {
2016 size_t len = strlen(service->menu);
2017 /* opt 43 max size is 255. encapsulated option has type and length
2018 bytes, so its max size is 253. */
2019 if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
2020 {
2021 *(p++) = service->type >> 8;
2022 *(p++) = service->type;
2023 *(p++) = len;
2024 memcpy(p, service->menu, len);
2025 p += len;
2026 i++;
2027 }
2028 else
2029 {
2030 toobig:
2031 my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
2032 return daemon->dhcp_opts;
2033 }
2034
751d6f4a
SK
2035 boot_server = service->basename ? local :
2036 (service->sname ? a_record_from_hosts(service->sname, now) : service->server);
2037
316e2730 2038 if (boot_server.s_addr != 0)
7622fc06 2039 {
8ef5ada2 2040 if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
316e2730
SK
2041 goto toobig;
2042
2043 /* Boot service with known address - give it */
2044 *(q++) = service->type >> 8;
2045 *(q++) = service->type;
2046 *(q++) = 1;
2047 /* dest misaligned */
2048 memcpy(q, &boot_server.s_addr, INADDRSZ);
2049 q += INADDRSZ;
2050 }
2051 else if (service->type != 0)
2052 /* We don't know the server for a service type, so we'll
2053 allow the client to broadcast for it */
2054 discovery_control = 2;
7622fc06
SK
2055 }
2056
2057 /* if no prompt, wait forever if there's a choice */
2058 fake_prompt[0] = (i > 1) ? 255 : 0;
2059
2060 if (i == 0)
2061 discovery_control = 8; /* no menu - just use use mess->filename */
2062 else
2063 {
2064 ret = &fake_opts[j--];
2065 ret->len = p - (unsigned char *)daemon->dhcp_buff;
2066 ret->val = (unsigned char *)daemon->dhcp_buff;
2067 ret->opt = SUBOPT_PXE_MENU;
2068
8ef5ada2 2069 if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
7622fc06
SK
2070 {
2071 ret = &fake_opts[j--];
8ef5ada2
SK
2072 ret->len = q - (unsigned char *)daemon->dhcp_buff3;
2073 ret->val = (unsigned char *)daemon->dhcp_buff3;
7622fc06
SK
2074 ret->opt = SUBOPT_PXE_SERVERS;
2075 }
2076 }
2077
2078 for (o = daemon->dhcp_opts; o; o = o->next)
2079 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
2080 break;
2081
2082 if (!o)
2083 {
2084 ret = &fake_opts[j--];
2085 ret->len = sizeof(fake_prompt);
2086 ret->val = fake_prompt;
2087 ret->opt = SUBOPT_PXE_MENU_PROMPT;
2088 }
2089
316e2730
SK
2090 ret = &fake_opts[j--];
2091 ret->len = 1;
2092 ret->opt = SUBOPT_PXE_DISCOVERY;
2093 ret->val= &discovery_control;
2094
7622fc06
SK
2095 return ret;
2096}
2097
2098static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
2099{
1b7ecd11
SK
2100 memset(mess->sname, 0, sizeof(mess->sname));
2101 memset(mess->file, 0, sizeof(mess->file));
2102 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
2103 mess->siaddr.s_addr = 0;
2104}
cdeda28f 2105
7622fc06
SK
2106struct dhcp_boot *find_boot(struct dhcp_netid *netid)
2107{
2108 struct dhcp_boot *boot;
2109
2110 /* decide which dhcp-boot option we're using */
2111 for (boot = daemon->boot_config; boot; boot = boot->next)
2112 if (match_netid(boot->netid, netid, 0))
2113 break;
2114 if (!boot)
2115 /* No match, look for one without a netid */
2116 for (boot = daemon->boot_config; boot; boot = boot->next)
2117 if (match_netid(boot->netid, netid, 1))
2118 break;
2119
2120 return boot;
9e038946
SK
2121}
2122
1b7ecd11
SK
2123static void do_options(struct dhcp_context *context,
2124 struct dhcp_packet *mess,
7622fc06 2125 unsigned char *end,
1b7ecd11 2126 unsigned char *req_options,
9009d746 2127 char *hostname,
70c5e3e0 2128 char *domain,
1b7ecd11
SK
2129 struct dhcp_netid *netid,
2130 struct in_addr subnet_addr,
2131 unsigned char fqdn_flags,
7622fc06 2132 int null_term, int pxe_arch,
8ef5ada2 2133 unsigned char *uuid,
7de060b0 2134 int vendor_class_len,
ca85a282
SK
2135 time_t now,
2136 unsigned int lease_time,
2137 unsigned short fuzz)
1b7ecd11
SK
2138{
2139 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2140 struct dhcp_boot *boot;
7622fc06 2141 unsigned char *p;
f2621c7f 2142 int i, len, force_encap = 0;
1b7ecd11 2143 unsigned char f0 = 0, s0 = 0;
824af85b 2144 int done_file = 0, done_server = 0;
8ef5ada2 2145 int done_vendor_class = 0;
7de060b0
SK
2146 struct dhcp_netid *tagif;
2147 struct dhcp_netid_list *id_list;
2148
4cb1b320 2149 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
7d2b5c95
SK
2150 if (context)
2151 context->netid.next = NULL;
57f460de 2152 tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
7de060b0 2153
f2621c7f 2154 /* logging */
28866e95 2155 if (option_bool(OPT_LOG_OPTS) && req_options)
f2621c7f
SK
2156 {
2157 char *q = daemon->namebuff;
2158 for (i = 0; req_options[i] != OPTION_END; i++)
2159 {
4cb1b320 2160 char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
824af85b
SK
2161 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
2162 "%d%s%s%s",
2163 req_options[i],
4cb1b320
SK
2164 strlen(s) != 0 ? ":" : "",
2165 s,
824af85b 2166 req_options[i+1] == OPTION_END ? "" : ", ");
f2621c7f
SK
2167 if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2168 {
2169 q = daemon->namebuff;
7622fc06 2170 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
f2621c7f
SK
2171 }
2172 }
2173 }
2174
7de060b0
SK
2175 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
2176 if ((!id_list->list) || match_netid(id_list->list, netid, 0))
2177 break;
2178 if (id_list)
2179 mess->flags |= htons(0x8000); /* force broadcast */
2180
73a08a24
SK
2181 if (context)
2182 mess->siaddr = context->local;
1b7ecd11
SK
2183
2184 /* See if we can send the boot stuff as options.
2185 To do this we need a requested option list, BOOTP
824af85b
SK
2186 and very old DHCP clients won't have this, we also
2187 provide an manual option to disable it.
1b7ecd11 2188 Some PXE ROMs have bugs (surprise!) and need zero-terminated
7622fc06 2189 names, so we always send those. */
7de060b0 2190 if ((boot = find_boot(tagif)))
91dccd09 2191 {
1b7ecd11 2192 if (boot->sname)
824af85b 2193 {
28866e95 2194 if (!option_bool(OPT_NO_OVERRIDE) &&
824af85b
SK
2195 req_options &&
2196 in_list(req_options, OPTION_SNAME))
1b7ecd11 2197 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
91dccd09 2198 else
824af85b 2199 strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
91dccd09 2200 }
1b7ecd11
SK
2201
2202 if (boot->file)
2203 {
28866e95 2204 if (!option_bool(OPT_NO_OVERRIDE) &&
824af85b
SK
2205 req_options &&
2206 in_list(req_options, OPTION_FILENAME))
1b7ecd11
SK
2207 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2208 else
824af85b 2209 strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
1b7ecd11
SK
2210 }
2211
7de060b0 2212 if (boot->next_server.s_addr)
1b7ecd11 2213 mess->siaddr = boot->next_server;
7de060b0
SK
2214 else if (boot->tftp_sname)
2215 mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
91dccd09 2216 }
824af85b
SK
2217 else
2218 /* Use the values of the relevant options if no dhcp-boot given and
1f15b81d
SK
2219 they're not explicitly asked for as options. OPTION_END is used
2220 as an internal way to specify siaddr without using dhcp-boot, for use in
2221 dhcp-optsfile. */
824af85b 2222 {
8ef5ada2 2223 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
7de060b0 2224 (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
824af85b
SK
2225 {
2226 strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
2227 done_file = 1;
2228 }
7622fc06 2229
824af85b 2230 if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
7de060b0 2231 (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
824af85b
SK
2232 {
2233 strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
2234 done_server = 1;
2235 }
1f15b81d 2236
7de060b0 2237 if ((opt = option_find2(OPTION_END)))
1f15b81d 2238 mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
824af85b 2239 }
7622fc06 2240
1b7ecd11
SK
2241 /* We don't want to do option-overload for BOOTP, so make the file and sname
2242 fields look like they are in use, even when they aren't. This gets restored
2243 at the end of this function. */
2244
28866e95 2245 if (!req_options || option_bool(OPT_NO_OVERRIDE))
91dccd09 2246 {
1b7ecd11
SK
2247 f0 = mess->file[0];
2248 mess->file[0] = 1;
2249 s0 = mess->sname[0];
2250 mess->sname[0] = 1;
91dccd09 2251 }
1b7ecd11
SK
2252
2253 /* At this point, if mess->sname or mess->file are zeroed, they are available
2254 for option overload, reserve space for the overload option. */
2255 if (mess->file[0] == 0 || mess->sname[0] == 0)
2256 end -= 3;
91dccd09 2257
3be34541
SK
2258 /* rfc3011 says this doesn't need to be in the requested options list. */
2259 if (subnet_addr.s_addr)
1b7ecd11 2260 option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
ca85a282
SK
2261
2262 if (lease_time != 0xffffffff)
2263 {
2264 unsigned int t1val = lease_time/2;
2265 unsigned int t2val = (lease_time*7)/8;
2266 unsigned int hval;
2267
2268 /* If set by user, sanity check, so not longer than lease. */
2269 if ((opt = option_find2(OPTION_T1)))
2270 {
2271 hval = ntohl(*((unsigned int *)opt->val));
2272 if (hval < lease_time && hval > 2)
2273 t1val = hval;
2274 }
2275
2276 if ((opt = option_find2(OPTION_T2)))
2277 {
2278 hval = ntohl(*((unsigned int *)opt->val));
2279 if (hval < lease_time && hval > 2)
2280 t2val = hval;
2281 }
2282
7c0f2543
SK
2283 /* ensure T1 is still < T2 */
2284 if (t2val <= t1val)
2285 t1val = t2val - 1;
2286
ca85a282
SK
2287 while (fuzz > (t1val/8))
2288 fuzz = fuzz/2;
2289
2290 t1val -= fuzz;
2291 t2val -= fuzz;
2292
ca85a282
SK
2293 option_put(mess, end, OPTION_T1, 4, t1val);
2294 option_put(mess, end, OPTION_T2, 4, t2val);
2295 }
2296
73a08a24
SK
2297 /* replies to DHCPINFORM may not have a valid context */
2298 if (context)
2299 {
7de060b0 2300 if (!option_find2(OPTION_NETMASK))
73a08a24 2301 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
9e4abcb5 2302
73a08a24
SK
2303 /* May not have a "guessed" broadcast address if we got no packets via a relay
2304 from this net yet (ie just unicast renewals after a restart */
2305 if (context->broadcast.s_addr &&
7de060b0 2306 !option_find2(OPTION_BROADCAST))
73a08a24
SK
2307 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2308
2309 /* Same comments as broadcast apply, and also may not be able to get a sensible
2310 default when using subnet select. User must configure by steam in that case. */
2311 if (context->router.s_addr &&
2312 in_list(req_options, OPTION_ROUTER) &&
7de060b0 2313 !option_find2(OPTION_ROUTER))
73a08a24
SK
2314 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2315
a21e27bc
SK
2316 if (daemon->port == NAMESERVER_PORT &&
2317 in_list(req_options, OPTION_DNSSERVER) &&
7de060b0 2318 !option_find2(OPTION_DNSSERVER))
73a08a24
SK
2319 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2320 }
2321
9009d746 2322 if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
7de060b0 2323 !option_find2(OPTION_DOMAINNAME))
9009d746 2324 option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
9e4abcb5 2325
824af85b 2326 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
3d8df260
SK
2327 if (hostname)
2328 {
824af85b 2329 if (in_list(req_options, OPTION_HOSTNAME) &&
7de060b0 2330 !option_find2(OPTION_HOSTNAME))
1b7ecd11 2331 option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
3d8df260
SK
2332
2333 if (fqdn_flags != 0)
2334 {
73a08a24
SK
2335 len = strlen(hostname) + 3;
2336
3d8df260
SK
2337 if (fqdn_flags & 0x04)
2338 len += 2;
cdeda28f
SK
2339 else if (null_term)
2340 len++;
2341
9009d746
SK
2342 if (domain)
2343 len += strlen(domain) + 1;
3f3adae6
RM
2344 else if (fqdn_flags & 0x04)
2345 len--;
2346
1b7ecd11 2347 if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
3d8df260 2348 {
2e34ac14 2349 *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
3d8df260
SK
2350 *(p++) = 255;
2351 *(p++) = 255;
2352
2353 if (fqdn_flags & 0x04)
2354 {
2355 p = do_rfc1035_name(p, hostname);
9009d746 2356 if (domain)
3f3adae6
RM
2357 {
2358 p = do_rfc1035_name(p, domain);
2359 *p++ = 0;
2360 }
3d8df260
SK
2361 }
2362 else
2363 {
2364 memcpy(p, hostname, strlen(hostname));
2365 p += strlen(hostname);
9009d746 2366 if (domain)
3d8df260
SK
2367 {
2368 *(p++) = '.';
9009d746
SK
2369 memcpy(p, domain, strlen(domain));
2370 p += strlen(domain);
cdeda28f
SK
2371 }
2372 if (null_term)
2373 *(p++) = 0;
3d8df260
SK
2374 }
2375 }
2376 }
2377 }
2378
6b01084f 2379 for (opt = config_opts; opt; opt = opt->next)
9e4abcb5 2380 {
824af85b
SK
2381 int optno = opt->opt;
2382
7de060b0
SK
2383 /* netids match and not encapsulated? */
2384 if (!(opt->flags & DHOPT_TAGOK))
2385 continue;
2386
6b01084f 2387 /* was it asked for, or are we sending it anyway? */
824af85b 2388 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
6b01084f
SK
2389 continue;
2390
ca85a282 2391 /* prohibit some used-internally options. T1 and T2 already handled. */
824af85b
SK
2392 if (optno == OPTION_CLIENT_FQDN ||
2393 optno == OPTION_MAXMESSAGE ||
2394 optno == OPTION_OVERLOAD ||
2395 optno == OPTION_PAD ||
ca85a282
SK
2396 optno == OPTION_END ||
2397 optno == OPTION_T1 ||
2398 optno == OPTION_T2)
824af85b
SK
2399 continue;
2400
2401 if (optno == OPTION_SNAME && done_server)
2402 continue;
2403
2404 if (optno == OPTION_FILENAME && done_file)
6b01084f
SK
2405 continue;
2406
33820b7e
SK
2407 /* For the options we have default values on
2408 dhc-option=<optionno> means "don't include this option"
2409 not "include a zero-length option" */
2410 if (opt->len == 0 &&
824af85b
SK
2411 (optno == OPTION_NETMASK ||
2412 optno == OPTION_BROADCAST ||
2413 optno == OPTION_ROUTER ||
2414 optno == OPTION_DNSSERVER ||
2415 optno == OPTION_DOMAINNAME ||
2416 optno == OPTION_HOSTNAME))
33820b7e 2417 continue;
7622fc06
SK
2418
2419 /* vendor-class comes from elsewhere for PXE */
2420 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2421 continue;
824af85b 2422
7622fc06 2423 /* always force null-term for filename and servername - buggy PXE again. */
73a08a24 2424 len = do_opt(opt, NULL, context,
824af85b 2425 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
91dccd09 2426
824af85b 2427 if ((p = free_space(mess, end, optno, len)))
6b01084f 2428 {
73a08a24 2429 do_opt(opt, p, context,
824af85b
SK
2430 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2431
6b01084f
SK
2432 /* If we send a vendor-id, revisit which vendor-ops we consider
2433 it appropriate to send. */
824af85b 2434 if (optno == OPTION_VENDOR_ID)
8ef5ada2
SK
2435 {
2436 match_vendor_opts(p - 2, config_opts);
2437 done_vendor_class = 1;
2438 }
6b01084f
SK
2439 }
2440 }
91dccd09 2441
73a08a24
SK
2442 /* Now send options to be encapsulated in arbitrary options,
2443 eg dhcp-option=encap:172,17,.......
4cb1b320
SK
2444 Also handle vendor-identifying vendor-encapsulated options,
2445 dhcp-option = vi-encap:13,17,.......
73a08a24
SK
2446 The may be more that one "outer" to do, so group
2447 all the options which match each outer in turn. */
7622fc06
SK
2448 for (opt = config_opts; opt; opt = opt->next)
2449 opt->flags &= ~DHOPT_ENCAP_DONE;
2450
73a08a24 2451 for (opt = config_opts; opt; opt = opt->next)
316e2730
SK
2452 {
2453 int flags;
2454
2455 if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
2456 {
2457 int found = 0;
2458 struct dhcp_opt *o;
2459
2460 if (opt->flags & DHOPT_ENCAP_DONE)
2461 continue;
2462
2463 for (len = 0, o = config_opts; o; o = o->next)
2464 {
2465 int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
2466
2467 o->flags &= ~DHOPT_ENCAP_MATCH;
2468
2469 if (!(o->flags & flags) || opt->u.encap != o->u.encap)
2470 continue;
2471
2472 o->flags |= DHOPT_ENCAP_DONE;
7de060b0 2473 if (match_netid(o->netid, tagif, 1) &&
316e2730
SK
2474 ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
2475 {
2476 o->flags |= DHOPT_ENCAP_MATCH;
2477 found = 1;
2478 len += do_opt(o, NULL, NULL, 0) + 2;
2479 }
2480 }
2481
2482 if (found)
2483 {
2484 if (flags & DHOPT_ENCAPSULATE)
2485 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
2486 else if (len > 250)
2487 my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
2488 else if ((p = free_space(mess, end, OPTION_VENDOR_IDENT_OPT, len + 5)))
2489 {
2490 int swap_ent = htonl(opt->u.encap);
2491 memcpy(p, &swap_ent, 4);
2492 p += 4;
2493 *(p++) = len;
2494 for (o = config_opts; o; o = o->next)
2495 if (o->flags & DHOPT_ENCAP_MATCH)
2496 {
2497 len = do_opt(o, p + 2, NULL, 0);
2498 *(p++) = o->opt;
2499 *(p++) = len;
2500 p += len;
2501 }
2502 }
2503 }
2504 }
2505 }
73a08a24 2506
7de060b0 2507 force_encap = prune_vendor_opts(tagif);
8ef5ada2 2508
316e2730 2509 if (context && pxe_arch != -1)
7622fc06
SK
2510 {
2511 pxe_misc(mess, end, uuid);
751d6f4a 2512 config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
7622fc06 2513 }
9e4abcb5 2514
8ef5ada2
SK
2515 if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
2516 do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term) &&
2517 pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
2518 (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
2519 /* If we send vendor encapsulated options, and haven't already sent option 60,
2520 echo back the value we got from the client. */
2521 memcpy(p, daemon->dhcp_buff3, vendor_class_len);
2522
7622fc06 2523 /* restore BOOTP anti-overload hack */
28866e95 2524 if (!req_options || option_bool(OPT_NO_OVERRIDE))
1b7ecd11
SK
2525 {
2526 mess->file[0] = f0;
2527 mess->sname[0] = s0;
2528 }
2529}
9e4abcb5 2530
7622fc06
SK
2531#endif
2532
2533
2534
2535
2536
2537
2538