Re: [Dnsmasq-discuss] DHCP from dnsmasq in docker container

2018-12-17 Thread Geert Stappers
On Sun, Dec 16, 2018 at 09:19:16PM -0500, Craig Younkins wrote:
> On Sun, Dec 16, 2018 at 5:15 PM Simon Kelley wrote:
> > On 13/12/2018 14:10, Craig Younkins wrote:
> > > First, thank you for dnsmasq!
> > >
> > > I'm among a number of people having trouble using dnsmasq
> > > for DHCP when it is running in a docker container. Everyone seems to get
> > > "no address range available for DHCP request via eth0" in their log
> > > unless they change to host networking mode.
> > >
> > > The code path for that error message is at [5]. I'm having a little
> > > trouble understanding the 'contexts', but I think the problem is that
> > > the container is running in bridged networking mode, and thus the
> > > interface has an IP address outside the netmask range.
> > >
> > > Is there a way to make this work without using host networking? Maybe
> > > adding the external IP to the container interface? Thank you for any
> > > suggestions!
> > >
> >
> >
> > I'm not familiar with these docker "networking modes", can you explain
> > what they mean?
> >
> >
> > What's happening here is quite straightforward to understand.  A DHCP
> > request arrives at an interface which has the IP address 172.17.0.2 and
> > netmask 172.17.255.255. Dnsmasq tries to find a dhcp-range from which is
> > can allocate an address by looking for a DHCP range which covers the
> > same network. Since the only available DHCP range is
> > 192.168.1.200,192.168.1.251 and that's not the same network, this fails.
> >
> >
> > Depending on exactly how docker is set up, something equivalent to the
> > ISC dhcpd's "shared-network" configuration might be the way to go. This
> > is a useful facility which I've considered adding before, essentially,
> > is allows you to tell dnsmasq that (in this case) 172.17.0.0/16 and
> > 192.168.1.0/24 are both on the same network segment or broadcast domain.
> > That would allow dnsmasq to deduce that the request which comes from the
> > 172.17.0.0/16 segment can be satisfied by a 192.168.1.0/24 address.
> >
> > Note that there are other requirements needed to make this work.
> > Notably, a DHCP client that gets a 192.168.1.0/24 address has to have
> > suitable routing to allow it to route packets to 172.17.0.2, and the
> > reverse route is also needed.
> >
> > To be clear: shared-network doesn't exist in released versions of
> > dnsmasq, I'm proposing new code.
> >
> >
>
>
> Thank you Simon for the explanation, that makes sense.
> 
> I did try manually adding the LAN IP to the interface visible from within
> the container via "ip address add 192.168.1.2/24 dev eth0". That eliminates
> the error message, and so I assume an offer was made, but the offer was not
> received by the requesting LAN device. I believe the bridged networking
> mode caused the kernel to drop the packet somewhere.
> 
> An overview of the docker networking modes can be found at [1], and a
> better view of the details of bridged networking can be found at [2]. In
> docker it's most common to use the default bridged network, and using host
> networking is considered poor practice because the lack of isolation.
> Looking at the list again, the newer macvlan networking driver may be the
> best bet for this situation.

A test with docker "macvlan networking" learn me that the docker macvlan
is not plain macvlan from Linux kernel[6]. Largest difference is that
dockerd does DHCP server for its container. Some beware when doing
DHCP server inside container connect with "macvlan". I do now understand
better why  pihole docker recommends "host networking".


> What I should have asked in my original message was "Is there a way to
> override this check?" I think manually adding the IP to the interface as
> above accomplishes the same thing, meaning I got dnsmasq to send the offer.
> Still there is something wrong, but I think the problematic behavior lies
> in the details of docker bridged networking mode rather than dnsmasq. I
> can't ask for anything more from the dnsmasq community, thank you!

Please report your milage.


> [1] https://docs.docker.com/network/
> [2] 
> https://github.com/docker/labs/blob/master/networking/concepts/05-bridge-networks.md
> [5] 
> http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=blob;f=src/rfc2131.c;h=56dc3d103741baeb68a730f0ce15a10338a2f885;hb=91421cb7575df7bb211dacc30dc7c7c715c38299#l345
> 
[6] https://en.wikipedia.org/wiki/TUN/TAP#External_links go to 
http://www.pocketnix.org/posts/Linux%20Networking:%20MAC%20VLANs%20and%20Virtual%20Ethernets


