Browse Source

Add domain search list plugin (#116)

Add searchdomains plugin to specify a list of default
search domains for DHCPv4 and DHCPv6 clients.

Signed-off-by: William Rory Kronmiller <wkronmiller@Williams-MacBook-Pro.local>
William Kronmiller 5 năm trước cách đây
mục cha
commit
9e42cc2ca0

+ 1 - 0
cmds/coredhcp-generator/core-plugins.txt

@@ -7,3 +7,4 @@ github.com/coredhcp/coredhcp/plugins/prefix
 github.com/coredhcp/coredhcp/plugins/range
 github.com/coredhcp/coredhcp/plugins/router
 github.com/coredhcp/coredhcp/plugins/serverid
+github.com/coredhcp/coredhcp/plugins/searchdomains

+ 2 - 0
cmds/coredhcp/main.go

@@ -27,6 +27,7 @@ import (
 	pl_prefix "github.com/coredhcp/coredhcp/plugins/prefix"
 	pl_range "github.com/coredhcp/coredhcp/plugins/range"
 	pl_router "github.com/coredhcp/coredhcp/plugins/router"
+	pl_searchdomains "github.com/coredhcp/coredhcp/plugins/searchdomains"
 	pl_serverid "github.com/coredhcp/coredhcp/plugins/serverid"
 
 	"github.com/sirupsen/logrus"
@@ -66,6 +67,7 @@ var desiredPlugins = []*plugins.Plugin{
 	&pl_prefix.Plugin,
 	&pl_range.Plugin,
 	&pl_router.Plugin,
+	&pl_searchdomains.Plugin,
 	&pl_serverid.Plugin,
 }
 

+ 1 - 0
go.mod

@@ -15,6 +15,7 @@ require (
 	github.com/sirupsen/logrus v1.6.0
 	github.com/spf13/cast v1.3.1
 	github.com/spf13/viper v1.7.0
+	github.com/stretchr/testify v1.3.0
 	github.com/u-root/u-root v6.0.0+incompatible // indirect
 	github.com/willf/bitset v1.1.10
 	github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect

+ 77 - 0
plugins/searchdomains/plugin.go

@@ -0,0 +1,77 @@
+// Copyright 2018-present the CoreDHCP Authors. All rights reserved
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+package searchdomains
+
+// This is an searchdomains plugin that adds default DNS search domains.
+
+import (
+	"github.com/coredhcp/coredhcp/handler"
+	"github.com/coredhcp/coredhcp/logger"
+	"github.com/coredhcp/coredhcp/plugins"
+	"github.com/insomniacslk/dhcp/dhcpv4"
+	"github.com/insomniacslk/dhcp/dhcpv6"
+	"github.com/insomniacslk/dhcp/rfc1035label"
+)
+
+var log = logger.GetLogger("plugins/searchdomains")
+
+// Plugin wraps the default DNS search domain options.
+// Note that importing the plugin is not enough to use it: you have to
+// explicitly specify the intention to use it in the `config.yml` file, in the
+// plugins section. For searchdomains:
+//
+// server6:
+//   listen: '[::]547'
+//   - searchdomains: domain.a domain.b
+//   - server_id: LL aa:bb:cc:dd:ee:ff
+//   - file: "leases.txt"
+//
+var Plugin = plugins.Plugin{
+	Name:   "searchdomains",
+	Setup6: setup6,
+	Setup4: setup4,
+}
+
+// These are the DNS search domains that are set by the plugin.
+// Note that DHCPv4 and DHCPv6 options are totally independent.
+// If you need the same settings for both, you'll need to configure
+// this plugin once for the v4 and once for the v6 server.
+var v4SearchList []string
+var v6SearchList []string
+
+// copySlice creates a new copy of a string slice in memory.
+// This helps to ensure that downstream plugins can't corrupt
+// this plugin's configuration
+func copySlice(original []string) []string {
+	copied := make([]string, len(original))
+	copy(copied, original)
+	return copied
+}
+
+func setup6(args ...string) (handler.Handler6, error) {
+	v6SearchList = args
+	log.Printf("Registered domain search list (DHCPv6) %s", v6SearchList)
+	return domainSearchListHandler6, nil
+}
+
+func setup4(args ...string) (handler.Handler4, error) {
+	v4SearchList = args
+	log.Printf("Registered domain search list (DHCPv4) %s", v4SearchList)
+	return domainSearchListHandler4, nil
+}
+
+func domainSearchListHandler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
+	resp.UpdateOption(dhcpv6.OptDomainSearchList(&rfc1035label.Labels{
+		Labels: copySlice(v6SearchList),
+	}))
+	return resp, false
+}
+
+func domainSearchListHandler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
+	resp.UpdateOption(dhcpv4.OptDomainSearch(&rfc1035label.Labels{
+		Labels: copySlice(v4SearchList),
+	}))
+	return resp, false
+}

+ 96 - 0
plugins/searchdomains/plugin_test.go

@@ -0,0 +1,96 @@
+// Copyright 2018-present the CoreDHCP Authors. All rights reserved
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+package searchdomains
+
+import (
+	"net"
+	"testing"
+
+	"github.com/insomniacslk/dhcp/dhcpv4"
+	"github.com/insomniacslk/dhcp/dhcpv6"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAddDomains6(t *testing.T) {
+	assert := assert.New(t)
+
+	// Search domains we will expect the DHCP server to assign
+	searchDomains := []string{"domain.a", "domain.b"}
+
+	// Init plugin
+	handler6, err := Plugin.Setup6(searchDomains...)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Fake request
+	req, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.MessageType = dhcpv6.MessageTypeRequest
+	req.AddOption(dhcpv6.OptRequestedOption(dhcpv6.OptionDNSRecursiveNameServer))
+
+	// Fake response input
+	stub, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	stub.MessageType = dhcpv6.MessageTypeReply
+
+	// Call plugin
+	resp, stop := handler6(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+
+	searchLabels := resp.(*dhcpv6.Message).Options.DomainSearchList().Labels
+	assert.Equal(searchDomains, searchLabels)
+}
+
+func TestAddDomains4(t *testing.T) {
+	assert := assert.New(t)
+
+	// Search domains we will expect the DHCP server to assign
+	// NOTE: these domains should be different from the v6 test domains;
+	// this tests that we haven't accidentally set the v6 domains in the
+	// v4 plugin handler or vice versa.
+	searchDomains := []string{"domain.b", "domain.c"}
+
+	// Init plugin
+	handler4, err := Plugin.Setup4(searchDomains...)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Fake request
+	req, err := dhcpv4.NewDiscovery(net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Fake response input
+	stub, err := dhcpv4.NewReplyFromRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Call plugin
+	resp, stop := handler4(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+
+	searchLabels := resp.DomainSearch().Labels
+	assert.Equal(searchDomains, searchLabels)
+
+}