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