Ver código fonte

Implemented DHCPv4 main handler

Andrea Barberio 7 anos atrás
pai
commit
f3d1f9896c

+ 4 - 1
cmds/coredhcp/config.yml.example

@@ -6,4 +6,7 @@ server6:
         # - dns: 8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844
 
 server4:
-    listen: '127.0.0.1:67'
+    listen: '0.0.0.0:67'
+    plugins:
+        - server_id: 192.168.1.12
+#        - file: "leases.txt"

+ 1 - 1
config/config.go

@@ -134,7 +134,7 @@ func (c *Config) getListenAddress(ver protocolVersion) (*net.UDPAddr, error) {
 func (c *Config) getPlugins(ver protocolVersion) ([]*PluginConfig, error) {
 	pluginList := cast.ToSlice(c.v.Get(fmt.Sprintf("server%d.plugins", ver)))
 	if pluginList == nil {
-		return nil, ConfigErrorFromString("dhcpv%d: invalid plugins section, not a list", ver)
+		return nil, ConfigErrorFromString("dhcpv%d: invalid plugins section, not a list or no plugin specified", ver)
 	}
 	return parsePlugins(pluginList)
 }

+ 58 - 9
coredhcp.go

@@ -2,6 +2,7 @@ package coredhcp
 
 import (
 	"errors"
+	"fmt"
 	"net"
 
 	"github.com/coredhcp/coredhcp/config"
@@ -101,27 +102,75 @@ func (s *Server) LoadPlugins(conf *config.Config) ([]*plugins.Plugin, []*plugins
 // It will not reply if the resulting response is `nil`.
 func (s *Server) MainHandler6(conn net.PacketConn, peer net.Addr, req dhcpv6.DHCPv6) {
 	var (
-		resp dhcpv6.DHCPv6
-		stop bool
+		resp, tmp dhcpv6.DHCPv6
+		stop      bool
+		err       error
 	)
+
+	// Create a suitable basic response packet
+	switch req.Type() {
+	case dhcpv6.MessageTypeSolicit:
+		tmp, err = dhcpv6.NewAdvertiseFromSolicit(req)
+	case dhcpv6.MessageTypeRequest, dhcpv6.MessageTypeConfirm, dhcpv6.MessageTypeRenew,
+		dhcpv6.MessageTypeRebind, dhcpv6.MessageTypeRelease, dhcpv6.MessageTypeInformationRequest:
+		tmp, err = dhcpv6.NewReplyFromDHCPv6Message(req)
+	default:
+		err = fmt.Errorf("MainHandler6: message type %d not supported", req.Type())
+	}
+
+	if err != nil {
+		log.Printf("MainHandler6: NewReplyFromDHCPv6Message failed: %v", err)
+		return
+	}
+	resp = tmp
 	for _, handler := range s.Handlers6 {
 		resp, stop = handler(req, resp)
 		if stop {
 			break
 		}
 	}
+
 	if resp != nil {
 		if _, err := conn.WriteTo(resp.ToBytes(), peer); err != nil {
-			log.Printf("conn.Write to %v failed: %v", peer, err)
+			log.Printf("MainHandler6: conn.Write to %v failed: %v", peer, err)
 		}
 	} else {
-		log.Print("Dropping request because response is nil")
+		log.Print("MainHandler6: dropping request because response is nil")
 	}
 }
 
 // MainHandler4 is like MainHandler6, but for DHCPv4 packets.
-func (s *Server) MainHandler4(conn net.PacketConn, peer net.Addr, d *dhcpv4.DHCPv4) {
-	log.Print(d.Summary())
+func (s *Server) MainHandler4(conn net.PacketConn, peer net.Addr, req *dhcpv4.DHCPv4) {
+	var (
+		resp, tmp *dhcpv4.DHCPv4
+		err       error
+		stop      bool
+	)
+	if req.OpCode != dhcpv4.OpcodeBootRequest {
+		log.Printf("MainHandler4: unsupported opcode %d. Only BootRequest (%d) is supported", req.OpCode, dhcpv4.OpcodeBootRequest)
+		return
+	}
+	tmp, err = dhcpv4.NewReplyFromRequest(req)
+	if err != nil {
+		log.Printf("MainHandler4: failed to build reply: %v", err)
+		return
+	}
+
+	resp = tmp
+	for _, handler := range s.Handlers4 {
+		resp, stop = handler(req, resp)
+		if stop {
+			break
+		}
+	}
+
+	if resp != nil {
+		if _, err := conn.WriteTo(resp.ToBytes(), peer); err != nil {
+			log.Printf("MainHandler4: conn.Write to %v failed: %v", peer, err)
+		}
+	} else {
+		log.Print("MainHandler4: dropping request because response is nil")
+	}
 }
 
 // Start will start the server asynchronously. See `Wait` to wait until
@@ -135,16 +184,16 @@ func (s *Server) Start() error {
 	// listen
 	if s.Config.Server6 != nil {
 		log.Printf("Starting DHCPv6 listener on %v", s.Config.Server6.Listener)
-		s.Server6 = dhcpv6.NewServer(*s.Config.Server6.Listener, s.MainHandler6)
 		go func() {
+			s.Server6 = dhcpv6.NewServer(*s.Config.Server6.Listener, s.MainHandler6)
 			s.errors <- s.Server6.ActivateAndServe()
 		}()
 	}
 
 	if s.Config.Server4 != nil {
-		log.Printf("Starting DHCPv4 listener on %v", s.Config.Server6.Listener)
-		s.Server4 = dhcpv4.NewServer(*s.Config.Server4.Listener, s.MainHandler4)
+		log.Printf("Starting DHCPv4 listener on %v", s.Config.Server4.Listener)
 		go func() {
+			s.Server4 = dhcpv4.NewServer(*s.Config.Server4.Listener, s.MainHandler4)
 			s.errors <- s.Server4.ActivateAndServe()
 		}()
 	}

+ 0 - 6
plugins/file/plugin.go

@@ -77,12 +77,6 @@ func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
 		return nil, false
 	}
 	log.Printf("Found IP address %s for MAC %s", ipaddr, mac)
-	if resp == nil {
-		resp, err = dhcpv6.NewAdvertiseFromSolicit(req)
-		if err != nil {
-			return nil, false
-		}
-	}
 	// TODO add an OptIANA based on the above data
 	return resp, true
 }

+ 41 - 30
plugins/server_id/plugin.go

@@ -2,7 +2,6 @@ package clientport
 
 import (
 	"errors"
-	"fmt"
 	"net"
 	"strings"
 
@@ -21,52 +20,64 @@ func init() {
 }
 
 // V6ServerID is the DUID of the v6 server
-var V6ServerID *dhcpv6.Duid
+var (
+	V6ServerID *dhcpv6.Duid
+	V4ServerID net.IP
+)
 
-// Handler6 handles DHCPv6 packets for the file plugin
+// Handler6 handles DHCPv6 packets for the server_id plugin.
 func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
 	if V6ServerID == nil {
 		return resp, false
 	}
-	if resp == nil {
-		var (
-			tmp dhcpv6.DHCPv6
-			err error
-		)
-
-		switch req.Type() {
-		case dhcpv6.MessageTypeSolicit:
-			tmp, err = dhcpv6.NewAdvertiseFromSolicit(req)
-		case dhcpv6.MessageTypeRequest, dhcpv6.MessageTypeConfirm, dhcpv6.MessageTypeRenew,
-			dhcpv6.MessageTypeRebind, dhcpv6.MessageTypeRelease, dhcpv6.MessageTypeInformationRequest:
-			tmp, err = dhcpv6.NewReplyFromDHCPv6Message(req)
-		default:
-			err = fmt.Errorf("plugins/server_id: message type %d not supported", req.Type())
-		}
-
-		if err != nil {
-			log.Printf("plugins/server_id: NewReplyFromDHCPv6Message failed: %v", err)
-			return resp, false
+	if opt := req.GetOneOption(dhcpv6.OptionServerID); opt != nil {
+		sid := opt.(*dhcpv6.OptServerId)
+		if !sid.Sid.Equal(*V6ServerID) {
+			log.Infof("plugins/server_id: requested server ID does not match this server's ID. Got %v, want %v", sid.Sid, V6ServerID)
 		}
-		resp = tmp
 	}
-	resp = dhcpv6.WithServerID(*V6ServerID)(resp)
-	return resp, false
+	return dhcpv6.WithServerID(*V6ServerID)(resp), false
 }
 
-// Handler4 handles DHCPv4 packets for the file plugin
+// Handler4 handles DHCPv4 packets for the server_id plugin.
 func Handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
-	// do nothing
+	if V4ServerID == nil || resp == nil {
+		return resp, false
+	}
+	if req.OpCode != dhcpv4.OpcodeBootRequest {
+		log.Warningf("plugins/server_id: not a BootRequest, ignoring")
+		return resp, false
+	}
+	if req.ServerIPAddr != nil &&
+		!req.ServerIPAddr.Equal(net.IPv4zero) &&
+		!req.ServerIPAddr.Equal(V4ServerID) {
+		// This request is not for us, drop it.
+		log.Infof("plugins/server_id: requested server ID does not match this server's ID. Got %v, want %v", req.ServerIPAddr, V4ServerID)
+		return nil, true
+	}
+	resp.ServerIPAddr = make(net.IP, net.IPv4len)
+	copy(resp.ServerIPAddr[:], V4ServerID)
 	return resp, false
 }
 
 func setupServerID4(args ...string) (handler.Handler4, error) {
-	// TODO implement this function
-	return nil, errors.New("plugins/server_id: not implemented for DHCPv4")
+	log.Print("plugins/server_id: loading `server_id` plugin for DHCPv4")
+	if len(args) < 1 {
+		return nil, errors.New("plugins/server_id: need an argument")
+	}
+	serverID := net.ParseIP(args[0])
+	if serverID == nil {
+		return nil, errors.New("plugins/server_id: invalid or empty IP address")
+	}
+	if serverID.To4() == nil {
+		return nil, errors.New("plugins/server_id: not a valid IPv4 address")
+	}
+	V4ServerID = serverID
+	return Handler4, nil
 }
 
 func setupServerID6(args ...string) (handler.Handler6, error) {
-	log.Print("plugins/server_id: loading `server_id` plugin")
+	log.Print("plugins/server_id: loading `server_id` plugin for DHCPv6")
 	if len(args) < 2 {
 		return nil, errors.New("plugins/server_id: need a DUID type and value")
 	}