[lxc-devel] [lxd/master] Use DHCP Release to remove dnsmasq leases to avoid restarting dnsmasq
tomponline on Github
lxc-bot at linuxcontainers.org
Mon Jun 17 14:12:25 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 570 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190617/baa0da0f/attachment.bin>
-------------- next part --------------
From d2eb90a1ee8973ce80d5d3935884909e1737feda Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 17 Jun 2019 15:08:16 +0100
Subject: [PATCH 1/3] container/lxc: Adds error checking for calls to
networkClearLease
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/container_lxc.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f5cad36e9e..ec4c845803 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -4103,7 +4103,10 @@ func (c *containerLXC) Delete() error {
continue
}
- networkClearLease(c.state, c.name, m["parent"], m["hwaddr"])
+ err = networkClearLease(c.state, c.name, m["parent"], m["hwaddr"])
+ if err != nil {
+ logger.Error("Failed to delete DHCP lease", log.Ctx{"name": c.Name(), "err": err, "device": k, "hwaddr": m["hwaddr"]})
+ }
}
}
From 2915a2fb22d9d21ffcf258e05adfee794c282032 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 17 Jun 2019 15:09:11 +0100
Subject: [PATCH 2/3] networks/utils: Adds networkDHCPRelease function
This function sends a manually crafted DHCP release packet to the local dnsmasq server to remove the lease.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks_utils.go | 56 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 7fd48a5caa..5f9ef034cb 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -20,6 +20,8 @@ import (
"sync"
"time"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
@@ -1443,3 +1445,57 @@ func networkApplyBootRoutesV6(devName string, routes []string) error {
return nil
}
+
+// networkDHCPRelease sends a DHCP release packet to a DHCP server
+func networkDHCPRelease(srcMAC net.HardwareAddr, srcIP net.IP, dstIP net.IP) error {
+ dstAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:67", dstIP.String()))
+ if err != nil {
+ return err
+ }
+ conn, err := net.DialUDP("udp", nil, dstAddr)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ //Random DHCP transaction ID
+ xid := rand.Uint32()
+
+ // Construct a DHCP packet pretending to be from the source IP and MAC supplied.
+ dhcp := layers.DHCPv4{
+ Operation: layers.DHCPOpRequest,
+ HardwareType: layers.LinkTypeEthernet,
+ ClientHWAddr: srcMAC,
+ ClientIP: srcIP,
+ Xid: xid,
+ }
+
+ // addOption function is used to append DHCP options.
+ addOption := func(optType layers.DHCPOpt, data []byte) {
+ dhcp.Options = append(dhcp.Options, layers.DHCPOption{
+ Type: optType,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+ return
+ }
+
+ // Add two options, one definging the message type (release), and one targetting the DHCP
+ // server ID that originally allocated the lease (so it responds to our packet).
+ addOption(layers.DHCPOptMessageType, []byte{byte(layers.DHCPMsgTypeRelease)})
+ addOption(layers.DHCPOptServerID, dstIP.To4())
+
+ buf := gopacket.NewSerializeBuffer()
+ opts := gopacket.SerializeOptions{
+ ComputeChecksums: true,
+ FixLengths: true,
+ }
+
+ err = gopacket.SerializeLayers(buf, opts, &dhcp)
+ if err != nil {
+ return err
+ }
+
+ _, err = conn.Write(buf.Bytes())
+ return err
+}
From ae573b1fe313a1dbb28f713f0895f53e3185d80f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 17 Jun 2019 15:10:02 +0100
Subject: [PATCH 3/3] networks/utils: Updates networkClearLease to use
networkDHCPRelease
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks_utils.go | 75 ++++++++++++++++++-------------------------
1 file changed, 32 insertions(+), 43 deletions(-)
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 5f9ef034cb..6bc9cc2420 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -1180,65 +1180,54 @@ func networkClearLease(s *state.State, name string, network string, hwaddr strin
return nil
}
- // Restart the network when we're done here
- n, err := networkLoadByName(s, network)
+ iface, err := net.InterfaceByName(network)
if err != nil {
return err
}
- defer func() {
- err := n.Start()
- if err != nil {
- logger.Errorf("Failed to reload network '%s': %v", network, err)
- }
- }()
- // Stop dnsmasq
- err = networkKillDnsmasq(network, false)
- if err != nil {
- return err
+ // Use first IPv4 address on network interface as destination IP to dnsmasq.
+ addrs, err := iface.Addrs()
+ var dstIP net.IP
+ if err == nil {
+ for _, addr := range addrs {
+ ip, _, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ return err
+ }
+ if ip.To4() != nil {
+ dstIP = ip
+ break
+ }
+ }
}
- // Mangle the lease file
- leases, err := ioutil.ReadFile(leaseFile)
- if err != nil {
- return err
+ if dstIP == nil {
+ return fmt.Errorf("No IPv4 addresses found on interface %s", iface.Name)
}
- fd, err := os.Create(leaseFile)
+ // Get the IP allocated to MAC address.
+ file, err := os.Open(leaseFile)
if err != nil {
return err
}
+ defer file.Close()
- knownMac := networkGetMacSlice(hwaddr)
- for _, lease := range strings.Split(string(leases), "\n") {
- if lease == "" {
- continue
- }
-
- fields := strings.Fields(lease)
- if len(fields) > 2 {
- if strings.Contains(fields[1], ":") {
- leaseMac := networkGetMacSlice(fields[1])
- leaseMacStr := strings.Join(leaseMac, ":")
-
- knownMacStr := strings.Join(knownMac[len(knownMac)-len(leaseMac):], ":")
- if knownMacStr == leaseMacStr {
- continue
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ fields := strings.Fields(scanner.Text())
+ if len(fields) >= 5 {
+ if hwaddr == fields[1] {
+ srcMac, err := net.ParseMAC(hwaddr)
+ if err != nil {
+ return err
}
- } else if len(fields) > 3 && fields[3] == name {
- // Mostly IPv6 leases which don't contain a MAC address...
- continue
- }
- }
- _, err := fd.WriteString(fmt.Sprintf("%s\n", lease))
- if err != nil {
- return err
+ srcIP := net.ParseIP(fields[2])
+ return networkDHCPRelease(srcMac, srcIP, dstIP)
+ }
}
}
-
- err = fd.Close()
- if err != nil {
+ if err := scanner.Err(); err != nil {
return err
}
More information about the lxc-devel
mailing list