Ver Fonte

plugins/dns: Implement DHCPv6 support (#54)

* plugins/dns: Implemented DHCPv6 support

Signed-off-by: Anatole Denis <anatole@unverle.fr>

* plugins/file: Remove hardcoded DNS servers

Those are handled by the DNS plugin and don't need to be hardcoded anymore

Signed-off-by: Anatole Denis <anatole@unverle.fr>

* plugins/dns: Only send option when requested

Both DHCP versions have a means for the client to specify what
additional information to send with replies. This adds logic to respect
that.

There is a difference between the protocols as to what happens when this
option doesn't exist. In DHCPv6, the option is mandatory. In DHCPv4 it
is not and indicates the server may send whatever it deems relevant

Signed-off-by: Anatole Denis <anatole@unverle.fr>

* Update dhcp library dependency

This pulls the enhancement from https://github.com/insomniacslk/dhcp/pull/315

generated by `go get github.com/insomniacslk/dhcp && go mod tidy`

Signed-off-by: Anatole Denis <anatole@unverle.fr>
Anatole Denis há 6 anos atrás
pai
commit
79f78359c2
5 ficheiros alterados com 179 adições e 22 exclusões
  1. 1 1
      go.mod
  2. 3 6
      go.sum
  3. 28 8
      plugins/dns/plugin.go
  4. 147 0
      plugins/dns/plugin_test.go
  5. 0 7
      plugins/file/plugin.go

+ 1 - 1
go.mod

@@ -5,7 +5,7 @@ go 1.12
 require (
 	github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb
 	github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 // indirect
-	github.com/insomniacslk/dhcp v0.0.0-20190814082028-393ae75a101b
+	github.com/insomniacslk/dhcp v0.0.0-20190916180653-834a63bade8a
 	github.com/mattn/go-colorable v0.1.2 // indirect
 	github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect
 	github.com/mdlayher/raw v0.0.0-20190606144222-a54781e5f38f // indirect

+ 3 - 6
go.sum

@@ -33,6 +33,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -48,12 +49,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
-github.com/insomniacslk/dhcp v0.0.0-20190729073401-393ae75 h1:6ml59HeoqwyEPJmBNSKksodppW/+A2zADk0Znv7WXQs=
-github.com/insomniacslk/dhcp v0.0.0-20190729073401-393ae75/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
-github.com/insomniacslk/dhcp v0.0.0-20190729073401-6d0d21cc6337 h1:zIo1LfD0djRD7qDyYAtUUKmbQshy1kUKANWaQL0Ptvw=
-github.com/insomniacslk/dhcp v0.0.0-20190729073401-6d0d21cc6337/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
-github.com/insomniacslk/dhcp v0.0.0-20190814082028-393ae75a101b h1:2PyiA5CVpWhQ4CPINgksFnopxYOGUN1n2IjKwrRqQDE=
-github.com/insomniacslk/dhcp v0.0.0-20190814082028-393ae75a101b/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
+github.com/insomniacslk/dhcp v0.0.0-20190916180653-834a63bade8a h1:2zDlT9dNJyaDPnJ23Q2LuztY/2TznrFFvAV17jCjgKY=
+github.com/insomniacslk/dhcp v0.0.0-20190916180653-834a63bade8a/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=

+ 28 - 8
plugins/dns/plugin.go

@@ -18,12 +18,22 @@ func init() {
 }
 
 var (
-	dnsServers []net.IP
+	dnsServers6 []net.IP
+	dnsServers4 []net.IP
 )
 
 func setupDNS6(args ...string) (handler.Handler6, error) {
-	// TODO setup function for IPv6
-	log.Warning("not implemented for IPv6")
+	if len(args) < 1 {
+		return nil, errors.New("need at least one DNS server")
+	}
+	for _, arg := range args {
+		server := net.ParseIP(arg)
+		if server.To16() == nil {
+			return Handler6, errors.New("expected an DNS server address, got: " + arg)
+		}
+		dnsServers6 = append(dnsServers6, server)
+	}
+	log.Infof("loaded %d DNS servers.", len(dnsServers6))
 	return Handler6, nil
 }
 
@@ -37,20 +47,30 @@ func setupDNS4(args ...string) (handler.Handler4, error) {
 		if DNSServer.To4() == nil {
 			return Handler4, errors.New("expected an DNS server address, got: " + arg)
 		}
-		dnsServers = append(dnsServers, DNSServer)
+		dnsServers4 = append(dnsServers4, DNSServer)
 	}
-	log.Infof("loaded %d DNS servers.", len(dnsServers))
+	log.Infof("loaded %d DNS servers.", len(dnsServers4))
 	return Handler4, nil
 }
 
-// Handler6 not implemented only IPv4
+// Handler6 handles DHCPv6 packets for the dns plugin
 func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
-	// TODO add DNS servers for v6 to the response
+	decap, err := req.GetInnerMessage()
+	if err != nil {
+		log.Errorf("Could not decapsulate relayed message, aborting: %v", err)
+		return nil, true
+	}
+
+	if decap.IsOptionRequested(dhcpv6.OptionDNSRecursiveNameServer) {
+		resp.UpdateOption(&dhcpv6.OptDNSRecursiveNameServer{NameServers: dnsServers6})
+	}
 	return resp, false
 }
 
 //Handler4 handles DHCPv4 packets for the dns plugin
 func Handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
