Compare commits

...

57 Commits

Author SHA1 Message Date
Dominik Derigs
ed4e7defd7 Do not fail hard when rev-server has a non-zero final address part
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-30 11:52:24 +01:00
Simon Kelley
267ab619c4 Get compilation flags for libnftables from pkg-config.
Omission spotted by Olaf Hering. Thanks.
2021-09-29 23:24:52 +01:00
Matt Whitlock
0140454ba2 dnsmasq_time: avoid signed integer overflow when HAVE_BROKEN_RTC
The dnsmasq_time() function, in the case of HAVE_BROKEN_RTC, was calling
times() to read the number of ticks "elapsed since an arbitrary point in
the past" and then dividing that by sysconf(_SC_CLK_TCK) to compute the
number of seconds elapsed since that arbitrary instant. This works fine
until the number of ticks exceeds 2^31, beyond which time the function
would begin erroneously returning negative times. On my system this
happens after approximately 248 days of uptime. A symptom is that
dnsmasq no longer populates the resolver cache with DHCP-derived names
at startup, as the inserted cache entries immediately expire due to
having negative expiration times that cause is_expired() to return true
when called with now==0.

This commit replaces the archaic implementation of dnsmasq_time() with a
call to the POSIX-standardized clock_gettime(CLOCK_MONOTONIC), thereby
eliminating the need to convert manually from ticks to seconds. The new
implementation will yield correct results until the system uptime
exceeds approximately 68 years.

Signed-off-by: Matt Whitlock <dnsmasq@mattwhitlock.name>
2021-09-29 09:46:13 +01:00
Simon Kelley
2c60441239 Fix FTBFS when CONNTRACK and UBUS but not DNSSEC compile options selected. 2021-09-28 23:42:15 +01:00
Simon Kelley
cbbd56c965 Build Debian binaries with NFTset support. 2021-09-27 23:16:18 +01:00
Simon Kelley
2561f9fe0e Fix confusion in DNS retries and --strict-order.
Behaviour to stop infinite loops when all servers return REFUSED
was wrongly activated on client retries, resulting in
incorrect REFUSED replies to client retries.

Thanks to Johannes Stezenbach for finding the problem.
2021-09-27 22:37:02 +01:00
Simon Kelley
47aefca5e4 Add --nftset option, like --ipset but for the newer nftables.
Thanks to Chen Zhenge for the original patch, which I've
reworked. Any bugs down to SRK.
2021-09-27 21:49:28 +01:00
Simon Kelley
981fb03710 Make --rebind-domain-ok work with IDN. 2021-09-24 15:25:05 +01:00
Paul Fertser
ef2f8d70d2 manpage: clarify tags: semantics for --dhcp-host
Mention that several tags can be specified and instruct the user that
some other match must still be provided for the directive to have any
effect.
2021-09-24 14:46:25 +01:00
Dominik Derigs
d9995a1add Improve last patch by splitting the previously combined if
Signed-off-by: DL6ER <dl6er@dl6er.de>

(also cosmetic change to logging for improved translation from
Matthias Andree <matthias.andree@gmx.de>)
2021-09-23 22:54:17 +01:00
Dominik Derigs
ea7a05ad43 Correcly warn if dynamic directory is actually no directory
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-23 11:02:11 +01:00
Simon Kelley
26bbf5a314 Fix --address=/#/...... which was lost in 2.86
A victim of the domain-search rewrite. Apologies.
2021-09-23 10:54:46 +01:00
Dominik DL6ER
c147329823 Check if allocation of 66573 bytes succeeded before accessing the memory to avoid crash in busy times
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-20 21:20:41 +01:00
hev
eb88eed1fc Optimize inserting records into server list.
Signed-off-by: hev <r@hev.cc>
2021-09-20 20:12:50 +01:00
Simon Kelley
8312a3ba4f Thinko in immediately previous commit. 2021-09-20 19:44:56 +01:00
Simon Kelley
35f93081dc Add support for arbitrary prefix lengths in --rev-server and --domain=....,local
Previously, the prefix was limited to [8,16,24,32] for IPv4 and
to multiples of 4 for IPv6. This patch also makes the prefix-length optional
for --rev-server.

Inspired by a patch from DL6ER <dl6er@dl6er.de>, but completely
re-written by srk. All bugs are his.
2021-09-20 00:05:42 +01:00
Simon Kelley
de372d6914 Fix confusion is server=/domain/# combined with server|address=/domain/....
The 2.86 domain matching rewrite failed to take into account the possibilty that

server=/example.com/#

could be combined with, for example

address=/example.com/1.2.3.4

resulting in the struct server datastructure for the former getting passed
to forward_query(), rapidly followed by a SEGV.

This fix makes server=/example.com/# a fully fledged member of the
priority list, which is now  IPv6 addr, IPv4 addr, all zero return,
resolvconf servers, upstream servers, no-data return

Thanks to dl6er@dl6er.de for finding and characterising the bug.
2021-09-18 23:01:12 +01:00
Petr Menšík
4ac517e4ac Fix coverity issues in dnssec.c
Error: CHECKED_RETURN (CWE-252): [#def26]
dnsmasq-2.86rc3/src/dnssec.c:727: check_return: Calling "extract_name" without checking return value (as is done elsewhere 9 out of 10 times).
dnsmasq-2.86rc3/src/dnssec.c:459: example_checked: Example 1: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:269: example_checked: Example 2: "extract_name(header, plen, &state->ip, state->buff, 1, 0)" has its value checked in "extract_name(header, plen, &state->ip, state->buff, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:569: example_checked: Example 3: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:648: example_checked: Example 4: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:787: example_checked: Example 5: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
 #  725|         /* namebuff used for workspace above, restore to leave unchanged on exit */
 #  726|         p = (unsigned char*)(rrset[0]);
 #  727|->       extract_name(header, plen, &p, name, 1, 0);
 #  728|
 #  729|         if (key)

Error: CHECKED_RETURN (CWE-252): [#def27]
dnsmasq-2.86rc3/src/dnssec.c:1020: check_return: Calling "extract_name" without checking return value (as is done elsewhere 7 out of 8 times).
dnsmasq-2.86rc3/src/auth.c:140: example_checked: Example 1: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/dnssec.c:771: example_checked: Example 2: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/hash-questions.c:57: example_checked: Example 3: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1028: example_checked: Example 4: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1438: example_checked: Example 5: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
 # 1018|
 # 1019|     p = (unsigned char *)(header+1);
 # 1020|->   extract_name(header, plen, &p, name, 1, 4);
 # 1021|     p += 4; /* qtype, qclass */
 # 1022|
2021-09-11 22:08:25 +01:00
Petr Menšík
e3651367b3 Fix coverity detected issues in dnsmasq.c
Error: DEADCODE (CWE-561): [#def12]
dnsmasq-2.86rc3/src/dnsmasq.c:37: assignment: Assigning: "bind_fallback" = "0".
dnsmasq-2.86rc3/src/dnsmasq.c:927: const: At condition "bind_fallback", the value of "bind_fallback" must be equal to 0.
dnsmasq-2.86rc3/src/dnsmasq.c:927: dead_error_condition: The condition "bind_fallback" cannot be true.
dnsmasq-2.86rc3/src/dnsmasq.c:928: dead_error_line: Execution cannot reach this statement: "my_syslog(4, "setting --bin...".
dnsmasq-2.86rc3/src/dnsmasq.c:928: effectively_constant: Local variable "bind_fallback" is assigned only once, to a constant value, making it effectively constant throughout its scope. If this is not the intent, examine the logic to see if there is a missing assignment that would make "bind_fallback" not remain constant.
 #  926|
 #  927|     if (bind_fallback)
 #  928|->     my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
 #  929|
 #  930|     if (option_bool(OPT_NOWILD))

Error: REVERSE_NEGATIVE (CWE-191): [#def13]
dnsmasq-2.86rc3/src/dnsmasq.c:383: negative_sink_in_call: Passing "dnsmasq_daemon->pxefd" to a parameter that cannot be negative.
dnsmasq-2.86rc3/src/dnsmasq.c:1086: check_after_sink: You might be using variable "dnsmasq_daemon->pxefd" before verifying that it is >= 0.
 # 1084|   	{
 # 1085|   	  poll_listen(daemon->dhcpfd, POLLIN);
 # 1086|-> 	  if (daemon->pxefd != -1)
 # 1087|   	    poll_listen(daemon->pxefd, POLLIN);
 # 1088|   	}

Error: CHECKED_RETURN (CWE-252): [#def18]
dnsmasq-2.86rc3/src/dnsmasq.c:1582: check_return: Calling "fcntl(dnsmasq_daemon->helperfd, 4, i & 0xfffffffffffff7ff)" without checking return value. This library function may fail and return an error code.
 # 1580|   	    /* block in writes until all done */
 # 1581|   	    if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
 # 1582|-> 	      fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
 # 1583|   	    do {
 # 1584|   	      helper_write();

Error: CHECKED_RETURN (CWE-252): [#def22]
dnsmasq-2.86rc3/src/dnsmasq.c:1991: check_return: Calling "fcntl(confd, 4, flags & 0xfffffffffffff7ff)" without checking return value. This library function may fail and return an error code.
 # 1989|   		 Reset that here. */
 # 1990|   	      if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
 # 1991|-> 		fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
 # 1992|
 # 1993|   	      buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);

Error: CHECKED_RETURN (CWE-252): [#def26]
dnsmasq-2.86rc3/src/dnssec.c:727: check_return: Calling "extract_name" without checking return value (as is done elsewhere 9 out of 10 times).
dnsmasq-2.86rc3/src/dnssec.c:459: example_checked: Example 1: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:269: example_checked: Example 2: "extract_name(header, plen, &state->ip, state->buff, 1, 0)" has its value checked in "extract_name(header, plen, &state->ip, state->buff, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:569: example_checked: Example 3: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:648: example_checked: Example 4: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:787: example_checked: Example 5: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
 #  725|         /* namebuff used for workspace above, restore to leave unchanged on exit */
 #  726|         p = (unsigned char*)(rrset[0]);
 #  727|->       extract_name(header, plen, &p, name, 1, 0);
 #  728|
 #  729|         if (key)

Error: CHECKED_RETURN (CWE-252): [#def27]
dnsmasq-2.86rc3/src/dnssec.c:1020: check_return: Calling "extract_name" without checking return value (as is done elsewhere 7 out of 8 times).
dnsmasq-2.86rc3/src/auth.c:140: example_checked: Example 1: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/dnssec.c:771: example_checked: Example 2: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/hash-questions.c:57: example_checked: Example 3: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1028: example_checked: Example 4: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1438: example_checked: Example 5: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
 # 1018|
 # 1019|     p = (unsigned char *)(header+1);
 # 1020|->   extract_name(header, plen, &p, name, 1, 4);
 # 1021|     p += 4; /* qtype, qclass */
 # 1022|
2021-09-11 22:08:14 +01:00
Petr Menšík
02ea41ddd1 Fix coverity issues detected in domain-match.c
Error: CHECKED_RETURN (CWE-252): [#def28]
dnsmasq-2.86rc3/src/domain-match.c:414: check_return: Calling "add_resource_record" without checking return value (as is done elsewhere 44 out of 46 times).
dnsmasq-2.86rc3/src/auth.c:214: example_checked: Example 1: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)".
dnsmasq-2.86rc3/src/auth.c:239: example_checked: Example 2: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)".
dnsmasq-2.86rc3/src/rfc1035.c:1463: example_checked: Example 3: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)".
dnsmasq-2.86rc3/src/rfc1035.c:1500: example_checked: Example 4: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)".
dnsmasq-2.86rc3/src/rfc1035.c:2021: example_checked: Example 5: "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)" has its value checked in "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)".
 #  412|
 #  413|   	header->ancount = htons(ntohs(header->ancount) + 1);
 #  414|-> 	add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr);
 #  415|   	log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL);
 #  416|         }

Error: CHECKED_RETURN (CWE-252): [#def29]
dnsmasq-2.86rc3/src/domain-match.c:429: check_return: Calling "add_resource_record" without checking return value (as is done elsewhere 44 out of 46 times).
dnsmasq-2.86rc3/src/auth.c:214: example_checked: Example 1: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", intr->name)".
dnsmasq-2.86rc3/src/auth.c:239: example_checked: Example 2: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, dnsmasq_daemon->auth_ttl, NULL, 12, 1, "d", name)".
dnsmasq-2.86rc3/src/rfc1035.c:1463: example_checked: Example 3: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, 5, 1, "d", cname_target)".
dnsmasq-2.86rc3/src/rfc1035.c:1500: example_checked: Example 4: "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)" has its value checked in "add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, 16, t->class, "t", t->len, t->txt)".
dnsmasq-2.86rc3/src/rfc1035.c:2021: example_checked: Example 5: "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)" has its value checked in "add_resource_record(header, limit, NULL, rec->offset, &ansp, crec_ttl(crecp, now), NULL, type, 1, ((crecp->flags & 0x80U) ? "4" : "6"), &crecp->addr)".
 #  427|
 #  428|   	header->ancount = htons(ntohs(header->ancount) + 1);
 #  429|-> 	add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr);
 #  430|   	log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL);
 #  431|         }

Error: NULL_RETURNS (CWE-476): [#def30]
dnsmasq-2.86rc3/src/domain-match.c:611: returned_null: "whine_malloc" returns "NULL" (checked 72 out of 76 times).
dnsmasq-2.86rc3/src/domain-match.c:611: var_assigned: Assigning: "alloc_domain" = "NULL" return value from "whine_malloc".
dnsmasq-2.86rc3/src/domain-match.c:620: dereference: Dereferencing a pointer that might be "NULL" "alloc_domain" when calling "hostname_isequal".
dnsmasq-2.86rc3/src/arp.c:88: example_checked: Example 1: "whine_malloc(48UL)" has its value checked in "arp = whine_malloc(48UL)".
dnsmasq-2.86rc3/src/blockdata.c:24: example_assign: Example 2: Assigning: "new" = return value from "whine_malloc(n * 48UL)".
dnsmasq-2.86rc3/src/blockdata.c:26: example_checked: Example 2 (cont.): "new" has its value checked in "new".
dnsmasq-2.86rc3/src/cache.c:1545: example_assign: Example 3: Assigning: "crecp" = return value from "whine_malloc(70UL)".
dnsmasq-2.86rc3/src/cache.c:1547: example_checked: Example 3 (cont.): "crecp" has its value checked in "crecp".
dnsmasq-2.86rc3/src/forward.c:1791: example_assign: Example 4: Assigning: "packet" = return value from "whine_malloc(66573UL)".
dnsmasq-2.86rc3/src/forward.c:1795: example_checked: Example 4 (cont.): "packet" has its value checked in "packet".
dnsmasq-2.86rc3/src/inotify.c:186: example_checked: Example 5: "whine_malloc(lendir + lenfile + 2UL)" has its value checked in "path = whine_malloc(lendir + lenfile + 2UL)".
 #  618|     if (flags & SERV_IS_LOCAL)
 #  619|       for (serv = daemon->servers; serv; serv = serv->next)
 #  620|->       if ((serv->flags & SERV_MARK) &&
 #  621|   	  hostname_isequal(alloc_domain, serv->domain))
 #  622|   	break;

Error: RESOURCE_LEAK (CWE-772): [#def31] [important]
dnsmasq-2.86rc3/src/domain-match.c:611: alloc_fn: Storage is returned from allocation function "whine_malloc".
dnsmasq-2.86rc3/src/domain-match.c:611: var_assign: Assigning: "alloc_domain" = storage returned from "whine_malloc(1UL)".
dnsmasq-2.86rc3/src/domain-match.c:620: noescape: Resource "alloc_domain" is not freed or pointed-to in "hostname_isequal".
dnsmasq-2.86rc3/src/domain-match.c:646: leaked_storage: Variable "alloc_domain" going out of scope leaks the storage it points to.
 #  644|
 #  645|         if (!(serv = whine_malloc(size)))
 #  646|-> 	return 0;
 #  647|
 #  648|         if (flags & SERV_IS_LOCAL)

Error: NULL_RETURNS (CWE-476): [#def32]
dnsmasq-2.86rc3/src/domain-match.c:611: returned_null: "whine_malloc" returns "NULL" (checked 72 out of 76 times).
dnsmasq-2.86rc3/src/domain-match.c:611: var_assigned: Assigning: "alloc_domain" = "NULL" return value from "whine_malloc".
dnsmasq-2.86rc3/src/domain-match.c:674: dereference: Dereferencing a pointer that might be "NULL" "alloc_domain" when calling "strlen".
dnsmasq-2.86rc3/src/arp.c:88: example_checked: Example 1: "whine_malloc(48UL)" has its value checked in "arp = whine_malloc(48UL)".
dnsmasq-2.86rc3/src/blockdata.c:24: example_assign: Example 2: Assigning: "new" = return value from "whine_malloc(n * 48UL)".
dnsmasq-2.86rc3/src/blockdata.c:26: example_checked: Example 2 (cont.): "new" has its value checked in "new".
dnsmasq-2.86rc3/src/cache.c:1545: example_assign: Example 3: Assigning: "crecp" = return value from "whine_malloc(70UL)".
dnsmasq-2.86rc3/src/cache.c:1547: example_checked: Example 3 (cont.): "crecp" has its value checked in "crecp".
dnsmasq-2.86rc3/src/forward.c:1791: example_assign: Example 4: Assigning: "packet" = return value from "whine_malloc(66573UL)".
dnsmasq-2.86rc3/src/forward.c:1795: example_checked: Example 4 (cont.): "packet" has its value checked in "packet".
dnsmasq-2.86rc3/src/inotify.c:186: example_checked: Example 5: "whine_malloc(lendir + lenfile + 2UL)" has its value checked in "path = whine_malloc(lendir + lenfile + 2UL)".
 #  672|     serv->flags = flags;
 #  673|     serv->domain = alloc_domain;
 #  674|->   serv->domain_len = strlen(alloc_domain);
 #  675|
 #  676|     if (flags & SERV_4ADDR)
2021-09-11 22:04:05 +01:00
Simon Kelley
51ffae4eab Fix coverity detected issues in cache.c
Error: UNINIT (CWE-457): [#def27]
dnsmasq-2.86test7/src/cache.c:1193: var_decl: Declaring variable "lrec" without initializer.
dnsmasq-2.86test7/src/cache.c:1315: uninit_use_in_call: Using uninitialized value "lrec.ttd" when calling "make_non_terminals".
 # 1313|       {
 # 1314|         lrec.name.namep = txt->name;
 # 1315|->       make_non_terminals(&lrec);
 # 1316|       }
 # 1317|

Error: CLANG_WARNING: [#def29]
dnsmasq-2.86test7/src/cache.c:1552:15: warning[core.uninitialized.Assign]: Assigned value is garbage or undefined
 # 1550|   	{
 # 1551|   	  crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
 # 1552|-> 	  crecp->ttd = source->ttd;
 # 1553|   	  crecp->name.namep = name;
 # 1554|
2021-09-11 21:57:30 +01:00
Petr Menšík
afe84f37f8 Fix coverity detected issue in radv.c
Error: NULL_RETURNS (CWE-476): [#def114]
dnsmasq-2.86test7/src/radv.c:748: returned_null: "expand" returns "NULL" (checked 10 out of 11 times).
dnsmasq-2.86test7/src/radv.c:748: var_assigned: Assigning: "p" = "NULL" return value from "expand".
dnsmasq-2.86test7/src/radv.c:749: dereference: Dereferencing a pointer that might be "NULL" "p" when calling "memset". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/outpacket.c:83: example_checked: Example 1: "expand(len)" has its value checked in "p = expand(len)".
dnsmasq-2.86test7/src/outpacket.c:109: example_checked: Example 2: "expand(1UL)" has its value checked in "p = expand(1UL)".
dnsmasq-2.86test7/src/radv.c:269: example_checked: Example 3: "expand(16UL)" has its value checked in "ra = expand(16UL)".
dnsmasq-2.86test7/src/radv.c:363: example_checked: Example 4: "expand(32UL)" has its value checked in "opt = expand(32UL)".
dnsmasq-2.86test7/src/radv.c:708: example_checked: Example 5: "expand(32UL)" has its value checked in "opt = expand(32UL)".
 #  747|         int len = (maclen + 9) >> 3;
 #  748|         unsigned char *p = expand(len << 3);
 #  749|->       memset(p, 0, len << 3);
 #  750|         *p++ = ICMP6_OPT_SOURCE_MAC;
 #  751|         *p++ = len;

Error: NULL_RETURNS (CWE-476): [#def115]
dnsmasq-2.86test7/src/radv.c:748: returned_null: "expand" returns "NULL" (checked 10 out of 11 times).
dnsmasq-2.86test7/src/radv.c:748: var_assigned: Assigning: "p" = "NULL" return value from "expand".
dnsmasq-2.86test7/src/radv.c:750: dereference: Incrementing a pointer which might be null: "p".
dnsmasq-2.86test7/src/outpacket.c:83: example_checked: Example 1: "expand(len)" has its value checked in "p = expand(len)".
dnsmasq-2.86test7/src/outpacket.c:109: example_checked: Example 2: "expand(1UL)" has its value checked in "p = expand(1UL)".
dnsmasq-2.86test7/src/radv.c:269: example_checked: Example 3: "expand(16UL)" has its value checked in "ra = expand(16UL)".
dnsmasq-2.86test7/src/radv.c:363: example_checked: Example 4: "expand(32UL)" has its value checked in "opt = expand(32UL)".
dnsmasq-2.86test7/src/radv.c:708: example_checked: Example 5: "expand(32UL)" has its value checked in "opt = expand(32UL)".
 #  748|         unsigned char *p = expand(len << 3);
 #  749|         memset(p, 0, len << 3);
 #  750|->       *p++ = ICMP6_OPT_SOURCE_MAC;
 #  751|         *p++ = len;
 #  752|         memcpy(p, mac, maclen);
2021-09-11 21:51:10 +01:00
Petr Menšík
0afeef0e00 Fix coverity detected issues in option.c
Error: STRING_OVERFLOW (CWE-120): [#def99]
dnsmasq-2.86test7/src/option.c:801: fixed_size_dest: You might overrun the 100-character fixed-size string "buff" by copying "usage[i].arg" without checking the length.
#  799|         if (usage[i].arg)
#  800|   	{
#  801|-> 	  strcpy(buff, usage[i].arg);
#  802|   	  for (j = 0; tab[j].handle; j++)
#  803|   	    if (tab[j].handle == *(usage[i].arg))

Error: CLANG_WARNING: [#def100]
dnsmasq-2.86test7/src/option.c:962:3: warning[deadcode.DeadStores]: Value stored to 'domain' is never read
#  960|       }
#  961|
#  962|->   domain += sprintf(domain, "in-addr.arpa");
#  963|
#  964|     return 1;

Error: CLANG_WARNING: [#def101]
dnsmasq-2.86test7/src/option.c:981:3: warning[deadcode.DeadStores]: Value stored to 'domain' is never read
#  979|         domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
#  980|       }
#  981|->   domain += sprintf(domain, "ip6.arpa");
#  982|
#  983|     return 1;

Error: RESOURCE_LEAK (CWE-772): [#def102] [important]
dnsmasq-2.86test7/src/option.c:1809: alloc_fn: Storage is returned from allocation function "opt_malloc".
dnsmasq-2.86test7/src/option.c:1809: var_assign: Assigning: "path" = storage returned from "opt_malloc(strlen(directory) + len + 2UL)".
dnsmasq-2.86test7/src/option.c:1810: noescape: Resource "path" is not freed or pointed-to in "strcpy". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1811: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1812: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1815: noescape: Resource "path" is not freed or pointed-to in "stat".
dnsmasq-2.86test7/src/option.c:1809: overwrite_var: Overwriting "path" in "path = opt_malloc(strlen(directory) + len + 2UL)" leaks the storage that "path" points to.
# 1807|   	      continue;
# 1808|
# 1809|-> 	    path = opt_malloc(strlen(directory) + len + 2);
# 1810|   	    strcpy(path, directory);
# 1811|   	    strcat(path, "/");

Error: RESOURCE_LEAK (CWE-772): [#def103] [important]
dnsmasq-2.86test7/src/option.c:1809: alloc_fn: Storage is returned from allocation function "opt_malloc".
dnsmasq-2.86test7/src/option.c:1809: var_assign: Assigning: "path" = storage returned from "opt_malloc(strlen(directory) + len + 2UL)".
dnsmasq-2.86test7/src/option.c:1810: noescape: Resource "path" is not freed or pointed-to in "strcpy". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1811: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1812: noescape: Resource "path" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.]
dnsmasq-2.86test7/src/option.c:1815: noescape: Resource "path" is not freed or pointed-to in "stat".
dnsmasq-2.86test7/src/option.c:1858: leaked_storage: Variable "path" going out of scope leaks the storage it points to.
# 1856|   	    free(files);
# 1857|   	  }
# 1858|-> 	break;
# 1859|         }
# 1860|

Error: RESOURCE_LEAK (CWE-772): [#def104] [important]
dnsmasq-2.86test7/src/option.c:1996: alloc_fn: Storage is returned from allocation function "canonicalise_opt".
dnsmasq-2.86test7/src/option.c:1996: var_assign: Assigning: "name" = storage returned from "canonicalise_opt(arg)".
dnsmasq-2.86test7/src/option.c:1998: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
# 1996|   	if (!(name = canonicalise_opt(arg)) ||
# 1997|   	    (comma && !(target = canonicalise_opt(comma))))
# 1998|-> 	  ret_err(_("bad MX name"));
# 1999|
# 2000|   	new = opt_malloc(sizeof(struct mx_srv_record));

Error: RESOURCE_LEAK (CWE-772): [#def106] [important]
dnsmasq-2.86test7/src/option.c:3477: alloc_fn: Storage is returned from allocation function "opt_malloc".
dnsmasq-2.86test7/src/option.c:3477: var_assign: Assigning: "new" = storage returned from "opt_malloc(96UL)".
dnsmasq-2.86test7/src/option.c:3618: leaked_storage: Variable "new" going out of scope leaks the storage it points to.
# 3616|   		      sprintf(errstr, _("duplicate dhcp-host IP address %s"),
# 3617|   			      daemon->addrbuff);
# 3618|-> 		      return 0;
# 3619|   		    }
# 3620|   	      }

Error: RESOURCE_LEAK (CWE-772): [#def108] [important]
dnsmasq-2.86test7/src/option.c:3781: alloc_fn: Storage is returned from allocation function "opt_malloc".
dnsmasq-2.86test7/src/option.c:3781: var_assign: Assigning: "new" = storage returned from "opt_malloc(32UL)".
dnsmasq-2.86test7/src/option.c:3786: leaked_storage: Variable "new" going out of scope leaks the storage it points to.
# 3784|
# 3785|   	if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
# 3786|-> 	  ret_err(gen_err);
# 3787|
# 3788|   	new->wildcard = 0;

Error: RESOURCE_LEAK (CWE-772): [#def109] [important]
dnsmasq-2.86test7/src/option.c:3921: alloc_fn: Storage is returned from allocation function "opt_malloc".
dnsmasq-2.86test7/src/option.c:3921: var_assign: Assigning: "new" = storage returned from "opt_malloc(56UL)".
dnsmasq-2.86test7/src/option.c:3994: leaked_storage: Variable "new" going out of scope leaks the storage it points to.
# 3992|   	   }
# 3993|
# 3994|-> 	 ret_err(gen_err);
# 3995|          }
# 3996|

Error: CLANG_WARNING: [#def111]
dnsmasq-2.86test7/src/option.c:4693:25: warning[deadcode.DeadStores]: Value stored to 'tmp' during its initialization is never read
# 4691|   		if (!canon)
# 4692|                     {
# 4693|-> 		    struct name_list *tmp = new->names, *next;
# 4694|   		    for (tmp = new->names; tmp; tmp = next)
# 4695|
2021-09-11 21:50:33 +01:00
Petr Menšík
94a17fd97f Address coverity issues detected in util.c 2021-09-11 21:49:28 +01:00
Petr Menšík
5b5ec55445 Fix coverity warnings on dbus
Error: CLANG_WARNING: [#def30]
dnsmasq-2.86test7/src/dbus.c:117:3: warning[deadcode.DeadStores]: Value stored to 'w' is never read
 #  115|     daemon->watches = w;
 #  116|
 #  117|->   w = data; /* no warning */
 #  118|     return TRUE;
 #  119|   }

Error: CLANG_WARNING: [#def31]
dnsmasq-2.86test7/src/dbus.c:137:3: warning[deadcode.DeadStores]: Value stored to 'w' is never read
 #  135|       }
 #  136|
 #  137|->   w = data; /* no warning */
 #  138|   }
 #  139|

Error: CHECKED_RETURN (CWE-252): [#def32]
dnsmasq-2.86test7/src/dbus.c:146: check_return: Calling "dbus_message_iter_init" without checking return value (as is done elsewhere 4 out of 5 times).
dnsmasq-2.86test7/src/dbus.c:460: example_checked: Example 1: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)".
dnsmasq-2.86test7/src/dbus.c:573: example_checked: Example 2: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)".
dnsmasq-2.86test7/src/dbus.c:257: example_checked: Example 3: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)".
dnsmasq-2.86test7/src/dbus.c:427: example_checked: Example 4: "dbus_message_iter_init(message, &iter)" has its value checked in "dbus_message_iter_init(message, &iter)".
 #  144|     char *domain;
 #  145|
 #  146|->   dbus_message_iter_init(message, &iter);
 #  147|
 #  148|     mark_servers(SERV_FROM_DBUS);

Error: NEGATIVE_RETURNS (CWE-394): [#def33]
dnsmasq-2.86test7/src/dbus.c:547: negative_return_fn: Function "parse_hex((char *)hwaddr, dhcp_chaddr, 16, NULL, &hw_type)" returns a negative number.
dnsmasq-2.86test7/src/dbus.c:547: assign: Assigning: "hw_len" = "parse_hex((char *)hwaddr, dhcp_chaddr, 16, NULL, &hw_type)".
dnsmasq-2.86test7/src/dbus.c:551: negative_returns: "hw_len" is passed to a parameter that cannot be negative.
 #  549|       hw_type = ARPHRD_ETHER;
 #  550|
 #  551|->   lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
 #  552|                      clid_len, now, 0);
 #  553|     lease_set_expires(lease, expires, now);

Error: CLANG_WARNING: [#def34]
dnsmasq-2.86test7/src/dbus.c:722:3: warning[deadcode.DeadStores]: Value stored to 'method' is never read
 #  720|       clear_cache_and_reload(dnsmasq_time());
 #  721|
 #  722|->   method = user_data; /* no warning */
 #  723|
 #  724|     /* If no reply or no error, return nothing */
2021-09-11 21:37:18 +01:00
Petr Menšík
1e6565c1a5 Retry dhcp6 ping on interrupts
Error: CHECKED_RETURN (CWE-252): [#def35]
dnsmasq-2.86test7/src/dhcp6.c:295: check_return: Calling "sendto(dnsmasq_daemon->icmp6fd, &neigh, 24UL, 0, __CONST_SOCKADDR_ARG({.__sockaddr__ = &addr.sa}), 28U)" without checking return value. This library function may fail and return an error code.
 #  293|   	break;
 #  294|
 #  295|->       sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
 #  296|
 #  297|         ts.tv_sec = 0;
2021-09-11 21:36:30 +01:00
Petr Menšík
fc522515b9 Fix coverity formats issues in blockdata
Error: PRINTF_ARGS (CWE-686): [#def16]
dnsmasq-2.86test7/src/blockdata.c:56: invalid_type: Argument "blockdata_count * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long".
 #   54|   {
 #   55|     my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
 #   56|-> 	    blockdata_count * sizeof(struct blockdata),
 #   57|   	    blockdata_hwm * sizeof(struct blockdata),
 #   58|   	    blockdata_alloced * sizeof(struct blockdata));

Error: PRINTF_ARGS (CWE-686): [#def17]
dnsmasq-2.86test7/src/blockdata.c:57: invalid_type: Argument "blockdata_hwm * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long".
 #   55|     my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
 #   56|   	    blockdata_count * sizeof(struct blockdata),
 #   57|-> 	    blockdata_hwm * sizeof(struct blockdata),
 #   58|   	    blockdata_alloced * sizeof(struct blockdata));
 #   59|   }

Error: PRINTF_ARGS (CWE-686): [#def18]
dnsmasq-2.86test7/src/blockdata.c:58: invalid_type: Argument "blockdata_alloced * 48UL" to format specifier "%u" was expected to have type "unsigned int" but has type "unsigned long".
 #   56|   	    blockdata_count * sizeof(struct blockdata),
 #   57|   	    blockdata_hwm * sizeof(struct blockdata),
 #   58|-> 	    blockdata_alloced * sizeof(struct blockdata));
 #   59|   }
 #   60|
2021-09-11 21:36:01 +01:00
Petr Menšík
9881b0736d Fix few coverity warnings in lease-tools
Error: UNINIT (CWE-457): [#def2]
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release.c:265: var_decl: Declaring variable "ifr" without initializer.
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release.c:285: uninit_use_in_call: Using uninitialized value "ifr". Field "ifr.ifr_ifru" is uninitialized when calling "setsockopt".
 #  283|     strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
 #  284|     ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
 #  285|->   if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
 #  286|       {
 #  287|         perror("cannot setup interface");

Error: CHECKED_RETURN (CWE-252): [#def3]
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:346: check_return: Calling "inet_pton" without checking return value (as is done elsewhere 61 out of 72 times).
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:188: example_assign: Example 1: Assigning: "s" = return value from "inet_pton(10, ip, &result.ip)".
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:189: example_checked: Example 1 (cont.): "s" has its value checked in "s <= 0".
dnsmasq-2.86test7/src/cache.c:1108: example_checked: Example 2: "inet_pton(10, token, &addr)" has its value checked in "inet_pton(10, token, &addr) > 0".
dnsmasq-2.86test7/src/dbus.c:525: example_checked: Example 3: "inet_pton(2, ipaddr, &addr.addr4)" has its value checked in "inet_pton(2, ipaddr, &addr.addr4)".
dnsmasq-2.86test7/src/domain.c:138: example_checked: Example 4: "inet_pton(prot, tail, addr)" has its value checked in "inet_pton(prot, tail, addr)".
dnsmasq-2.86test7/src/lease.c:81: example_checked: Example 5: "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)" has its value checked in "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)".
 #  344|       client_addr.sin6_flowinfo = 0;
 #  345|       client_addr.sin6_scope_id =0;
 #  346|->     inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
 #  347|       bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
 #  348|       inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);

Error: CHECKED_RETURN (CWE-252): [#def4]
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:347: check_return: Calling "bind(sock, (struct sockaddr *)&client_addr, 28U)" without checking return value. This library function may fail and return an error code.
 #  345|       client_addr.sin6_scope_id =0;
 #  346|       inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
 #  347|->     bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
 #  348|       inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
 #  349|       server_addr.sin6_port = htons(DHCP6_SERVER_PORT);

Error: CHECKED_RETURN (CWE-252): [#def5]
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:348: check_return: Calling "inet_pton" without checking return value (as is done elsewhere 61 out of 72 times).
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:188: example_assign: Example 1: Assigning: "s" = return value from "inet_pton(10, ip, &result.ip)".
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:189: example_checked: Example 1 (cont.): "s" has its value checked in "s <= 0".
dnsmasq-2.86test7/src/cache.c:1108: example_checked: Example 2: "inet_pton(10, token, &addr)" has its value checked in "inet_pton(10, token, &addr) > 0".
dnsmasq-2.86test7/src/dbus.c:525: example_checked: Example 3: "inet_pton(2, ipaddr, &addr.addr4)" has its value checked in "inet_pton(2, ipaddr, &addr.addr4)".
dnsmasq-2.86test7/src/domain.c:138: example_checked: Example 4: "inet_pton(prot, tail, addr)" has its value checked in "inet_pton(prot, tail, addr)".
dnsmasq-2.86test7/src/lease.c:81: example_checked: Example 5: "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)" has its value checked in "inet_pton(10, dnsmasq_daemon->namebuff, &addr.addr6)".
 #  346|       inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
 #  347|       bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
 #  348|->     inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
 #  349|       server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
 #  350|       int16_t recv_size = 0;

Error: NEGATIVE_RETURNS (CWE-394): [#def6]
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:360: var_tested_neg: Variable "recv_size" tests negative.
dnsmasq-2.86test7/contrib/lease-tools/dhcp_release6.c:373: negative_returns: "recv_size" is passed to a parameter that cannot be negative.
 #  371|   	  }
 #  372|
 #  373|->         int16_t result = parse_packet(response, recv_size);
 #  374|           if (result == NOT_REPLY_CODE)
 #  375|   	  {
2021-09-11 18:01:49 +01:00
Petr Menšík
e52b4b1466 Fix bunch of warnings in auth.c
Error: CLANG_WARNING: [#def7]
dnsmasq-2.86test7/src/auth.c:420:5: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  418|          if (!found && is_name_synthetic(flag, name, &addr) )
 #  419|   	 {
 #  420|-> 	   found = 1;
 #  421|   	   nxdomain = 0;
 #  422|

Error: CLANG_WARNING: [#def8]
dnsmasq-2.86test7/src/auth.c:436:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  434|   	    {
 #  435|   	      auth = soa = 1; /* inhibits auth section */
 #  436|-> 	      found = 1;
 #  437|   	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
 #  438|   	    }

Error: CLANG_WARNING: [#def9]
dnsmasq-2.86test7/src/auth.c:472:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  470|   	      ns = 1; /* ensure we include NS records! */
 #  471|   	      axfr = 1;
 #  472|-> 	      found = 1;
 #  473|   	      axfroffset = nameoffset;
 #  474|   	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");

Error: CLANG_WARNING: [#def10]
dnsmasq-2.86test7/src/auth.c:480:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  478|   	      auth = 1;
 #  479|   	      ns = 1; /* inhibits auth section */
 #  480|-> 	      found = 1;
 #  481|   	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
 #  482|   	    }

Error: CLANG_WARNING: [#def11]
dnsmasq-2.86test7/src/auth.c:501:4: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  499|   			log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
 #  500|   			*cut  = 0; /* remove domain part */
 #  501|-> 			found = 1;
 #  502|   			if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
 #  503|   						daemon->auth_ttl, NULL, qtype, C_IN,

Error: CLANG_WARNING: [#def12]
dnsmasq-2.86test7/src/auth.c:522:8: warning[deadcode.DeadStores]: Value stored to 'found' is never read
 #  520|   		   {
 #  521|   		     log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
 #  522|-> 		     found = 1;
 #  523|   		     if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
 #  524|   					     daemon->auth_ttl, NULL, qtype, C_IN,

Error: CLANG_WARNING: [#def13]
dnsmasq-2.86test7/src/auth.c:617:8: warning[deadcode.DeadStores]: Value stored to 'p' is never read
 #  615|   		p += sprintf(p, "%u.", a & 0xff);
 #  616|   	      a = a >> 8;
 #  617|-> 	      p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
 #  618|
 #  619|   	    }

Error: CPPCHECK_WARNING (CWE-758): [#def14]
dnsmasq-2.86test7/src/auth.c:627: warning[objectIndex]: The address of local variable 'addr6' might be accessed at non-zero index.
 #  625|   	      for (i = subnet->prefixlen-1; i >= 0; i -= 4)
 #  626|   		{
 #  627|-> 		  int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
 #  628|   		  p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
 #  629|   		}

Error: CLANG_WARNING: [#def15]
dnsmasq-2.86test7/src/auth.c:630:8: warning[deadcode.DeadStores]: Value stored to 'p' is never read
 #  628|   		  p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
 #  629|   		}
 #  630|-> 	      p += sprintf(p, "ip6.arpa");
 #  631|
 #  632|   	    }
2021-09-11 17:56:01 +01:00
Petr Menšík
2f45670951 Add safety checks to places pointed by Coverity
GCC Analyzer (experimental)

1. dnsmasq-2.85/src/forward.c:0: scope_hint: In function 'allocate_rfd.part.0'
2. dnsmasq-2.85/src/forward.c:2321:18: warning[-Wanalyzer-null-dereference]: dereference of NULL 'rfd'
 #  2319|     *fdlp = rfl;
 #  2320|
 #  2321|->   return rfl->rfd->fd;
 #  2322|   }
 #  2323|

1. dnsmasq-2.85/src/cache.c:0: scope_hint: In function 'log_query'
2. dnsmasq-2.85/src/cache.c:1969:20: warning[-Wanalyzer-null-dereference]: dereference of NULL 'name'
 #  1967|       source = "cached";
 #  1968|
 #  1969|->   if (strlen(name) == 0)
 #  1970|       name = ".";
 #  1971|

1. dnsmasq-2.85/src/cache.c:0: scope_hint: In function 'cache_scan_free'
2. dnsmasq-2.85/src/cache.c:436:20: warning[-Wanalyzer-null-argument]: use of NULL 'addr' where non-null expected
40. /usr/include/sys/un.h:37: included_from: Included from here.
41. dnsmasq-2.85/src/dnsmasq.h:101: included_from: Included from here.
42. dnsmasq-2.85/src/cache.c:17: included_from: Included from here.
43. /usr/include/string.h:64:12: note: argument 2 of 'memcmp' must be non-null
 #   434|   		   (flags & crecp->flags & F_REVERSE) &&
 #   435|   		   (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
 #   436|-> 		   memcmp(&crecp->addr, addr, addrlen) == 0)
 #   437|   	    {
 #   438|   	      *up = crecp->hash_next;
2021-09-11 14:48:17 +01:00
Petr Menšík
50d75ae514 Retry on interrupted error in tftp
Interrupt might arrive when sending error reply. Retry if possible.

Wrong Check of Return Value

10. dnsmasq-2.85/src/tftp.c:603: check_return: Calling "sendto(transfer->sockfd, dnsmasq_daemon->packet, len, 0, __CONST_SOCKADDR_ARG({.__sockaddr__ = &peer.sa}), sa_len(&peer))" without checking return value. This library function may fail and return an error code.
 #   601|   		  prettyprint_addr(&peer, daemon->addrbuff);
 #   602|   		  len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
 #   603|-> 		  sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
 #   604|   		}
 #   605|   	    }
2021-09-11 14:39:36 +01:00
Petr Menšík
dea69a12aa Small sanity check in wildcard tag matching code. 2021-09-11 14:26:03 +01:00
Dominik DL6ER
e0ce3c12f2 Add all current RR types to the table of type names used for query logging.
This patch also changes the method of calling querystr() such that
it is only called when logging is enabled, to eliminate any
possible performance problems from searching the larger table.
2021-09-10 23:13:53 +01:00
Gustaf Ullberg
93cf516bf1 check_name() determines if IDN processing is needed.
Optimization that only runs IDN processing if it would alter the domain
name (non-ascii or uppercase characters).

This patch has conributions from Petr Menšík.
2021-09-10 00:13:39 +01:00
Simon Kelley
6f4de018af Revert "Skip ascii-only names IDN processing"
This reverts commit 9cb7f8a655.
2021-09-10 00:02:11 +01:00
Simon Kelley
6e91cf3172 Bump version in Debian changelog. 2021-09-08 23:19:08 +01:00
Petr Menšík
9cb7f8a655 Skip ascii-only names IDN processing
Calls to libidn on names without with only a-z A-Z - _ 0-9
have no effect, but are slow. This change elides those calls.

Patch inspire by analysis and an earlier patch from
Gustaf Ullberg <gustaf.ullberg@gmail.com>
2021-09-08 23:08:21 +01:00
Simon Kelley
5d8d1ad14b Merge branch 'nxdomain' 2021-09-08 23:05:35 +01:00
Simon Kelley
cac9ca38f6 Treat ANY queries the same as CNAME queries WRT to DNSSEC on CNAME targets. 2021-09-08 21:21:22 +01:00
Simon Kelley
c4523639d5 Treat ANY queries the same as CNAME queries WRT to DNSSEC on CNAME targets. 2021-09-08 21:19:15 +01:00
Simon Kelley
1ce1c6beae Caching cleanup. Use cached NXDOMAIN to answer queries of any type. 2021-09-05 18:47:45 +01:00
DL6ER
51d56df7a3 Add RFC 4833 DHCP options "posix-timezone" and "tzdb-timezone".
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-04 22:24:14 +01:00
Simon Kelley
860a9a57d6 Get logging of DNSSEC status right when Checking Disabled bit set. 2021-09-02 10:07:08 +01:00
Dominik DL6ER
c83e33d608 Final logging tweaks. 2021-09-01 21:19:47 +01:00
Simon Kelley
7b80c75d9d Rationalise query-reply logging.
Try and log exactly what was returned, rather than just what
got cached. Also give validation status of RRsets if extra logging specified.

This commit also fixes a long-standing bug in caching of CNAME chains
leading to a PTR record.

Based on and inspired by a patch from Dominik DL6ER <dl6er@dl6er.de>
2021-08-31 18:23:03 +01:00
Geoff Back
79337f99ae Support limited wildcards in the input tags for --tag-if. 2021-08-29 13:27:27 +01:00
Geert Stappers via Dnsmasq-discuss
a42ee397f3 Man page BNF error fix.
Move dhcp-range bracket indicating option.

There should already be an end-address or mode  when adding a netmask.

Also the date bumped.

Signed-off-by: Geert Stappers <stappers@stappers.nl>
2021-08-25 14:32:43 +01:00
Simon Kelley
e58f8bb8c1 Merge message changes into I18N files. 2021-08-25 14:11:42 +01:00
Dominik DL6ER
58cf958e41 Fix empty domain in server option parsing when more than one domain is given
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-08-25 14:09:40 +01:00
Etan Kissling
06d01f7ae4 Make comment style consistent.
Majority of code base does not use C90-style // end of line comments.
This formats the few existing exceptions using /* */ for consistency.
2021-08-12 17:02:45 +01:00
Etan Kissling
1a33eec0ba Adjust logging levels for connmark patterns.
This brings the log levels emitted by connmark pattern code in line with
the rest of the code base. LOG_DEBUG is used for diagnostics that may be
verbose depending on the request patterns. LOG_ERR is used for problems
with the implementation itself.

Signed-off-by: Etan Kissling <etan.kissling@gmail.com>
2021-08-12 17:02:24 +01:00
Etan Kissling
82de7a1e96 Re-order UBus teardown logic.
When destroying the UBus context, private fields of our ubus_object were
being reset to 0 while UBus was still owning those objects. While this
seems to work out fine, it seems cleaner to first release the object so
that UBus no longer owns it, before proceding to reset those fields.

Signed-off-by: Etan Kissling <etan.kissling@gmail.com>
2021-08-12 17:02:07 +01:00
Etan Kissling
8e9bde57c5 Eliminate redundant UBus notify variable.
There was a `notify` variable to keep track whether a subscriber is
observing our UBus object. However, it was not properly cleaned up in
`ubus_destroy`, potentially becoming stale over UBus reconnections.
The variable was removed and the current state is examined when sending
notifications, similarly as is done in other existing OpenWrt code.

Signed-off-by: Etan Kissling <etan.kissling@gmail.com>
2021-08-12 17:01:17 +01:00
Etan Kissling
1bb70e08be Handle UBus serialization errors.
The various blob / blobmsg commands can fail, e.g., when memory is low.
Previously, those errors were silently discarded. This patch adds checks
for the error conditions, logging them and exiting from the functions.

Signed-off-by: Etan Kissling <etan.kissling@gmail.com>
2021-08-12 17:00:18 +01:00
Simon Kelley
9afcb7ae61 Revert "There was a notify variable to keep track whether a subscriber is"
This reverts commit ea43234c86.
2021-08-12 17:00:10 +01:00
Simon Kelley
545c4955e6 Revert "Re-order UBus teardown logic."
This reverts commit d387f8f06c.
2021-08-12 16:58:30 +01:00
Simon Kelley
2f2d59b35c Define order of reading files when --addn-hosts given a directory.
Also applies to --dhcp-hostsfile and --dhcp-optsfile though it is
less useful there.
2021-08-12 16:48:54 +01:00
43 changed files with 8482 additions and 6290 deletions

View File

@@ -1,3 +1,14 @@
version 2.87
Allow arbitrary prefix lengths in --rev-server and
--domain=....,local
Replace --address=/#/..... functionality which got
missed in the 2.86 domain search rewrite.
Add --nftset option, like --ipset but for the newer nftables.
Thanks to Chen Zhenge for the patch.
version 2.86
Handle DHCPREBIND requests in the DHCPv6 server code.
Thanks to Aichun Li for spotting this omission, and the initial
@@ -86,6 +97,15 @@ version 2.86
conntrack is configured. Thanks to Yick Xie for spotting
the lack of this.
When --dhcp-hostsfile --dhcp-optsfile and --addn-hosts are
given a directory as argument, define the order in which
files within that directory are read (alphabetical order
of filename). Thanks to Ed Wildgoose for the initial patch
and motivation for this.
Allow adding IP address to nftables set in addition to
ipset.
version 2.85
Fix problem with DNS retries in 2.83/2.84.
@@ -157,6 +177,9 @@ version 2.85
Tweak TFTP code to check sender of all received packets, as
specified in RFC 1350 para 4.
Support some wildcard matching of input tags to --tag-if.
Thanks to Geoff Back for the idea and the patch.
version 2.84
Fix a problem, introduced in 2.83, which could see DNS replies

View File

@@ -70,7 +70,9 @@ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CO
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
@@ -82,7 +84,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o pattern.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
metrics.o hash-questions.o domain-match.o
metrics.o hash-questions.o domain-match.o nftset.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
@@ -90,8 +92,8 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
-f $(top)/Makefile dnsmasq
mostly_clean :
@@ -115,8 +117,8 @@ all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \

View File

@@ -280,6 +280,7 @@ int main(int argc, char **argv)
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
a DHCP server */
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)

View File

@@ -318,6 +318,12 @@ void usage(const char* arg, FILE* stream)
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
}
static void fail_fatal(const char *errstr, int exitcode)
{
perror(errstr);
exit(exitcode);
}
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
{
struct sockaddr_in6 server_addr, client_addr;
@@ -343,18 +349,19 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
client_addr.sin6_flowinfo = 0;
client_addr.sin6_scope_id =0;
inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
fail_fatal("inet_pton", 5);
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
perror("bind"); /* continue on bind error */
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
fail_fatal("inet_pton", 5);
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
int16_t recv_size = 0;
ssize_t recv_size = 0;
int result;
for (i = 0; i < 5; i++)
{
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
perror("sendto failed");
exit(4);
}
fail_fatal("sendto failed", 4);
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
if (recv_size == -1)
@@ -367,16 +374,18 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
else
{
perror("recvfrom");
result = UNSPEC_FAIL;
}
}
int16_t result = parse_packet(response, recv_size);
if (result == NOT_REPLY_CODE)
else
{
sleep(1);
continue;
result = parse_packet(response, recv_size);
if (result == NOT_REPLY_CODE)
{
sleep(1);
continue;
}
}
close(sock);
return result;
}

7
debian/changelog vendored
View File

@@ -1,3 +1,10 @@
dnsmasq (2.87-1) unstable; urgency=low
* New upstream.
* Include new NFTset support in the build.
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 08 Sep 2021 23:11:25 +0000
dnsmasq (2.86-1) unstable; urgency=low
* Fix debian/changelog format error. (closes: #986626)

2
debian/control vendored
View File

@@ -5,7 +5,7 @@ Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
pkg-config
pkg-config, libnftables-dev
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git

1
debian/readme vendored
View File

@@ -60,6 +60,7 @@ Notes on configuring dnsmasq as packaged for Debian.
nodbus : omit DBus support.
noconntrack : omit connection tracking support.
noipset : omit IPset support.
nonftset : omit nftset support.
nortc : compile alternate mode suitable for systems without an RTC.
noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be

4
debian/rules vendored
View File

@@ -52,6 +52,10 @@ ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_LIBIDN2
endif
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_NFTSET
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK

View File

@@ -85,6 +85,16 @@
# subdomains to the vpn and search ipsets:
#ipset=/yahoo.com/google.com/vpn,search
# Add the IPs of all queries to yahoo.com, google.com, and their
# subdomains to netfilters sets, which is equivalent to
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
# Use netfilters sets for both IPv4 and IPv6:
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
#nftset=/yahoo.com/4#ip#test#vpn4
#nftset=/yahoo.com/6#ip#test#vpn6
# You can control how dnsmasq talks to a server: this forces
# queries to 10.1.2.3 to be routed via eth1
# server=10.1.2.3@eth1

View File

@@ -1,4 +1,4 @@
.TH DNSMASQ 8 2020-04-05
.TH DNSMASQ 8 2021-08-16
.SH NAME
dnsmasq \- A lightweight DHCP and caching DNS server.
.SH SYNOPSIS
@@ -55,7 +55,8 @@ Don't read the hostnames in /etc/hosts.
.B \-H, --addn-hosts=<file>
Additional hosts file. Read the specified file as well as /etc/hosts. If \fB--no-hosts\fP is given, read
only the specified file. This option may be repeated for more than one
additional hosts file. If a directory is given, then read all the files contained in that directory.
additional hosts file. If a directory is given, then read all the files contained in that directory
in alphabetical order.
.TP
.B --hostsdir=<path>
Read all the hosts files contained in the directory. New or changed files
@@ -504,13 +505,14 @@ source address specified but the port may be specified directly as
part of the source address. Forcing queries to an interface is not
implemented on all platforms supported by dnsmasq.
.TP
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
.B --rev-server=<ip-address>[/<prefix-len>][,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
This is functionally the same as
.B --server,
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
.B --rev-server=1.2.3.0/24,192.168.0.1
is exactly equivalent to
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is omitted, dnsmasq substitutes either 32 (IPv4) or 128 (IPv6).
.TP
.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
Specify an IP address to return for any host in the given domains.
@@ -548,6 +550,15 @@ These IP sets must already exist. See
.BR ipset (8)
for more details.
.TP
.B --nftset=/<domain>[/<domain>...]/[(6|4)#[<family>#]<table>#<set>[,[(6|4)#[<family>#]<table>#<set>]...]
Similar to the \fB--ipset\fP option, but accepts one or more nftables
sets to add IP addresses into.
These sets must already exist. See
.BR nft (8)
for more details. The family, table and set are passed directly to the nft. If the spec starts with 4# or 6# then
only A or AAAA records respectively are added to the set. Since an nftset can hold only IPv4 or IPv6 addresses, this
avoids errors being logged for addresses of the wrong type.
.TP
.B --connmark-allowlist-enable[=<mask>]
Enables filtering of incoming DNS queries with associated Linux connection track marks
according to individual allowlists configured via a series of \fB--connmark-allowlist\fP
@@ -905,7 +916,7 @@ compiled in and the kernel must have conntrack support
included and configured. This option cannot be combined with
.B --query-port.
.TP
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>][,<netmask>[,<broadcast>]][,<lease time>]
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>[,<netmask>[,<broadcast>]]][,<lease time>]
.TP
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
@@ -1035,7 +1046,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=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,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
@@ -1134,7 +1145,10 @@ ignore requests from unknown machines using
If the host matches only a \fB--dhcp-host\fP directive which cannot
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
The tag:<tag> construct filters which dhcp-host directives are used; more than
one can be provided, in this case the request must match all of them. Tagged
directives are used in preference to untagged ones. Note that one of <hwaddr>,
<client_id> or <hostname> still needs to be specified (can be a wildcard).
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
@@ -1165,7 +1179,7 @@ has both wired and wireless interfaces.
.TP
.B --dhcp-hostsfile=<path>
Read DHCP host information from the specified file. If a directory
is given, then read all the files contained in that directory. The file contains
is given, then read all the files contained in that directory in alphabetical order. The file contains
information about one host per line. The format of a line is the same
as text to the right of '=' in \fB--dhcp-host\fP. The advantage of storing DHCP host information
in this file is that it can be changed without re-starting dnsmasq:
@@ -1173,7 +1187,7 @@ the file will be re-read when dnsmasq receives SIGHUP.
.TP
.B --dhcp-optsfile=<path>
Read DHCP option information from the specified file. If a directory
is given, then read all the files contained in that directory. The advantage of
is given, then read all the files contained in that directory in alphabetical order. The advantage of
using this option is the same as for \fB--dhcp-hostsfile\fP: the
\fB--dhcp-optsfile\fP will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a
@@ -1188,7 +1202,8 @@ directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP.
If a file is deleted or changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq receives a SIGHUP, or
is restarted; ie host records are only added dynamically.
is restarted; ie host records are only added dynamically. The order in which the
files in a directory are read is not defined.
.TP
.B --dhcp-optsdir=<path>
This is equivalent to \fB--dhcp-optsfile\fP, with the differences noted for \fB--dhcp-hostsdir\fP.
@@ -1433,6 +1448,12 @@ Any number of set: and tag: forms may appear, in any order.
tag set by another
.B --tag-if,
the line which sets the tag must precede the one which tests it.
As an extension, the tag:<tag> clauses support limited wildcard matching,
similar to the matching in the \fB--interface\fP directive. This allows, for
example, using \fB--tag-if=set:ppp,tag:ppp*\fP to set the tag 'ppp' for all requests
received on any matching interface (ppp0, ppp1, etc). This can be used in conjunction
with the tag:!<tag> format meaning that no tag matching the wildcard may be set.
.TP
.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
When all the given tags appear in the tag set ignore the host and do
@@ -1915,7 +1936,6 @@ additional flag "local" may be supplied which has the effect of adding
is identical to
.B --domain=thekelleys.org.uk,192.168.0.0/24
.B --local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
The network size must be 8, 16 or 24 for this to be legal.
.TP
.B --dhcp-fqdn
In the default mode, dnsmasq inserts the unqualified names of

1183
po/de.po

File diff suppressed because it is too large Load Diff

1213
po/es.po

File diff suppressed because it is too large Load Diff

1310
po/fi.po

File diff suppressed because it is too large Load Diff

1215
po/fr.po

File diff suppressed because it is too large Load Diff

1228
po/id.po

File diff suppressed because it is too large Load Diff

1310
po/it.po

File diff suppressed because it is too large Load Diff

1271
po/no.po

File diff suppressed because it is too large Load Diff

1214
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1271
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -210,7 +210,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (local_query || in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
@@ -234,7 +234,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
strcat(name, ".");
strcat(name, zone->domain);
}
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
@@ -243,7 +243,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
{
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
@@ -257,7 +257,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
{
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL);
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
@@ -269,7 +269,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (found)
nxdomain = 0;
else
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
continue;
}
@@ -300,7 +300,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_MX)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
anscount++;
@@ -315,7 +315,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_SRV)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
@@ -349,7 +349,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && txt->class == qtype)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++;
@@ -363,7 +363,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_TXT)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
anscount++;
@@ -377,7 +377,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_NAPTR)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
@@ -407,7 +407,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
continue;
found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &addrlist->addr))
@@ -417,10 +417,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (!found && is_name_synthetic(flag, name, &addr) )
{
found = 1;
nxdomain = 0;
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
anscount++;
@@ -433,8 +432,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (qtype == T_SOA)
{
auth = soa = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
}
else if (qtype == T_AXFR)
{
@@ -469,16 +467,14 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1;
found = 1;
axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
}
else if (qtype == T_NS)
{
auth = 1;
ns = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
}
}
@@ -496,9 +492,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
(local_query || filter_zone(zone, flag, &(crecp->addr))))
{
*cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
*cut = 0; /* remove domain part */
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
@@ -518,8 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
nxdomain = 0;
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
{
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
found = 1;
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
@@ -566,7 +560,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (candidate)
{
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
strcpy(name, candidate->target);
if (!strchr(name, '.'))
{
@@ -584,7 +578,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
else if (cache_find_non_terminal(name, now))
nxdomain = 0;
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
}
}
@@ -614,7 +608,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%u.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
sprintf(p, "%u.in-addr.arpa", a & 0xff);
}
else
@@ -627,7 +621,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
}
p += sprintf(p, "ip6.arpa");
sprintf(p, "ip6.arpa");
}
}
@@ -892,7 +886,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
header->nscount = htons(0);
addr.log.rcode = REFUSED;
addr.log.ede = EDE_NOT_AUTH;
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL);
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
}

View File

@@ -52,7 +52,7 @@ void blockdata_init(void)
void blockdata_report(void)
{
my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
blockdata_count * sizeof(struct blockdata),
blockdata_hwm * sizeof(struct blockdata),
blockdata_alloced * sizeof(struct blockdata));

View File

@@ -30,50 +30,100 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
time_t now, unsigned long ttl, unsigned int flags);
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
/* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */
static const struct {
unsigned int type;
const char * const name;
} typestr[] = {
{ 1, "A" },
{ 2, "NS" },
{ 5, "CNAME" },
{ 6, "SOA" },
{ 10, "NULL" },
{ 11, "WKS" },
{ 12, "PTR" },
{ 13, "HINFO" },
{ 15, "MX" },
{ 16, "TXT" },
{ 22, "NSAP" },
{ 23, "NSAP_PTR" },
{ 24, "SIG" },
{ 25, "KEY" },
{ 28, "AAAA" },
{ 29, "LOC" },
{ 33, "SRV" },
{ 35, "NAPTR" },
{ 36, "KX" },
{ 37, "CERT" },
{ 38, "A6" },
{ 39, "DNAME" },
{ 41, "OPT" },
{ 43, "DS" },
{ 46, "RRSIG" },
{ 47, "NSEC" },
{ 48, "DNSKEY" },
{ 50, "NSEC3" },
{ 51, "NSEC3PARAM" },
{ 52, "TLSA" },
{ 53, "SMIMEA" },
{ 55, "HIP" },
{ 249, "TKEY" },
{ 250, "TSIG" },
{ 251, "IXFR" },
{ 252, "AXFR" },
{ 253, "MAILB" },
{ 254, "MAILA" },
{ 255, "ANY" },
{ 257, "CAA" }
{ 1, "A" }, /* a host address [RFC1035] */
{ 2, "NS" }, /* an authoritative name server [RFC1035] */
{ 3, "MD" }, /* a mail destination (OBSOLETE - use MX) [RFC1035] */
{ 4, "MF" }, /* a mail forwarder (OBSOLETE - use MX) [RFC1035] */
{ 5, "CNAME" }, /* the canonical name for an alias [RFC1035] */
{ 6, "SOA" }, /* marks the start of a zone of authority [RFC1035] */
{ 7, "MB" }, /* a mailbox domain name (EXPERIMENTAL) [RFC1035] */
{ 8, "MG" }, /* a mail group member (EXPERIMENTAL) [RFC1035] */
{ 9, "MR" }, /* a mail rename domain name (EXPERIMENTAL) [RFC1035] */
{ 10, "NULL" }, /* a null RR (EXPERIMENTAL) [RFC1035] */
{ 11, "WKS" }, /* a well known service description [RFC1035] */
{ 12, "PTR" }, /* a domain name pointer [RFC1035] */
{ 13, "HINFO" }, /* host information [RFC1035] */
{ 14, "MINFO" }, /* mailbox or mail list information [RFC1035] */
{ 15, "MX" }, /* mail exchange [RFC1035] */
{ 16, "TXT" }, /* text strings [RFC1035] */
{ 17, "RP" }, /* for Responsible Person [RFC1183] */
{ 18, "AFSDB" }, /* for AFS Data Base location [RFC1183][RFC5864] */
{ 19, "X25" }, /* for X.25 PSDN address [RFC1183] */
{ 20, "ISDN" }, /* for ISDN address [RFC1183] */
{ 21, "RT" }, /* for Route Through [RFC1183] */
{ 22, "NSAP" }, /* for NSAP address, NSAP style A record [RFC1706] */
{ 23, "NSAP_PTR" }, /* for domain name pointer, NSAP style [RFC1348][RFC1637][RFC1706] */
{ 24, "SIG" }, /* for security signature [RFC2535][RFC2536][RFC2537][RFC2931][RFC3008][RFC3110][RFC3755][RFC4034] */
{ 25, "KEY" }, /* for security key [RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110][RFC3755][RFC4034] */
{ 26, "PX" }, /* X.400 mail mapping information [RFC2163] */
{ 27, "GPOS" }, /* Geographical Position [RFC1712] */
{ 28, "AAAA" }, /* IP6 Address [RFC3596] */
{ 29, "LOC" }, /* Location Information [RFC1876] */
{ 30, "NXT" }, /* Next Domain (OBSOLETE) [RFC2535][RFC3755] */
{ 31, "EID" }, /* Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
{ 32, "NIMLOC" }, /* Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
{ 33, "SRV" }, /* Server Selection [1][RFC2782] */
{ 34, "ATMA" }, /* ATM Address [ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.] */
{ 35, "NAPTR" }, /* Naming Authority Pointer [RFC2168][RFC2915][RFC3403] */
{ 36, "KX" }, /* Key Exchanger [RFC2230] */
{ 37, "CERT" }, /* CERT [RFC4398] */
{ 38, "A6" }, /* A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563] */
{ 39, "DNAME" }, /* DNAME [RFC6672] */
{ 40, "SINK" }, /* SINK [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink] 1997-11*/
{ 41, "OPT" }, /* OPT [RFC3225][RFC6891] */
{ 42, "APL" }, /* APL [RFC3123] */
{ 43, "DS" }, /* Delegation Signer [RFC3658][RFC4034] */
{ 44, "SSHFP" }, /* SSH Key Fingerprint [RFC4255] */
{ 45, "IPSECKEY" }, /* IPSECKEY [RFC4025] */
{ 46, "RRSIG" }, /* RRSIG [RFC3755][RFC4034] */
{ 47, "NSEC" }, /* NSEC [RFC3755][RFC4034][RFC9077] */
{ 48, "DNSKEY" }, /* DNSKEY [RFC3755][RFC4034] */
{ 49, "DHCID" }, /* DHCID [RFC4701] */
{ 50, "NSEC3" }, /* NSEC3 [RFC5155][RFC9077] */
{ 51, "NSEC3PARAM" }, /* NSEC3PARAM [RFC5155] */
{ 52, "TLSA" }, /* TLSA [RFC6698] */
{ 53, "SMIMEA" }, /* S/MIME cert association [RFC8162] SMIMEA/smimea-completed-template 2015-12-01*/
{ 55, "HIP" }, /* Host Identity Protocol [RFC8005] */
{ 56, "NINFO" }, /* NINFO [Jim_Reid] NINFO/ninfo-completed-template 2008-01-21*/
{ 57, "RKEY" }, /* RKEY [Jim_Reid] RKEY/rkey-completed-template 2008-01-21*/
{ 58, "TALINK" }, /* Trust Anchor LINK [Wouter_Wijngaards] TALINK/talink-completed-template 2010-02-17*/
{ 59, "CDS" }, /* Child DS [RFC7344] CDS/cds-completed-template 2011-06-06*/
{ 60, "CDNSKEY" }, /* DNSKEY(s) the Child wants reflected in DS [RFC7344] 2014-06-16*/
{ 61, "OPENPGPKEY" }, /* OpenPGP Key [RFC7929] OPENPGPKEY/openpgpkey-completed-template 2014-08-12*/
{ 62, "CSYNC" }, /* Child-To-Parent Synchronization [RFC7477] 2015-01-27*/
{ 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
{ 99, "SPF" }, /* [RFC7208] */
{ 100, "UINFO" }, /* [IANA-Reserved] */
{ 101, "UID" }, /* [IANA-Reserved] */
{ 102, "GID" }, /* [IANA-Reserved] */
{ 103, "UNSPEC" }, /* [IANA-Reserved] */
{ 104, "NID" }, /* [RFC6742] ILNP/nid-completed-template */
{ 105, "L32" }, /* [RFC6742] ILNP/l32-completed-template */
{ 106, "L64" }, /* [RFC6742] ILNP/l64-completed-template */
{ 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */
{ 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/
{ 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/
{ 249, "TKEY" }, /* Transaction Key [RFC2930] */
{ 250, "TSIG" }, /* Transaction Signature [RFC8945] */
{ 251, "IXFR" }, /* incremental transfer [RFC1995] */
{ 252, "AXFR" }, /* transfer of an entire zone [RFC1035][RFC5936] */
{ 253, "MAILB" }, /* mailbox-related RRs (MB, MG or MR) [RFC1035] */
{ 254, "MAILA" }, /* mail agent RRs (OBSOLETE - see MX) [RFC1035] */
{ 255, "ANY" }, /* A request for some or all records the server has available [RFC1035][RFC6895][RFC8482] */
{ 256, "URI" }, /* URI [RFC7553] URI/uri-completed-template 2011-02-22*/
{ 257, "CAA" }, /* Certification Authority Restriction [RFC8659] CAA/caa-completed-template 2011-04-07*/
{ 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/
{ 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/
{ 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/
{ 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/
{ 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */
};
static void cache_free(struct crec *crecp);
@@ -433,7 +483,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
(flags & crecp->flags & F_REVERSE) &&
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
memcmp(&crecp->addr, addr, addrlen) == 0)
addr && memcmp(&crecp->addr, addr, addrlen) == 0)
{
*up = crecp->hash_next;
cache_unlink(crecp);
@@ -488,8 +538,6 @@ struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class
else
#endif
{
/* Don't log DNSSEC records here, done elsewhere */
log_query(flags | F_UPSTREAM, name, addr, NULL);
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl;
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
@@ -1549,7 +1597,8 @@ static void make_non_terminals(struct crec *source)
if (crecp)
{
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
crecp->ttd = source->ttd;
if (!(crecp->flags & F_IMMORTAL))
crecp->ttd = source->ttd;
crecp->name.namep = name;
cache_hash(crecp);
@@ -1807,7 +1856,7 @@ char *record_source(unsigned int index)
return "<unknown>";
}
char *querystr(char *desc, unsigned short type)
static char *querystr(char *desc, unsigned short type)
{
unsigned int i;
int len = 10; /* strlen("type=xxxxx") */
@@ -1855,7 +1904,7 @@ char *querystr(char *desc, unsigned short type)
if (types)
sprintf(buff, "<%s>", types);
else
sprintf(buff, "type=%d", type);
sprintf(buff, "<type=%d>", type);
}
}
@@ -1895,19 +1944,30 @@ static char *edestr(int ede)
}
}
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
{
char *source, *dest = daemon->addrbuff;
char *source, *dest = arg;
char *verb = "is";
char *extra = "";
if (!option_bool(OPT_LOG))
return;
/* build query type string if requested */
if(type > 0)
arg = querystr(arg, type);
#ifdef HAVE_DNSSEC
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
extra = " (DNSSEC signed)";
#endif
name = sanitise(name);
if (addr)
{
dest = daemon->addrbuff;
if (flags & F_KEYTAG)
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
else if (flags & F_RCODE)
@@ -1929,13 +1989,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
}
}
else
else if (flags & (F_IPV4 | F_IPV6))
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
addr, daemon->addrbuff, ADDRSTRLEN);
else
dest = arg;
}
else
dest = arg;
if (flags & F_REVERSE)
{
@@ -2001,7 +2060,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
}
else if (flags & F_IPSET)
{
source = "ipset add";
source = type ? "ipset add" : "nftset add";
dest = name;
name = arg;
verb = daemon->addrbuff;
@@ -2009,7 +2068,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
else
source = "cached";
if (strlen(name) == 0)
if (name && !name[0])
name = ".";
if (option_bool(OPT_EXTRALOG))

View File

@@ -115,6 +115,10 @@ HAVE_IPSET
define this to include the ability to selectively add resolved ip addresses
to given ipsets.
HAVE_NFTSET
define this to include the ability to selectively add resolved ip addresses
to given nftables sets.
HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
@@ -192,7 +196,7 @@ RESOLVFILE
/* #define HAVE_CONNTRACK */
/* #define HAVE_CRYPTOHASH */
/* #define HAVE_DNSSEC */
/* #define HAVE_NFTSET */
/* Default locations for important system files. */
@@ -420,6 +424,10 @@ static char *compile_opts =
"no-"
#endif
"ipset "
#ifndef HAVE_NFTSET
"no-"
#endif
"nftset "
#ifndef HAVE_AUTH
"no-"
#endif

View File

@@ -114,7 +114,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
w->next = daemon->watches;
daemon->watches = w;
w = data; /* no warning */
(void)data; /* no warning */
return TRUE;
}
@@ -134,16 +134,20 @@ static void remove_watch(DBusWatch *watch, void *data)
up = &(w->next);
}
w = data; /* no warning */
(void)data; /* no warning */
}
static void dbus_read_servers(DBusMessage *message)
static DBusMessage* dbus_read_servers(DBusMessage *message)
{
DBusMessageIter iter;
union mysockaddr addr, source_addr;
char *domain;
dbus_message_iter_init(message, &iter);
if (!dbus_message_iter_init(message, &iter))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
}
mark_servers(SERV_FROM_DBUS);
@@ -222,6 +226,7 @@ static void dbus_read_servers(DBusMessage *message)
/* unlink and free anything still marked. */
cleanup_servers();
return NULL;
}
#ifdef HAVE_LOOP
@@ -545,6 +550,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
"Invalid IP address '%s'", ipaddr);
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
if (hw_len < 0)
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid HW address '%s'", hwaddr);
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
@@ -668,7 +677,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
#endif
else if (strcmp(method, "SetServers") == 0)
{
dbus_read_servers(message);
reply = dbus_read_servers(message);
new_servers = 1;
}
else if (strcmp(method, "SetServersEx") == 0)
@@ -719,7 +728,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
if (clear_cache)
clear_cache_and_reload(dnsmasq_time());
method = user_data; /* no warning */
(void)user_data; /* no warning */
/* If no reply or no error, return nothing */
if (!reply)

View File

@@ -79,13 +79,46 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
}
/* like match_netid() except that the check can have a trailing * for wildcard */
/* started as a direct copy of match_netid() */
int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
{
struct dhcp_netid *tmp1;
for (; check; check = check->next)
{
const int check_len = strlen(check->net);
const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
(strcmp(check->net, tmp1->net) == 0))
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
(strcmp((check->net)+1, tmp1->net) == 0))
return 0;
}
return 1;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
/* this now uses match_netid_wild() above so that tag_if can
* be used to set a 'group of interfaces' tag.
*/
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
if (match_netid_wild(exprs->tag, tags))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
@@ -620,6 +653,8 @@ static const struct opttab_t {
{ "client-arch", 93, 2 | OT_DEC },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },

View File

@@ -292,7 +292,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr))));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */

View File

@@ -34,7 +34,6 @@ static void poll_resolv(int force, int do_reload, time_t now);
int main (int argc, char **argv)
{
int bind_fallback = 0;
time_t now;
struct sigaction sigact;
struct iname *if_tmp;
@@ -59,6 +58,8 @@ int main (int argc, char **argv)
int did_bind = 0;
struct server *serv;
char *netlink_warn;
#else
int bind_fallback = 0;
#endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
struct dhcp_context *context;
@@ -345,6 +346,16 @@ int main (int argc, char **argv)
}
#endif
#ifdef HAVE_NFTSET
if (daemon->nftsets)
{
nftset_init();
# ifdef HAVE_LINUX_NETWORK
need_cap_net_admin = 1;
# endif
}
#endif
#if defined(HAVE_LINUX_NETWORK)
netlink_warn = netlink_init();
#elif defined(HAVE_BSD_NETWORK)
@@ -377,7 +388,7 @@ int main (int argc, char **argv)
bindtodevice(bound_device, daemon->dhcpfd);
did_bind = 1;
}
if (daemon->enable_pxe && bound_device)
if (daemon->enable_pxe && bound_device && daemon->pxefd != -1)
{
bindtodevice(bound_device, daemon->pxefd);
did_bind = 1;
@@ -920,8 +931,10 @@ int main (int argc, char **argv)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
daemon->log_file, strerror(log_err));
#ifndef HAVE_LINUX_NETWORK
if (bind_fallback)
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
#endif
if (option_bool(OPT_NOWILD))
warn_bound_listeners();
@@ -1575,7 +1588,7 @@ static void async_event(int pipe, time_t now)
{
/* block in writes until all done */
if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
while(retry_send(fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK)));
do {
helper_write();
} while (!helper_buf_empty() || do_script_run(now));
@@ -1984,7 +1997,7 @@ static void check_dns_listeners(time_t now)
attribute from the listening socket.
Reset that here. */
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);

View File

@@ -530,23 +530,23 @@ union mysockaddr {
/* The actual values here matter, since we sort on them to get records in the order
IPv6 addr, IPv4 addr, all zero return, no-data return, send upstream. */
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next three flags */
#define SERV_ALL_ZEROS 2 /* return all zeros for A and AAAA */
#define SERV_4ADDR 4 /* addr is IPv4 */
#define SERV_6ADDR 8 /* addr is IPv6 */
#define SERV_HAS_SOURCE 16 /* source address defined */
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
#define SERV_MARK 256 /* for mark-and-delete and log code */
#define SERV_WILDCARD 512 /* domain has leading '*' */
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
#define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */
#define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */
#define SERV_4ADDR 8 /* addr is IPv4 */
#define SERV_6ADDR 16 /* addr is IPv6 */
#define SERV_HAS_SOURCE 32 /* source address defined */
#define SERV_FOR_NODOTS 64 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 128 /* avoid warning spam */
#define SERV_FROM_DBUS 256 /* 1 if source is DBus */
#define SERV_MARK 512 /* for mark-and-delete and log code */
#define SERV_WILDCARD 1024 /* domain has leading '*' */
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
#define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
struct serverfd {
int fd;
@@ -609,6 +609,11 @@ struct serv_local {
struct server *next;
};
struct rebind_domain {
char *domain;
struct rebind_domain *next;
};
struct ipsets {
char **sets;
char *domain;
@@ -1105,10 +1110,11 @@ extern struct daemon {
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers, *local_domains, **serverarray, *no_rebind;
struct server *servers, *servers_tail, *local_domains, **serverarray;
struct rebind_domain *no_rebind;
int server_has_wildcard;
int serverarraysz, serverarrayhwm;
struct ipsets *ipsets;
struct ipsets *ipsets, *nftsets;
u32 allowlist_mask;
struct allowlist *allowlists;
int log_fac; /* log facility */
@@ -1167,9 +1173,12 @@ extern struct daemon {
char *packet; /* packet buffer */
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
char *workspacename;
#endif
#ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
int rr_status_sz;
int dnssec_no_time_check;
@@ -1245,9 +1254,8 @@ extern struct daemon {
/* cache.c */
void cache_init(void);
void next_uid(struct crec *crecp);
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg);
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type);
char *record_source(unsigned int index);
char *querystr(char *desc, unsigned short type);
int cache_find_non_terminal(char *name, time_t now);
struct crec *cache_find_by_addr(struct crec *crecp,
union all_addr *addr, time_t now,
@@ -1298,8 +1306,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep);
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, char **ipsets, int is_sign, int check_rebind,
int no_cache_dnssec, int secure, int *doctored);
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
void report_addresses(struct dns_header *header, size_t len, u32 mark);
#endif
@@ -1583,6 +1591,12 @@ void ipset_init(void);
int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove);
#endif
/* nftset.c */
#ifdef HAVE_NFTSET
void nftset_init(void);
int add_to_nftset(const char *setpath, const union all_addr *ipaddr, int flags, int remove);
#endif
/* pattern.c */
#ifdef HAVE_CONNTRACK
int is_valid_dns_name(const char *value);

View File

@@ -724,7 +724,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
/* namebuff used for workspace above, restore to leave unchanged on exit */
p = (unsigned char*)(rrset[0]);
extract_name(header, plen, &p, name, 1, 0);
if (!extract_name(header, plen, &p, name, 1, 0))
return STAT_BOGUS;
if (key)
{
@@ -954,9 +955,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
a.log.keytag = keytag;
a.log.algo = algo;
if (algo_digest_name(algo))
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu", 0);
else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)", 0);
}
}
}
@@ -973,7 +974,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
return STAT_OK;
}
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY", 0);
return STAT_BOGUS | failflags;
}
@@ -1012,12 +1013,14 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
if (STAT_ISEQUAL(rc, STAT_INSECURE))
{
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure");
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
return STAT_BOGUS | DNSSEC_FAIL_INDET;
}
p = (unsigned char *)(header+1);
extract_name(header, plen, &p, name, 1, 4);
if (!extract_name(header, plen, &p, name, 1, 4))
return STAT_BOGUS;
p += 4; /* qtype, qclass */
/* If the key needed to validate the DS is on the same domain as the DS, we'll
@@ -1025,7 +1028,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
from the DS's zone, and not the parent zone. */
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
{
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
return STAT_BOGUS;
}
@@ -1081,9 +1084,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
a.log.algo = algo;
a.log.digest = digest;
if (ds_digest_name(digest) && algo_digest_name(algo))
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
}
}
@@ -1116,7 +1119,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
cache_end_insert();
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
}
return STAT_OK;
@@ -1893,7 +1896,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
/* Find all the targets we're looking for answers to.
The zeroth array element is for the query, subsequent ones
for CNAME targets, unless the query is for a CNAME. */
for CNAME targets, unless the query is for a CNAME or ANY. */
if (!expand_workspace(&targets, &target_sz, 0))
return STAT_BOGUS;
@@ -1912,7 +1915,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
if (qtype == T_RRSIG)
return STAT_INSECURE;
if (qtype != T_CNAME)
if (qtype != T_CNAME && qtype != T_ANY)
for (j = ntohs(header->ancount); j != 0; j--)
{
if (!(p1 = skip_name(p1, header, plen, 10)))

View File

@@ -207,16 +207,16 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
}
}
if (found)
if (found && filter_servers(try, flags, &nlow, &nhigh))
/* We have a match, but it may only be (say) an IPv6 address, and
if the query wasn't for an AAAA record, it's no good, and we need
to continue generalising */
{
/* We've matched a setting which says to use servers without a domain.
Continue the search with empty query */
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
crop_query = qlen;
else if (filter_servers(try, flags, &nlow, &nhigh))
/* We have a match, but it may only be (say) an IPv6 address, and
if the query wasn't for an AAAA record, it's no good, and we need
to continue generalising */
else
break;
}
}
@@ -273,7 +273,7 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
nlow--;
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
nhigh++;
nhigh++;
nhigh++;
@@ -293,10 +293,10 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
else
{
/* Now the servers are on order between low and high, in the order
IPv6 addr, IPv4 addr, return zero for both, send upstream, no-data return.
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
See which of those match our query in that priority order and narrow (low, high) */
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
if (i != nlow && (flags & F_IPV6))
@@ -321,32 +321,40 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
{
nlow = i;
/* now look for a server */
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
/* Short to resolv.conf servers */
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
if (i != nlow)
{
/* If we want a server that can do DNSSEC, and this one can't,
return nothing, similarly if were looking only for a server
for a particular domain. */
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
nlow = nhigh;
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
nlow = nhigh;
else
nhigh = i;
}
nhigh = i;
else
{
/* --local=/domain/, only return if we don't need a server. */
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
nhigh = i;
/* now look for a server */
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
if (i != nlow)
{
/* If we want a server that can do DNSSEC, and this one can't,
return nothing, similarly if were looking only for a server
for a particular domain. */
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
nlow = nhigh;
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
nlow = nhigh;
else
nhigh = i;
}
else
{
/* --local=/domain/, only return if we don't need a server. */
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
nhigh = i;
}
}
}
}
}
}
*lowout = nlow;
*highout = nhigh;
@@ -393,7 +401,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
union all_addr addr;
if (flags & (F_NXDOMAIN | F_NOERR))
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
setup_reply(header, flags, ede);
@@ -411,8 +419,9 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
addr.addr4 = srv->addr;
header->ancount = htons(ntohs(header->ancount) + 1);
add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr);
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL);
if (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
return 0;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
}
if (flags & gotname & F_IPV6)
@@ -427,7 +436,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
header->ancount = htons(ntohs(header->ancount) + 1);
add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr);
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL);
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
}
if (trunc)
@@ -520,10 +529,10 @@ static int order_qsort(const void *a, const void *b)
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
so the order is IPv6 literal, IPv4 literal, all-zero literal,
upstream server, NXDOMAIN literal. */
unqualified servers, upstream server, NXDOMAIN literal. */
if (rc == 0)
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
if (rc == 0)
@@ -567,7 +576,10 @@ void cleanup_servers(void)
free(serv);
}
else
up = &serv->next;
{
up = &serv->next;
daemon->servers_tail = serv;
}
}
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
@@ -609,7 +621,10 @@ int add_update_server(int flags,
if (*domain == 0)
alloc_domain = whine_malloc(1);
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
else
alloc_domain = canonicalise((char *)domain, NULL);
if (!alloc_domain)
return 0;
/* See if there is a suitable candidate, and unmark
@@ -630,7 +645,7 @@ int add_update_server(int flags,
{
size_t size;
if (flags & SERV_LITERAL_ADDRESS)
if (flags & SERV_IS_LOCAL)
{
if (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
@@ -643,56 +658,50 @@ int add_update_server(int flags,
size = sizeof(struct server);
if (!(serv = whine_malloc(size)))
return 0;
{
free(alloc_domain);
return 0;
}
if (flags & SERV_IS_LOCAL)
{
serv->next = daemon->local_domains;
daemon->local_domains = serv;
if (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
}
else
{
struct server *s;
/* Add to the end of the chain, for order */
if (!daemon->servers)
daemon->servers = serv;
else
{
for (s = daemon->servers; s->next; s = s->next);
s->next = serv;
}
memset(serv, 0, sizeof(struct server));
serv->next = NULL;
/* Add to the end of the chain, for order */
if (daemon->servers_tail)
daemon->servers_tail->next = serv;
else
daemon->servers = serv;
daemon->servers_tail = serv;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
}
if (!(flags & SERV_IS_LOCAL))
memset(serv, 0, sizeof(struct server));
serv->flags = flags;
serv->domain = alloc_domain;
serv->domain_len = strlen(alloc_domain);
if (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
if (!(flags & SERV_IS_LOCAL))
{
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
return 1;
}

View File

@@ -119,12 +119,12 @@ static void set_outgoing_mark(struct frec *forward, int fd)
}
#endif
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg, unsigned short type)
{
if (addr->sa.sa_family == AF_INET)
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
else
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
}
static void server_send(struct server *server, int fd,
@@ -138,23 +138,24 @@ static void server_send(struct server *server, int fd,
#ifdef HAVE_DNSSEC
static void server_send_log(struct server *server, int fd,
const void *header, size_t plen, int dumpflags,
unsigned int logflags, char *name, char *arg)
unsigned int logflags, char *name, char *arg,
unsigned short type)
{
#ifdef HAVE_DUMPFILE
dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
#endif
log_query_mysockaddr(logflags, name, &server->addr, arg);
log_query_mysockaddr(logflags, name, &server->addr, arg, type);
server_send(server, fd, header, plen, 0);
}
#endif
static int domain_no_rebind(char *domain)
{
struct server *serv;
int dlen = (int)strlen(domain);
struct rebind_domain *rbd;
size_t tlen, dlen = strlen(domain);
for (serv = daemon->no_rebind; serv; serv = serv->next)
if (dlen >= serv->domain_len && strcmp(serv->domain, &domain[dlen - serv->domain_len]) == 0)
for (rbd = daemon->no_rebind; rbd; rbd = rbd->next)
if (dlen >= (tlen = strlen(rbd->domain)) && strcmp(rbd->domain, &domain[dlen - tlen]) == 0)
return 1;
return 0;
@@ -172,7 +173,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
void *hash = hash_questions(header, plen, daemon->namebuff);
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
int old_src = 0;
int old_src = 0, old_reply = 0;
int first, last, start = 0;
int subnet, cacheable, forwarded = 0;
size_t edns0_len;
@@ -198,7 +199,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
Similarly FREC_NO_CACHE is never set in flags, so a query which is
contigent on a particular source address EDNS0 option will never be matched. */
if (forward)
old_src = 1;
{
old_src = 1;
old_reply = 1;
}
else if ((forward = lookup_frec_by_query(hash, fwd_flags,
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
@@ -375,9 +379,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* In strict order mode, there must be a server later in the list
left to send to, otherwise without the forwardall mechanism,
code further on will cycle around the list forwever if they
all return REFUSED. If at the last, give up. */
all return REFUSED. If at the last, give up.
Note that we can get here EITHER because a client retried,
or an upstream server returned REFUSED. The above only
applied in the later case. For client retries,
keep tyring the last server.. */
if (++start == last)
goto reply;
{
if (old_reply)
goto reply;
else
start--;
}
}
}
}
@@ -494,12 +507,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (!gotname)
strcpy(daemon->namebuff, "query");
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
&srv->addr, NULL);
&srv->addr, NULL, 0);
}
#ifdef HAVE_DNSSEC
else
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, daemon->namebuff, &srv->addr,
querystr("dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS));
"dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
#endif
srv->queries++;
@@ -555,12 +568,33 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 0;
}
static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domain) {
/* Similar algorithm to search_servers. */
struct ipsets *ipset_pos, *ret = NULL;
unsigned int namelen = strlen(domain);
unsigned int matchlen = 0;
for (ipset_pos = setlist; ipset_pos; ipset_pos = ipset_pos->next)
{
unsigned int domainlen = strlen(ipset_pos->domain);
const char *matchstart = domain + namelen - domainlen;
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
domainlen >= matchlen)
{
matchlen = domainlen;
ret = ipset_pos;
}
}
return ret;
}
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede)
{
unsigned char *pheader, *sizep;
char **sets = 0;
struct ipsets *ipsets = NULL, *nftsets = NULL;
int munged = 0, is_sign;
unsigned int rcode = RCODE(header);
size_t plen;
@@ -571,24 +605,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
#ifdef HAVE_IPSET
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
{
/* Similar algorithm to search_servers. */
struct ipsets *ipset_pos;
unsigned int namelen = strlen(daemon->namebuff);
unsigned int matchlen = 0;
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
{
unsigned int domainlen = strlen(ipset_pos->domain);
char *matchstart = daemon->namebuff + namelen - domainlen;
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
domainlen >= matchlen)
{
matchlen = domainlen;
sets = ipset_pos->sets;
}
}
}
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
#endif
#ifdef HAVE_NFTSET
if (daemon->nftsets && extract_request(header, n, daemon->namebuff, NULL))
nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
#endif
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
@@ -653,7 +675,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
union all_addr a;
a.log.rcode = rcode;
a.log.ede = ede;
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL, 0);
return resize_packet(header, n, pheader, plen);
}
@@ -697,7 +719,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
}
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
if (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
munged = 1;
@@ -889,7 +911,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
#endif
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
F_NOEXTRA | F_DNSSEC, daemon->keyname,
querystr("dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
"dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
server->queries++;
}
@@ -1136,7 +1158,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
domain = daemon->namebuff;
}
log_query(F_SECSTAT, domain, &a, result);
log_query(F_SECSTAT, domain, &a, result, 0);
}
}
#endif
@@ -1202,7 +1224,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
{
daemon->log_display_id = src->log_id;
daemon->log_source_addr = &src->source;
log_query(F_UPSTREAM, "query", NULL, "duplicate");
log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
}
}
}
@@ -1509,10 +1531,8 @@ void receive_query(struct listener *listen, time_t now)
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
char *types = querystr(auth_dns ? "auth" : "query", type);
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
&source_addr, types);
&source_addr, auth_dns ? "auth" : "query", type);
#ifdef HAVE_CONNTRACK
is_single_query = 1;
@@ -1808,7 +1828,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
daemon->log_display_id = ++daemon->log_id;
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
querystr("dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
"dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
@@ -1864,7 +1884,7 @@ unsigned char *tcp_request(int confd, time_t now,
int first, last;
unsigned int flags = 0;
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
#ifdef HAVE_CONNTRACK
@@ -1946,11 +1966,10 @@ unsigned char *tcp_request(int confd, time_t now,
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
char *types = querystr(auth_dns ? "auth" : "query", qtype);
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
&peer_addr, types);
&peer_addr, auth_dns ? "auth" : "query", qtype);
#ifdef HAVE_CONNTRACK
is_single_query = 1;
#endif
@@ -2089,7 +2108,7 @@ unsigned char *tcp_request(int confd, time_t now,
/* get query name again for logging - may have been overwritten */
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
strcpy(daemon->namebuff, "query");
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL);
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
@@ -2121,7 +2140,7 @@ unsigned char *tcp_request(int confd, time_t now,
domain = daemon->namebuff;
}
log_query(F_SECSTAT, domain, &a, result);
log_query(F_SECSTAT, domain, &a, result, 0);
}
#endif
@@ -2276,7 +2295,7 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
}
}
if (j == daemon->numrrand)
if (!rfd) /* should be when j == daemon->numrrand */
{
struct randfd_list *rfl_poll;

View File

@@ -76,9 +76,9 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
#else /* HAVE_DNSSEC || HAVE_CRYPTOHASH */
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
#define SHA256_BLOCK_SIZE 32 /* SHA256 outputs a 32 byte digest */
typedef unsigned char BYTE; /* 8-bit byte */
typedef unsigned int WORD; /* 32-bit word, change to "long" for 16-bit machines */
typedef struct {
BYTE data[64];
@@ -238,7 +238,7 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
i = ctx->datalen;
// Pad whatever data is left in the buffer.
/* Pad whatever data is left in the buffer. */
if (ctx->datalen < 56)
{
ctx->data[i++] = 0x80;
@@ -254,7 +254,7 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
/* Append to the padding the total message's length in bits and transform. */
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
@@ -266,8 +266,8 @@ static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
/* Since this implementation uses little endian byte ordering and SHA uses big endian,
reverse all the bytes when copying the final state to the output hash. */
for (i = 0; i < 4; ++i)
{
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;

View File

@@ -148,12 +148,19 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
if (!(ah->flags & flag))
continue;
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
if (stat(ah->fname, &buf) == -1)
{
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
ah->fname, strerror(errno));
continue;
}
if (!(S_ISDIR(buf.st_mode)))
{
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
ah->fname, _("not a directory"));
continue;
}
if (!(ah->flags & AH_WD_DONE))
{

View File

@@ -1586,6 +1586,9 @@ void check_servers(int no_loop_check)
if (serv->sfd)
serv->sfd->used = 1;
if (count == SERVERS_LOGGED)
my_syslog(LOG_INFO, _("more servers are defined but not logged"));
if (++count > SERVERS_LOGGED)
continue;
@@ -1623,7 +1626,8 @@ void check_servers(int no_loop_check)
continue;
if ((serv->flags & SERV_LITERAL_ADDRESS) &&
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)))
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)) &&
strlen(serv->domain))
{
count--;
if (++locals <= LOCALS_LOGGED)

94
src/nftset.c Normal file
View File

@@ -0,0 +1,94 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#if defined (HAVE_NFTSET) && defined (HAVE_LINUX_NETWORK)
#include <nftables/libnftables.h>
#include <string.h>
#include <arpa/inet.h>
static struct nft_ctx *ctx = NULL;
static const char *cmd_add = "add element %s { %s }";
static const char *cmd_del = "delete element %s { %s }";
void nftset_init()
{
ctx = nft_ctx_new(NFT_CTX_DEFAULT);
if (ctx == NULL)
die(_("failed to create nftset context"), NULL, EC_MISC);
/* disable libnftables output */
nft_ctx_buffer_error(ctx);
}
int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags, int remove)
{
const char *cmd = remove ? cmd_del : cmd_add;
int ret, af = (flags & F_IPV4) ? AF_INET : AF_INET6;
size_t new_sz;
char *new, *err, *nl;
static char *cmd_buf = NULL;
static size_t cmd_buf_sz = 0;
inet_ntop(af, ipaddr, daemon->addrbuff, ADDRSTRLEN);
if (setname[1] == ' ' && (setname[0] == '4' || setname[0] == '6'))
{
if (setname[0] == '4' && !(flags & F_IPV4))
return -1;
if (setname[0] == '6' && !(flags & F_IPV6))
return -1;
setname += 2;
}
if (cmd_buf_sz == 0)
new_sz = 150; /* initial allocation */
else
new_sz = snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
if (new_sz > cmd_buf_sz)
{
if (!(new = whine_malloc(new_sz + 10)))
return 0;
if (cmd_buf)
free(cmd_buf);
cmd_buf = new;
cmd_buf_sz = new_sz + 10;
snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
}
ret = nft_run_cmd_from_buffer(ctx, cmd_buf);
err = (char *)nft_ctx_get_error_buffer(ctx);
if (ret != 0)
{
/* Log only first line of error return. */
if ((nl = strchr(err, '\n')))
*nl = 0;
my_syslog(LOG_ERR, "nftset %s %s", setname, err);
}
return ret;
}
#endif

