Re: [Dnsmasq-discuss] Does the --interface option to dnsmasq also apply to incoming broadcast DHCP requests?

2023-11-30 Thread Buck Horn via Dnsmasq-discuss


On 30.11.23 00:09, Chris Friesen via Dnsmasq-discuss wrote:

I was just wondering whether the --interface and --except-interface
options to dnsmasq would also apply to messages like DHCPDISCOVER and
DHCPREQUEST


Yes.

You may also want to further tune usage via '--no-dhcp-interface' (or
maybe '--no-dhcpv4-interface' and '--no-dhcpv6-interface' in a future
release, see
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/msg16828.html
).

However, I wonder whether tagging requests for the interfaces and
setting up corresponding dhcp options for those tags wouldn't already
match your requirements with only one instance of dnsmasq running.

Kind regards,
    Buck


___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss


Re: [Dnsmasq-discuss] Does the --interface option to dnsmasq also apply to incoming broadcast DHCP requests?

2023-11-30 Thread Simon Kelley



On 29/11/2023 23:09, Chris Friesen via Dnsmasq-discuss wrote:

Hi,

I was just wondering whether the --interface and --except-interface 
options to dnsmasq would also apply to messages like DHCPDISCOVER and 
DHCPREQUEST which are broadcast to 255.255.255.255.


In my particular case I have an existing dnsmasq instance that is 
running, and I want to add a second dnsmasq instance to handle DHCP 
requests coming from a specific subset of interfaces.   I don't want the 
primary dnsmasq instance to see the requests coming in on those 
interfaces, and I don't want the second dnsmasq instance to see requests 
coming in on the other interfaces.


As a concrete example, suppose I have network interfaces eth0/eth1/eth2 
and I have instance A of dnsmasq which is run as "dnsmasq 
--except-interface eth2", and instance B of dnsmasq which is run as 
"dnsmasq --interface eth2 --except-interface lo".


If a broadcast DHCPDISCOVER or DHCPREQUEST comes in on eth0/eth1 which 
dnsmasq instance(s) will see it?


If a broadcast DHCPDISCOVER or DHCPREQUEST comes in on eth2 which 
dnsmasq instance(s) will see it?


If a broadcast DHCPDISCOVER or DHCPREQUEST is emitted by an entity on 
the local host which dnsmasq instance(s) will see it?


Thanks,

Chris Friesen



As you've surmised, making more than one dnsmasq/DHCP instance on a 
server work is tricky.


It can be done, but only in a very specific way.

Each dnsmasq instance must be configured to serve exactly one interface, 
using the --interface config option.


Under these circumstances, dnsmasq will log

DHCP, sockets bound exclusively to interface 

at startup.

Your example will not work, because your instance A is binding to more 
than one interface. To fix this you need to start separate dnsmasq 
instances for eth0 and eth1, or you need to bridge eth0 and eth1 to 
single bridge interface and configure dnsmasq to listen on that.



The reason behind this is that the dnsmasq DHCP subsystem uses one 
socket, which listens on the wildcard address (so that broadcasts to 
255.255.255.255 arrive, amongst other reasons.) In the "exactly one 
interface" state, dnsmasq can also bind that socket to a physical 
interface, using the SO_BINDTODEVICE socket option, which allows  the 
multiple-server setup to work. SO_BINDTODEVICE only allows one device, 
hence the one interface limitation.



Cheers,

Simon.

___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss


Re: [Dnsmasq-discuss] Does the --interface option to dnsmasq also apply to incoming broadcast DHCP requests?

2023-11-30 Thread Chris Friesen via Dnsmasq-discuss

On 11/30/2023 6:13 AM, Simon Kelley wrote:

As you've surmised, making more than one dnsmasq/DHCP instance on a
server work is tricky.

It can be done, but only in a very specific way.

Each dnsmasq instance must be configured to serve exactly one interface,
using the --interface config option.


Perfect, thanks.

Chris


___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss


Re: [Dnsmasq-discuss] [PATCH] Add number of forks for TCP to metrics and dump

2023-11-30 Thread Simon Kelley



Looks good. Patch applied.


Cheers,

Simon.

On 24/11/2023 11:13, Damian Sawicki via Dnsmasq-discuss wrote:

Hello dnsmasq experts,

Following up on the recent addition of the flag --max-tcp-connections, I'd like 
to propose a patch with monitoring of the number of TCP connections. This way, 
a user can actually estimate their usage and adjust --max-tcp-connections 
accordingly to prevent overload.

The patch adds the relevant information to the metrics and to the output of 
dump_cache() (which is called when dnsmasq receives SIGUSR1). Hence, users not 
collecting metrics will still be able to troubleshoot with SIGUSR1. In addition 
to the current usage, dump_cache() contains the information on the highest 
usage since it was last called.

Please kindly let me know what you think.

Best regards,

Damian Sawicki

*