Groeten
Geert Stappers
-- 
Leven en laten leven

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


[Dnsmasq-discuss] [PATCH] DHCPv6: Honor assigning IPv6 address based on MAC address

2018-12-17 Thread Pali Rohár
Currently IPv6 addresses are assigned to tuple (IAID, DUID). When system
changes IAID/DUID then old assigned IPv6 address cannot be reused, even
when in config file was DHCPv6 assignment based on MAC address (and not on
DUID).

IAID/DUID is changed when rebooting from one operating system to another;
or after reinstalling system. In reality it is normal that DUID of some
machine is changed, so people rather assign also IPv6 addresses based on
MAC address.

So assigning IPv6 based on MAC address in dnsmasq is currently semi-broken.

This patch tries to fix it and honors IPv6 config rules with MAC address,
to always assign particular IPv6 address to specific MAC address (when
configured). And ignores the fact if IAID/DUID was changed.

Normally IPv6 address should be assigned by IAID/DUID (which also state
DHCPv6 RFCs), but dnsmasq has already some support for assigning IPv6
address based on MAC address, when users configured in config file.

So this patch just tries to fix above problem for user configuration with
MAC addresses. It does not change assignment based on DUID.

Also this patch adds support for allowing IPv6 address to be associated
with multiple hardware addresses, and gives dnsmasq permission to abandon a
lease. This is similar functionality as already supported for IPv4 address.
---
 man/dnsmasq.8 |  9 ++---
 src/rfc3315.c | 62 ++-
 2 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index f01a5ba..8614f08 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1068,10 +1068,13 @@ will only match a
 Token-Ring hardware address, since the ARP-address type for token ring
 is 6. 
 
-As a special case, in DHCPv4, it is possible to include more than one
-hardware address. eg:
+It is possible to include more than one hardware address. eg for IPv4:
 .B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
-This allows an IP address to be associated with
+or for IPv6:
+.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,[::2]
+or for both:
+.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2,[::2]
+This allows an IPv4 and/or IPv6 address to be associated with
 multiple hardware addresses, and gives dnsmasq permission to abandon a
 DHCP lease to one of the hardware addresses when another one asks for
 a lease. Beware that this is a dangerous thing to do, it will only
diff --git a/src/rfc3315.c b/src/rfc3315.c
index a20776d..c83cf2d 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -54,7 +54,7 @@ static struct prefix_class *prefix_class_from_context(struct 
dhcp_context *conte
 #endif
 static void mark_context_used(struct state *state, struct in6_addr *addr);
 static void mark_config_used(struct dhcp_context *context, struct in6_addr 
*addr);
-static int check_address(struct state *state, struct in6_addr *addr);
+static int check_address(struct state *state, struct dhcp_config *config, 
struct in6_addr *addr);
 static void add_address(struct state *state, struct dhcp_context *context, 
unsigned int lease_time, void *ia_option, 
unsigned int *min_time, struct in6_addr *addr, time_t 
now);
 static void update_leases(struct state *state, struct dhcp_context *context, 
struct in6_addr *addr, unsigned int lease_time, time_t now);
@@ -746,7 +746,7 @@ static int dhcp6_no_relay(struct state *state, int 
msg_type, void *inbuff, size_
/* If the client asks for an address on the same network as 
a configured address, 
   offer the configured address instead, to make moving to 
newly-configured
   addresses automatic. */
-   if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, 
c, &addr) && check_address(state, &addr))
+   if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, 
c, &addr) && check_address(state, config, &addr))
  {
req_addr = addr;
mark_config_used(c, &addr);
@@ -755,8 +755,14 @@ static int dhcp6_no_relay(struct state *state, int 
msg_type, void *inbuff, size_
  }
else if (!(c = address6_available(state->context, 
&req_addr, solicit_tags, plain_range)))
  continue; /* not an address we're allowed */
-   else if (!check_address(state, &req_addr))
+   else if (!check_address(state, config, &req_addr))
  continue; /* address leased elsewhere */
+   else if (state->mac_len && config &&
+config_has_mac(config, state->mac, state->mac_len, 
state->mac_type) &&
+match_netid(c->filter, solicit_tags, plain_range) 
&&
+config_valid(config, c, &addr) &&
+!IN6_ARE_ADDR_EQUAL(&req_addr, &addr))
+ continue; /* another static address is configured */