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