Add to the metrics and dump_cache() the info on the utilisation of
the limit on concurrent TCP connections (the variable
daemon->max_procs, customisable via  --max-tcp-connections).
---
  man/dnsmasq.8 |  2 +-
  src/cache.c   |  5 +
  src/dnsmasq.c | 11 ++-
  src/dnsmasq.h |  1 +
  src/metrics.c |  1 +
  src/metrics.h |  1 +
  src/option.c  |  1 +
  7 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 6d37360..1b5ebda 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -2303,7 +2303,7 @@ they expired in order to make room for new names and the 
total number
  of names that have been inserted into the cache. The number of cache hits and
  misses and the number of authoritative queries answered are also given. For 
each upstream
  server it gives the number of queries sent, and the number which
-resulted in an error. In
+resulted in an error. It also gives information on the number of forks for TCP 
connections. In
  .B --no-daemon
  mode or when full logging is enabled (\fB--log-queries\fP), a complete dump 
of the
  contents of the cache is made.
diff --git a/src/cache.c b/src/cache.c
index 5342ce2..b95e3c7 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1895,6 +1895,11 @@ void dump_cache(time_t now)
  #endif
  
blockdata_report();

+  my_syslog(LOG_INFO, _("child processes for TCP requests: in use %zu, highest 
since last SIGUSR1 %zu, max %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)
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 65ba334..39aaf19 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1534,7 +1534,11 @@ static void async_event(int pipe, time_t now)
  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;
+  if (daemon->tcp_pipes[i] == -1)
+daemon->metrics[METRIC_TCP_CONNECTIONS]--;
+}
break;

  #if defined(HAVE_SCRIPT)  
@@ -1844,6 +1848,8 @@ static void check_dns_listeners(time_t now)
{
  close(daemon->tcp_pipes[i]);
  daemon->tcp_pipes[i] = -1; 
+if (daemon->tcp_pids[i] == 0)
+  daemon->metrics[METRIC_TCP_CONNECTIONS]--;
}

for (listener = daemon->listeners; listener; listener = listener->next)
@@ -1972,6 +1978,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);
  
diff --git a/src/dnsmasq.h b/src/dnsmasq.h

