diff --git a/SOURCES/dnsmasq-2.80-rh1795370.patch b/SOURCES/dnsmasq-2.80-rh1795370.patch new file mode 100644 index 0000000..220a6af --- /dev/null +++ b/SOURCES/dnsmasq-2.80-rh1795370.patch @@ -0,0 +1,47 @@ +From 69bc94779c2f035a9fffdb5327a54c3aeca73ed5 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Wed, 14 Aug 2019 20:44:50 +0100 +Subject: [PATCH] Fix memory leak in helper.c + +Thanks to Xu Mingjie for spotting this. +--- + src/helper.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/helper.c b/src/helper.c +index 33ba120..c392eec 100644 +--- a/src/helper.c ++++ b/src/helper.c +@@ -80,7 +80,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + pid_t pid; + int i, pipefd[2]; + struct sigaction sigact; +- ++ unsigned char *alloc_buff = NULL; ++ + /* create the pipe through which the main program sends us commands, + then fork our process. */ + if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1) +@@ -186,11 +187,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + struct script_data data; + char *p, *action_str, *hostname = NULL, *domain = NULL; + unsigned char *buf = (unsigned char *)daemon->namebuff; +- unsigned char *end, *extradata, *alloc_buff = NULL; ++ unsigned char *end, *extradata; + int is6, err = 0; + int pipeout[2]; + +- free(alloc_buff); ++ /* Free rarely-allocated memory from previous iteration. */ ++ if (alloc_buff) ++ { ++ free(alloc_buff); ++ alloc_buff = NULL; ++ } + + /* we read zero bytes when pipe closed: this is our signal to exit */ + if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1)) +-- +1.7.10.4 + + diff --git a/SOURCES/dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch b/SOURCES/dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch new file mode 100644 index 0000000..bc55656 --- /dev/null +++ b/SOURCES/dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch @@ -0,0 +1,317 @@ +From 653481c6ebf46dcadb5a017085325d956dd04a28 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Tue, 21 Aug 2018 22:06:36 +0100 +Subject: [PATCH] Properly deal with unaligned addresses in DHCPv6 packets. + +Thanks to Vladislav Grishenko for spotting this. + +(cherry picked from commit 97f876b64c22b2b18412e2e3d8506ee33e42db7c) + +Conflicts: + src/rfc3315.c +--- + src/rfc1035.c | 2 +- + src/rfc3315.c | 101 ++++++++++++++++++++++++++++++++++------------------------ + 2 files changed, 61 insertions(+), 42 deletions(-) + +diff --git a/src/rfc1035.c b/src/rfc1035.c +index 6b3bb27..ee5f7a0 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -1376,7 +1376,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->local_ttl, NULL, + t->class, C_IN, "t", t->len, t->txt)) +- anscount ++; ++ anscount++; + } + } + +diff --git a/src/rfc3315.c b/src/rfc3315.c +index 21fcd9b..ee1cf17 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -639,9 +639,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + int plain_range = 1; + u32 lease_time; + struct dhcp_lease *ltmp; +- struct in6_addr *req_addr; +- struct in6_addr addr; +- ++ struct in6_addr req_addr, addr; ++ + if (!check_ia(state, opt, &ia_end, &ia_option)) + continue; + +@@ -709,9 +708,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + + for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { +- req_addr = opt6_ptr(ia_option, 0); ++ /* worry about alignment here. */ ++ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + +- if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range))) ++ if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range))) + { + lease_time = c->lease_time; + /* If the client asks for an address on the same network as a configured address, +@@ -719,14 +719,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + addresses automatic. */ + if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr)) + { +- req_addr = &addr; ++ req_addr = addr; + mark_config_used(c, &addr); + if (have_config(config, CONFIG_TIME)) + lease_time = config->lease_time; + } +- else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range))) ++ else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range))) + continue; /* not an address we're allowed */ +- else if (!check_address(state, req_addr)) ++ else if (!check_address(state, &req_addr)) + continue; /* address leased elsewhere */ + + /* add address to output packet */ +@@ -734,8 +734,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); + #endif +- add_address(state, c, lease_time, ia_option, &min_time, req_addr, now); +- mark_context_used(state, req_addr); ++ add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now); ++ mark_context_used(state, &req_addr); + get_context_tag(state, c); + address_assigned = 1; + } +@@ -768,15 +768,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + ltmp = NULL; + while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid))) + { +- req_addr = <mp->addr6; +- if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range))) ++ req_addr = ltmp->addr6; ++ if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range))) + { + #ifdef OPTION6_PREFIX_CLASS + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); + #endif +- add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now); +- mark_context_used(state, req_addr); ++ add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now); ++ mark_context_used(state, &req_addr); + get_context_tag(state, c); + address_assigned = 1; + } +@@ -892,16 +892,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + + for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { +- struct in6_addr *req_addr = opt6_ptr(ia_option, 0); ++ struct in6_addr req_addr; + struct dhcp_context *dynamic, *c; + unsigned int lease_time; + struct in6_addr addr; + int config_ok = 0; ++ ++ /* align. */ ++ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + +- if ((c = address6_valid(state->context, req_addr, tagif, 1))) +- config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr); ++ if ((c = address6_valid(state->context, &req_addr, tagif, 1))) ++ config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr); + +- if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c) ++ if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c) + { + if (!dynamic && !config_ok) + { +@@ -911,7 +914,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + put_opt6_string(_("address unavailable")); + end_opt6(o1); + } +- else if (!check_address(state, req_addr)) ++ else if (!check_address(state, &req_addr)) + { + /* Address leased to another DUID/IAID */ + o1 = new_opt6(OPTION6_STATUS_CODE); +@@ -933,7 +936,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); + #endif +- add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now); ++ add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now); + get_context_tag(state, dynamic); + address_assigned = 1; + } +@@ -996,15 +999,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { + struct dhcp_lease *lease = NULL; +- struct in6_addr *req_addr = opt6_ptr(ia_option, 0); ++ struct in6_addr req_addr; + unsigned int preferred_time = opt6_uint(ia_option, 16, 4); + unsigned int valid_time = opt6_uint(ia_option, 20, 4); + char *message = NULL; + struct dhcp_context *this_context; ++ ++ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + + if (!(lease = lease6_find(state->clid, state->clid_len, + state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, +- state->iaid, req_addr))) ++ state->iaid, &req_addr))) + { + /* If the server cannot find a client entry for the IA the server + returns the IA containing no addresses with a Status Code option set +@@ -1012,7 +1017,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + save_counter(iacntr); + t1cntr = 0; + +- log6_packet(state, "DHCPREPLY", req_addr, _("lease not found")); ++ log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found")); + + o1 = new_opt6(OPTION6_STATUS_CODE); + put_opt6_short(DHCP6NOBINDING); +@@ -1024,15 +1029,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + } + + +- if ((this_context = address6_available(state->context, req_addr, tagif, 1)) || +- (this_context = address6_valid(state->context, req_addr, tagif, 1))) ++ if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) || ++ (this_context = address6_valid(state->context, &req_addr, tagif, 1))) + { + struct in6_addr addr; + unsigned int lease_time; + + get_context_tag(state, this_context); + +- if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME)) ++ if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME)) + lease_time = config->lease_time; + else + lease_time = this_context->lease_time; +@@ -1045,7 +1050,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0); + if (state->ia_type == OPTION6_IA_NA && state->hostname) + { +- char *addr_domain = get_domain6(req_addr); ++ char *addr_domain = get_domain6(&req_addr); + if (!state->send_domain) + state->send_domain = addr_domain; + lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); +@@ -1063,12 +1068,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + } + + if (message && (message != state->hostname)) +- log6_packet(state, "DHCPREPLY", req_addr, message); ++ log6_packet(state, "DHCPREPLY", &req_addr, message); + else +- log6_quiet(state, "DHCPREPLY", req_addr, message); ++ log6_quiet(state, "DHCPREPLY", &req_addr, message); + + o1 = new_opt6(OPTION6_IAADDR); +- put_opt6(req_addr, sizeof(*req_addr)); ++ put_opt6(&req_addr, sizeof(req_addr)); + put_opt6_long(preferred_time); + put_opt6_long(valid_time); + end_opt6(o1); +@@ -1100,19 +1105,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + ia_option; + ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { +- struct in6_addr *req_addr = opt6_ptr(ia_option, 0); ++ struct in6_addr req_addr; ++ ++ /* alignment */ ++ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + +- if (!address6_valid(state->context, req_addr, tagif, 1)) ++ if (!address6_valid(state->context, &req_addr, tagif, 1)) + { + o1 = new_opt6(OPTION6_STATUS_CODE); + put_opt6_short(DHCP6NOTONLINK); + put_opt6_string(_("confirm failed")); + end_opt6(o1); ++ log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed")); + return 1; + } + + good_addr = 1; +- log6_quiet(state, "DHCPREPLY", req_addr, state->hostname); ++ log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname); + } + } + +@@ -1171,9 +1180,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { + struct dhcp_lease *lease; +- ++ struct in6_addr addr; ++ ++ /* align */ ++ memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, +- state->iaid, opt6_ptr(ia_option, 0)))) ++ state->iaid, &addr))) + lease_prune(lease, now); + else + { +@@ -1233,12 +1245,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) + { + struct dhcp_lease *lease; +- struct in6_addr *addrp = opt6_ptr(ia_option, 0); ++ struct in6_addr addr; + +- if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp)) ++ /* align */ ++ memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); ++ ++ if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr)) + { + prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF); +- inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN); ++ inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); + my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), + daemon->addrbuff, daemon->dhcp_buff3); + config->flags |= CONFIG_DECLINED; +@@ -1250,7 +1265,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + context_tmp->addr_epoch++; + + if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, +- state->iaid, opt6_ptr(ia_option, 0)))) ++ state->iaid, &addr))) + lease_prune(lease, now); + else + { +@@ -1267,7 +1282,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + } + + o1 = new_opt6(OPTION6_IAADDR); +- put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ); ++ put_opt6(&addr, IN6ADDRSZ); + put_opt6_long(0); + put_opt6_long(0); + end_opt6(o1); +@@ -1935,7 +1950,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op + } + else if (type == OPTION6_IAADDR) + { +- inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN); ++ struct in6_addr addr; ++ ++ /* align */ ++ memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ); ++ inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); + sprintf(daemon->namebuff, "%s PL=%u VL=%u", + daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4)); + optname = "iaaddr"; +-- +1.8.3.1 + diff --git a/SOURCES/dnsmasq-2.81-correct-range-check-of-dhcp-host-prefix.patch b/SOURCES/dnsmasq-2.81-correct-range-check-of-dhcp-host-prefix.patch new file mode 100644 index 0000000..fad386f --- /dev/null +++ b/SOURCES/dnsmasq-2.81-correct-range-check-of-dhcp-host-prefix.patch @@ -0,0 +1,44 @@ +From 6307208c806f9b968eca178931b3d77c4ed83c54 Mon Sep 17 00:00:00 2001 +From: Petr Mensik +Date: Fri, 6 Mar 2020 15:37:23 +0100 +Subject: [PATCH] Correct range check of dhcp-host prefix + +It incorrectly works with 32 bit integer only when counting number of +addresses in range. It works correctly only between prefixlen 96 and +128. Use 64bit shift to work with well with numbers higher than 64. + +Fixes commit 79aba0f10ad0157fb4f48afbbcb03f094caff97a error. +--- + src/option.c | 2 +- + src/rfc3315.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/option.c b/src/option.c +index 88cd2ab..79122df 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -3247,7 +3247,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + + if (!atoi_check(pref, &new_addr->prefixlen) || + new_addr->prefixlen > 128 || +- (((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0) ++ ((((u64)1<<(128-new_addr->prefixlen))-1) & addrpart) != 0) + { + dhcp_config_free(new); + ret_err(_("bad IPv6 prefix")); +diff --git a/src/rfc3315.c b/src/rfc3315.c +index a0067e9..f59aedc 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -1798,7 +1798,7 @@ static int config_valid(struct dhcp_config *config, struct dhcp_context *context + addresses = 1; + + if (addr_list->flags & ADDRLIST_PREFIX) +- addresses = 1<<(128-addr_list->prefixlen); ++ addresses = (u64)1<<(128-addr_list->prefixlen); + + if ((addr_list->flags & ADDRLIST_WILDCARD)) + { +-- +2.21.1 + diff --git a/SOURCES/dnsmasq-2.81-optimize-fds-close.patch b/SOURCES/dnsmasq-2.81-optimize-fds-close.patch new file mode 100644 index 0000000..58689da --- /dev/null +++ b/SOURCES/dnsmasq-2.81-optimize-fds-close.patch @@ -0,0 +1,132 @@ +commit 98c6998116e33f9f34b798682e0695f4166bd86d +Author: Simon Kelley +Date: Mon Mar 2 17:10:25 2020 +0000 + + Optimise closing file descriptors. + + Dnsmasq needs to close all the file descriptors it inherits, for security + reasons. This is traditionally done by calling close() on every possible + file descriptor (most of which won't be open.) On big servers where + "every possible file descriptor" is a rather large set, this gets + rather slow, so we use the /proc//fd directory to get a list + of the fds which are acually open. + + This only works on Linux. On other platforms, and on Linux systems + without a /proc filesystem, we fall back to the old way. + +diff --git a/src/dnsmasq.c b/src/dnsmasq.c +index 573aac0..10f19ea 100644 +--- a/src/dnsmasq.c ++++ b/src/dnsmasq.c +@@ -138,20 +138,18 @@ int main (int argc, char **argv) + } + #endif + +- /* Close any file descriptors we inherited apart from std{in|out|err} +- +- Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist, ++ /* Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist, + otherwise file descriptors we create can end up being 0, 1, or 2 + and then get accidentally closed later when we make 0, 1, and 2 + open to /dev/null. Normally we'll be started with 0, 1 and 2 open, + but it's not guaranteed. By opening /dev/null three times, we + ensure that we're not using those fds for real stuff. */ +- for (i = 0; i < max_fd; i++) +- if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO) +- close(i); +- else +- open("/dev/null", O_RDWR); +- ++ for (i = 0; i < 3; i++) ++ open("/dev/null", O_RDWR); ++ ++ /* Close any file descriptors we inherited apart from std{in|out|err} */ ++ close_fds(max_fd, -1, -1, -1); ++ + #ifndef HAVE_LINUX_NETWORK + # if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)) + if (!option_bool(OPT_NOWILD)) +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 6103eb5..c46bfeb 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -1283,7 +1283,7 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len, + int expand_buf(struct iovec *iov, size_t size); + char *print_mac(char *buff, unsigned char *mac, int len); + int read_write(int fd, unsigned char *packet, int size, int rw); +- ++void close_fds(long max_fd, int spare1, int spare2, int spare3); + int wildcard_match(const char* wildcard, const char* match); + int wildcard_matchn(const char* wildcard, const char* match, int num); + +diff --git a/src/helper.c b/src/helper.c +index 1b260a1..7072cf4 100644 +--- a/src/helper.c ++++ b/src/helper.c +@@ -131,12 +131,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) + Don't close err_fd, in case the lua-init fails. + Note that we have to do this before lua init + so we don't close any lua fds. */ +- for (max_fd--; max_fd >= 0; max_fd--) +- if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && +- max_fd != STDIN_FILENO && max_fd != pipefd[0] && +- max_fd != event_fd && max_fd != err_fd) +- close(max_fd); +- ++ close_fds(max_fd, pipefd[0], event_fd, err_fd); ++ + #ifdef HAVE_LUASCRIPT + if (daemon->luascript) + { +diff --git a/src/util.c b/src/util.c +index 73bf62a..f058c92 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -705,6 +705,47 @@ int read_write(int fd, unsigned char *packet, int size, int rw) + return 1; + } + ++/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */ ++void close_fds(long max_fd, int spare1, int spare2, int spare3) ++{ ++ /* On Linux, use the /proc/ filesystem to find which files ++ are actually open, rather than iterate over the whole space, ++ for efficiency reasons. If this fails we drop back to the dumb code. */ ++#ifdef HAVE_LINUX_NETWORK ++ DIR *d; ++ ++ if ((d = opendir("/proc/self/fd"))) ++ { ++ struct dirent *de; ++ ++ while ((de = readdir(d))) ++ { ++ long fd; ++ char *e = NULL; ++ ++ errno = 0; ++ fd = strtol(de->d_name, &e, 10); ++ ++ if (errno != 0 || !e || *e || fd == dirfd(d) || ++ fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO || ++ fd == spare1 || fd == spare2 || fd == spare3) ++ continue; ++ ++ close(fd); ++ } ++ ++ closedir(d); ++ return; ++ } ++#endif ++ ++ /* fallback, dumb code. */ ++ for (max_fd--; max_fd >= 0; max_fd--) ++ if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO && ++ max_fd != spare1 && max_fd != spare2 && max_fd != spare3) ++ close(max_fd); ++} ++ + /* Basically match a string value against a wildcard pattern. */ + int wildcard_match(const char* wildcard, const char* match) + { diff --git a/SOURCES/dnsmasq-2.81-prefix-ranges-or-list-of-ipv6-addresses.patch b/SOURCES/dnsmasq-2.81-prefix-ranges-or-list-of-ipv6-addresses.patch new file mode 100644 index 0000000..cf4833f --- /dev/null +++ b/SOURCES/dnsmasq-2.81-prefix-ranges-or-list-of-ipv6-addresses.patch @@ -0,0 +1,895 @@ +From 9b200103342c0909def9f8d9b97cfd889be6bfd8 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Mon, 3 Feb 2020 23:58:45 +0000 +Subject: [PATCH] Support prefixed ranges of ipv6 addresses in dhcp-host. + +When a request matching the clid or mac address is +recieved the server will iterate over all candidate +addresses until it find's one that is not already +leased to a different clid/iaid and advertise +this address. + +Using multiple reservations for a single host makes it +possible to maintain a static leases only configuration +which support network booting systems with UEFI firmware +that request a new address (a new SOLICIT with a new IA_NA +option using a new IAID) for different boot modes, for +instance 'PXE over IPv6', and 'HTTP-Boot over IPv6'. Open +Virtual Machine Firmware (OVMF) and most UEFI firmware +build on the EDK2 code base exhibit this behaviour. + +(cherry picked from commit 79aba0f10ad0157fb4f48afbbcb03f094caff97a) + +Conflicts: + CHANGELOG + src/dhcp-common.c + src/dnsmasq.h + src/dhcp6.c + +Extend 79aba0f10ad0157fb4f48afbbcb03f094caff97a for multiple IPv6 addresses. + +(cherry picked from commit 137286e9baecf6a3ba97722ef1b49c851b531810) + +Conflicts: + man/dnsmasq.8 + src/dhcp-common.c + src/dhcp6.c + src/rfc3315.c + src/option.c + +Fix bug with prefixed wildcard addresses in 137286e9baecf6a3ba97722ef1b49c851b531810 + +(cherry picked from commit f064188032a829efdcf3988b24ac795ff52785ec) + +Conflicts: + src/rfc3315.c +--- + man/dnsmasq.8 | 13 +- + src/dhcp-common.c | 56 +++++--- + src/dhcp6.c | 51 +++---- + src/dnsmasq.h | 17 +-- + src/option.c | 402 ++++++++++++++++++++++++++++++------------------------ + src/rfc3315.c | 83 ++++++++++- + 6 files changed, 370 insertions(+), 252 deletions(-) + +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 +index f52762f..2c9d9f6 100644 +--- a/man/dnsmasq.8 ++++ b/man/dnsmasq.8 +@@ -985,13 +985,20 @@ allowed to specify the client ID as text, like this: + .B --dhcp-host=id:clientidastext,..... + + A single +-.B dhcp-host +-may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus: ++.B --dhcp-host ++may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 addresses must be bracketed by square brackets thus: + .B --dhcp-host=laptop,[1234::56] + IPv6 addresses may contain only the host-identifier part: + .B --dhcp-host=laptop,[::56] + in which case they act as wildcards in constructed dhcp ranges, with +-the appropriate network part inserted. ++the appropriate network part inserted. For IPv6, an address may include a prefix length: ++.B --dhcp-host=laptop,[1234:50/126] ++which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability ++to specify multiple addresses) is useful ++when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows ++dnsmasq to honour the static address allocation but assign a different adddress for each DUID. This ++typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address. ++ + Note that in IPv6 DHCP, the hardware address may not be + available, though it normally is for direct-connected clients, or + clients using DHCP relays which support RFC 6939. +diff --git a/src/dhcp-common.c b/src/dhcp-common.c +index d9719d1..5d437dd 100644 +--- a/src/dhcp-common.c ++++ b/src/dhcp-common.c +@@ -271,26 +271,35 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config + { + if (!context) /* called via find_config() from lease_update_from_configs() */ + return 1; +- +- if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6))) +- return 1; + + #ifdef HAVE_DHCP6 +- if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD)) +- return 1; +-#endif ++ if (context->flags & CONTEXT_V6) ++ { ++ struct addrlist *addr_list; + +- for (; context; context = context->current) +-#ifdef HAVE_DHCP6 +- if (context->flags & CONTEXT_V6) +- { +- if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix)) +- return 1; +- } +- else ++ if (!(config->flags & CONFIG_ADDR6)) ++ return 1; ++ ++ for (; context; context = context->current) ++ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) ++ { ++ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64) ++ return 1; ++ ++ if (is_same_net6(&addr_list->addr.addr.addr6, &context->start6, context->prefix)) ++ return 1; ++ } ++ } ++ else + #endif +- if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) ++ { ++ if (!(config->flags & CONFIG_ADDR)) + return 1; ++ ++ for (; context; context = context->current) ++ if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) ++ return 1; ++ } + + return 0; + } +@@ -418,10 +427,21 @@ void dhcp_update_configs(struct dhcp_config *configs) + + #ifdef HAVE_DHCP6 + if (prot == AF_INET6 && +- (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config)) ++ (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr.addr.addr6)) || conf_tmp == config)) + { +- memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ); +- config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS; ++ /* host must have exactly one address if comming from /etc/hosts. */ ++ if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist)))) ++ { ++ config->addr6->next = NULL; ++ config->addr6->flags = 0; ++ } ++ ++ if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX))) ++ { ++ memcpy(&config->addr6->addr.addr.addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ); ++ config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS; ++ } ++ + continue; + } + #endif +diff --git a/src/dhcp6.c b/src/dhcp6.c +index 0853664..6f1f54e 100644 +--- a/src/dhcp6.c ++++ b/src/dhcp6.c +@@ -384,21 +384,26 @@ static int complete_context6(struct in6_addr *local, int prefix, + return 1; + } + +-struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr) ++struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, struct in6_addr *addr) + { + struct dhcp_config *config; + + for (config = configs; config; config = config->next) +- if ((config->flags & CONFIG_ADDR6) && +- is_same_net6(&config->addr6, net, prefix) && +- (prefix == 128 || addr6part(&config->addr6) == addr)) +- return config; ++ if (config->flags & CONFIG_ADDR6) ++ { ++ struct addrlist *addr_list; ++ ++ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) ++ if ((!net || is_same_net6(&addr_list->addr.addr.addr6, net, prefix) || ((addr_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) && ++ is_same_net6(&addr_list->addr.addr.addr6, addr, (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128)) ++ return config; ++ } + + return NULL; + } + + struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr, +- int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans) ++ unsigned int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans) + { + /* Find a free address: exclude anything in use and anything allocated to + a particular hwaddr/clientid/hostname in our configuration. +@@ -453,16 +458,15 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c + for (d = context; d; d = d->current) + if (addr == addr6part(&d->local6)) + break; ++ ++ *ans = c->start6; ++ setaddr6part (ans, addr); + + if (!d && + !lease6_find_by_addr(&c->start6, c->prefix, addr) && +- !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr)) +- { +- *ans = c->start6; +- setaddr6part (ans, addr); +- return c; +- } +- ++ !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, ans)) ++ return c; ++ + addr++; + + if (addr == addr6part(&c->end6) + 1) +@@ -516,27 +520,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context, + return NULL; + } + +-int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr) +-{ +- if (!config || !(config->flags & CONFIG_ADDR6)) +- return 0; +- +- if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64) +- { +- *addr = context->start6; +- setaddr6part(addr, addr6part(&config->addr6)); +- return 1; +- } +- +- if (is_same_net6(&context->start6, &config->addr6, context->prefix)) +- { +- *addr = config->addr6; +- return 1; +- } +- +- return 0; +-} +- + void make_duid(time_t now) + { + (void)now; +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 6b18bb7..9437226 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -343,9 +343,11 @@ struct ds_config { + struct ds_config *next; + }; + +-#define ADDRLIST_LITERAL 1 +-#define ADDRLIST_IPV6 2 +-#define ADDRLIST_REVONLY 4 ++#define ADDRLIST_LITERAL 1 ++#define ADDRLIST_IPV6 2 ++#define ADDRLIST_REVONLY 4 ++#define ADDRLIST_PREFIX 8 ++#define ADDRLIST_WILDCARD 16 + + struct addrlist { + struct all_addr addr; +@@ -748,7 +750,7 @@ struct dhcp_config { + char *hostname, *domain; + struct dhcp_netid_list *netid; + #ifdef HAVE_DHCP6 +- struct in6_addr addr6; ++ struct addrlist *addr6; + #endif + struct in_addr addr; + time_t decline_time; +@@ -770,7 +772,7 @@ struct dhcp_config { + #define CONFIG_DECLINED 1024 /* address declined by client */ + #define CONFIG_BANK 2048 /* from dhcp hosts file */ + #define CONFIG_ADDR6 4096 +-#define CONFIG_WILDCARD 8192 ++#define CONFIG_ADDR6_HOSTS 16384 /* address added by from /etc/hosts */ + + struct dhcp_opt { + int opt, len, flags; +@@ -1463,8 +1465,7 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, + void dhcp6_init(void); + void dhcp6_packet(time_t now); + struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr, +- int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans); +-int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr); ++ unsigned int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans); + struct dhcp_context *address6_available(struct dhcp_context *context, + struct in6_addr *taddr, + struct dhcp_netid *netids, +@@ -1474,7 +1475,7 @@ struct dhcp_context *address6_valid(struct dhcp_context *context, + struct dhcp_netid *netids, + int plain_range); + struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, +- int prefix, u64 addr); ++ int prefix, struct in6_addr *addr); + void make_duid(time_t now); + void dhcp_construct_contexts(time_t now); + void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, +diff --git a/src/option.c b/src/option.c +index b12183b..ea70ee3 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -1010,15 +1010,30 @@ static void dhcp_config_free(struct dhcp_config *config) + if (config) + { + struct hwaddr_config *hwaddr = config->hwaddr; ++ + while (hwaddr) + { + struct hwaddr_config *tmp = hwaddr; + hwaddr = hwaddr->next; + free(tmp); + } ++ + dhcp_netid_list_free(config->netid); ++ + if (config->flags & CONFIG_CLID) + free(config->clid); ++ ++ if (config->flags & CONFIG_ADDR6) ++ { ++ struct addrlist *addr, *tmp; ++ ++ for (addr = config->addr6; addr; addr = tmp) ++ { ++ tmp = addr->next; ++ free(addr); ++ } ++ } ++ + free(config); + } + } +@@ -3143,8 +3158,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + case LOPT_BANK: + case 'G': /* --dhcp-host */ + { +- int j, k = 0; +- char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + struct dhcp_config *new; + struct in_addr in; + +@@ -3155,197 +3168,222 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + new->hwaddr = NULL; + new->netid = NULL; + new->clid = NULL; ++ new->addr6 = NULL; + +- if ((a[0] = arg)) +- for (k = 1; k < 7; k++) +- if (!(a[k] = split(a[k-1]))) +- break; +- +- for (j = 0; j < k; j++) +- if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */ +- { +- char *arg = a[j]; +- +- if ((arg[0] == 'i' || arg[0] == 'I') && +- (arg[1] == 'd' || arg[1] == 'D') && +- arg[2] == ':') +- { +- if (arg[3] == '*') +- new->flags |= CONFIG_NOCLID; +- else +- { +- int len; +- arg += 3; /* dump id: */ +- if (strchr(arg, ':')) +- len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL); +- else +- { +- unhide_metas(arg); +- len = (int) strlen(arg); +- } +- +- if (len == -1) +- { +- dhcp_config_free(new); +- ret_err(_("bad hex constant")); +- } +- else if ((new->clid = opt_malloc(len))) +- { +- new->flags |= CONFIG_CLID; +- new->clid_len = len; +- memcpy(new->clid, arg, len); +- } +- } +- } +- /* dhcp-host has strange backwards-compat needs. */ +- else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg) +- { +- struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list)); +- newlist->next = new->netid; +- new->netid = newlist; +- newlist->list = dhcp_netid_create(arg+4, NULL); +- } +- else if (strstr(arg, "tag:") == arg) +- { +- +- dhcp_config_free(new); +- ret_err(_("cannot match tags in --dhcp-host")); +- } ++ while (arg) ++ { ++ comma = split(arg); ++ if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */ ++ { ++ if ((arg[0] == 'i' || arg[0] == 'I') && ++ (arg[1] == 'd' || arg[1] == 'D') && ++ arg[2] == ':') ++ { ++ if (arg[3] == '*') ++ new->flags |= CONFIG_NOCLID; ++ else ++ { ++ int len; ++ arg += 3; /* dump id: */ ++ if (strchr(arg, ':')) ++ len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL); ++ else ++ { ++ unhide_metas(arg); ++ len = (int) strlen(arg); ++ } ++ ++ if (len == -1) ++ { ++ dhcp_config_free(new); ++ ret_err(_("bad hex constant")); ++ } ++ else if ((new->clid = opt_malloc(len))) ++ { ++ new->flags |= CONFIG_CLID; ++ new->clid_len = len; ++ memcpy(new->clid, arg, len); ++ } ++ } ++ } ++ /* dhcp-host has strange backwards-compat needs. */ ++ else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg) ++ { ++ struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list)); ++ newlist->next = new->netid; ++ new->netid = newlist; ++ newlist->list = dhcp_netid_create(arg+4, NULL); ++ } ++ else if (strstr(arg, "tag:") == arg) ++ { ++ ++ dhcp_config_free(new); ++ ret_err(_("cannot match tags in --dhcp-host")); ++ } + #ifdef HAVE_DHCP6 +- else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') +- { +- arg[strlen(arg)-1] = 0; +- arg++; +- +- if (!inet_pton(AF_INET6, arg, &new->addr6)) +- { +- dhcp_config_free(new); +- ret_err(_("bad IPv6 address")); +- } +- +- for (i= 0; i < 8; i++) +- if (new->addr6.s6_addr[i] != 0) +- break; ++ else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') ++ { ++ char *pref; ++ struct in6_addr in6; ++ struct addrlist *new_addr; ++ ++ arg[strlen(arg)-1] = 0; ++ arg++; ++ pref = split_chr(arg, '/'); ++ ++ if (!inet_pton(AF_INET6, arg, &in6)) ++ { ++ dhcp_config_free(new); ++ ret_err(_("bad IPv6 address")); ++ } + +- /* set WILDCARD if network part all zeros */ +- if (i == 8) +- new->flags |= CONFIG_WILDCARD; ++ new_addr = opt_malloc(sizeof(struct addrlist)); ++ new_addr->next = new->addr6; ++ new_addr->flags = 0; ++ new_addr->addr.addr.addr6 = in6; ++ new->addr6 = new_addr; ++ ++ if (pref) ++ { ++ u64 addrpart = addr6part(&in6); ++ ++ if (!atoi_check(pref, &new_addr->prefixlen) || ++ new_addr->prefixlen > 128 || ++ (((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0) ++ { ++ dhcp_config_free(new); ++ ret_err(_("bad IPv6 prefix")); ++ } ++ ++ new_addr->flags |= ADDRLIST_PREFIX; ++ } + +- new->flags |= CONFIG_ADDR6; +- } ++ for (i= 0; i < 8; i++) ++ if (in6.s6_addr[i] != 0) ++ break; ++ ++ /* set WILDCARD if network part all zeros */ ++ if (i == 8) ++ new_addr->flags |= ADDRLIST_WILDCARD; ++ ++ new->flags |= CONFIG_ADDR6; ++ } + #endif +- else +- { +- struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config)); +- if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, +- &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1) +- { +- free(newhw); +- dhcp_config_free(new); +- ret_err(_("bad hex constant")); +- } +- else +- { +- newhw->next = new->hwaddr; +- new->hwaddr = newhw; +- } +- } +- } +- else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0)) +- { +- struct dhcp_config *configs; +- +- new->addr = in; +- new->flags |= CONFIG_ADDR; +- +- /* If the same IP appears in more than one host config, then DISCOVER +- for one of the hosts will get the address, but REQUEST will be NAKed, +- since the address is reserved by the other one -> protocol loop. */ +- for (configs = daemon->dhcp_conf; configs; configs = configs->next) +- if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr) ++ else + { +- sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in)); +- return 0; +- } +- } +- else +- { +- char *cp, *lastp = NULL, last = 0; +- int fac = 1, isdig = 0; +- +- if (strlen(a[j]) > 1) +- { +- lastp = a[j] + strlen(a[j]) - 1; +- last = *lastp; +- switch (last) ++ struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config)); ++ if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX, ++ &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1) ++ { ++ free(newhw); ++ dhcp_config_free(new); ++ ret_err(_("bad hex constant")); ++ } ++ else ++ { ++ newhw->next = new->hwaddr; ++ new->hwaddr = newhw; ++ } ++ } ++ } ++ else if (strchr(arg, '.') && (inet_pton(AF_INET, arg, &in) > 0)) ++ { ++ struct dhcp_config *configs; ++ ++ new->addr = in; ++ new->flags |= CONFIG_ADDR; ++ ++ /* If the same IP appears in more than one host config, then DISCOVER ++ for one of the hosts will get the address, but REQUEST will be NAKed, ++ since the address is reserved by the other one -> protocol loop. */ ++ for (configs = daemon->dhcp_conf; configs; configs = configs->next) ++ if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr) + { +- case 'w': +- case 'W': +- fac *= 7; +- /* fall through */ +- case 'd': +- case 'D': +- fac *= 24; +- /* fall through */ +- case 'h': +- case 'H': +- fac *= 60; +- /* fall through */ +- case 'm': +- case 'M': +- fac *= 60; +- /* fall through */ +- case 's': +- case 'S': +- *lastp = 0; +- } +- } +- +- for (cp = a[j]; *cp; cp++) +- if (isdigit((unsigned char)*cp)) +- isdig = 1; +- else if (*cp != ' ') +- break; ++ sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in)); ++ return 0; ++ } ++ } ++ else ++ { ++ char *cp, *lastp = NULL, last = 0; ++ int fac = 1, isdig = 0; ++ ++ if (strlen(arg) > 1) ++ { ++ lastp = arg + strlen(arg) - 1; ++ last = *lastp; ++ switch (last) ++ { ++ case 'w': ++ case 'W': ++ fac *= 7; ++ /* fall through */ ++ case 'd': ++ case 'D': ++ fac *= 24; ++ /* fall through */ ++ case 'h': ++ case 'H': ++ fac *= 60; ++ /* fall through */ ++ case 'm': ++ case 'M': ++ fac *= 60; ++ /* fall through */ ++ case 's': ++ case 'S': ++ *lastp = 0; ++ } ++ } ++ ++ for (cp = arg; *cp; cp++) ++ if (isdigit((unsigned char)*cp)) ++ isdig = 1; ++ else if (*cp != ' ') ++ break; ++ ++ if (*cp) ++ { ++ if (lastp) ++ *lastp = last; ++ if (strcmp(arg, "infinite") == 0) ++ { ++ new->lease_time = 0xffffffff; ++ new->flags |= CONFIG_TIME; ++ } ++ else if (strcmp(arg, "ignore") == 0) ++ new->flags |= CONFIG_DISABLE; ++ else ++ { ++ if (!(new->hostname = canonicalise_opt(arg)) || ++ !legal_hostname(new->hostname)) ++ { ++ dhcp_config_free(new); ++ ret_err(_("bad DHCP host name")); ++ } ++ ++ new->flags |= CONFIG_NAME; ++ new->domain = strip_hostname(new->hostname); ++ } ++ } ++ else if (isdig) ++ { ++ new->lease_time = atoi(arg) * fac; ++ /* Leases of a minute or less confuse ++ some clients, notably Apple's */ ++ if (new->lease_time < 120) ++ new->lease_time = 120; ++ new->flags |= CONFIG_TIME; ++ } ++ } ++ ++ arg = comma; ++ } + +- if (*cp) +- { +- if (lastp) +- *lastp = last; +- if (strcmp(a[j], "infinite") == 0) +- { +- new->lease_time = 0xffffffff; +- new->flags |= CONFIG_TIME; +- } +- else if (strcmp(a[j], "ignore") == 0) +- new->flags |= CONFIG_DISABLE; +- else +- { +- if (!(new->hostname = canonicalise_opt(a[j])) || +- !legal_hostname(new->hostname)) +- { +- dhcp_config_free(new); +- ret_err(_("bad DHCP host name")); +- } +- +- new->flags |= CONFIG_NAME; +- new->domain = strip_hostname(new->hostname); +- } +- } +- else if (isdig) +- { +- new->lease_time = atoi(a[j]) * fac; +- /* Leases of a minute or less confuse +- some clients, notably Apple's */ +- if (new->lease_time < 120) +- new->lease_time = 120; +- new->flags |= CONFIG_TIME; +- } +- } +- + daemon->dhcp_conf = new; + break; + } +- ++ + case LOPT_TAG_IF: /* --tag-if */ + { + struct tag_if *new = opt_malloc(sizeof(struct tag_if)); +diff --git a/src/rfc3315.c b/src/rfc3315.c +index ee1cf17..ee58b57 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -55,6 +55,8 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte + static void mark_context_used(struct state *state, struct in6_addr *addr); + static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr); + static int check_address(struct state *state, struct in6_addr *addr); ++static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state); ++static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr); + static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, + unsigned int *min_time, struct in6_addr *addr, time_t now); + static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now); +@@ -717,7 +719,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + /* If the client asks for an address on the same network as a configured address, + offer the configured address instead, to make moving to newly-configured + addresses automatic. */ +- if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr)) ++ if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state)) + { + req_addr = addr; + mark_config_used(c, &addr); +@@ -745,8 +747,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + for (c = state->context; c; c = c->current) + if (!(c->flags & CONTEXT_CONF_USED) && + match_netid(c->filter, solicit_tags, plain_range) && +- config_valid(config, c, &addr) && +- check_address(state, &addr)) ++ config_valid(config, c, &addr, state)) + { + mark_config_used(state->context, &addr); + if (have_config(config, CONFIG_TIME)) +@@ -895,14 +896,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + struct in6_addr req_addr; + struct dhcp_context *dynamic, *c; + unsigned int lease_time; +- struct in6_addr addr; + int config_ok = 0; + + /* align. */ + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + + if ((c = address6_valid(state->context, &req_addr, tagif, 1))) +- config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr); ++ config_ok = config_implies(config, c, &req_addr); + + if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c) + { +@@ -1032,12 +1032,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) || + (this_context = address6_valid(state->context, &req_addr, tagif, 1))) + { +- struct in6_addr addr; + unsigned int lease_time; + + get_context_tag(state, this_context); + +- if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME)) ++ if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME)) + lease_time = config->lease_time; + else + lease_time = this_context->lease_time; +@@ -1760,6 +1759,76 @@ static int check_address(struct state *state, struct in6_addr *addr) + } + + ++/* return true of *addr could have been generated from config. */ ++static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr) ++{ ++ int prefix; ++ struct in6_addr wild_addr; ++ struct addrlist *addr_list; ++ ++ if (!config || !(config->flags & CONFIG_ADDR6)) ++ return 0; ++ ++ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) ++ { ++ prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128; ++ wild_addr = addr_list->addr.addr.addr6; ++ ++ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64) ++ { ++ wild_addr = context->start6; ++ setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr.addr6)); ++ } ++ else if (!is_same_net6(&context->start6, addr, context->prefix)) ++ continue; ++ ++ if (is_same_net6(&wild_addr, addr, prefix)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state) ++{ ++ u64 addrpart, i, addresses; ++ struct addrlist *addr_list; ++ ++ if (!config || !(config->flags & CONFIG_ADDR6)) ++ return 0; ++ ++ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) ++ { ++ addrpart = addr6part(&addr_list->addr.addr.addr6); ++ addresses = 1; ++ ++ if (addr_list->flags & ADDRLIST_PREFIX) ++ addresses = 1<<(128-addr_list->prefixlen); ++ ++ if ((addr_list->flags & ADDRLIST_WILDCARD)) ++ { ++ if (context->prefix != 64) ++ continue; ++ ++ *addr = context->start6; ++ } ++ else if (is_same_net6(&context->start6, &addr_list->addr.addr.addr6, context->prefix)) ++ *addr = addr_list->addr.addr.addr6; ++ else ++ continue; ++ ++ for (i = 0 ; i < addresses; i++) ++ { ++ setaddr6part(addr, addrpart+i); ++ ++ if (check_address(state, addr)) ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ + /* Calculate valid and preferred times to send in leases/renewals. + + Inputs are: +-- +1.8.3.1 + diff --git a/SOURCES/dnsmasq-2.81-rh1829448.patch b/SOURCES/dnsmasq-2.81-rh1829448.patch new file mode 100644 index 0000000..f31b230 --- /dev/null +++ b/SOURCES/dnsmasq-2.81-rh1829448.patch @@ -0,0 +1,62 @@ +From 3d113137fd64cd0723cbecab6a36a75d3ecfb0a6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Harald=20Jens=C3=A5s?= +Date: Thu, 7 May 2020 00:33:54 +0200 +Subject: [PATCH 1/1] Fix regression in s_config_in_context() method + +Prior to commit 137286e9baecf6a3ba97722ef1b49c851b531810 +a config would not be considered in context if: +a) it has no address family flags set +b) it has the address family flag of current context set + +Since above commit config is considered in context if the +address family is the opposite of current context. + +The result is that a config with two dhcp-host records, +one for IPv6 and another for IPv4 no longer works, for +example with the below config the config with the IPv6 +address would be considered in context for a DHCP(v4) +request. + dhcp-host=52:54:00:bc:c3:fd,172.20.0.11,host2 + dhcp-host=52:54:00:bc:c3:fd,[fd12:3456:789a:1::aadd],host2 + +This commit restores the previous behavior. +--- + src/dhcp-common.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/dhcp-common.c b/src/dhcp-common.c +index eae9886..ffc78ca 100644 +--- a/src/dhcp-common.c ++++ b/src/dhcp-common.c +@@ -280,14 +280,18 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config + { + if (!context) /* called via find_config() from lease_update_from_configs() */ + return 1; +- ++ ++ /* No address present in config == in context */ ++ if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6))) ++ return 1; ++ + #ifdef HAVE_DHCP6 + if (context->flags & CONTEXT_V6) + { + struct addrlist *addr_list; + + if (!(config->flags & CONFIG_ADDR6)) +- return 1; ++ return 0; + + for (; context; context = context->current) + for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) +@@ -303,7 +307,7 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config + #endif + { + if (!(config->flags & CONFIG_ADDR)) +- return 1; ++ return 0; + + for (; context; context = context->current) + if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) +-- +2.25.4 diff --git a/SOURCES/dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch b/SOURCES/dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch new file mode 100644 index 0000000..65592a0 --- /dev/null +++ b/SOURCES/dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch @@ -0,0 +1,322 @@ +From dd04a0d90d2fca66b5f91952ae7286c5de1714f1 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Fri, 7 Feb 2020 21:05:54 +0000 +Subject: [PATCH] Add tag filtering of dhcp-host directives. + +(cherry picked from commit 52ec7836139e7a11374971905e5ac0d2d02e32c0) + +Conflicts: + CHANGELOG + src/rfc3315.c +--- + man/dnsmasq.8 | 5 ++++- + src/dhcp-common.c | 42 ++++++++++++++++++++++++++++++++---------- + src/dnsmasq.h | 4 +++- + src/lease.c | 2 +- + src/option.c | 14 ++++++-------- + src/rfc2131.c | 6 +++--- + src/rfc3315.c | 49 ++++++++++++++++++++++--------------------------- + 7 files changed, 71 insertions(+), 51 deletions(-) + +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 +index 2c9d9f6..a59b06f 100644 +--- a/man/dnsmasq.8 ++++ b/man/dnsmasq.8 +@@ -953,7 +953,7 @@ is also included, as described in RFC-3775 section 7.3. + tells dnsmasq to advertise the prefix without the on-link (aka L) bit set. + + .TP +-.B \-G, --dhcp-host=[][,id:|*][,set:][,][,][,][,ignore] ++.B \-G, --dhcp-host=[][,id:|*][,set:][tag:][,][,][,][,ignore] + Specify per host parameters for the DHCP server. This allows a machine + with a particular hardware address to be always allocated the same + hostname, IP address and lease time. A hostname specified like this +@@ -1038,6 +1038,9 @@ ignore requests from unknown machines using + .B --dhcp-ignore=tag:!known + If the host matches only a dhcp-host directive which cannot + be used because it specifies an address on different subnet, the tag "known-othernet" is set. ++ ++The tag: construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones. ++ + Ethernet addresses (but not client-ids) may have + wildcard bytes, so for example + .B --dhcp-host=00:20:e0:3b:13:*,ignore +diff --git a/src/dhcp-common.c b/src/dhcp-common.c +index 5d437dd..71e9e5b 100644 +--- a/src/dhcp-common.c ++++ b/src/dhcp-common.c +@@ -304,11 +304,12 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config + return 0; + } + +-struct dhcp_config *find_config(struct dhcp_config *configs, +- struct dhcp_context *context, +- unsigned char *clid, int clid_len, +- unsigned char *hwaddr, int hw_len, +- int hw_type, char *hostname) ++static struct dhcp_config *find_config_match(struct dhcp_config *configs, ++ struct dhcp_context *context, ++ unsigned char *clid, int clid_len, ++ unsigned char *hwaddr, int hw_len, ++ int hw_type, char *hostname, ++ struct dhcp_netid *tags, int tag_not_needed) + { + int count, new; + struct dhcp_config *config, *candidate; +@@ -320,7 +321,9 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + { + if (config->clid_len == clid_len && + memcmp(config->clid, clid, clid_len) == 0 && +- is_config_in_context(context, config)) ++ is_config_in_context(context, config) && ++ match_netid(config->filter, tags, tag_not_needed)) ++ + return config; + + /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and +@@ -328,7 +331,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + see lease_update_from_configs() */ + if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 && + memcmp(config->clid, clid+1, clid_len-1) == 0 && +- is_config_in_context(context, config)) ++ is_config_in_context(context, config) && ++ match_netid(config->filter, tags, tag_not_needed)) + return config; + } + +@@ -336,14 +340,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + if (hwaddr) + for (config = configs; config; config = config->next) + if (config_has_mac(config, hwaddr, hw_len, hw_type) && +- is_config_in_context(context, config)) ++ is_config_in_context(context, config) && ++ match_netid(config->filter, tags, tag_not_needed)) + return config; + + if (hostname && context) + for (config = configs; config; config = config->next) + if ((config->flags & CONFIG_NAME) && + hostname_isequal(config->hostname, hostname) && +- is_config_in_context(context, config)) ++ is_config_in_context(context, config) && ++ match_netid(config->filter, tags, tag_not_needed)) + return config; + + +@@ -352,7 +358,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + + /* use match with fewest wildcard octets */ + for (candidate = NULL, count = 0, config = configs; config; config = config->next) +- if (is_config_in_context(context, config)) ++ if (is_config_in_context(context, config) && ++ match_netid(config->filter, tags, tag_not_needed)) + for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) + if (conf_addr->wildcard_mask != 0 && + conf_addr->hwaddr_len == hw_len && +@@ -366,6 +373,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + return candidate; + } + ++/* Find tagged configs first. */ ++struct dhcp_config *find_config(struct dhcp_config *configs, ++ struct dhcp_context *context, ++ unsigned char *clid, int clid_len, ++ unsigned char *hwaddr, int hw_len, ++ int hw_type, char *hostname, struct dhcp_netid *tags) ++{ ++ struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0); ++ ++ if (!ret) ++ ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1); ++ ++ return ret; ++} ++ + void dhcp_update_configs(struct dhcp_config *configs) + { + /* Some people like to keep all static IP addresses in /etc/hosts. +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 9437226..055a0d1 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -749,6 +749,7 @@ struct dhcp_config { + unsigned char *clid; /* clientid */ + char *hostname, *domain; + struct dhcp_netid_list *netid; ++ struct dhcp_netid *filter; + #ifdef HAVE_DHCP6 + struct addrlist *addr6; + #endif +@@ -1514,7 +1515,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs, + struct dhcp_context *context, + unsigned char *clid, int clid_len, + unsigned char *hwaddr, int hw_len, +- int hw_type, char *hostname); ++ int hw_type, char *hostname, ++ struct dhcp_netid *filter); + int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); + #ifdef HAVE_LINUX_NETWORK + char *whichdevice(void); +diff --git a/src/lease.c b/src/lease.c +index 5c33df7..00c82f6 100644 +--- a/src/lease.c ++++ b/src/lease.c +@@ -222,7 +222,7 @@ void lease_update_from_configs(void) + if (lease->flags & (LEASE_TA | LEASE_NA)) + continue; + else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, +- lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && ++ lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) && + (config->flags & CONFIG_NAME) && + (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) + lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL); +diff --git a/src/option.c b/src/option.c +index ea70ee3..88cd2ab 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -953,8 +953,7 @@ static char *set_prefix(char *arg) + return arg; + } + +-static struct dhcp_netid * +-dhcp_netid_create(const char *net, struct dhcp_netid *next) ++static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next) + { + struct dhcp_netid *tt; + tt = opt_malloc(sizeof (struct dhcp_netid)); +@@ -1019,7 +1018,8 @@ static void dhcp_config_free(struct dhcp_config *config) + } + + dhcp_netid_list_free(config->netid); +- ++ dhcp_netid_free(config->filter); ++ + if (config->flags & CONFIG_CLID) + free(config->clid); + +@@ -3167,6 +3167,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0; + new->hwaddr = NULL; + new->netid = NULL; ++ new->filter = NULL; + new->clid = NULL; + new->addr6 = NULL; + +@@ -3215,11 +3216,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma + newlist->list = dhcp_netid_create(arg+4, NULL); + } + else if (strstr(arg, "tag:") == arg) +- { +- +- dhcp_config_free(new); +- ret_err(_("cannot match tags in --dhcp-host")); +- } ++ new->filter = dhcp_netid_create(arg+4, new->filter); ++ + #ifdef HAVE_DHCP6 + else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') + { +diff --git a/src/rfc2131.c b/src/rfc2131.c +index 997575a..a741f9f 100644 +--- a/src/rfc2131.c ++++ b/src/rfc2131.c +@@ -479,7 +479,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, + mess->op = BOOTREPLY; + + config = find_config(daemon->dhcp_conf, context, clid, clid_len, +- mess->chaddr, mess->hlen, mess->htype, NULL); ++ mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)); + + /* set "known" tag for known hosts */ + if (config) +@@ -489,7 +489,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, + netid = &known_id; + } + else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, +- mess->chaddr, mess->hlen, mess->htype, NULL)) ++ mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid))) + { + known_id.net = "known-othernet"; + known_id.next = netid; +@@ -725,7 +725,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, + to avoid impersonation by name. */ + struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, + mess->chaddr, mess->hlen, +- mess->htype, hostname); ++ mess->htype, hostname, run_tag_if(netid)); + if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) + { + config = new; +diff --git a/src/rfc3315.c b/src/rfc3315.c +index ee58b57..a0067e9 100644 +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -486,35 +486,29 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + } + } + +- if (state->clid) ++ if (state->clid && ++ (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, ++ state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) && ++ have_config(config, CONFIG_NAME)) + { +- config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL); +- +- if (have_config(config, CONFIG_NAME)) +- { +- state->hostname = config->hostname; +- state->domain = config->domain; +- state->hostname_auth = 1; +- } +- else if (state->client_hostname) +- { +- state->domain = strip_hostname(state->client_hostname); ++ state->hostname = config->hostname; ++ state->domain = config->domain; ++ state->hostname_auth = 1; ++ } ++ else if (state->client_hostname) ++ { ++ state->domain = strip_hostname(state->client_hostname); + +- if (strlen(state->client_hostname) != 0) +- { +- state->hostname = state->client_hostname; +- if (!config) +- { +- /* Search again now we have a hostname. +- Only accept configs without CLID here, (it won't match) +- to avoid impersonation by name. */ +- struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname); +- if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) +- config = new; +- } +- } ++ if (strlen(state->client_hostname) != 0) ++ { ++ /* Search again now we have a hostname. ++ Only accept configs without CLID here, (it won't match) ++ to avoid impersonation by name. */ ++ struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags)); ++ if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) ++ config = new; + } +- } ++ } + + if (config) + { +@@ -535,7 +529,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ + ignore = 1; + } + else if (state->clid && +- find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL)) ++ find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, ++ state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) + { + known_id.net = "known-othernet"; + known_id.next = state->tags; +-- +1.8.3.1 + diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec index 74fb635..061f998 100644 --- a/SPECS/dnsmasq.spec +++ b/SPECS/dnsmasq.spec @@ -13,7 +13,7 @@ Name: dnsmasq Version: 2.79 -Release: 9%{?extraversion:.%{extraversion}}%{?dist} +Release: 13%{?extraversion:.%{extraversion}}%{?dist} Summary: A lightweight DHCP/caching DNS server License: GPLv2 or GPLv3 @@ -39,6 +39,19 @@ Patch11: dnsmasq-2.76-rh1728698-3.patch Patch12: dnsmasq-2.79-rh1728698-4.patch Patch13: dnsmasq-2.79-rh1746411.patch Patch14: dnsmasq-2.79-rh1700916.patch +Patch15: dnsmasq-2.80-rh1795370.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1779187 +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=97f876b64c22b2b18412e2e3d8506ee33e42db7c +Patch16: dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=f064188032a829efdcf3988b24ac795ff52785ec +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=137286e9baecf6a3ba97722ef1b49c851b531810 +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=79aba0f10ad0157fb4f48afbbcb03f094caff97a +Patch17: dnsmasq-2.81-prefix-ranges-or-list-of-ipv6-addresses.patch +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=52ec7836139e7a11374971905e5ac0d2d02e32c0 +Patch18: dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch +Patch19: dnsmasq-2.81-correct-range-check-of-dhcp-host-prefix.patch +Patch20: dnsmasq-2.81-optimize-fds-close.patch +Patch21: dnsmasq-2.81-rh1829448.patch # This is workaround to nettle bug #1549190 # https://bugzilla.redhat.com/show_bug.cgi?id=1549190 @@ -86,6 +99,13 @@ server's leases. %patch12 -p1 -b .rh1728698-4 %patch13 -p1 -b .rh1746411 %patch14 -p1 -b .rh1700916 +%patch15 -p1 -b .rh1795370 +%patch16 -p1 -b .rh1779187-1 +%patch17 -p1 -b .rh1779187-2 +%patch18 -p1 -b .rh1779187-3 +%patch19 -p1 -b .rh1779187-4 +%patch20 -p1 -b .rh1816613 +%patch21 -p1 -b .rh1829448 # use /var/lib/dnsmasq instead of /var/lib/misc for file in dnsmasq.conf.example man/dnsmasq.8 man/es/dnsmasq.8 src/config.h; do @@ -186,6 +206,18 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/dnsmasq.conf %{_mandir}/man1/dhcp_* %changelog +* Tue May 05 2020 Petr Menšík - 2.79-13 +- Fix mixed address family reservations on DHCP (#1829448) + +* Mon Mar 30 2020 Tomas Korbar - 2.79-12 +- Minimize count of close syscalls on startup (#1816613) + +* Mon Mar 02 2020 Petr Menšík - 2.79-11 +- Support multiple static leases for single mac on IPv6 (#1779187) + +* Mon Feb 17 2020 Tomas Korbar - 2.79-10 +- Fix memory leak in helper.c (#1795370) + * Tue Dec 10 2019 Tomas Korbar - 2.79-9 - Fix replies to non-recursive queries (#1700916)