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