Bläddra i källkod

Proposed redis plugin (#64)

* simplify boot file URL

Signed-off-by: kevin <kworm@missouri-telecom.com>
kworm83 6 år sedan
förälder
incheckning
eaaeff9d7a
4 ändrade filer med 162 tillägg och 1 borttagningar
  1. 1 0
      cmds/coredhcp/main.go
  2. 2 1
      go.mod
  3. 4 0
      go.sum
  4. 155 0
      plugins/redis/plugin.go

+ 1 - 0
cmds/coredhcp/main.go

@@ -15,6 +15,7 @@ import (
 	_ "github.com/coredhcp/coredhcp/plugins/file"
 	_ "github.com/coredhcp/coredhcp/plugins/netmask"
 	_ "github.com/coredhcp/coredhcp/plugins/range"
+	_ "github.com/coredhcp/coredhcp/plugins/redis"
 	_ "github.com/coredhcp/coredhcp/plugins/router"
 	_ "github.com/coredhcp/coredhcp/plugins/server_id"
 )

+ 2 - 1
go.mod

@@ -4,8 +4,9 @@ go 1.12
 
 require (
 	github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb
+	github.com/gomodule/redigo v2.0.0+incompatible
 	github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 // indirect
-	github.com/insomniacslk/dhcp v0.0.0-20191002211418-651e0846f780
+	github.com/insomniacslk/dhcp v0.0.0-20191112140002-c05874014012
 	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

+ 4 - 0
go.sum

@@ -35,6 +35,8 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 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/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
@@ -51,6 +53,8 @@ github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8
 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
 github.com/insomniacslk/dhcp v0.0.0-20191002211418-651e0846f780 h1:ty8rDh2kTAoxelUsFLMwjcQ3YW7lF7NHHcpUGuKMMNE=
 github.com/insomniacslk/dhcp v0.0.0-20191002211418-651e0846f780/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
+github.com/insomniacslk/dhcp v0.0.0-20191112140002-c05874014012 h1:FPWfO4cQp0BS5WKI9Yoak1IlPNU9IUzGUmFZEfVG7V4=
+github.com/insomniacslk/dhcp v0.0.0-20191112140002-c05874014012/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=

+ 155 - 0
plugins/redis/plugin.go

@@ -0,0 +1,155 @@
+// 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 redisplugin
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"strings"
+	"time"
+
+	"github.com/coredhcp/coredhcp/handler"
+	"github.com/coredhcp/coredhcp/logger"
+	"github.com/coredhcp/coredhcp/plugins"
+	"github.com/gomodule/redigo/redis"
+	"github.com/insomniacslk/dhcp/dhcpv4"
+	"github.com/insomniacslk/dhcp/dhcpv6"
+)
+
+// various global variables
+var (
+	log  = logger.GetLogger("plugins/redis")
+	pool *redis.Pool
+)
+
+func init() {
+	plugins.RegisterPlugin("redis", setupRedis6, setupRedis4)
+}
+
+// Handler6 handles DHCPv6 packets for the redis plugin
+func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
+	// TODO add IPv6 support
+	return nil, true
+}
+
+// Handler4 handles DHCPv4 packets for the redis plugin
+func Handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
+	// Get redis connection from pool
+	conn := pool.Get()
+
+	// defer redis connection close so we don't leak connections
+	defer conn.Close()
+
+	// Get all options for a MAC
+	options, err := redis.StringMap(conn.Do("HGETALL", "mac:"+req.ClientHWAddr.String()))
+
+	// Handle redis error
+	if err != nil {
+		log.Printf("Redis error: %s...dropping request", err)
+		return nil, true
+	}
+
+	// Handle no hash found
+	if len(options) == 0 {
+		log.Printf("MAC %s not found...dropping request", req.ClientHWAddr.String())
+		return nil, true
+	}
+
+	// Handle no ipv4 field
+	if options["ipv4"] == "" {
+		log.Printf("MAC %s has no ipv4 field...dropping request", req.ClientHWAddr.String())
+		return nil, true
+	}
+
+	// Loop through options returned and assign as needed
+	for option, value := range options {
+		switch option {
+		case "ipv4":
+			ipaddr, ipnet, err := net.ParseCIDR(value)
+			if err != nil {
+				log.Printf("MAC %s malformed IP %s error: %s...dropping request", req.ClientHWAddr.String(), value, err)
+				return nil, true
+			}
+			resp.YourIPAddr = ipaddr
+			resp.Options.Update(dhcpv4.OptSubnetMask(ipnet.Mask))
+			log.Printf("MAC %s assigned IPv4 address %s", req.ClientHWAddr.String(), value)
+
+		case "router":
+			router := net.ParseIP(value)
+			if router.To4() == nil {
+				log.Printf("MAC %s Invalid router option: %s...option skipped", req.ClientHWAddr.String(), value)
+				break
+			}
+			resp.Options.Update(dhcpv4.OptRouter(router))
+
+		case "dns":
+			var dnsServers4 []net.IP
+			servers := strings.Split(value, ",")
+			for _, server := range servers {
+				DNSServer := net.ParseIP(server)
+				if DNSServer.To4() == nil {
+					log.Printf("MAC %s Invalid dns server: %s...dropping request", req.ClientHWAddr.String(), server)
+					return nil, true
+				}
+				dnsServers4 = append(dnsServers4, DNSServer)
+			}
+			if req.IsOptionRequested(dhcpv4.OptionDomainNameServer) {
+				resp.Options.Update(dhcpv4.OptDNS(dnsServers4...))
+			}
+
+		case "leaseTime":
+			lt, err := time.ParseDuration(value)
+			if err != nil {
+				log.Printf("MAC %s invalid lease time %s...option skipped", req.ClientHWAddr.String(), value)
+				break
+			}
+			// Set lease time
+			resp.Options.Update(dhcpv4.OptIPAddressLeaseTime(lt))
+
+		default:
+			log.Printf("MAC %s found un-handled option %s...option skipped", req.ClientHWAddr.String(), option)
+		}
+	}
+
+	return resp, false
+}
+
+func setupRedis6(args ...string) (handler.Handler6, error) {
+	// TODO setup function for IPv6
+	log.Warning("not implemented for IPv6")
+	return Handler6, nil
+}
+
+func setupRedis4(args ...string) (handler.Handler4, error) {
+	_, h4, err := setupRedis(false, args...)
+	return h4, err
+}
+
+func setupRedis(v6 bool, args ...string) (handler.Handler6, handler.Handler4, error) {
+	if len(args) < 1 {
+		return nil, nil, fmt.Errorf("invalid number of arguments, want: 1 (redis server:port), got: %d", len(args))
+	}
+	if args[0] == "" {
+		return nil, nil, errors.New("Redis server can't be empty")
+	}
+
+	if v6 {
+		log.Printf("Using redis server %s for DHCPv6 static leases", args[0])
+	} else {
+		log.Printf("Using redis server %s for DHCPv4 static leases", args[0])
+	}
+
+	// Initialize Redis Pool
+	pool = &redis.Pool{
+		MaxIdle:     10,
+		IdleTimeout: 240 * time.Second,
+		Dial: func() (redis.Conn, error) {
+			return redis.Dial("tcp", args[0])
+		},
+	}
+
+	return Handler6, Handler4, nil
+}