Lines Matching +full:- +full:- +full:daemon
1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
25 /* The Linux in-kernel DHCP client silently ignores any packet
80 #define have_config(config, mask) ((config) && ((config)->flags & (mask)))
124 int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1; in dhcp_reply()
125 struct dhcp_packet* mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base; in dhcp_reply()
153 if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX) return 0; in dhcp_reply()
155 if (mess->htype == 0 && mess->hlen != 0) return 0; in dhcp_reply()
162 if (*((u32*) &mess->options) != htonl(DHCP_COOKIE)) return 0; in dhcp_reply()
165 so reassign mess from daemon->packet. Also, the size in dhcp_reply()
166 sent includes the IP and UDP headers, hence the magic "-28" */ in dhcp_reply()
168 size_t size = (size_t) option_uint(opt, 0, 2) - 28; in dhcp_reply()
175 if (expand_buf(&daemon->dhcp_packet, size)) { in dhcp_reply()
176 mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base; in dhcp_reply()
182 it can affect the context-determination code. */ in dhcp_reply()
184 mess->ciaddr.s_addr = 0; in dhcp_reply()
187 /* Any agent-id needs to be copied back out, verbatim, as the last option in dhcp_reply()
195 if (last_opt && last_opt < end - total) { in dhcp_reply()
196 end -= total; in dhcp_reply()
201 /* look for RFC3527 Link selection sub-option */ in dhcp_reply()
206 /* look for RFC5107 server-identifier-override */ in dhcp_reply()
211 /* if a circuit-id or remote-is option is provided, exact-match to options. */ in dhcp_reply()
212 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next) { in dhcp_reply()
215 if (vendor->match_type == MATCH_CIRCUIT) in dhcp_reply()
217 else if (vendor->match_type == MATCH_REMOTE) in dhcp_reply()
219 else if (vendor->match_type == MATCH_SUBSCRIBER) in dhcp_reply()
226 vendor->len == option_len(sopt) && in dhcp_reply()
227 memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0) { in dhcp_reply()
228 vendor->netid.next = netid; in dhcp_reply()
229 netid = &vendor->netid; in dhcp_reply()
235 /* Check for RFC3011 subnet selector - only if RFC3527 one not present */ in dhcp_reply()
246 lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len); in dhcp_reply()
250 if (lease && !clid && lease->clid) { in dhcp_reply()
251 clid_len = lease->clid_len; in dhcp_reply()
252 clid = lease->clid; in dhcp_reply()
256 emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len); in dhcp_reply()
259 for (mac = daemon->dhcp_macs; mac; mac = mac->next) in dhcp_reply()
260 if (mac->hwaddr_len == mess->hlen && in dhcp_reply()
261 (mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) && in dhcp_reply()
262 memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask)) { in dhcp_reply()
263 mac->netid.next = netid; in dhcp_reply()
264 netid = &mac->netid; in dhcp_reply()
274 if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr) { in dhcp_reply()
282 } else if (mess->giaddr.s_addr) { in dhcp_reply()
283 addr = mess->giaddr; in dhcp_reply()
287 addr = mess->ciaddr; in dhcp_reply()
288 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current) in dhcp_reply()
289 if (context_tmp->netmask.s_addr && in dhcp_reply()
290 is_same_net(addr, context_tmp->start, context_tmp->netmask) && in dhcp_reply()
291 is_same_net(addr, context_tmp->end, context_tmp->netmask)) { in dhcp_reply()
298 for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next) in dhcp_reply()
299 if (context_tmp->netmask.s_addr && in dhcp_reply()
300 is_same_net(addr, context_tmp->start, context_tmp->netmask) && in dhcp_reply()
301 is_same_net(addr, context_tmp->end, context_tmp->netmask)) { in dhcp_reply()
302 context_tmp->current = context_new; in dhcp_reply()
313 // subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? in dhcp_reply()
314 //inet_ntoa(mess->giaddr) : iface_name)); in dhcp_reply()
319 fallback = context->local; in dhcp_reply()
321 if (daemon->options & OPT_LOG_OPTS) { in dhcp_reply()
323 for (context_tmp = context; context_tmp; context_tmp = context_tmp->current) { in dhcp_reply()
324 strcpy(daemon->namebuff, inet_ntoa(context_tmp->start)); in dhcp_reply()
325 if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) in dhcp_reply()
327 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask)); in dhcp_reply()
329 my_syslog(MS_DHCP | LOG_INFO, _("%u Available DHCP range: %s -- %s"), in dhcp_reply()
330 ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end)); in dhcp_reply()
334 mess->op = BOOTREPLY; in dhcp_reply()
336 config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, mess->hlen, in dhcp_reply()
337 mess->htype, NULL); in dhcp_reply()
352 if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY)) return 0; in dhcp_reply()
356 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */ in dhcp_reply()
359 hostname = config->hostname; in dhcp_reply()
360 domain = config->domain; in dhcp_reply()
364 config->netid.next = netid; in dhcp_reply()
365 netid = &config->netid; in dhcp_reply()
369 if (mess->file[0]) { in dhcp_reply()
370 memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file)); in dhcp_reply()
371 daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */ in dhcp_reply()
372 id.net = (char*) daemon->dhcp_buff2; in dhcp_reply()
383 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next) in dhcp_reply()
384 if (match_netid(id_list->list, netid, 0)) message = _("ignored"); in dhcp_reply()
391 logaddr = &config->addr; in dhcp_reply()
392 mess->yiaddr = config->addr; in dhcp_reply()
393 if ((lease = lease_find_by_addr(config->addr)) && in dhcp_reply()
394 (lease->hwaddr_len != mess->hlen || lease->hwaddr_type != mess->htype || in dhcp_reply()
395 memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0)) in dhcp_reply()
398 … if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) || in dhcp_reply()
399 !address_available(context, lease->addr, netid)) { in dhcp_reply()
405 if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, netid, in dhcp_reply()
409 mess->yiaddr = lease->addr; in dhcp_reply()
412 if (!message && !(context = narrow_context(context, mess->yiaddr, netid))) in dhcp_reply()
414 else if (context->netid.net) { in dhcp_reply()
415 context->netid.next = netid; in dhcp_reply()
416 netid = &context->netid; in dhcp_reply()
420 for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next) in dhcp_reply()
421 if ((!id_list->list) || match_netid(id_list->list, netid, 0)) break; in dhcp_reply()
425 if (!message && !lease && (!(lease = lease_allocate(mess->yiaddr)))) in dhcp_reply()
429 logaddr = &mess->yiaddr; in dhcp_reply()
431 lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0); in dhcp_reply()
433 /* infinite lease unless nailed in dhcp-host line. */ in dhcp_reply()
435 lease, have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, now); in dhcp_reply()
439 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), domain, in dhcp_reply()
444 log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid); in dhcp_reply()
450 … /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */ in dhcp_reply()
452 char* pq = daemon->dhcp_buff; in dhcp_reply()
456 len -= 3; in dhcp_reply()
467 while (*op != 0 && ((op + (*op) + 1) - pp) < len) { in dhcp_reply()
475 if (len > 0 && op[len - 1] == 0) borken_opt = 1; in dhcp_reply()
479 if (pq != daemon->dhcp_buff) pq--; in dhcp_reply()
483 if (legal_hostname(daemon->dhcp_buff)) offer_hostname = client_hostname = daemon->dhcp_buff; in dhcp_reply()
486 memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len); in dhcp_reply()
487 /* Microsoft clients are broken, and need zero-terminated strings in dhcp_reply()
490 if (len > 0 && daemon->dhcp_buff[len - 1] == 0) in dhcp_reply()
493 daemon->dhcp_buff[len] = 0; in dhcp_reply()
494 if (legal_hostname(daemon->dhcp_buff)) client_hostname = daemon->dhcp_buff; in dhcp_reply()
497 if (client_hostname && daemon->options & OPT_LOG_OPTS) in dhcp_reply()
498 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), in dhcp_reply()
502 hostname = config->hostname; in dhcp_reply()
503 domain = config->domain; in dhcp_reply()
518 find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, mess->hlen, in dhcp_reply()
519 mess->htype, hostname); in dhcp_reply()
520 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) { in dhcp_reply()
532 config->netid.next = netid; in dhcp_reply()
533 netid = &config->netid; in dhcp_reply()
536 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match. in dhcp_reply()
539 for (o = daemon->dhcp_match; o; o = o->next) { in dhcp_reply()
542 if (!(opt = option_find(mess, sz, o->opt, 1)) || o->len > option_len(opt)) continue; in dhcp_reply()
544 if (o->len == 0) in dhcp_reply()
546 else if (o->flags & DHOPT_HEX) { in dhcp_reply()
547 if (memcmp_masked(o->val, option_ptr(opt, 0), o->len, o->u.wildcard_mask)) matched = 1; in dhcp_reply()
549 for (i = 0; i <= (option_len(opt) - o->len);) { in dhcp_reply()
550 if (memcmp(o->val, option_ptr(opt, i), o->len) == 0) { in dhcp_reply()
555 if (o->flags & DHOPT_STRING) in dhcp_reply()
558 i += o->len; in dhcp_reply()
562 o->netid->next = netid; in dhcp_reply()
563 netid = o->netid; in dhcp_reply()
567 /* user-class options are, according to RFC3004, supposed to contain in dhcp_reply()
574 The code, later, which sends user-class data to the lease-change script in dhcp_reply()
590 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next) { in dhcp_reply()
593 if (vendor->match_type == MATCH_VENDOR) in dhcp_reply()
595 else if (vendor->match_type == MATCH_USER) in dhcp_reply()
602 for (i = 0; i <= (option_len(opt) - vendor->len); i++) in dhcp_reply()
603 if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0) { in dhcp_reply()
604 vendor->netid.next = netid; in dhcp_reply()
605 netid = &vendor->netid; in dhcp_reply()
611 /* mark vendor-encapsulated options which match the client-supplied vendor class */ in dhcp_reply()
612 match_vendor_opts(option_find(mess, sz, OPTION_VENDOR_ID, 1), daemon->dhcp_opts); in dhcp_reply()
614 if (daemon->options & OPT_LOG_OPTS) { in dhcp_reply()
615 if (sanitise(option_find(mess, sz, OPTION_VENDOR_ID, 1), daemon->namebuff)) in dhcp_reply()
616 my_syslog(MS_DHCP | LOG_INFO, _("%u Vendor class: %s"), ntohl(mess->xid), in dhcp_reply()
617 daemon->namebuff); in dhcp_reply()
618 if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff)) in dhcp_reply()
619 my_syslog(MS_DHCP | LOG_INFO, _("%u User class: %s"), ntohl(mess->xid), in dhcp_reply()
620 daemon->namebuff); in dhcp_reply()
624 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next) in dhcp_reply()
625 if (match_netid(id_list->list, netid, 0)) ignore = 1; in dhcp_reply()
631 if (daemon->enable_pxe && (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) && in dhcp_reply()
658 for (service = daemon->pxe_services; service; service = service->next) in dhcp_reply()
659 if (service->type == type) break; in dhcp_reply()
661 if (!service || !service->basename) return 0; in dhcp_reply()
665 mess->yiaddr = mess->ciaddr; in dhcp_reply()
666 mess->ciaddr.s_addr = 0; in dhcp_reply()
667 if (service->server.s_addr != 0) in dhcp_reply()
668 mess->siaddr = service->server; in dhcp_reply()
670 mess->siaddr = context->local; in dhcp_reply()
672 snprintf((char*) mess->file, sizeof(mess->file), "%s.%d", service->basename, layer); in dhcp_reply()
674 option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr)); in dhcp_reply()
683 opt71.next = daemon->dhcp_opts; in dhcp_reply()
686 log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char*) mess->file, in dhcp_reply()
687 mess->xid); in dhcp_reply()
696 (context->flags & CONTEXT_PROXY)) { in dhcp_reply()
699 mess->yiaddr.s_addr = 0; in dhcp_reply()
700 if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0) { in dhcp_reply()
701 mess->ciaddr.s_addr = 0; in dhcp_reply()
702 mess->flags |= htons(0x8000); /* broadcast */ in dhcp_reply()
710 if (boot->next_server.s_addr) mess->siaddr = boot->next_server; in dhcp_reply()
712 if (boot->file) strncpy((char*) mess->file, boot->file, sizeof(mess->file) - 1); in dhcp_reply()
718 htonl(context->local.s_addr)); in dhcp_reply()
725 ignore ? "proxy" : "proxy-ignored", mess->xid); in dhcp_reply()
732 if (context->flags & CONTEXT_PROXY) return 0; in dhcp_reply()
735 req_options = (unsigned char*) daemon->dhcp_buff2; in dhcp_reply()
747 sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff); in dhcp_reply()
752 daemon->dhcp_buff, mess->xid); in dhcp_reply()
754 if (lease && lease->addr.s_addr == option_addr(opt).s_addr) lease_prune(lease, now); in dhcp_reply()
756 … if (have_config(config, CONFIG_ADDR) && config->addr.s_addr == option_addr(opt).s_addr) { in dhcp_reply()
757 prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF); in dhcp_reply()
759 inet_ntoa(config->addr), daemon->dhcp_buff); in dhcp_reply()
760 config->flags |= CONFIG_DECLINED; in dhcp_reply()
761 config->decline_time = now; in dhcp_reply()
764 for (; context; context = context->current) context->addr_epoch++; in dhcp_reply()
769 if (!(context = narrow_context(context, mess->ciaddr, netid)) || in dhcp_reply()
774 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr) in dhcp_reply()
779 … log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid); in dhcp_reply()
796 char* addrs = inet_ntoa(config->addr); in dhcp_reply()
798 if ((ltmp = lease_find_by_addr(config->addr)) && ltmp != lease && in dhcp_reply()
799 … !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type)) { in dhcp_reply()
802 extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len, ltmp->hwaddr, in dhcp_reply()
803 ltmp->clid_len, ltmp->clid, &len); in dhcp_reply()
806 addrs, print_mac(daemon->namebuff, mac, len)); in dhcp_reply()
809 for (tmp = context; tmp; tmp = tmp->current) in dhcp_reply()
810 if (context->router.s_addr == config->addr.s_addr) break; in dhcp_reply()
817 difftime(now, config->decline_time) < (float) DECLINE_BACKOFF) in dhcp_reply()
823 conf = config->addr; in dhcp_reply()
828 mess->yiaddr = conf; in dhcp_reply()
829 else if (lease && address_available(context, lease->addr, netid) && in dhcp_reply()
830 !config_find_by_address(daemon->dhcp_conf, lease->addr)) in dhcp_reply()
831 mess->yiaddr = lease->addr; in dhcp_reply()
834 !config_find_by_address(daemon->dhcp_conf, addr)) in dhcp_reply()
835 mess->yiaddr = addr; in dhcp_reply()
837 message = _("no unique-id"); in dhcp_reply()
838 else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, netid, now)) in dhcp_reply()
843 message, mess->xid); in dhcp_reply()
845 if (message || !(context = narrow_context(context, mess->yiaddr, netid))) return 0; in dhcp_reply()
847 log_packet("DHCPOFFER", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid); in dhcp_reply()
849 if (context->netid.net) { in dhcp_reply()
850 context->netid.next = netid; in dhcp_reply()
851 netid = &context->netid; in dhcp_reply()
865 do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), in dhcp_reply()
874 mess->yiaddr = option_addr(opt); in dhcp_reply()
886 for (; context; context = context->current) in dhcp_reply()
887 if (context->local.s_addr == option_addr(opt).s_addr) break; in dhcp_reply()
893 if (!(daemon->options & OPT_AUTHORITATIVE)) return 0; in dhcp_reply()
894 message = _("wrong server-ID"); in dhcp_reply()
899 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr) { in dhcp_reply()
904 /* INIT-REBOOT */ in dhcp_reply()
905 if (!lease && !(daemon->options & OPT_AUTHORITATIVE)) return 0; in dhcp_reply()
907 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr) { in dhcp_reply()
909 /* avoid loops when client brain-dead */ in dhcp_reply()
917 We allow it to be missing if dhcp-authoritative mode in dhcp_reply()
918 as long as we can allocate the lease now - checked below. in dhcp_reply()
920 if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) || in dhcp_reply()
921 (!lease && !(daemon->options & OPT_AUTHORITATIVE))) { in dhcp_reply()
928 mess->yiaddr = mess->ciaddr; in dhcp_reply()
931 log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid); in dhcp_reply()
938 for (tmp = context; tmp; tmp = tmp->current) in dhcp_reply()
939 if (context->router.s_addr == config->addr.s_addr) break; in dhcp_reply()
941 if (!(context = narrow_context(context, mess->yiaddr, netid))) { in dhcp_reply()
949 else if (!address_available(context, mess->yiaddr, netid) && in dhcp_reply()
951 config->addr.s_addr != mess->yiaddr.s_addr)) in dhcp_reply()
959 difftime(now, config->decline_time) > (float) DECLINE_BACKOFF) && in dhcp_reply()
960 config->addr.s_addr != mess->yiaddr.s_addr && in dhcp_reply()
961 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease)) in dhcp_reply()
965 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && in dhcp_reply()
969 else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr))) { in dhcp_reply()
973 config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type)) { in dhcp_reply()
975 print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len), in dhcp_reply()
976 inet_ntoa(ltmp->addr)); in dhcp_reply()
984 message = _("no unique-id"); in dhcp_reply()
987 if ((lease = lease_allocate(mess->yiaddr))) in dhcp_reply()
996 … log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid); in dhcp_reply()
998 mess->yiaddr.s_addr = 0; in dhcp_reply()
1006 if (!unicast_dest || mess->giaddr.s_addr != 0 || mess->ciaddr.s_addr == 0 || in dhcp_reply()
1007 is_same_net(context->local, mess->ciaddr, context->netmask)) { in dhcp_reply()
1008 mess->flags |= htons(0x8000); /* broadcast */ in dhcp_reply()
1009 mess->ciaddr.s_addr = 0; in dhcp_reply()
1013 if (mess->giaddr.s_addr) lease->giaddr = mess->giaddr; in dhcp_reply()
1015 lease->changed = 1; in dhcp_reply()
1016 /* copy user-class and vendor class into new lease, for the script */ in dhcp_reply()
1020 /* If the user-class option started as counted strings, the first byte will in dhcp_reply()
1022 if (len != 0 && ucp[0] == 0) ucp++, len--; in dhcp_reply()
1023 free(lease->userclass); in dhcp_reply()
1024 if ((lease->userclass = whine_malloc(len + 1))) { in dhcp_reply()
1025 memcpy(lease->userclass, ucp, len); in dhcp_reply()
1026 lease->userclass[len] = 0; in dhcp_reply()
1027 lease->userclass_len = len + 1; in dhcp_reply()
1033 free(lease->vendorclass); in dhcp_reply()
1034 if ((lease->vendorclass = whine_malloc(len + 1))) { in dhcp_reply()
1035 memcpy(lease->vendorclass, ucp, len); in dhcp_reply()
1036 lease->vendorclass[len] = 0; in dhcp_reply()
1037 lease->vendorclass_len = len + 1; in dhcp_reply()
1043 free(lease->supplied_hostname); in dhcp_reply()
1044 if ((lease->supplied_hostname = whine_malloc(len + 1))) { in dhcp_reply()
1045 memcpy(lease->supplied_hostname, ucp, len); in dhcp_reply()
1046 lease->supplied_hostname[len] = 0; in dhcp_reply()
1047 lease->supplied_hostname_len = len + 1; in dhcp_reply()
1052 if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr))) { in dhcp_reply()
1057 if (context->netid.net) { in dhcp_reply()
1058 context->netid.next = netid; in dhcp_reply()
1059 netid = &context->netid; in dhcp_reply()
1063 lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len); in dhcp_reply()
1065 … /* if all the netids in the ignore_name list are present, ignore client-supplied name */ in dhcp_reply()
1067 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next) in dhcp_reply()
1068 if ((!id_list->list) || match_netid(id_list->list, netid, 0)) break; in dhcp_reply()
1077 lease->override = override; in dhcp_reply()
1079 override = lease->override; in dhcp_reply()
1081 log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, in dhcp_reply()
1082 mess->xid); in dhcp_reply()
1091 option_put(mess, end, OPTION_T1, 4, (time / 2) - fuzz); in dhcp_reply()
1092 option_put(mess, end, OPTION_T2, 4, ((time / 8) * 7) - fuzz); in dhcp_reply()
1094 do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), in dhcp_reply()
1103 log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid); in dhcp_reply()
1105 if (message || mess->ciaddr.s_addr == 0) return 0; in dhcp_reply()
1108 context = narrow_context(context, mess->ciaddr, netid); in dhcp_reply()
1111 get one from MAC address/client-d */ in dhcp_reply()
1112 if (!lease && (lease = lease_find_by_addr(mess->ciaddr)) && lease->hostname) in dhcp_reply()
1113 hostname = lease->hostname; in dhcp_reply()
1115 if (!hostname) hostname = host_from_dns(mess->ciaddr); in dhcp_reply()
1117 log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid); in dhcp_reply()
1119 if (context && context->netid.net) { in dhcp_reply()
1120 context->netid.next = netid; in dhcp_reply()
1121 netid = &context->netid; in dhcp_reply()
1126 lease->override = override; in dhcp_reply()
1128 override = lease->override; in dhcp_reply()
1137 if (lease->expires == 0) in dhcp_reply()
1140 time = (unsigned int) difftime(lease->expires, now); in dhcp_reply()
1145 do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr), domain, in dhcp_reply()
1155 /* find a good value to use as MAC address for logging and address-allocation hashing.
1157 but eg Firewire will have hlen == 0 and use the client-id instead.
1159 We assume that if the first byte of the client-id equals the htype byte
1160 then the client-id is using the usual encoding and use the rest of the
1161 client-id: if not we can use the whole client-id. This should give
1167 *len_out = clid_len - 1; in extended_hwaddr()
1173 *len_out = clid_len - 1; in extended_hwaddr()
1188 unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time; in calc_time()
1204 return context->local; in server_id()
1219 for (i = option_len(opt); i > 0; i--) { in sanitise()
1235 print_mac(daemon->namebuff, ext_mac, mac_len); in log_packet()
1237 if (daemon->options & OPT_LOG_OPTS) in log_packet()
1239 … addr ? inet_ntoa(a) : "", addr ? " " : "", daemon->namebuff, string ? string : ""); in log_packet()
1242 addr ? " " : "", daemon->namebuff, string ? string : ""); in log_packet()
1252 for (daemon->namebuff[0] = 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ) { in log_options()
1253 if (i != 0) strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff)); in log_options()
1254 strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), in log_options()
1255 256 - strlen(daemon->namebuff)); in log_options()
1257 else if (!is_name || !sanitise(start, daemon->namebuff)) { in log_options()
1259 print_mac(daemon->namebuff, option_ptr(start, 0), trunc); in log_options()
1264 trunc == 0 ? "" : " ", trunc == 0 ? "" : daemon->namebuff, in log_options()
1280 if (p > end - 2) return NULL; /* malformed packet */ in option_find1()
1282 if (p > end - (2 + opt_len)) return NULL; /* malformed packet */ in option_find1()
1293 if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char*) mess) + size, in option_find()
1298 if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char*) mess) + size, in option_find()
1304 (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize))) in option_find()
1309 (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize))) in option_find()
1347 unsigned char* p = &mess->options[0] + sizeof(u32); in find_overload()
1358 unsigned char* p = dhcp_skip_opts(&mess->options[0] + sizeof(u32)); in dhcp_packet_size()
1366 memmove(p, agent_id, real_end - agent_id); in dhcp_packet_size()
1367 p += real_end - agent_id; in dhcp_packet_size()
1368 memset(p, 0, real_end - p); /* in case of overlap */ in dhcp_packet_size()
1372 if (netid && (daemon->options & OPT_LOG_OPTS)) { in dhcp_packet_size()
1373 char* s = daemon->namebuff; in dhcp_packet_size()
1374 for (*s = 0; netid; netid = netid->next) { in dhcp_packet_size()
1376 for (n = netid->next; n; n = n->next) in dhcp_packet_size()
1377 if (strcmp(netid->net, n->net) == 0) break; in dhcp_packet_size()
1380 strncat(s, netid->net, (MAXDNAME - 1) - strlen(s)); in dhcp_packet_size()
1381 if (netid->next) strncat(s, ", ", (MAXDNAME - 1) - strlen(s)); in dhcp_packet_size()
1384 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s); in dhcp_packet_size()
1391 *dhcp_skip_opts(mess->file) = OPTION_END; in dhcp_packet_size()
1392 if (daemon->options & OPT_LOG_OPTS) log_options(mess->file, mess->xid); in dhcp_packet_size()
1393 } else if ((daemon->options & OPT_LOG_OPTS) && strlen((char*) mess->file) != 0) in dhcp_packet_size()
1394 my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), in dhcp_packet_size()
1395 (char*) mess->file); in dhcp_packet_size()
1398 *dhcp_skip_opts(mess->sname) = OPTION_END; in dhcp_packet_size()
1399 if (daemon->options & OPT_LOG_OPTS) log_options(mess->sname, mess->xid); in dhcp_packet_size()
1400 } else if ((daemon->options & OPT_LOG_OPTS) && strlen((char*) mess->sname) != 0) in dhcp_packet_size()
1401 my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), in dhcp_packet_size()
1402 (char*) mess->sname); in dhcp_packet_size()
1406 if (daemon->options & OPT_LOG_OPTS) { in dhcp_packet_size()
1407 if (mess->siaddr.s_addr != 0) in dhcp_packet_size()
1408 my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), in dhcp_packet_size()
1409 inet_ntoa(mess->siaddr)); in dhcp_packet_size()
1411 log_options(&mess->options[0] + sizeof(u32), mess->xid); in dhcp_packet_size()
1414 for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next) in dhcp_packet_size()
1415 if (match_netid(id_list->list, netid, 0)) in dhcp_packet_size()
1416 mess->flags |= htons(0x8000); /* force broadcast */ in dhcp_packet_size()
1418 ret = (size_t)(p - (unsigned char*) mess); in dhcp_packet_size()
1426 unsigned char* p = dhcp_skip_opts(&mess->options[0] + sizeof(u32)); in free_space()
1433 if (!(overload = find_overload(mess)) && (mess->file[0] == 0 || mess->sname[0] == 0)) { in free_space()
1445 if (mess->file[0] == 0) overload[2] |= 1; in free_space()
1448 p = dhcp_skip_opts(mess->file); in free_space()
1449 if (p + len + 3 >= mess->file + sizeof(mess->file)) p = NULL; in free_space()
1454 if (mess->sname[0] == 0) overload[2] |= 2; in free_space()
1457 p = dhcp_skip_opts(mess->sname); in free_space()
1458 if (p + len + 3 >= mess->sname + sizeof(mess->file)) p = NULL; in free_space()
1482 for (i = 0; i < len; i++) *(p++) = val >> (8 * (len - (i + 1))); in option_put()
1498 int len = opt->len; in do_opt()
1500 if ((opt->flags & DHOPT_STRING) && null_term && len != 255) len++; in do_opt()
1503 if (context && (opt->flags & DHOPT_ADDR)) { in do_opt()
1505 struct in_addr* a = (struct in_addr*) opt->val; in do_opt()
1506 for (j = 0; j < opt->len; j += INADDRSZ, a++) { in do_opt()
1508 if (a->s_addr == 0) in do_opt()
1509 memcpy(p, &context->local, INADDRSZ); in do_opt()
1515 memcpy(p, opt->val, len); in do_opt()
1534 for (tmp = opts; tmp; tmp = tmp->next) in option_find2()
1535 if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR))) in option_find2()
1536 if (match_netid(tmp->netid, netid, netid ? 0 : 1)) return tmp; in option_find2()
1541 /* mark vendor-encapsulated options which match the client-supplied or
1542 config-supplied vendor class */
1544 for (; dopt; dopt = dopt->next) { in match_vendor_opts()
1545 dopt->flags &= ~DHOPT_VENDOR_MATCH; in match_vendor_opts()
1546 if (opt && (dopt->flags & DHOPT_VENDOR)) { in match_vendor_opts()
1548 if (dopt->u.vendor_class) len = strlen((char*) dopt->u.vendor_class); in match_vendor_opts()
1549 for (i = 0; i <= (option_len(opt) - len); i++) in match_vendor_opts()
1550 if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0) { in match_vendor_opts()
1551 dopt->flags |= DHOPT_VENDOR_MATCH; in match_vendor_opts()
1565 for (enc_len = 0, start = opt; opt; opt = opt->next) in do_encap_opts()
1566 if (opt->flags & flag) { in do_encap_opts()
1572 for (; start && start != opt; start = start->next) in do_encap_opts()
1573 if (p && (start->flags & flag)) { in do_encap_opts()
1575 *(p++) = start->opt; in do_encap_opts()
1585 for (; start; start = start->next) in do_encap_opts()
1586 if (start->flags & flag) { in do_encap_opts()
1588 *(p++) = start->opt; in do_encap_opts()
1607 … /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */ in prune_vendor_opts()
1608 for (opt = daemon->dhcp_opts; opt; opt = opt->next) in prune_vendor_opts()
1609 if (opt->flags & DHOPT_VENDOR_MATCH) { in prune_vendor_opts()
1610 if (!match_netid(opt->netid, netid, 1)) in prune_vendor_opts()
1611 opt->flags &= ~DHOPT_VENDOR_MATCH; in prune_vendor_opts()
1612 else if (opt->flags & DHOPT_FORCE) in prune_vendor_opts()
1624 int i, j = NUM_OPTS - 1; in pxe_opts()
1638 ret = daemon->dhcp_opts; in pxe_opts()
1645 fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i + 1]; in pxe_opts()
1649 p = (unsigned char*) daemon->dhcp_buff; in pxe_opts()
1650 q = (unsigned char*) daemon->dhcp_buff2; in pxe_opts()
1652 for (i = 0, service = daemon->pxe_services; service; service = service->next) in pxe_opts()
1653 if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1)) { in pxe_opts()
1654 size_t len = strlen(service->menu); in pxe_opts()
1657 if (p - (unsigned char*) daemon->dhcp_buff + len + 3 < 253) { in pxe_opts()
1658 *(p++) = service->type >> 8; in pxe_opts()
1659 *(p++) = service->type; in pxe_opts()
1661 memcpy(p, service->menu, len); in pxe_opts()
1667 return daemon->dhcp_opts; in pxe_opts()
1670 if (!service->basename) { in pxe_opts()
1671 if (service->server.s_addr != 0) { in pxe_opts()
1672 if (q - (unsigned char*) daemon->dhcp_buff2 + 3 + INADDRSZ >= 253) goto toobig; in pxe_opts()
1674 /* Boot service with known address - give it */ in pxe_opts()
1675 *(q++) = service->type >> 8; in pxe_opts()
1676 *(q++) = service->type; in pxe_opts()
1679 memcpy(q, &service->server.s_addr, INADDRSZ); in pxe_opts()
1681 } else if (service->type != 0) in pxe_opts()
1692 discovery_control = 8; /* no menu - just use use mess->filename */ in pxe_opts()
1694 ret = &fake_opts[j--]; in pxe_opts()
1695 ret->len = p - (unsigned char*) daemon->dhcp_buff; in pxe_opts()
1696 ret->val = (unsigned char*) daemon->dhcp_buff; in pxe_opts()
1697 ret->opt = SUBOPT_PXE_MENU; in pxe_opts()
1699 if (q - (unsigned char*) daemon->dhcp_buff2 != 0) { in pxe_opts()
1700 ret = &fake_opts[j--]; in pxe_opts()
1701 ret->len = q - (unsigned char*) daemon->dhcp_buff2; in pxe_opts()
1702 ret->val = (unsigned char*) daemon->dhcp_buff2; in pxe_opts()
1703 ret->opt = SUBOPT_PXE_SERVERS; in pxe_opts()
1707 for (o = daemon->dhcp_opts; o; o = o->next) in pxe_opts()
1708 if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT) break; in pxe_opts()
1711 ret = &fake_opts[j--]; in pxe_opts()
1712 ret->len = sizeof(fake_prompt); in pxe_opts()
1713 ret->val = fake_prompt; in pxe_opts()
1714 ret->opt = SUBOPT_PXE_MENU_PROMPT; in pxe_opts()
1718 ret = &fake_opts[j--]; in pxe_opts()
1719 ret->len = 1; in pxe_opts()
1720 ret->opt = SUBOPT_PXE_DISCOVERY; in pxe_opts()
1721 ret->val = &discovery_control; in pxe_opts()
1728 memset(mess->sname, 0, sizeof(mess->sname)); in clear_packet()
1729 memset(mess->file, 0, sizeof(mess->file)); in clear_packet()
1730 memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32))); in clear_packet()
1731 mess->siaddr.s_addr = 0; in clear_packet()
1737 /* decide which dhcp-boot option we're using */ in find_boot()
1738 for (boot = daemon->boot_config; boot; boot = boot->next) in find_boot()
1739 if (match_netid(boot->netid, netid, 0)) break; in find_boot()
1741 for (boot = daemon->boot_config; boot; boot = boot->next) in find_boot()
1742 if (match_netid(boot->netid, netid, 1)) break; in find_boot()
1751 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts; in do_options()
1763 if ((daemon->options & OPT_LOG_OPTS) && req_options) { in do_options()
1764 char* q = daemon->namebuff; in do_options()
1767 q += snprintf(q, MAXDNAME - (q - daemon->namebuff), "%d%s%s%s", req_options[i], in do_options()
1769 if (req_options[i + 1] == OPTION_END || (q - daemon->namebuff) > 40) { in do_options()
1770 q = daemon->namebuff; in do_options()
1771 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), in do_options()
1772 daemon->namebuff); in do_options()
1777 if (context) mess->siaddr = context->local; in do_options()
1783 Some PXE ROMs have bugs (surprise!) and need zero-terminated in do_options()
1786 if (boot->sname) { in do_options()
1787 if (!(daemon->options & OPT_NO_OVERRIDE) && req_options && in do_options()
1789 option_put_string(mess, end, OPTION_SNAME, boot->sname, 1); in do_options()
1791 strncpy((char*) mess->sname, boot->sname, sizeof(mess->sname) - 1); in do_options()
1794 if (boot->file) { in do_options()
1795 if (!(daemon->options & OPT_NO_OVERRIDE) && req_options && in do_options()
1797 option_put_string(mess, end, OPTION_FILENAME, boot->file, 1); in do_options()
1799 strncpy((char*) mess->file, boot->file, sizeof(mess->file) - 1); in do_options()
1802 if (boot->next_server.s_addr) mess->siaddr = boot->next_server; in do_options()
1804 /* Use the values of the relevant options if no dhcp-boot given and in do_options()
1806 as an internal way to specify siaddr without using dhcp-boot, for use in in do_options()
1807 dhcp-optsfile. */ in do_options()
1809 if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && mess->file[0] == 0 && in do_options()
1811 !(opt->flags & DHOPT_FORCE)) { in do_options()
1812 strncpy((char*) mess->file, (char*) opt->val, sizeof(mess->file) - 1); in do_options()
1817 (opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE)) { in do_options()
1818 strncpy((char*) mess->sname, (char*) opt->val, sizeof(mess->sname) - 1); in do_options()
1823 mess->siaddr.s_addr = ((struct in_addr*) opt->val)->s_addr; in do_options()
1826 /* We don't want to do option-overload for BOOTP, so make the file and sname in do_options()
1830 if (!req_options || (daemon->options & OPT_NO_OVERRIDE)) { in do_options()
1831 f0 = mess->file[0]; in do_options()
1832 mess->file[0] = 1; in do_options()
1833 s0 = mess->sname[0]; in do_options()
1834 mess->sname[0] = 1; in do_options()
1837 /* At this point, if mess->sname or mess->file are zeroed, they are available in do_options()
1839 if (mess->file[0] == 0 || mess->sname[0] == 0) end -= 3; in do_options()
1848 option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr)); in do_options()
1852 if (context->broadcast.s_addr && !option_find2(netid, config_opts, OPTION_BROADCAST)) in do_options()
1853 option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr)); in do_options()
1857 if (context->router.s_addr && in_list(req_options, OPTION_ROUTER) && in do_options()
1859 option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr)); in do_options()
1863 option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr)); in do_options()
1870 /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */ in do_options()
1909 for (opt = config_opts; opt; opt = opt->next) { in do_options()
1910 int optno = opt->opt; in do_options()
1913 if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno)) continue; in do_options()
1915 /* prohibit some used-internally options */ in do_options()
1928 dhc-option=<optionno> means "don't include this option" in do_options()
1929 not "include a zero-length option" */ in do_options()
1930 if (opt->len == 0 && in do_options()
1935 /* vendor-class comes from elsewhere for PXE */ in do_options()
1936 if (pxe_arch != -1 && optno == OPTION_VENDOR_ID) continue; in do_options()
1938 /* always force null-term for filename and servername - buggy PXE again. */ in do_options()
1946 /* If we send a vendor-id, revisit which vendor-ops we consider in do_options()
1948 if (optno == OPTION_VENDOR_ID) match_vendor_opts(p - 2, config_opts); in do_options()
1953 eg dhcp-option=encap:172,17,....... in do_options()
1956 for (opt = config_opts; opt; opt = opt->next) opt->flags &= ~DHOPT_ENCAP_DONE; in do_options()
1958 for (opt = config_opts; opt; opt = opt->next) in do_options()
1959 if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE) { in do_options()
1963 for (o = config_opts; o; o = o->next) { in do_options()
1964 o->flags &= ~DHOPT_ENCAP_MATCH; in do_options()
1965 if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap) { in do_options()
1966 o->flags |= DHOPT_ENCAP_DONE; in do_options()
1967 if (match_netid(o->netid, netid, 1) && in do_options()
1968 (o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap))) { in do_options()
1969 o->flags |= DHOPT_ENCAP_MATCH; in do_options()
1976 do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term); in do_options()
1983 if (pxe_arch != -1) { in do_options()
1992 /* restore BOOTP anti-overload hack */ in do_options()
1993 if (!req_options || (daemon->options & OPT_NO_OVERRIDE)) { in do_options()
1994 mess->file[0] = f0; in do_options()
1995 mess->sname[0] = s0; in do_options()