index 67c083b..3d85b73 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1314,6 +1314,7 @@ extern struct daemon {
int dumpfd;
  #endif
int max_procs;
+  uint max_procs_used;
  } *daemon;
  
  struct server_details {

diff --git a/src/metrics.c b/src/metrics.c
index 050ccb3..1a9a4d3 100644
--- a/src/metrics.c
+++ b/src/metrics.c
@@ -39,6 +39,7 @@ const char * metric_names[] = {
  "leases_pruned_4",
  "leases_allocated_6",
  "leases_pruned_6",
+"tcp_connections",
  };
  
  const char* get_metric_name(int i) {

diff --git a/src/metrics.h b/src/metrics.h
index 22e9e48..e1cdd87 100644
--- a/src/metrics.h
+++ b/src/metrics.h
@@ -38,6 +38,7 @@ enum {
METRIC_LEASES_PRUNED_4,
METRIC_LEASES_ALLOCATED_6,
METRIC_LEASES_PRUNED_6,
+  METRIC_TCP_CONNECTIONS,

__METRIC_MAX,

  };
diff --git a/src/option.c b/src/option.c
index 9423582..3eeda18 100644
--- a/src/option.c
+++ b/src/option.c
@@ -5855,6 +5855,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->randport_limit = 

[Dnsmasq-discuss] [PATCH] Introduce local-service=host specialization

2023-11-30 Thread Petr Menšík

Hello!

I have sent similar proposal already in year 2021 [1]. But I have 
reworked that a bit to reuse existing --local-service option and just 
add new parameter to it. If --local-service=host is used, dnsmasq will 
bind to addresses on lo interface only. It will not even open port on 
other interfaces, preventing possible scanning of running service from 
outside.


It roughly becomes similar default like other resolvers without 
configuration use. BIND9 or unbound will listen also on localhost only.


To avoid regressions, it still becomes inactive when any --interface, 
--listen-address or similar is specified at least once. Then you have to 
explicitly use --interface=lo to listen *also* on localhost.


The change is related to Fedora bug #1852373 [2], also newly re-opened 
CVE-2020-14312 issue for RHEL8 [3]. Having explicitly specified 
bind-interfaces & interface=lo in dnsmasq default configuration has 
resulted in multiple regressions across different packages, which did 
not rewrite distribution provided configuration. I think it could be 
useful also for others.


What do you think?

Looking for any feedback!

Regards,
Petr

1. 
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q4/015749.html

2. https://bugzilla.redhat.com/show_bug.cgi?id=1852373
3. https://issues.redhat.com/browse/RHEL-9516

--
Petr Menšík
Software Engineer, RHEL
Red Hat, https://www.redhat.com/
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB

From fa6c187cb12d275b6cffc0d7659ed6dd9ae06b1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= 
Date: Tue, 5 Oct 2021 13:46:51 +0200
Subject: [PATCH] Introduce new --local-service=host parameter
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Similar to local-service, but more strict. Listen only on localhost
unless other interface is specified. Has no effect when interface is
provided explicitly. I had multiple bugs fillen on Fedora, because I have
changed default configuration to:

interface=lo
bind-interfaces

People just adding configuration parts to /etc/dnsmasq.d or appending to
existing configuration often fail to see some defaults are already there.
Give them auto-ignored configuration as smart default.

Signed-off-by: Petr Menšík 

Do not add a new parameter on command line. Instead add just parameter
for behaviour modification of existing local-service option. Now it
accepts two optional values:
- net: exactly the same as before
- host: bind only to lo interface, do not listen on any other addresses
  than loopback.
---
 man/dnsmasq.8 |  8 +---
 src/dnsmasq.c |  2 ++
 src/dnsmasq.h |  3 ++-
 src/option.c  | 44 +---
 4 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 6d37360..0f0f0c8 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -270,14 +270,16 @@ the address dnsmasq is listening on. When an interface is specified,
 it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
 addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the primary external nameserver.
 .TP
-.B --local-service
+.B --local-service[=net|host]
+Without parameter or with net parameter, restricts service to connected network.
 Accept DNS queries only from hosts whose address is on a local subnet,
-ie a subnet for which an interface exists on the server. This option
+ie a subnet for which an interface exists on the server. With host parameter, listens
+only on lo interface and accepts queries from localhost only. This option
 only has effect if there are no \fB--interface\fP, \fB--except-interface\fP,
 \fB--listen-address\fP or \fB--auth-server\fP options. It is intended to be set as
 a default on installation, to allow unconfigured installations to be
 useful but also safe from being used for DNS amplification attacks.
-.TP 
+.TP
 .B \-2, --no-dhcp-interface=
 Do not provide DHCP, TFTP or router advertisement on the specified interface, but do provide DNS service.
 .TP
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 65ba334..83174cf 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -861,6 +861,8 @@ int main (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);
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 67c083b..d6985b6 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -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_LOC

Re: [Dnsmasq-discuss] Does the --interface option to dnsmasq also apply to incoming broadcast DHCP requests?

2023-11-30 Thread Chris Friesen via Dnsmasq-discuss

On 11/30/2023 6:13 AM, Simon Kelley wrote:

As you've surmised, making more than one dnsmasq/DHCP instance on a
server work is tricky.

It can be done, but only in a very specific way.

Each dnsmasq instance must be configured to serve exactly one interface,
using the --interface config option.

Under these circumstances, dnsmasq will log

DHCP, sockets bound exclusively to interface 

at startup.

Your example will not work, because your instance A is binding to more
than one interface. To fix this you need to start separate dnsmasq
instances for eth0 and eth1, or you need to bridge eth0 and eth1 to
single bridge interface and configure dnsmasq to listen on that.


The reason behind this is that the dnsmasq DHCP subsystem uses one
socket, which listens on the wildcard address (so that broadcasts to
255.255.255.255 arrive, amongst other reasons.) In the "exactly one
interface" state, dnsmasq can also bind that socket to a physical
interface, using the SO_BINDTODEVICE socket option, which allows the
multiple-server setup to work. SO_BINDTODEVICE only allows one device,
hence the one interface limitation. 


I performed some practical tests in case anyone is interested. I created 
one dnsmasq instance with:


interface=enp0s8
interface=enp0s10
bind-interfaces
listen-address=192.168.204.1

and another with

interface=enp0s9
bind-interfaces
except-interface=lo

Both instances were able to start up without any issues, presumably 
because of SO_REUSEADDR /SO_REUSEPORT being used on the socket.


NOTE: If I don't specify "bind-interfaces" in the second case, then it 
errors out with "failed to bind DHCP server socket: Address already in use".


From another host I then ran "dhclient -d enp0s9" to emit a broadcast 
packet, or "dhclient  -d enp0s9 -s " to emit a unicast packet.


If the incoming DHCP packets on enp0s9 are broadcast packets, everything 
is fine because both instances of dnsmasq receive the packet (due to 
SO_REUSEADDR /SO_REUSEPORT).  The first instance just ignores it, the 
second instance replies to it.


If the incoming DHCP packets on enp0s9 are unicast packets (like a 
DHCPREQUEST to the IP address of enp0s9), it's non-deterministic which 
instance of dnsmasq receives the packet.  If it's the first, the packet 
is ignored and the client gets no response.  If it's the second, it 
works as expected.


Following the instructions above to ensure that each instance binds to a 
single interface with SO_BINDTODEVICE would avoid the issue with the 
unicast packets by ensuring that all the incoming packets are processed 
by the dnsmasq instance which actually cares about them.


Chris Friesen


___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss