Merge branch 'development-v6' into tweak/allow_adlist_dups

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2024-02-13 21:06:43 +01:00
59 changed files with 2013 additions and 1312 deletions
+1 -1
View File
@@ -12,6 +12,6 @@ cmake_minimum_required(VERSION 2.8.12)
project(PIHOLE_FTL C)
set(DNSMASQ_VERSION pi-hole-v2.89-e1de9c2)
set(DNSMASQ_VERSION pi-hole-v2.90)
add_subdirectory(src)
+4 -1
View File
@@ -244,7 +244,10 @@ components:
- Authentication
operationId: "add_app"
description: |
Create a new application password. The generated password is shown only once and cannot be retrieved later so make sure to store it in a safe place. The application password can be used to authenticate against the API instead of the regular password. It does not require 2FA verification. Generating a new application password will invalidate all currently active sessions.
Create a new application password. The generated password is shown only once and cannot be retrieved later - make sure to store it in a safe place. The application password can be used to authenticate against the API instead of the regular password.
It does not require 2FA verification. Generating a new application password will invalidate all currently active sessions.
Note that this endpoint only generates an application password accompanied by its hash. To make this new password effective, the returned `hash` has to be set as `webserver.api.app_password` in the Pi-hole configuration in a follow-up step. This can be done in various ways, e.g. via the API (`PATCH /api/config/webserver/api/app_pwhash`), the graphical web interface (Settings -> All Settings) or by editing the configuration file directly.
responses:
'200':
description: OK
+109
View File
@@ -752,6 +752,115 @@ components:
type: boolean
description: Whether or not FTL is allowed to perform destructive actions
example: true
dnsmasq:
type: object
description: Metrics from the embedded dnsmasq resolver
properties:
dns_cache_inserted:
type: integer
description: Number of inserted entries in DNS cache
example: 8
dns_cache_live_freed:
type: integer
description: Number of freed live entries in DNS cache
example: 0
dns_queries_forwarded:
type: integer
description: Number of forwarded DNS queries
example: 2
dns_auth_answered:
type: integer
description: Number of DNS queries for authoritative zones
example: 0
dns_local_answered:
type: integer
description: Number of DNS queries answered from local cache
example: 74
dns_stale_answered:
type: integer
description: Number of DNS queries answered from local cache (stale entries)
example: 0
dns_unanswered:
type: integer
description: Number of unanswered DNS queries
example: 0
bootp:
type: integer
description: Number of BOOTP requests
example: 0
pxe:
type: integer
description: Number of PXE requests
example: 0
dhcp_ack:
type: integer
description: Number of DHCP ACK
example: 0
dhcp_decline:
type: integer
description: Number of DHCP DECLINE
example: 0
dhcp_discover:
type: integer
description: Number of DHCP DISCOVER
example: 0
dhcp_inform:
type: integer
description: Number of DHCP INFORM
example: 0
dhcp_nak:
type: integer
description: Number of DHCP NAK
example: 0
dhcp_offer:
type: integer
description: Number of DHCP OFFER
example: 0
dhcp_release:
type: integer
description: Number of DHCP RELEASE
example: 0
dhcp_request:
type: integer
description: Number of DHCP REQUEST
example: 0
noanswer:
type: integer
description: Number of DHCP requests without answer (rapid commit)
example: 0
leases_allocated_4:
type: integer
description: Number of allocated IPv4 leases
example: 0
leases_pruned_4:
type: integer
description: Number of pruned IPv4 leases
example: 0
leases_allocated_6:
type: integer
description: Number of allocated IPv6 leases
example: 0
leases_pruned_6:
type: integer
description: Number of pruned IPv6 leases
example: 0
tcp_connections:
type: integer
description: Number of dedicated TCP workers
example: 0
dnssec_max_crypto_use:
type: integer
description: DNSSEC per-query crypto work HWM
example: 0
dnssec_max_sig_fail:
type: integer
description: DNSSEC per-RRSet signature fails HWM
example: 0
dnssec_max_work:
type: integer
description: DNSSEC per-query subqueries HWM
example: 0
database:
type: object
properties:
+5
View File
@@ -590,6 +590,11 @@ static int get_ftl_obj(struct ftl_conn *api, cJSON *ftl)
JSON_ADD_BOOL_TO_OBJECT(ftl, "allow_destructive", config.webserver.api.allow_destructive.v.b);
// dnsmasq struct
cJSON *dnsmasq = JSON_NEW_OBJECT();
get_dnsmasq_metrics_obj(dnsmasq);
JSON_ADD_ITEM_TO_OBJECT(ftl, "dnsmasq", dnsmasq);
// All okay
return 0;
}
+9
View File
@@ -658,6 +658,15 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
}
}
// Add ANY filtering
fputs("# RFC 8482: Providing Minimal-Sized Responses to DNS Queries That Have QTYPE=ANY\n", pihole_conf);
fputs("# Filters replies to queries for type ANY. Everything other than A, AAAA, MX and CNAME\n", pihole_conf);
fputs("# records are removed. Since ANY queries with forged source addresses can be used in DNS amplification attacks\n", pihole_conf);
fputs("# replies to ANY queries can be large) this defangs such attacks, whilst still supporting the\n", pihole_conf);
fputs("# one remaining possible use of ANY queries. See RFC 8482 para 4.3 for details.\n", pihole_conf);
fputs("filter-rr=ANY\n", pihole_conf);
fputs("\n", pihole_conf);
// Add additional config lines to disk (if present)
if(conf->misc.dnsmasq_lines.v.json != NULL &&
cJSON_GetArraySize(conf->misc.dnsmasq_lines.v.json) > 0)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+107 -62
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -126,6 +126,7 @@ static const struct {
{ 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*/
{ 261, "RESINFO" }, /* Resolver Information as Key/Value Pairs https://datatracker.ietf.org/doc/draft-ietf-add-resolver-info/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] */
};
@@ -441,18 +442,21 @@ unsigned int cache_remove_uid(const unsigned int uid)
{
int i;
unsigned int removed = 0;
struct crec *crecp, **up;
struct crec *crecp, *tmp, **up;
for (i = 0; i < hash_size; i++)
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
{
*up = crecp->hash_next;
free(crecp);
removed++;
}
else
up = &crecp->hash_next;
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = tmp)
{
tmp = crecp->hash_next;
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
{
*up = tmp;
free(crecp);
removed++;
}
else
up = &crecp->hash_next;
}
return removed;
}
@@ -815,32 +819,28 @@ void cache_end_insert(void)
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
if (flags & F_RR)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
if (flags & F_RR)
{
/* A negative RR entry is possible and has no data, obviously. */
if (!(flags & F_NEG) && (flags & F_KEYTAG))
blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
}
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
}
else if (flags & F_DS)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
/* A negative DS entry is possible and has no data, obviously. */
if (!(flags & F_NEG))
blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
}
#endif
/* A negative RR entry is possible and has no data, obviously. */
if (!(flags & F_NEG) && (flags & F_KEYTAG))
blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
}
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
}
else if (flags & F_DS)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
/* A negative DS entry is possible and has no data, obviously. */
if (!(flags & F_NEG))
blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
}
#endif
}
}
@@ -851,7 +851,18 @@ void cache_end_insert(void)
if (daemon->pipe_to_parent != -1)
{
ssize_t m = -1;
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
#ifdef HAVE_DNSSEC
/* Sneak out possibly updated crypto HWM values. */
m = daemon->metrics[METRIC_CRYPTO_HWM];
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
m = daemon->metrics[METRIC_SIG_FAIL_HWM];
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
m = daemon->metrics[METRIC_WORK_HWM];
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
#endif
}
new_chain = NULL;
@@ -870,7 +881,7 @@ int cache_recv_insert(time_t now, int fd)
cache_start_insert();
while(1)
while (1)
{
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
@@ -878,13 +889,29 @@ int cache_recv_insert(time_t now, int fd)
if (m == -1)
{
#ifdef HAVE_DNSSEC
/* Sneak in possibly updated crypto HWM. */
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
return 0;
if (m > daemon->metrics[METRIC_CRYPTO_HWM])
daemon->metrics[METRIC_CRYPTO_HWM] = m;
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
return 0;
if (m > daemon->metrics[METRIC_SIG_FAIL_HWM])
daemon->metrics[METRIC_SIG_FAIL_HWM] = m;
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
return 0;
if (m > daemon->metrics[METRIC_WORK_HWM])
daemon->metrics[METRIC_WORK_HWM] = m;
#endif
cache_end_insert();
return 1;
}
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1) ||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
return 0;
daemon->namebuff[m] = 0;
@@ -915,30 +942,23 @@ int cache_recv_insert(time_t now, int fd)
{
unsigned short class = C_IN;
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
{
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
return 0;
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
return 0;
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
return 0;
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
{
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
return 0;
}
else if (flags & F_DS)
{
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
return 0;
}
#endif
if (flags & F_DNSKEY)
{
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
return 0;
}
else if (flags & F_DS)
{
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
return 0;
}
#endif
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
}
}
@@ -1839,8 +1859,18 @@ static void dump_cache_entry(struct crec *cache, time_t now)
p = buff;
*a = 0;
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
n = "<Root>";
if (cache->flags & F_REVERSE)
{
if ((cache->flags & F_NEG))
n = "";
}
else
{
if (strlen(n) == 0)
n = "<Root>";
}
p += sprintf(p, "%-30.30s ", sanitise(n));
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
a = sanitise(cache_get_cname_target(cache));
@@ -2005,9 +2035,19 @@ void dump_cache(time_t now)
#ifdef HAVE_AUTH
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
#endif
#ifdef HAVE_DNSSEC
my_syslog(LOG_INFO, _("DNSSEC per-query subqueries HWM %u"), daemon->metrics[METRIC_WORK_HWM]);
my_syslog(LOG_INFO, _("DNSSEC per-query crypto work HWM %u"), daemon->metrics[METRIC_CRYPTO_HWM]);
my_syslog(LOG_INFO, _("DNSSEC per-RRSet signature fails HWM %u"), daemon->metrics[METRIC_SIG_FAIL_HWM]);
#endif
blockdata_report();
my_syslog(LOG_INFO, _("child processes for TCP requests: in use %zu, highest since last SIGUSR1 %zu, max allowed %zu."),
daemon->metrics[METRIC_TCP_CONNECTIONS],
daemon->max_procs_used,
daemon->max_procs);
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
/* sum counts from different records for same server */
for (serv = daemon->servers; serv; serv = serv->next)
serv->flags &= ~SERV_MARK;
@@ -2161,6 +2201,11 @@ const char *edestr(int ede)
case EDE_NO_AUTH: return "no reachable authority";
case EDE_NETERR: return "network error";
case EDE_INVALID_DATA: return "invalid data";
case EDE_SIG_E_B_V: return "signature expired before valid";
case EDE_TOO_EARLY: return "too early";
case EDE_UNS_NS3_ITER: return "unsupported NSEC3 iterations value";
case EDE_UNABLE_POLICY: return "uanble to conform to policy";
case EDE_SYNTHESIZED: return "synthesized";
default: return "unknown";
}
}
+6 -3
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -15,14 +15,17 @@
*/
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 60 /* max no children for TCP requests */
#define MAX_PROCS 60 /* default max no children for TCP requests */
#define CHILD_LIFETIME 300 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
#define SAFE_PKTSZ 1232 /* "go anywhere" UDP packet size, see https://dnsflagday.net/2020/ */
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
#define DNSSEC_LIMIT_WORK 40 /* Max number of queries to validate one question */
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
#define DNSSEC_LIMIT_NSEC3_ITERS 150 /* Max. number if iterations allowed in NSEC3 record. */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
#define FORWARD_TEST 1000 /* try all servers every 1000 queries */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -92,7 +92,7 @@ void dhcp6_packet(time_t now)
struct iface_param parm;
struct cmsghdr *cmptr;
struct msghdr msg;
int if_index = 0;
uint32_t if_index = 0;
union {
struct cmsghdr align; /* this ensures alignment */
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+6 -3
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -112,8 +112,11 @@
#define EDE_NO_AUTH 22 /* No Reachable Authority */
#define EDE_NETERR 23 /* Network error */
#define EDE_INVALID_DATA 24 /* Invalid Data */
#define EDE_SIG_E_B_V 25 /* Signature Expired before Valid */
#define EDE_TOO_EARLY 26 /* To Early */
#define EDE_UNS_NS3_ITER 27 /* Unsupported NSEC3 Iterations Value */
#define EDE_UNABLE_POLICY 28 /* Unable to conform to policy */
#define EDE_SYNTHESIZED 29 /* Synthesized */
struct dns_header {
+81 -46
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -36,12 +36,14 @@ static volatile int pipewrite;
volatile char FTL_terminate = 0;
static void set_dns_listeners(void);
static void set_tftp_listeners(void);
static void check_dns_listeners(time_t now);
static void sig_handler(int sig);
static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev, char *msg);
static int read_event(int fd, struct event_desc *evp, char **msg);
static void poll_resolv(int force, int do_reload, time_t now);
static void tcp_init(void);
int main_dnsmasq (int argc, char **argv)
{
@@ -135,19 +137,11 @@ int main_dnsmasq (int argc, char **argv)
'.' or NAME_ESCAPE then all would have to be escaped, so the
presentation format would be twice as long as the spec. */
daemon->keyname = safe_malloc((MAXDNAME * 2) + 1);
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
/* one char flag per possible RR in answer section (may get extended). */
daemon->rr_status_sz = 64;
daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz);
}
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
/* CONNTRACK UBUS code uses this buffer, so if not allocated above,
we need to allocate it here. */
if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename)
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
#endif
#ifdef HAVE_DHCP
if (!daemon->lease_file)
@@ -378,6 +372,13 @@ int main_dnsmasq (int argc, char **argv)
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
#ifdef HAVE_DHCP
/* Determine lease FQDNs after enumerate_interfaces() call, since it needs
to call get_domain and that's only valid for some domain configs once we
have interface addresses. */
lease_calc_fqdns();
#endif
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
@@ -421,11 +422,13 @@ int main_dnsmasq (int argc, char **argv)
daemon->numrrand = max_fd/3;
/* safe_malloc returns zero'd memory */
daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd));
tcp_init();
}
#ifdef HAVE_INOTIFY
if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
&& (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
if ((daemon->port != 0 && !option_bool(OPT_NO_RESOLV)) ||
daemon->dynamic_dirs)
inotify_dnsmasq_init();
else
daemon->inotifyfd = -1;
@@ -865,6 +868,8 @@ int main_dnsmasq (int argc, char **argv)
if (option_bool(OPT_LOCAL_SERVICE))
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
else if (option_bool(OPT_LOCALHOST_SERVICE))
my_syslog(LOG_INFO, _("DNS service limited to localhost"));
}
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
@@ -1051,8 +1056,10 @@ int main_dnsmasq (int argc, char **argv)
pid = getpid();
daemon->pipe_to_parent = -1;
for (i = 0; i < MAX_PROCS; i++)
daemon->tcp_pipes[i] = -1;
if (daemon->port != 0)
for (i = 0; i < daemon->max_procs; i++)
daemon->tcp_pipes[i] = -1;
#ifdef HAVE_INOTIFY
/* Using inotify, have to select a resolv file at startup */
@@ -1079,7 +1086,12 @@ int main_dnsmasq (int argc, char **argv)
(timeout == -1 || timeout > 1000))
timeout = 1000;
set_dns_listeners();
if (daemon->port != 0)
set_dns_listeners();
#ifdef HAVE_TFTP
set_tftp_listeners();
#endif
#ifdef HAVE_DBUS
if (option_bool(OPT_DBUS))
@@ -1264,8 +1276,9 @@ int main_dnsmasq (int argc, char **argv)
check_ubus_listeners();
}
#endif
check_dns_listeners(now);
if (daemon->port != 0)
check_dns_listeners(now);
#ifdef HAVE_TFTP
check_tftp_listeners(now);
@@ -1538,10 +1551,15 @@ static void async_event(int pipe, time_t now)
if (errno != EINTR)
break;
}
else
for (i = 0 ; i < MAX_PROCS; i++)
else if (daemon->port != 0)
for (i = 0 ; i < daemon->max_procs; i++)
if (daemon->tcp_pids[i] == p)
daemon->tcp_pids[i] = 0;
{
daemon->tcp_pids[i] = 0;
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pipes[i] == -1)
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
}
break;
#if defined(HAVE_SCRIPT)
@@ -1604,9 +1622,10 @@ static void async_event(int pipe, time_t now)
case EVENT_TERM:
/* Knock all our children on the head. */
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
if (daemon->port != 0)
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
/* handle pending lease transitions */
@@ -1756,23 +1775,33 @@ void clear_cache_and_reload(time_t now)
#endif
}
static void set_dns_listeners(void)
{
struct serverfd *serverfdp;
struct listener *listener;
struct randfd_list *rfl;
int i;
#ifdef HAVE_TFTP
static void set_tftp_listeners(void)
{
int tftp = 0;
struct tftp_transfer *transfer;
struct listener *listener;
if (!option_bool(OPT_SINGLE_PORT))
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
{
tftp++;
poll_listen(transfer->sockfd, POLLIN);
}
for (listener = daemon->listeners; listener; listener = listener->next)
/* tftp == 0 in single-port mode. */
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
poll_listen(listener->tftpfd, POLLIN);
}
#endif
static void set_dns_listeners(void)
{
struct serverfd *serverfdp;
struct listener *listener;
struct randfd_list *rfl;
int i;
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
poll_listen(serverfdp->fd, POLLIN);
@@ -1786,7 +1815,7 @@ static void set_dns_listeners(void)
poll_listen(rfl->rfd->fd, POLLIN);
/* check to see if we have free tcp process slots. */
for (i = MAX_PROCS - 1; i >= 0; i--)
for (i = daemon->max_procs - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
@@ -1801,16 +1830,10 @@ static void set_dns_listeners(void)
we'll be called again when a slot becomes available. */
if (listener->tcpfd != -1 && i >= 0)
poll_listen(listener->tcpfd, POLLIN);
#ifdef HAVE_TFTP
/* tftp == 0 in single-port mode. */
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
poll_listen(listener->tftpfd, POLLIN);
#endif
}
if (!option_bool(OPT_DEBUG))
for (i = 0; i < MAX_PROCS; i++)
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1)
poll_listen(daemon->tcp_pipes[i], POLLIN);
}
@@ -1845,13 +1868,16 @@ static void check_dns_listeners(time_t now)
to free the process slot. Once the child process has gone, poll()
returns POLLHUP, not POLLIN, so have to check for both here. */
if (!option_bool(OPT_DEBUG))
for (i = 0; i < MAX_PROCS; i++)
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
!cache_recv_insert(now, daemon->tcp_pipes[i]))
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pids[i] == 0)
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
}
for (listener = daemon->listeners; listener; listener = listener->next)
@@ -1860,17 +1886,12 @@ static void check_dns_listeners(time_t now)
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
receive_query(listener, now);
#ifdef HAVE_TFTP
if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
tftp_request(listener, now);
#endif
/* check to see if we have a free tcp process slot.
Note that we can't assume that because we had
at least one a poll() time, that we still do.
There may be more waiting connections after
poll() returns then free process slots. */
for (i = MAX_PROCS - 1; i >= 0; i--)
for (i = daemon->max_procs - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
@@ -1986,6 +2007,9 @@ static void check_dns_listeners(time_t now)
/* i holds index of free slot */
daemon->tcp_pids[i] = p;
daemon->tcp_pipes[i] = pipefd[0];
daemon->metrics[METRIC_TCP_CONNECTIONS]++;
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
}
close(confd);
@@ -2171,7 +2195,11 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
poll_reset();
if (fd != -1)
poll_listen(fd, POLLIN);
set_dns_listeners();
if (daemon->port != 0)
set_dns_listeners();
#ifdef HAVE_TFTP
set_tftp_listeners();
#endif
set_log_writer();
#ifdef HAVE_DHCP6
@@ -2189,7 +2217,8 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
now = dnsmasq_time();
check_log_writer(0);
check_dns_listeners(now);
if (daemon->port != 0)
check_dns_listeners(now);
#ifdef HAVE_DHCP6
if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
@@ -2232,3 +2261,9 @@ void print_dnsmasq_version(const char *yellow, const char *green, const char *bo
printf(_("Features: %s\n\n"), compile_opts);
}
/**************************************************************************************/
void tcp_init(void)
{
daemon->tcp_pids = safe_malloc(daemon->max_procs*sizeof(pid_t));
daemon->tcp_pipes = safe_malloc(daemon->max_procs*sizeof(int));
}
+28 -14
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2023 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2024 Simon Kelley"
/* We do defines that influence behavior of stdio.h, so complain
if included too early. */
@@ -281,7 +281,8 @@ struct event_desc {
#define OPT_NORR 69
#define OPT_NO_IDENT 70
#define OPT_CACHE_RR 71
#define OPT_LAST 72
#define OPT_LOCALHOST_SERVICE 72
#define OPT_LAST 73
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -340,7 +341,7 @@ union all_addr {
in the cache flags. */
struct datablock {
unsigned short rrtype;
unsigned char datalen;
unsigned char datalen; /* also length of SOA in negative records. */
char data[];
} rrdata;
};
@@ -762,6 +763,9 @@ struct dyndir {
#define DNSSEC_FAIL_NONSEC 0x0040 /* No NSEC */
#define DNSSEC_FAIL_NODSSUP 0x0080 /* no supported DS algo. */
#define DNSSEC_FAIL_NOKEY 0x0100 /* no DNSKEY */
#define DNSSEC_FAIL_NSEC3_ITERS 0x0200 /* too many iterations in NSEC3 */
#define DNSSEC_FAIL_BADPACKET 0x0400 /* bad packet */
#define DNSSEC_FAIL_WORK 0x0800 /* too much crypto */
#define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b))
@@ -799,7 +803,7 @@ struct frec {
struct blockdata *stash; /* Saved reply, whilst we validate */
size_t stash_len;
#ifdef HAVE_DNSSEC
int class, work_counter;
int class, work_counter, validate_counter;
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
struct frec *next_dependent; /* list of above. */
struct frec *blocking_query; /* Query which is blocking us. */
@@ -836,6 +840,12 @@ struct frec {
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
#define LEASE_EXP_CHANGED 256 /* Lease expiry time changed */
#define LIMIT_SIG_FAIL 0
#define LIMIT_CRYPTO 1
#define LIMIT_WORK 2
#define LIMIT_NSEC3_ITERS 3
#define LIMIT_MAX 4
struct dhcp_lease {
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
@@ -1238,16 +1248,14 @@ 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 */
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
int rr_status_sz;
int dnssec_no_time_check;
int back_to_the_future;
int limit[LIMIT_MAX];
#endif
struct frec *frec_list;
struct frec_src *free_frec_src;
@@ -1258,8 +1266,8 @@ extern struct daemon {
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
int fd_save; /* " " */
pid_t tcp_pids[MAX_PROCS];
int tcp_pipes[MAX_PROCS];
pid_t *tcp_pids;
int *tcp_pipes;
int pipe_to_parent;
int numrrand;
struct randfd *randomsocks;
@@ -1319,6 +1327,8 @@ extern struct daemon {
/* file for packet dumps. */
int dumpfd;
#endif
int max_procs;
uint max_procs_used;
} *daemon;
struct server_details {
@@ -1383,6 +1393,7 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr);
int is_rev_synth(int flag, union all_addr *addr, char *name);
/* rfc1035.c */
int do_doctor(struct dns_header *header, size_t qlen, char *namebuff);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
@@ -1393,7 +1404,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
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, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
int check_rebind, int no_cache_dnssec, int secure);
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
void report_addresses(struct dns_header *header, size_t len, u32 mark);
#endif
@@ -1424,10 +1435,12 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
/* dnssec.c */
#ifdef HAVE_DNSSEC
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, int edns_pktsz);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name,
char *keyname, int class, int *validate_count);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name,
char *keyname, int class, int *validate_count);
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl, int *validate_count);
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
size_t filter_rrsigs(struct dns_header *header, size_t plen);
int setup_timestamp(void);
@@ -1613,6 +1626,7 @@ void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
void lease_find_interfaces(time_t now);
void lease_calc_fqdns(void);
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim);
+356 -242
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+15 -9
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -22,12 +22,13 @@ static int match_domain(struct in_addr addr, struct cond_domain *c);
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
int is_name_synthetic(int flags, char *name, union all_addr *addr)
int is_name_synthetic(int flags, char *name, union all_addr *addrp)
{
char *p;
struct cond_domain *c = NULL;
int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET;
union all_addr addr;
for (c = daemon->synth_domains; c; c = c->next)
{
int found = 0;
@@ -74,7 +75,7 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
if (!c->is6 &&
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
{
addr->addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
found = 1;
}
}
@@ -86,8 +87,8 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
index <= addr6part(&c->end6) - addr6part(&c->start6))
{
u64 start = addr6part(&c->start6);
addr->addr6 = c->start6;
setaddr6part(&addr->addr6, start + index);
addr.addr6 = c->start6;
setaddr6part(&addr.addr6, start + index);
found = 1;
}
}
@@ -135,8 +136,8 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
}
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, &addr))
found = (prot == AF_INET) ? match_domain(addr.addr4, c) : match_domain6(&addr.addr6, c);
}
/* restore name */
@@ -148,7 +149,12 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
if (found)
return 1;
{
if (addrp)
*addrp = addr;
return 1;
}
}
return 0;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+172 -119
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -344,7 +344,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (ad_reqd)
forward->flags |= FREC_AD_QUESTION;
#ifdef HAVE_DNSSEC
forward->work_counter = DNSSEC_WORK;
forward->work_counter = daemon->limit[LIMIT_WORK];
forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
if (do_bit)
forward->flags |= FREC_DO_QUESTION;
#endif
@@ -697,7 +698,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
{
unsigned char *pheader, *sizep;
struct ipsets *ipsets = NULL, *nftsets = NULL;
int munged = 0, is_sign;
int is_sign;
unsigned int rcode = RCODE(header);
size_t plen;
/******** Pi-hole modification ********/
@@ -706,8 +707,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
(void)ad_reqd;
(void)do_bit;
(void)bogusanswer;
#ifdef HAVE_IPSET
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
@@ -801,91 +801,108 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
server->flags |= SERV_WARNED_RECURSIVE;
}
if (daemon->bogus_addr && rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
if (header->hb3 & HB3_TC)
{
munged = 1;
SET_RCODE(header, NXDOMAIN);
header->hb3 &= ~HB3_AA;
cache_secure = 0;
ede = EDE_BLOCKED;
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
}
else
{
int doctored = 0;
if (rcode == NXDOMAIN &&
extract_request(header, n, daemon->namebuff, NULL))
{
if (check_for_local_domain(daemon->namebuff, now) ||
lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL))
{
/* if we forwarded a query for a locally known name (because it was for
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
since we know that the domain exists, even if upstream doesn't */
munged = 1;
header->hb3 |= HB3_AA;
SET_RCODE(header, NOERROR);
cache_secure = 0;
}
}
switch (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
if (!(header->hb3 & HB3_TC) && (!bogusanswer || (header->hb4 & HB4_CD)))
{
if (rcode == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) &&
(check_for_local_domain(daemon->namebuff, now) || lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL)))
{
case 1:
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
munged = 1;
/* if we forwarded a query for a locally known name (because it was for
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
since we know that the domain exists, even if upstream doesn't */
header->hb3 |= HB3_AA;
SET_RCODE(header, NOERROR);
cache_secure = 0;
}
if (daemon->doctors && do_doctor(header, n, daemon->namebuff))
cache_secure = 0;
/* check_for_bogus_wildcard() does it's own caching, so
don't call extract_addresses() if it triggers. */
if (daemon->bogus_addr && rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
{
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
SET_RCODE(header, NXDOMAIN);
header->hb3 &= ~HB3_AA;
cache_secure = 0;
ede = EDE_BLOCKED;
break;
/* extract_addresses() found a malformed answer. */
case 2:
munged = 1;
SET_RCODE(header, SERVFAIL);
cache_secure = 0;
ede = EDE_OTHER;
break;
/* Pi-hole modification */
case 99:
cache_secure = 0;
// Make a private copy of the pheader to ensure
// we are not accidentially rewriting what is in
// the pheader when we're creating a crafted reply
// further below (when a query is to be blocked)
if (pheader)
{
pheader_copy = calloc(1, plen);
memcpy(pheader_copy, pheader, plen);
}
// Generate DNS packet for reply, a possibly existing pseudo header
// will be restored later inside resize_packet()
n = FTL_make_answer(header, ((char *) header) + 65536, n, &ede);
break;
}
else
{
int rc = extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure);
if (rcode == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
ede = EDE_FILTERED;
if (rc != 0)
{
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
cache_secure = 0;
}
if (rc == 1)
{
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
ede = EDE_BLOCKED;
}
if (rc == 2)
{
/* extract_addresses() found a malformed answer. */
SET_RCODE(header, SERVFAIL);
ede = EDE_OTHER;
}
/* Pi-hole modification */
if(rc == 99)
{
cache_secure = 0;
// Make a private copy of the pheader to ensure
// we are not accidentially rewriting what is in
// the pheader when we're creating a crafted reply
// further below (when a query is to be blocked)
if (pheader)
{
pheader_copy = calloc(1, plen);
memcpy(pheader_copy, pheader, plen);
}
// Generate DNS packet for reply, a possibly existing pseudo header
// will be restored later inside resize_packet()
n = FTL_make_answer(header, ((char *) header) + 65536, n, &ede);
}
}
if (doctored)
cache_secure = 0;
if (RCODE(header) == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
ede = EDE_FILTERED;
}
#ifdef HAVE_DNSSEC
if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
{
/* Bogus reply, turn into SERVFAIL */
SET_RCODE(header, SERVFAIL);
munged = 1;
}
if (option_bool(OPT_DNSSEC_VALID))
{
header->hb4 &= ~HB4_AD;
if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
if (bogusanswer)
{
if (!(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
{
/* Bogus reply, turn into SERVFAIL */
SET_RCODE(header, SERVFAIL);
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
ede = EDE_DNSSEC_BOGUS;
}
}
else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
header->hb4 |= HB4_AD;
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
@@ -893,20 +910,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
rrfilter(header, &n, RRFILTER_DNSSEC);
}
#endif
/* do this after extract_addresses. Ensure NODATA reply and remove
nameserver info. */
if (munged)
{
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
header->hb3 &= ~HB3_TC;
}
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
sections of the packet. Find the new length here and put back pseudoheader
if it was removed. */
/* the code above can elide sections of the packet. Find the new length here
and put back pseudoheader if it was removed. */
n = resize_packet(header, n, pheader_copy ? pheader_copy : pheader, plen);
/******** Pi-hole modification ********/
// The line above was modified to use
@@ -931,6 +937,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
static void dnssec_validate(struct frec *forward, struct dns_header *header,
ssize_t plen, int status, time_t now)
{
struct frec *orig;
int log_resource = 0;
daemon->log_display_id = forward->frec_src.log_id;
/* We've had a reply already, which we're validating. Ignore this duplicate */
@@ -955,6 +964,9 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
log_query(F_UPSTREAM | F_NOEXTRA, daemon->namebuff, NULL, "truncated", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
}
}
/* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent);
/* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
would invite infinite loops, since the answers to DNSKEY and DS queries
@@ -962,19 +974,17 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
if (!STAT_ISEQUAL(status, STAT_BOGUS) && !STAT_ISEQUAL(status, STAT_TRUNCATED) && !STAT_ISEQUAL(status, STAT_ABANDONED))
{
if (forward->flags & FREC_DNSKEY_QUERY)
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class);
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
else if (forward->flags & FREC_DS_QUERY)
status = dnssec_validate_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class);
status = dnssec_validate_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
else
status = dnssec_validate_reply(now, header, plen, daemon->namebuff, daemon->keyname, &forward->class,
!option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
NULL, NULL, NULL);
#ifdef HAVE_DUMPFILE
if (STAT_ISEQUAL(status, STAT_BOGUS))
dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)plen, &forward->sentto->addr, NULL, -daemon->port);
#endif
NULL, NULL, NULL, &orig->validate_counter);
}
if (STAT_ISEQUAL(status, STAT_ABANDONED))
log_resource = 1;
/* Can't validate, as we're missing key data. Put this
answer aside, whilst we get that. */
@@ -1018,18 +1028,19 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
return;
}
}
else if (orig->work_counter-- == 0)
{
my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
log_resource = 1;
}
else
{
struct server *server;
struct frec *orig;
void *hash;
size_t nn;
int serverind, fd;
struct randfd_list *rfds = NULL;
/* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent);
/* Make sure we don't expire and free the orig frec during the
allocation of a new one: third arg of get_new_frec() does that. */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
@@ -1038,7 +1049,6 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
daemon->keyname, forward->class,
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz)) &&
(hash = hash_questions(header, nn, daemon->namebuff)) &&
--orig->work_counter != 0 &&
(fd = allocate_rfd(&rfds, server)) != -1 &&
(new = get_new_frec(now, server, 1)))
{
@@ -1104,6 +1114,21 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
status = STAT_ABANDONED;
}
if (log_resource)
{
/* Log the actual validation that made us barf. */
unsigned char *p = (unsigned char *)(header+1);
if (extract_name(header, plen, &p, daemon->namebuff, 0, 4) == 1)
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
daemon->namebuff[0] ? daemon->namebuff : ".");
}
#ifdef HAVE_DUMPFILE
if (STAT_ISEQUAL(status, STAT_BOGUS) || STAT_ISEQUAL(status, STAT_ABANDONED))
dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)plen, &forward->sentto->addr, NULL, -daemon->port);
#endif
/* Validated original answer, all done. */
if (!forward->dependent)
return_reply(now, forward, header, plen, status);
@@ -1112,7 +1137,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
/* validated subsidiary query/queries, (and cached result)
pop that and return to the previous query/queries we were working on. */
struct frec *prev, *nxt = forward->dependent;
free_frec(forward);
while ((prev = nxt))
@@ -1378,6 +1403,12 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
log_query(F_SECSTAT, domain, &a, result, 0);
}
}
if ((daemon->limit[LIMIT_CRYPTO] - forward->validate_counter) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - forward->validate_counter;
if ((daemon->limit[LIMIT_WORK] - forward->work_counter) > (int)daemon->metrics[METRIC_WORK_HWM])
daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - forward->work_counter;
#endif
if (option_bool(OPT_NO_REBIND))
@@ -2107,7 +2138,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
/* Recurse down the key hierarchy */
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
int class, char *name, char *keyname, struct server *server,
int have_mark, unsigned int mark, int *keycount)
int have_mark, unsigned int mark, int *keycount, int *validatecount)
{
int first, last, start, new_status;
unsigned char *packet = NULL;
@@ -2121,20 +2152,34 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
int log_save;
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
if (--(*keycount) == 0)
new_status = STAT_ABANDONED;
else if (STAT_ISEQUAL(status, STAT_NEED_KEY))
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
if (STAT_ISEQUAL(status, STAT_NEED_KEY))
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class, validatecount);
else if (STAT_ISEQUAL(status, STAT_NEED_DS))
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
new_status = dnssec_validate_ds(now, header, n, name, keyname, class, validatecount);
else
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL, NULL);
NULL, NULL, NULL, validatecount);
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY))
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY) && !STAT_ISEQUAL(new_status, STAT_ABANDONED))
break;
if ((*keycount)-- == 0)
{
my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
new_status = STAT_ABANDONED;
}
if (STAT_ISEQUAL(new_status, STAT_ABANDONED))
{
/* Log the actual validation that made us barf. */
unsigned char *p = (unsigned char *)(header+1);
if (extract_name(header, n, &p, daemon->namebuff, 0, 4) == 1)
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
daemon->namebuff[0] ? daemon->namebuff : ".");
break;
}
/* Can't validate because we need a key/DS whose name now in keyname.
Make query for same, and recurse to validate */
if (!packet)
@@ -2148,7 +2193,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
new_status = STAT_ABANDONED;
break;
}
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
@@ -2163,10 +2208,11 @@ 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 | F_SERVER, keyname, &server->addr,
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server,
have_mark, mark, keycount, validatecount);
daemon->log_display_id = log_save;
if (!STAT_ISEQUAL(new_status, STAT_OK))
@@ -2508,9 +2554,10 @@ unsigned char *tcp_request(int confd, time_t now,
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
{
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
int validatecount = daemon->limit[LIMIT_CRYPTO];
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
serv, have_mark, mark, &keycount);
serv, have_mark, mark, &keycount, &validatecount);
char *result, *domain = "result";
union all_addr a;
@@ -2536,6 +2583,12 @@ unsigned char *tcp_request(int confd, time_t now,
}
log_query(F_SECSTAT, domain, &a, result, 0);
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - validatecount;
if ((daemon->limit[LIMIT_WORK] - keycount) > (int)daemon->metrics[METRIC_WORK_HWM])
daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - keycount;
}
#endif
+1 -1
View File
@@ -165,7 +165,7 @@ static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
m[i] = (((WORD)data[j]) << 24) | (((WORD)data[j + 1]) << 16) | (((WORD)data[j + 2]) << 8) | (((WORD)data[j + 3]));
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -94,7 +94,7 @@ void inotify_dnsmasq_init()
if (daemon->inotifyfd == -1)
die(_("failed to create inotify: %s"), NULL, EC_MISC);
if (option_bool(OPT_NO_RESOLV))
if (daemon->port == 0 || option_bool(OPT_NO_RESOLV))
return;
for (res = daemon->resolv_files; res; res = res->next)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+36 -11
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -15,7 +15,6 @@
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
@@ -28,8 +27,7 @@ static int read_leases(time_t now, FILE *leasestream)
struct dhcp_lease *lease;
int clid_len, hw_len, hw_type;
int items;
char *domain = NULL;
*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
/* client-id max length is 255 which is 255*2 digits + 254 colons
@@ -69,8 +67,8 @@ static int read_leases(time_t now, FILE *leasestream)
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr4))
{
if ((lease = lease4_allocate(addr.addr4)))
domain = get_domain(lease->addr);
lease = lease4_allocate(addr.addr4);
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explicit MAC address type means ether. */
@@ -90,10 +88,7 @@ static int read_leases(time_t now, FILE *leasestream)
}
if ((lease = lease6_allocate(&addr.addr6, lease_type)))
{
lease_set_iaid(lease, strtoul(s, NULL, 10));
domain = get_domain6(&lease->addr6);
}
lease_set_iaid(lease, strtoul(s, NULL, 10));
}
#endif
else
@@ -114,7 +109,7 @@ static int read_leases(time_t now, FILE *leasestream)
hw_len, hw_type, clid_len, now, 0);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
lease_set_hostname(lease, daemon->dhcp_buff, 0, NULL, NULL);
ei = atol(daemon->dhcp_buff3);
@@ -946,6 +941,36 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL;
}
void lease_calc_fqdns(void)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
char *domain;
if (lease->hostname)
{
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
domain = get_domain6(&lease->addr6);
else
#endif
domain = get_domain(lease->addr);
if (domain)
{
/* This is called only during startup, before forking, hence safe_malloc() */
lease->fqdn = safe_malloc(strlen(lease->hostname) + strlen(domain) + 2);
strcpy(lease->fqdn, lease->hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, domain);
}
}
}
}
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
{
struct dhcp_lease *lease_tmp;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+5 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -24,6 +24,9 @@ const char * metric_names[] = {
"dns_local_answered",
"dns_stale_answered",
"dns_unanswered",
"dnssec_max_crypto_use",
"dnssec_max_sig_fail",
"dnssec_max_work",
"bootp",
"pxe",
"dhcp_ack",
@@ -39,6 +42,7 @@ const char * metric_names[] = {
"leases_pruned_4",
"leases_allocated_6",
"leases_pruned_6",
"tcp_connections",
};
const char* get_metric_name(int i) {
+5 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -23,6 +23,9 @@ enum {
METRIC_DNS_LOCAL_ANSWERED,
METRIC_DNS_STALE_ANSWERED,
METRIC_DNS_UNANSWERED_QUERY,
METRIC_CRYPTO_HWM,
METRIC_SIG_FAIL_HWM,
METRIC_WORK_HWM,
METRIC_BOOTP,
METRIC_PXE,
METRIC_DHCPACK,
@@ -38,6 +41,7 @@ enum {
METRIC_LEASES_PRUNED_4,
METRIC_LEASES_ALLOCATED_6,
METRIC_LEASES_PRUNED_6,
METRIC_TCP_CONNECTIONS,
__METRIC_MAX,
};
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+16 -7
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -929,15 +929,24 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
errno = errsave;
if (dienow)
/* Failure to bind addresses given by --listen-address at this point
because there's no interface with the address is OK if we're doing bind-dynamic.
If/when an interface is created with the relevant address we'll notice
and attempt to bind it then. This is in the generic error path so we close the socket,
but EADDRNOTAVAIL is only a possible error from bind()
When a new address is created and we call this code again (dienow == 0) there
may still be configured addresses when don't exist, (consider >1 --listen-address,
when the first is created, the second will still be missing) so we suppress
EADDRNOTAVAIL even in that case to avoid confusing log entries.
*/
if (!option_bool(OPT_CLEVERBIND) || errno != EADDRNOTAVAIL)
{
/* failure to bind addresses given by --listen-address at this point
is OK if we're doing bind-dynamic */
if (!option_bool(OPT_CLEVERBIND))
if (dienow)
die(s, daemon->addrbuff, EC_BADNET);
else
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
}
else
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
return -1;
}
+12 -6
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -43,7 +43,8 @@ int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags,
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;
char *err_str, *new, *nl;
const char *err;
static char *cmd_buf = NULL;
static size_t cmd_buf_sz = 0;
@@ -78,14 +79,19 @@ int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags,
}
ret = nft_run_cmd_from_buffer(ctx, cmd_buf);
err = (char *)nft_ctx_get_error_buffer(ctx);
err = 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);
if ((err_str = whine_malloc(strlen(err) + 1)))
{
strcpy(err_str, err);
if ((nl = strchr(err_str, '\n')))
*nl = 0;
my_syslog(LOG_ERR, "nftset %s %s", setname, err_str);
free(err_str);
}
}
return ret;
+78 -14
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -194,6 +194,8 @@ struct myoption {
#define LOPT_FILTER_RR 381
#define LOPT_NO_DHCP6 382
#define LOPT_NO_DHCP4 383
#define LOPT_MAX_PROCS 384
#define LOPT_DNSSEC_LIMITS 385
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -225,7 +227,7 @@ static const struct myoption opts[] =
{ "domain-suffix", 1, 0, 's' },
{ "interface", 1, 0, 'i' },
{ "listen-address", 1, 0, 'a' },
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
{ "local-service", 2, 0, LOPT_LOCAL_SERVICE },
{ "bogus-priv", 0, 0, 'b' },
{ "bogus-nxdomain", 1, 0, 'B' },
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
@@ -367,6 +369,7 @@ static const struct myoption opts[] =
{ "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
{ "dnssec-limits", 1, 0, LOPT_DNSSEC_LIMITS },
{ "dhcp-relay", 1, 0, LOPT_RELAY },
{ "ra-param", 1, 0, LOPT_RA_PARAM },
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
@@ -388,6 +391,7 @@ static const struct myoption opts[] =
{ "fast-dns-retry", 2, 0, LOPT_FAST_RETRY },
{ "use-stale-cache", 2, 0 , LOPT_STALE_CACHE },
{ "no-ident", 0, 0, LOPT_NO_IDENT },
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
{ NULL, 0, 0, 0 }
};
@@ -570,12 +574,13 @@ static struct {
{ LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
{ LOPT_DNSSEC_LIMITS, ARG_ONE, "<limit>,..", gettext_noop("Set resource limits for DNSSEC validation"), NULL },
{ LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
{ LOPT_LOG_DEBUG, OPT_LOG_DEBUG, NULL, gettext_noop("Log debugging information."), NULL },
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
{ LOPT_LOCAL_SERVICE, ARG_ONE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
@@ -589,6 +594,7 @@ static struct {
{ LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL },
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -1283,6 +1289,17 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
return NULL;
}
static void if_names_add(const char *ifname)
{
struct iname *new = opt_malloc(sizeof(struct iname));
new->next = daemon->if_names;
daemon->if_names = new;
/* new->name may be NULL if someone does
"interface=" to disable all interfaces except loop. */
new->name = opt_string_alloc(ifname);
new->flags = 0;
}
#ifdef HAVE_DHCP
static int is_tag_prefix(char *arg)
@@ -1412,7 +1429,6 @@ static void dhcp_opt_free(struct dhcp_opt *opt)
free(opt);
}
/* This is too insanely large to keep in-line in the switch */
static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{
@@ -2836,14 +2852,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'i': /* --interface */
do {
struct iname *new = opt_malloc(sizeof(struct iname));
comma = split(arg);
new->next = daemon->if_names;
daemon->if_names = new;
/* new->name may be NULL if someone does
"interface=" to disable all interfaces except loop. */
new->name = opt_string_alloc(arg);
new->flags = 0;
comma = split(arg);
if_names_add(arg);
arg = comma;
} while (arg);
break;
@@ -3409,6 +3419,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
else if (daemon->max_logs > 100)
daemon->max_logs = 100;
break;
case LOPT_LOCAL_SERVICE: /* --local-service */
if (!arg || !strcmp(arg, "net"))
set_option_bool(OPT_LOCAL_SERVICE);
else if (!strcmp(arg, "host"))
set_option_bool(OPT_LOCALHOST_SERVICE);
else
ret_err(gen_err);
break;
case 'P': /* --edns-packet-max */
@@ -5246,6 +5265,24 @@ err:
}
#ifdef HAVE_DNSSEC
case LOPT_DNSSEC_LIMITS:
{
int lim, val;
for (lim = LIMIT_SIG_FAIL; arg && lim < LIMIT_MAX ; lim++, arg = comma)
{
comma = split(arg);
if (!atoi_check(arg, &val))
ret_err(gen_err);
if (val != 0)
daemon->limit[lim] = val;
}
break;
}
case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
daemon->timestamp_file = opt_string_alloc(arg);
break;
@@ -5317,7 +5354,17 @@ err:
break;
}
#endif
case LOPT_MAX_PROCS: /* --max-tcp-connections */
{
int max_procs;
/* Don't accept numbers less than 1. */
if (!atoi_check(arg, &max_procs) || max_procs < 1)
ret_err(gen_err);
daemon->max_procs = max_procs;
break;
}
default:
ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
@@ -5822,6 +5869,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon = opt_malloc(sizeof(struct daemon));
memset(daemon, 0, sizeof(struct daemon));
daemon->namebuff = buff;
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
/* Set defaults - everything else is zero or NULL */
@@ -5845,6 +5893,13 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_expiry = SOA_EXPIRY;
daemon->randport_limit = 1;
daemon->host_index = SRC_AH;
daemon->max_procs = MAX_PROCS;
#ifdef HAVE_DNSSEC
daemon->limit[LIMIT_SIG_FAIL] = DNSSEC_LIMIT_SIG_FAIL;
daemon->limit[LIMIT_CRYPTO] = DNSSEC_LIMIT_CRYPTO;
daemon->limit[LIMIT_WORK] = DNSSEC_LIMIT_WORK;
daemon->limit[LIMIT_NSEC3_ITERS] = DNSSEC_LIMIT_NSEC3_ITERS;
#endif
/* See comment above make_servers(). Optimises server-read code. */
mark_servers(0);
@@ -6148,7 +6203,16 @@ void read_opts(int argc, char **argv, char *compile_opts)
/* If there's access-control config, then ignore --local-service, it's intended
as a system default to keep otherwise unconfigured installations safe. */
if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
reset_option_bool(OPT_LOCAL_SERVICE);
{
reset_option_bool(OPT_LOCAL_SERVICE);
reset_option_bool(OPT_LOCALHOST_SERVICE);
}
else if (option_bool(OPT_LOCALHOST_SERVICE) && !option_bool(OPT_LOCAL_SERVICE))
{
/* listen only on localhost, emulate --interface=lo --bind-interfaces */
if_names_add(NULL);
set_option_bool(OPT_NOWILD);
}
if (testmode)
{
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+858 -733
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+9 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -213,6 +213,14 @@ size_t rrfilter(struct dns_header *header, size_t *plen, int mode)
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
continue;
}
else if (qtype == T_ANY && rr_on_list(daemon->filter_rr, T_ANY))
{
/* Filter replies to ANY queries in the spirit of
RFC RFC 8482 para 4.3 */
if (class != C_IN ||
type == T_A || type == T_AAAA || type == T_MX || type == T_CNAME)
continue;
}
else
{
/* Only looking at answer section now. */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+6 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -585,8 +585,13 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *c
void check_tftp_listeners(time_t now)
{
struct listener *listener;
struct tftp_transfer *transfer, *tmp, **up;
for (listener = daemon->listeners; listener; listener = listener->next)
if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
tftp_request(listener, now);
/* In single port mode, all packets come via port 69 and tftp_request() */
if (!option_bool(OPT_SINGLE_PORT))
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2023 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2024 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
@@ -119,7 +119,7 @@ int rr_on_list(struct rrlist *list, unsigned short rr)
{
while (list)
{
if (list->rr == rr || list->rr == T_ANY)
if (list->rr == rr)
return 1;
list = list->next;
+17
View File
@@ -2426,6 +2426,17 @@ static void FTL_dnssec(const char *arg, const union all_addr *addr, const int id
else
log_warn("Unknown DNSSEC status \"%s\"", arg);
// Set reply to NONE (if not already set) as we will not reply to this
// query when the status is neither SECURE nor INSECURE
if (query->reply == REPLY_UNKNOWN &&
query->dnssec != DNSSEC_SECURE &&
query->dnssec != DNSSEC_INSECURE)
{
struct timeval response;
gettimeofday(&response, 0);
query_set_reply(0, REPLY_NONE, addr, query, response);
}
// Mark query for updating in the database
query->flags.database.changed = true;
@@ -3489,3 +3500,9 @@ static const char *check_dnsmasq_name(const char *name)
// else
return name;
}
void get_dnsmasq_metrics_obj(cJSON *json)
{
for (unsigned int i = 0; i < __METRIC_MAX; i++)
cJSON_AddNumberToObject(json, get_metric_name(i), daemon->metrics[i]);
}
+4
View File
@@ -10,6 +10,8 @@
#ifndef METRICS_H
#define METRICS_H
#include "webserver/cJSON/cJSON.h"
// defined in src/dnsmasq/cache.c
const char *rrtype_name(unsigned short type);
@@ -88,4 +90,6 @@ struct metrics
void get_dnsmasq_metrics(struct metrics *ci);
void get_dnsmasq_metrics_obj(cJSON *json);
#endif // METRICS_H
+14 -2
View File
@@ -78,6 +78,8 @@ src/dnsmasq/dnsmasq.c
my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
src/dnsmasq/dnsmasq.c
my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
src/dnsmasq/dnssec.c
my_syslog(LOG_WARNING, "limit exceeded: %s", message ? message : _("per-query crypto work"));
src/dnsmasq/dnssec.c
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
src/dnsmasq/forward.c
@@ -85,11 +87,21 @@ src/dnsmasq/forward.c
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
daemon->namebuff[0] ? daemon->namebuff : ".");
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s (logged only once)"), daemon->addrbuff);
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
daemon->namebuff[0] ? daemon->namebuff : ".");
src/dnsmasq/forward.c
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
src/dnsmasq/forward.c
@@ -108,7 +120,7 @@ src/dnsmasq/lease.c
src/dnsmasq/log.c
my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
src/dnsmasq/network.c
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
src/dnsmasq/network.c
my_syslog(LOG_WARNING,
_("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
+3
View File
@@ -114,6 +114,9 @@ pdnsutil add-record ftl. regex-multiple AAAA fe80::3f41
pdnsutil add-record ftl. regex-notMultiple A 192.168.3.12
pdnsutil add-record ftl. regex-notMultiple AAAA fe80::3f41
# TXT
pdnsutil add-record ftl. any TXT "\"Some example text\""
# Create reverse lookup zone
pdnsutil create-zone arpa ns1.ftl
pdnsutil add-record arpa. 1.1.168.192.in-addr PTR ftl.
+16
View File
@@ -311,6 +311,8 @@
printf "%s\n" "${lines[@]}"
[[ ${lines[@]} == *"192.168.3.1"* ]]
[[ ${lines[@]} == *"fe80::3c01"* ]]
# TXT records should not be returned due to filter-rr=ANY
[[ ${lines[@]} != *"Some example text"* ]]
}
@test "Local DNS test: CNAME cname-ok.ftl" {
@@ -1442,6 +1444,20 @@
[[ ${lines[@]} == *"block"* ]]
}
@test "API: No UNKNOWN reply in API" {
run bash -c 'curl -s 127.0.0.1/api/queries?reply=UNKNOWN | jq .queries'
printf "%s\n" "${lines[@]}"
run bash -c 'curl -s 127.0.0.1/api/queries?reply=UNKNOWN | jq ".queries | length"'
[[ ${lines[0]} == "0" ]]
}
@test "API: No UNKNOWN status in API" {
run bash -c 'curl -s 127.0.0.1/api/queries?status=UNKNOWN | jq .queries'
printf "%s\n" "${lines[@]}"
run bash -c 'curl -s 127.0.0.1/api/queries?status=UNKNOWN | jq ".queries | length"'
[[ ${lines[0]} == "0" ]]
}
@test "API authorization (without password): No login required" {
run bash -c 'curl -s 127.0.0.1/api/auth'
printf "%s\n" "${lines[@]}"