View File

@@ -174,6 +174,7 @@ struct myoption {
#define LOPT_CMARK_ALST_EN 365
#define LOPT_CMARK_ALST 366
#define LOPT_QUIET_TFTP 367
#define LOPT_NFTSET 368
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -327,6 +328,7 @@ static const struct myoption opts[] =
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
{ "ipset", 1, 0, LOPT_IPSET },
{ "nftset", 1, 0, LOPT_NFTSET },
{ "connmark-allowlist-enable", 2, 0, LOPT_CMARK_ALST_EN },
{ "connmark-allowlist", 1, 0, LOPT_CMARK_ALST },
{ "synth-domain", 1, 0, LOPT_SYNTH },
@@ -514,6 +516,7 @@ static struct {
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
{ LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
{ LOPT_NFTSET, ARG_DUP, "/<domain>[/<domain>...]/<nftset>...", gettext_noop("Specify nftables sets to which matching domains should be added"), NULL },
{ LOPT_CMARK_ALST_EN, ARG_ONE, "[=<mask>]", gettext_noop("Enable filtering of DNS queries with connection-track marks."), NULL },
{ LOPT_CMARK_ALST, ARG_DUP, "<connmark>[/<mask>][,<pattern>[/<pattern>...]]", gettext_noop("Set allowed DNS patterns for a connection-track mark."), NULL },
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
@@ -798,7 +801,7 @@ static void do_usage(void)
if (usage[i].arg)
{
strcpy(buff, usage[i].arg);
safe_strncpy(buff, usage[i].arg, sizeof(buff));
for (j = 0; tab[j].handle; j++)
if (tab[j].handle == *(usage[i].arg))
sprintf(buff, "%d", tab[j].val);
@@ -935,52 +938,124 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return NULL;
}
static int domain_rev4(char *domain, struct in_addr addr, int msize)
static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size)
{
in_addr_t a = ntohl(addr.s_addr);
*domain = 0;
int i, j;
char *string;
int msize;
u16 flags = 0;
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
switch (msize)
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
return string;
if (from_file)
flags |= SERV_FROM_FILE;
rem = size & 0x7;
addrbytes = (32 - size) >> 3;
addrbits = (32 - size) & 7;
if (size > 32 || size < 1)
return _("bad IPv4 prefix length");
/* Zero out last address bits according to CIDR mask */
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
size = size & ~0x7;
if (rem != 0)
count = 1 << (8 - rem);
for (i = 0; i < count; i++)
{
case 32:
domain += sprintf(domain, "%u.", a & 0xff);
/* fall through */
case 24:
domain += sprintf(domain, "%d.", (a >> 8) & 0xff);
/* fall through */
case 16:
domain += sprintf(domain, "%d.", (a >> 16) & 0xff);
/* fall through */
case 8:
domain += sprintf(domain, "%d.", (a >> 24) & 0xff);
break;
default:
return 0;
*domain = 0;
string = domain;
msize = size/8;
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
{
int dig = ((unsigned char *)addr4)[j];
if (j == msize)
dig += i;
string += sprintf(string, "%d.", dig);
}
sprintf(string, "in-addr.arpa");
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
return _("error");
}
domain += sprintf(domain, "in-addr.arpa");
return 1;
return NULL;
}
static int domain_rev6(char *domain, struct in6_addr *addr, int msize)
static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size)
{
int i;
int i, j;
char *string;
int msize;
u16 flags = 0;
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
if (msize > 128 || msize%4)
return 0;
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
return string;
if (from_file)
flags |= SERV_FROM_FILE;
*domain = 0;
rem = size & 0x3;
addrbytes = (128 - size) >> 3;
addrbits = (128 - size) & 7;
if (size > 128 || size < 1)
return _("bad IPv6 prefix length");
/* Zero out last address bits according to CIDR mask */
addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1);
size = size & ~0x3;
if (rem != 0)
count = 1 << (4 - rem);
for (i = 0; i < count; i++)
{
*domain = 0;
string = domain;
msize = size/4;
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
{
int dig = ((unsigned char *)addr6)[j>>1];
dig = j & 1 ? dig & 15 : dig >> 4;
if (j == msize)
dig += i;
string += sprintf(string, "%.1x.", dig);
}
sprintf(string, "ip6.arpa");
for (i = msize-1; i >= 0; i -= 4)
{
int dig = ((unsigned char *)addr)[i>>3];
domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
return _("error");
}
domain += sprintf(domain, "ip6.arpa");
return 1;
return NULL;
}
#ifdef HAVE_DHCP
@@ -1829,6 +1904,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = li;
*up = new;
}
else
free(path);
}
@@ -1995,7 +2072,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!(name = canonicalise_opt(arg)) ||
(comma && !(target = canonicalise_opt(comma))))
ret_err(_("bad MX name"));
{
free(name);
free(target);
ret_err(_("bad MX name"));
}
new = opt_malloc(sizeof(struct mx_srv_record));
new->next = daemon->mxnames;
@@ -2302,17 +2383,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
ret_err_free(_("bad prefix"), new);
}
else if (strcmp(arg, "local") != 0 ||
(msize != 8 && msize != 16 && msize != 24))
else if (strcmp(arg, "local") != 0)
ret_err_free(gen_err, new);
else
{
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
/* local=/xxx.yyy.zzz.in-addr.arpa/ */
/* domain_rev4 can't fail here, msize checked above. */
domain_rev4(domain, new->start, msize);
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
domain_rev4(0, NULL, &new->start, msize);
/* local=/<domain>/ */
/* d_raw can't failed to canonicalise here, checked above. */
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
@@ -2347,16 +2424,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
ret_err_free(_("bad prefix"), new);
}
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
else if (strcmp(arg, "local") != 0)
ret_err_free(gen_err, new);
else
{
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
/* generate the equivalent of
local=/xxx.yyy.zzz.ip6.arpa/ */
domain_rev6(domain, &new->start6, msize);
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
domain_rev6(0, NULL, &new->start6, msize);
/* local=/<domain>/ */
/* d_raw can't failed to canonicalise here, checked above. */
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
@@ -2635,7 +2710,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_NO_REBIND: /* --rebind-domain-ok */
{
struct server *new;
struct rebind_domain *new;
unhide_metas(arg);
@@ -2644,9 +2719,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
do {
comma = split_chr(arg, '/');
new = opt_malloc(sizeof(struct serv_local));
new->domain = opt_string_alloc(arg);
new->domain_len = strlen(arg);
new = opt_malloc(sizeof(struct rebind_domain));
new->domain = canonicalise_opt(arg);
new->next = daemon->no_rebind;
daemon->no_rebind = new;
arg = comma;
@@ -2684,7 +2758,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!arg || !*arg)
flags = SERV_LITERAL_ADDRESS;
else if (option == 'A')
else if (option != 'S')
{
/* # as literal address means return zero address for 4 and 6 */
if (strcmp(arg, "#") == 0)
@@ -2700,11 +2774,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
if ((err = parse_server(arg, &serv_addr, &source_addr, interface, &flags)))
ret_err(err);
/* server=//1.2.3.4 is special. */
if (strlen(domain) == 0 && lastdomain)
flags |= SERV_FOR_NODOTS;
}
if (servers_only && option == 'S')
@@ -2712,6 +2781,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
while (1)
{
/* server=//1.2.3.4 is special. */
if (lastdomain)
{
if (strlen(domain) == 0)
flags |= SERV_FOR_NODOTS;
else
flags &= ~SERV_FOR_NODOTS;
/* address=/#/ matches the same as without domain */
if (option != 'S' && domain[0] == '#' && domain[1] == 0)
domain[0] = 0;
}
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, &addr))
ret_err(gen_err);
@@ -2728,57 +2810,62 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
char *string;
int size;
u16 flags = 0;
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
struct in_addr addr4;
struct in6_addr addr6;
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
unhide_metas(arg);
if (!arg)
ret_err(gen_err);
comma=split(arg);
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
ret_err(gen_err);
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
size = -1;
if (inet_pton(AF_INET, arg, &addr4))
{
if (!domain_rev4(domain, addr4, size))
ret_err(_("bad IPv4 prefix"));
if (size == -1)
size = 32;
if ((string = domain_rev4(servers_only, comma, &addr4, size)))
ret_err(string);
}
else if (inet_pton(AF_INET6, arg, &addr6))
{
if (!domain_rev6(domain, &addr6, size))
ret_err(_("bad IPv6 prefix"));
if (size == -1)
size = 128;
if ((string = domain_rev6(servers_only, comma, &addr6, size)))
ret_err(string);
}
else
ret_err(gen_err);
if (!comma)
flags |= SERV_LITERAL_ADDRESS;
else if ((string = parse_server(comma, &serv_addr, &source_addr, interface, &flags)))
ret_err(string);
if (servers_only)
flags |= SERV_FROM_FILE;
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
ret_err(gen_err);
break;
}
case LOPT_IPSET: /* --ipset */
case LOPT_NFTSET: /* --nftset */
#ifndef HAVE_IPSET
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
break;
#else
if (option == LOPT_IPSET)
{
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
break;
}
#endif
#ifndef HAVE_NFTSET
if (option == LOPT_NFTSET)
{
ret_err(_("recompile with HAVE_NFTSET defined to enable nftset directives"));
break;
}
#endif
{
struct ipsets ipsets_head;
struct ipsets *ipsets = &ipsets_head;
struct ipsets **daemon_sets =
(option == LOPT_IPSET) ? &daemon->ipsets : &daemon->nftsets;
int size;
char *end;
char **sets, **sets_pos;
@@ -2823,19 +2910,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
sets = sets_pos = opt_malloc(sizeof(char *) * size);
do {
char *p;
end = split(arg);
*sets_pos++ = opt_string_alloc(arg);
*sets_pos = opt_string_alloc(arg);
/* Use '#' to delimit table and set */
if (option == LOPT_NFTSET)
while ((p = strchr(*sets_pos, '#')))
*p = ' ';
sets_pos++;
arg = end;
} while (end);
*sets_pos = 0;
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
ipsets->next->sets = sets;
ipsets->next = daemon->ipsets;
daemon->ipsets = ipsets_head.next;
ipsets->next = *daemon_sets;
*daemon_sets = ipsets_head.next;
break;
}
#endif
case LOPT_CMARK_ALST_EN: /* --connmark-allowlist-enable */
#ifndef HAVE_CONNTRACK
@@ -3615,6 +3707,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
inet_ntop(AF_INET, &in, daemon->addrbuff, ADDRSTRLEN);
sprintf(errstr, _("duplicate dhcp-host IP address %s"),
daemon->addrbuff);
dhcp_config_free(new);
return 0;
}
}
@@ -3778,16 +3871,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_NAME_MATCH: /* --dhcp-name-match */
{
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
struct dhcp_match_name *new;
ssize_t len;
if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
ret_err(gen_err);
new = opt_malloc(sizeof(struct dhcp_match_name));
new->wildcard = 0;
new->netid = id;
id->net = opt_string_alloc(set_prefix(arg));
new->netid = opt_malloc(sizeof(struct dhcp_netid));
new->netid->net = opt_string_alloc(set_prefix(arg));
if (comma[len-1] == '*')
{
@@ -3991,6 +4084,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
dhcp_netid_free(new->netid);
free(new);
ret_err(gen_err);
}
@@ -4366,7 +4461,7 @@ err:
case LOPT_CNAME: /* --cname */
{
struct cname *new;
char *alias, *target, *last, *pen;
char *alias, *target=NULL, *last, *pen;
int ttl = -1;
for (last = pen = NULL, comma = arg; comma; comma = split(comma))
@@ -4381,13 +4476,13 @@ err:
if (pen != arg && atoi_check(last, &ttl))
last = pen;
target = canonicalise_opt(last);
while (arg != last)
{
int arglen = strlen(arg);
alias = canonicalise_opt(arg);
if (!target)
target = canonicalise_opt(last);
if (!alias || !target)
{
free(target);
@@ -4690,7 +4785,7 @@ err:
struct name_list *nl;
if (!canon)
{
struct name_list *tmp = new->names, *next;
struct name_list *tmp, *next;
for (tmp = new->names; tmp; tmp = next)
{
next = tmp->next;
@@ -5027,15 +5122,33 @@ static int one_file(char *file, int hard_opt)
return 1;
}
static int file_filter(const struct dirent *ent)
{
size_t lenfile = strlen(ent->d_name);
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
return 0;
return 1;
}
/* expand any name which is a directory */
struct hostsfile *expand_filelist(struct hostsfile *list)
{
unsigned int i;
struct hostsfile *ah;
int entcnt, n;
struct hostsfile *ah, *last, *next, **up;
struct dirent **namelist;
/* find largest used index */
for (i = SRC_AH, ah = list; ah; ah = ah->next)
{
last = ah;
if (i <= ah->index)
i = ah->index + 1;
@@ -5051,46 +5164,48 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
struct stat buf;
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
{
DIR *dir_stream;
struct dirent *ent;
/* don't read this as a file */
ah->flags |= AH_INACTIVE;
if (!(dir_stream = opendir(ah->fname)))
entcnt = scandir(ah->fname, &namelist, file_filter, alphasort);
if (entcnt < 0)
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
ah->fname, strerror(errno));
else
{
while ((ent = readdir(dir_stream)))
for (n = 0; n < entcnt; n++)
{
ent = namelist[n];
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
struct hostsfile *ah1;
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
/* see if we have an existing record.
dir is ah->fname
file is ent->d_name
path to match is ah1->fname */
for (ah1 = list; ah1; ah1 = ah1->next)
for (up = &list, ah1 = list; ah1; ah1 = next)
{
next = ah1->next;
if (lendir < strlen(ah1->fname) &&
strstr(ah1->fname, ah->fname) == ah1->fname &&
ah1->fname[lendir] == '/' &&
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
{
ah1->flags &= ~AH_INACTIVE;
/* If found, remove from list to re-insert at the end.
Unless it's already at the end. */
if (last != ah1)
*up = next;
break;
}
up = &ah1->next;
}
/* make new record */
@@ -5111,17 +5226,21 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
ah1->fname = path;
ah1->index = i++;
ah1->flags = AH_DIR;
ah1->next = list;
list = ah1;
}
/* Edge case, may be the last in the list anyway */
if (last != ah1)
last->next = ah1;
ah1->next = NULL;
last = ah1;
/* inactivate record if not regular file */
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
ah1->flags |= AH_INACTIVE;
}
closedir(dir_stream);
}
free(namelist);
}
}

View File

@@ -20,13 +20,13 @@
#define LOG(...) \
do { \
my_syslog(LOG_WARNING, __VA_ARGS__); \
my_syslog(LOG_DEBUG, __VA_ARGS__); \
} while (0)
#define ASSERT(condition) \
do { \
if (!(condition)) \
LOG("[pattern.c:%d] Assertion failure: %s", __LINE__, #condition); \
my_syslog(LOG_ERR, _("[pattern.c:%d] Assertion failure: %s"), __LINE__, #condition); \
} while (0)
/**
@@ -66,8 +66,8 @@ static int is_string_matching_glob_pattern(
pattern_character -= 'a' - 'A';
if (pattern_character == '*')
{
// zero-or-more-character wildcard
// Try to match at value_index, otherwise restart at value_index + 1 next.
/* zero-or-more-character wildcard */
/* Try to match at value_index, otherwise restart at value_index + 1 next. */
next_pattern_index = pattern_index;
pattern_index++;
if (value_index < num_value_bytes)
@@ -78,7 +78,7 @@ static int is_string_matching_glob_pattern(
}
else
{
// ordinary character
/* ordinary character */
if (value_index < num_value_bytes)
{
char value_character = value[value_index];
@@ -139,7 +139,7 @@ int is_valid_dns_name(const char *value)
(*c < 'A' || *c > 'Z') &&
(*c < 'a' || *c > 'z'))
{
LOG("Invalid DNS name: Invalid character %c.", *c);
LOG(_("Invalid DNS name: Invalid character %c."), *c);
return 0;
}
if (*c)
@@ -148,12 +148,12 @@ int is_valid_dns_name(const char *value)
{
if (!*c || *c == '.')
{
LOG("Invalid DNS name: Empty label.");
LOG(_("Invalid DNS name: Empty label."));
return 0;
}
if (*c == '-')
{
LOG("Invalid DNS name: Label starts with hyphen.");
LOG(_("Invalid DNS name: Label starts with hyphen."));
return 0;
}
label = c;
@@ -167,13 +167,13 @@ int is_valid_dns_name(const char *value)
{
if (c[-1] == '-')
{
LOG("Invalid DNS name: Label ends with hyphen.");
LOG(_("Invalid DNS name: Label ends with hyphen."));
return 0;
}
size_t num_label_bytes = (size_t) (c - label);
if (num_label_bytes > 63)
{
LOG("Invalid DNS name: Label is too long (%zu).", num_label_bytes);
LOG(_("Invalid DNS name: Label is too long (%zu)."), num_label_bytes);
return 0;
}
num_labels++;
@@ -181,12 +181,12 @@ int is_valid_dns_name(const char *value)
{
if (num_labels < 2)
{
LOG("Invalid DNS name: Not enough labels (%zu).", num_labels);
LOG(_("Invalid DNS name: Not enough labels (%zu)."), num_labels);
return 0;
}
if (is_label_numeric)
{
LOG("Invalid DNS name: Final label is fully numeric.");
LOG(_("Invalid DNS name: Final label is fully numeric."));
return 0;
}
if (num_label_bytes == 5 &&
@@ -196,12 +196,12 @@ int is_valid_dns_name(const char *value)
(label[3] == 'a' || label[3] == 'A') &&
(label[4] == 'l' || label[4] == 'L'))
{
LOG("Invalid DNS name: \"local\" pseudo-TLD.");
LOG(_("Invalid DNS name: \"local\" pseudo-TLD."));
return 0;
}
if (num_bytes < 1 || num_bytes > 253)
{
LOG("DNS name has invalid length (%zu).", num_bytes);
LOG(_("DNS name has invalid length (%zu)."), num_bytes);
return 0;
}
return 1;
@@ -249,13 +249,13 @@ int is_valid_dns_name_pattern(const char *value)
for (const char *c = value;; c++)
{
if (*c &&
*c != '*' && // Wildcard.
*c != '*' && /* Wildcard. */
*c != '-' && *c != '.' &&
(*c < '0' || *c > '9') &&
(*c < 'A' || *c > 'Z') &&
(*c < 'a' || *c > 'z'))
{
LOG("Invalid DNS name pattern: Invalid character %c.", *c);
LOG(_("Invalid DNS name pattern: Invalid character %c."), *c);
return 0;
}
if (*c && *c != '*')
@@ -264,12 +264,12 @@ int is_valid_dns_name_pattern(const char *value)
{
if (!*c || *c == '.')
{
LOG("Invalid DNS name pattern: Empty label.");
LOG(_("Invalid DNS name pattern: Empty label."));
return 0;
}
if (*c == '-')
{
LOG("Invalid DNS name pattern: Label starts with hyphen.");
LOG(_("Invalid DNS name pattern: Label starts with hyphen."));
return 0;
}
label = c;
@@ -282,7 +282,7 @@ int is_valid_dns_name_pattern(const char *value)
{
if (num_wildcards >= 2)
{
LOG("Invalid DNS name pattern: Wildcard character used more than twice per label.");
LOG(_("Invalid DNS name pattern: Wildcard character used more than twice per label."));
return 0;
}
num_wildcards++;
@@ -292,13 +292,13 @@ int is_valid_dns_name_pattern(const char *value)
{
if (c[-1] == '-')
{
LOG("Invalid DNS name pattern: Label ends with hyphen.");
LOG(_("Invalid DNS name pattern: Label ends with hyphen."));
return 0;
}
size_t num_label_bytes = (size_t) (c - label) - num_wildcards;
if (num_label_bytes > 63)
{
LOG("Invalid DNS name pattern: Label is too long (%zu).", num_label_bytes);
LOG(_("Invalid DNS name pattern: Label is too long (%zu)."), num_label_bytes);
return 0;
}
num_labels++;
@@ -306,17 +306,17 @@ int is_valid_dns_name_pattern(const char *value)
{
if (num_labels < 2)
{
LOG("Invalid DNS name pattern: Not enough labels (%zu).", num_labels);
LOG(_("Invalid DNS name pattern: Not enough labels (%zu)."), num_labels);
return 0;
}
if (num_wildcards != 0 || previous_label_has_wildcard)
{
LOG("Invalid DNS name pattern: Wildcard within final two labels.");
LOG(_("Invalid DNS name pattern: Wildcard within final two labels."));
return 0;
}
if (is_label_numeric)
{
LOG("Invalid DNS name pattern: Final label is fully numeric.");
LOG(_("Invalid DNS name pattern: Final label is fully numeric."));
return 0;
}
if (num_label_bytes == 5 &&
@@ -326,12 +326,12 @@ int is_valid_dns_name_pattern(const char *value)
(label[3] == 'a' || label[3] == 'A') &&
(label[4] == 'l' || label[4] == 'L'))
{
LOG("Invalid DNS name pattern: \"local\" pseudo-TLD.");
LOG(_("Invalid DNS name pattern: \"local\" pseudo-TLD."));
return 0;
}
if (num_bytes < 1 || num_bytes > 253)
{
LOG("DNS name pattern has invalid length after removing wildcards (%zu).", num_bytes);
LOG(_("DNS name pattern has invalid length after removing wildcards (%zu)."), num_bytes);
return 0;
}
return 1;

View File

@@ -746,6 +746,8 @@ static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void
add 7 to round up */
int len = (maclen + 9) >> 3;
unsigned char *p = expand(len << 3);
if (!p)
return 1;
memset(p, 0, len << 3);
*p++ = ICMP6_OPT_SOURCE_MAC;
*p++ = len;

File diff suppressed because it is too large Load Diff

View File

@@ -600,7 +600,7 @@ void check_tftp_listeners(time_t now)
/* Wrong source address. See rfc1350 para 4. */
prettyprint_addr(&peer, daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
}
}
}

View File

@@ -84,7 +84,7 @@ static void ubus_destroy(struct ubus_context *ubus)
ubus_free(ubus);
daemon->ubus = NULL;
// Forces re-initialization when we're reusing the same definitions later on.
/* Forces re-initialization when we're reusing the same definitions later on. */
ubus_object.id = 0;
ubus_object_type.id = 0;
}
@@ -171,6 +171,16 @@ void check_ubus_listeners()
}
}
#define CHECK(stmt) \
do { \
int e = (stmt); \
if (e) \
{ \
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
return (UBUS_STATUS_UNKNOWN_ERROR); \
} \
} while (0)
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
@@ -181,12 +191,13 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
(void)method;
(void)msg;
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
for (i=0; i < __METRIC_MAX; i++)
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
return ubus_send_reply(ctx, req, b.head);
CHECK(ubus_send_reply(ctx, req, b.head));
return UBUS_STATUS_OK;
}
#ifdef HAVE_CONNTRACK
@@ -305,66 +316,71 @@ fail:
}
#endif
#undef CHECK
#define CHECK(stmt) \
do { \
int e = (stmt); \
if (e) \
{ \
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
return; \
} \
} while (0)
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
{
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
int ret;
if (!ubus || !ubus_object.has_subscribers)
return;
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
if (mac)
blobmsg_add_string(&b, "mac", mac);
CHECK(blobmsg_add_string(&b, "mac", mac));
if (ip)
blobmsg_add_string(&b, "ip", ip);
CHECK(blobmsg_add_string(&b, "ip", ip));
if (name)
blobmsg_add_string(&b, "name", name);
CHECK(blobmsg_add_string(&b, "name", name));
if (interface)
blobmsg_add_string(&b, "interface", interface);
CHECK(blobmsg_add_string(&b, "interface", interface));
ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
if (ret)
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
}
#ifdef HAVE_CONNTRACK
void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
{
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
int ret;
if (!ubus || !ubus_object.has_subscribers)
return;
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "mark", mark);
blobmsg_add_string(&b, "name", name);
CHECK(blob_buf_init(&b, 0));
CHECK(blobmsg_add_u32(&b, "mark", mark));
CHECK(blobmsg_add_string(&b, "name", name));
ret = ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1);
if (ret)
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
}
void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
{
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
int ret;
if (!ubus || !ubus_object.has_subscribers)
return;
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "mark", mark);
blobmsg_add_string(&b, "name", name);
blobmsg_add_string(&b, "value", value);
blobmsg_add_u32(&b, "ttl", ttl);
CHECK(blob_buf_init(&b, 0));
CHECK(blobmsg_add_u32(&b, "mark", mark));
CHECK(blobmsg_add_string(&b, "name", name));
CHECK(blobmsg_add_string(&b, "value", value));
CHECK(blobmsg_add_u32(&b, "ttl", ttl));
ret = ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000);
if (ret)
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
/* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
}
#endif
#undef CHECK
#endif /* HAVE_UBUS */

View File

@@ -115,7 +115,8 @@ u64 rand64(void)
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
}
/* returns 2 if names is OK but contains one or more underscores */
/* returns 1 if name is OK and ascii printable
* returns 2 if name should be processed by IDN */
static int check_name(char *in)
{
/* remove trailing .
@@ -123,7 +124,9 @@ static int check_name(char *in)
size_t dotgap = 0, l = strlen(in);
char c;
int nowhite = 0;
int idn_encode = 0;
int hasuscore = 0;
int hasucase = 0;
if (l == 0 || l > MAXDNAME) return 0;
@@ -136,28 +139,49 @@ static int check_name(char *in)
for (; (c = *in); in++)
{
if (c == '.')
dotgap = 0;
dotgap = 0;
else if (++dotgap > MAXLABEL)
return 0;
return 0;
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
/* iscntrl only gives expected results for ascii */
return 0;
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
/* iscntrl only gives expected results for ascii */
return 0;
else if (!isascii((unsigned char)c))
return 0;
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
return 0;
#else
idn_encode = 1;
#endif
else if (c != ' ')
{
nowhite = 1;
if (c == '_')
hasuscore = 1;
}
{
nowhite = 1;
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
if (c == '_')
hasuscore = 1;
#else
(void)hasuscore;
#endif
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
if (c >= 'A' && c <= 'Z')
hasucase = 1;
#else
(void)hasucase;
#endif
}
}
if (!nowhite)
return 0;
return hasuscore ? 2 : 1;
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
/* Older libidn2 strips underscores, so don't do IDN processing
if the name has an underscore unless it also has non-ascii characters. */
idn_encode = idn_encode || (hasucase && !hasuscore);
#else
idn_encode = idn_encode || hasucase;
#endif
return (idn_encode) ? 2 : 1;
}
/* Hostnames have a more limited valid charset than domain names
@@ -204,12 +228,8 @@ char *canonicalise(char *in, int *nomem)
if (!(rc = check_name(in)))
return NULL;
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
/* older libidn2 strips underscores, so don't do IDN processing
if the name has an underscore (check_name() returned 2) */
if (rc != 2)
#endif
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
if (rc == 2)
{
# ifdef HAVE_LIBIDN2
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
@@ -234,12 +254,14 @@ char *canonicalise(char *in, int *nomem)
return ret;
}
#else
(void)rc;
#endif
if ((ret = whine_malloc(strlen(in)+1)))
strcpy(ret, in);
else if (nomem)
*nomem = 1;
*nomem = 1;
return ret;
}
@@ -408,13 +430,12 @@ int hostname_issubdomain(char *a, char *b)
time_t dnsmasq_time(void)
{
#ifdef HAVE_BROKEN_RTC
struct tms dummy;
static long tps = 0;
struct timespec ts;
if (tps == 0)
tps = sysconf(_SC_CLK_TCK);
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
return (time_t)(times(&dummy)/tps);
return ts.tv_sec;
#else
return time(NULL);
#endif
@@ -528,7 +549,7 @@ void prettyprint_time(char *buf, unsigned int t)
if ((x = (t/60)%60))
p += sprintf(&buf[p], "%um", x);
if ((x = t%60))
p += sprintf(&buf[p], "%us", x);
sprintf(&buf[p], "%us", x);
}
}
@@ -574,7 +595,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
int j, bytes = (1 + (r - in))/2;
for (j = 0; j < bytes; j++)
{
char sav = sav;
char sav;
if (j < bytes - 1)
{
sav = in[(j+1)*2];