-	resp.Options.Update(dhcpv4.OptDNS(dnsServers...))
+	if req.IsOptionRequested(dhcpv4.OptionDomainNameServer) {
+		resp.Options.Update(dhcpv4.OptDNS(dnsServers4...))
+	}
 	return resp, false
 }

+ 147 - 0
plugins/dns/plugin_test.go

@@ -0,0 +1,147 @@
+package dns
+
+import (
+	"net"
+	"testing"
+
+	"github.com/insomniacslk/dhcp/dhcpv4"
+	"github.com/insomniacslk/dhcp/dhcpv6"
+)
+
+func TestAddServer6(t *testing.T) {
+	req, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.MessageType = dhcpv6.MessageTypeRequest
+	oro := dhcpv6.OptRequestedOption{}
+	oro.AddRequestedOption(dhcpv6.OptionDNSRecursiveNameServer)
+	req.AddOption(&oro)
+
+	stub, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	stub.MessageType = dhcpv6.MessageTypeReply
+
+	dnsServers6 = []net.IP{
+		net.ParseIP("2001:db8::1"),
+		net.ParseIP("2001:db8::3"),
+	}
+
+	resp, stop := Handler6(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+	opts := resp.GetOption(dhcpv6.OptionDNSRecursiveNameServer)
+	if len(opts) != 1 {
+		t.Fatalf("Expected 1 RDNSS option, got %d: %v", len(opts), opts)
+	}
+	foundServers := opts[0].(*dhcpv6.OptDNSRecursiveNameServer).NameServers
+	// XXX: is enforcing the order relevant here ?
+	for i, srv := range foundServers {
+		if !srv.Equal(dnsServers6[i]) {
+			t.Errorf("Found server %s, expected %s", srv, dnsServers6[i])
+		}
+	}
+	if len(foundServers) != len(dnsServers6) {
+		t.Errorf("Found %d servers, expected %d", len(foundServers), len(dnsServers6))
+	}
+}
+
+func TestNotRequested6(t *testing.T) {
+	req, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.MessageType = dhcpv6.MessageTypeRequest
+	req.AddOption(&dhcpv6.OptRequestedOption{})
+
+	stub, err := dhcpv6.NewMessage()
+	if err != nil {
+		t.Fatal(err)
+	}
+	stub.MessageType = dhcpv6.MessageTypeReply
+
+	dnsServers6 = []net.IP{
+		net.ParseIP("2001:db8::1"),
+	}
+
+	resp, stop := Handler6(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+
+	opts := resp.GetOption(dhcpv6.OptionDNSRecursiveNameServer)
+	if len(opts) != 0 {
+		t.Errorf("RDNSS options were added when not requested: %v", opts)
+	}
+}
+
+func TestAddServer4(t *testing.T) {
+	req, err := dhcpv4.NewDiscovery(net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
+	if err != nil {
+		t.Fatal(err)
+	}
+	stub, err := dhcpv4.NewReplyFromRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	dnsServers4 = []net.IP{
+		net.ParseIP("192.0.2.1"),
+		net.ParseIP("192.0.2.3"),
+	}
+
+	resp, stop := Handler4(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+	servers := resp.DNS()
+	for i, srv := range servers {
+		if !srv.Equal(dnsServers4[i]) {
+			t.Errorf("Found server %s, expected %s", srv, dnsServers4[i])
+		}
+	}
+	if len(servers) != len(dnsServers4) {
+		t.Errorf("Found %d servers, expected %d", len(servers), len(dnsServers4))
+	}
+}
+
+func TestNotRequested4(t *testing.T) {
+	req, err := dhcpv4.NewDiscovery(net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
+	if err != nil {
+		t.Fatal(err)
+	}
+	stub, err := dhcpv4.NewReplyFromRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	dnsServers4 = []net.IP{
+		net.ParseIP("192.0.2.1"),
+	}
+	req.UpdateOption(dhcpv4.OptParameterRequestList(dhcpv4.OptionBroadcastAddress))
+
+	resp, stop := Handler4(req, stub)
+	if resp == nil {
+		t.Fatal("plugin did not return a message")
+	}
+	if stop {
+		t.Error("plugin interrupted processing")
+	}
+	servers := dhcpv4.GetIPs(dhcpv4.OptionDomainNameServer, resp.Options)
+	if len(servers) != 0 {
+		t.Errorf("Found %d DNS servers when explicitly not requested", len(servers))
+	}
+}

+ 0 - 7
plugins/file/plugin.go

@@ -143,13 +143,6 @@ func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
 			},
 		},
 	})
-	resp.AddOption(&dhcpv6.OptDNSRecursiveNameServer{
-		NameServers: []net.IP{
-			// FIXME this must be read from the config file
-			net.ParseIP("2001:4860:4860::8888"),
-			net.ParseIP("2001:4860:4860::4444"),
-		},
-	})
 
 	decap, err := req.GetInnerMessage()
 	if err != nil {