plugin.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2018-present the CoreDHCP Authors. All rights reserved
  2. // This source code is licensed under the MIT license found in the
  3. // LICENSE file in the root directory of this source tree.
  4. package redisplugin
  5. import (
  6. "errors"
  7. "fmt"
  8. "net"
  9. "strings"
  10. "time"
  11. "github.com/coredhcp/coredhcp/handler"
  12. "github.com/coredhcp/coredhcp/logger"
  13. "github.com/coredhcp/coredhcp/plugins"
  14. "github.com/gomodule/redigo/redis"
  15. "github.com/insomniacslk/dhcp/dhcpv4"
  16. "github.com/insomniacslk/dhcp/dhcpv6"
  17. )
  18. // various global variables
  19. var (
  20. log = logger.GetLogger("plugins/redis")
  21. pool *redis.Pool
  22. )
  23. func init() {
  24. plugins.RegisterPlugin("redis", setupRedis6, setupRedis4)
  25. }
  26. // Handler6 handles DHCPv6 packets for the redis plugin
  27. func Handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
  28. // TODO add IPv6 support
  29. return nil, true
  30. }
  31. // Handler4 handles DHCPv4 packets for the redis plugin
  32. func Handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
  33. // Get redis connection from pool
  34. conn := pool.Get()
  35. // defer redis connection close so we don't leak connections
  36. defer conn.Close()
  37. // Get all options for a MAC
  38. options, err := redis.StringMap(conn.Do("HGETALL", "mac:"+req.ClientHWAddr.String()))
  39. // Handle redis error
  40. if err != nil {
  41. log.Printf("Redis error: %s...dropping request", err)
  42. return nil, true
  43. }
  44. // Handle no hash found
  45. if len(options) == 0 {
  46. log.Printf("MAC %s not found...dropping request", req.ClientHWAddr.String())
  47. return nil, true
  48. }
  49. // Handle no ipv4 field
  50. if options["ipv4"] == "" {
  51. log.Printf("MAC %s has no ipv4 field...dropping request", req.ClientHWAddr.String())
  52. return nil, true
  53. }
  54. // Loop through options returned and assign as needed
  55. for option, value := range options {
  56. switch option {
  57. case "ipv4":
  58. ipaddr, ipnet, err := net.ParseCIDR(value)
  59. if err != nil {
  60. log.Printf("MAC %s malformed IP %s error: %s...dropping request", req.ClientHWAddr.String(), value, err)
  61. return nil, true
  62. }
  63. resp.YourIPAddr = ipaddr
  64. resp.Options.Update(dhcpv4.OptSubnetMask(ipnet.Mask))
  65. log.Printf("MAC %s assigned IPv4 address %s", req.ClientHWAddr.String(), value)
  66. case "router":
  67. router := net.ParseIP(value)
  68. if router.To4() == nil {
  69. log.Printf("MAC %s Invalid router option: %s...option skipped", req.ClientHWAddr.String(), value)
  70. break
  71. }
  72. resp.Options.Update(dhcpv4.OptRouter(router))
  73. case "dns":
  74. var dnsServers4 []net.IP
  75. servers := strings.Split(value, ",")
  76. for _, server := range servers {
  77. DNSServer := net.ParseIP(server)
  78. if DNSServer.To4() == nil {
  79. log.Printf("MAC %s Invalid dns server: %s...dropping request", req.ClientHWAddr.String(), server)
  80. return nil, true
  81. }
  82. dnsServers4 = append(dnsServers4, DNSServer)
  83. }
  84. if req.IsOptionRequested(dhcpv4.OptionDomainNameServer) {
  85. resp.Options.Update(dhcpv4.OptDNS(dnsServers4...))
  86. }
  87. case "leaseTime":
  88. lt, err := time.ParseDuration(value)
  89. if err != nil {
  90. log.Printf("MAC %s invalid lease time %s...option skipped", req.ClientHWAddr.String(), value)
  91. break
  92. }
  93. // Set lease time
  94. resp.Options.Update(dhcpv4.OptIPAddressLeaseTime(lt))
  95. default:
  96. log.Printf("MAC %s found un-handled option %s...option skipped", req.ClientHWAddr.String(), option)
  97. }
  98. }
  99. return resp, false
  100. }
  101. func setupRedis6(args ...string) (handler.Handler6, error) {
  102. // TODO setup function for IPv6
  103. log.Warning("not implemented for IPv6")
  104. return Handler6, nil
  105. }
  106. func setupRedis4(args ...string) (handler.Handler4, error) {
  107. _, h4, err := setupRedis(false, args...)
  108. return h4, err
  109. }
  110. func setupRedis(v6 bool, args ...string) (handler.Handler6, handler.Handler4, error) {
  111. if len(args) < 1 {
  112. return nil, nil, fmt.Errorf("invalid number of arguments, want: 1 (redis server:port), got: %d", len(args))
  113. }
  114. if args[0] == "" {
  115. return nil, nil, errors.New("Redis server can't be empty")
  116. }
  117. if v6 {
  118. log.Printf("Using redis server %s for DHCPv6 static leases", args[0])
  119. } else {
  120. log.Printf("Using redis server %s for DHCPv4 static leases", args[0])
  121. }
  122. // Initialize Redis Pool
  123. pool = &redis.Pool{
  124. MaxIdle: 10,
  125. IdleTimeout: 240 * time.Second,
  126. Dial: func() (redis.Conn, error) {
  127. return redis.Dial("tcp", args[0])
  128. },
  129. }
  130. return Handler6, Handler4, nil
  131. }