Proposed redis plugin (#64)

* simplify boot file URL

Signed-off-by: kevin <kworm@missouri-telecom.com>
This commit is contained in:
kworm83 2019-11-20 08:35:43 -06:00 committed by Pablo Mazzini
parent d1f76861c7
commit eaaeff9d7a
4 changed files with 162 additions and 1 deletions

View File

@ -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"
)

3
go.mod
View File

@ -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
go.sum
View File

@ -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
plugins/redis/plugin.go Normal file
View File

@ -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
}