config.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package config
  2. import (
  3. "errors"
  4. "net"
  5. "strconv"
  6. "strings"
  7. "github.com/coredhcp/coredhcp/logger"
  8. "github.com/spf13/cast"
  9. "github.com/spf13/viper"
  10. )
  11. var log = logger.GetLogger()
  12. // Config holds the DHCPv6/v4 server configuration
  13. type Config struct {
  14. v *viper.Viper
  15. Server6 *ServerConfig
  16. Server4 *ServerConfig
  17. }
  18. // New returns a new initialized instance of a Config object
  19. func New() *Config {
  20. return &Config{v: viper.New()}
  21. }
  22. // ServerConfig holds a server configuration that is specific to either the
  23. // DHCPv6 server or the DHCPv4 server.
  24. type ServerConfig struct {
  25. Listener *net.UDPAddr
  26. Plugins []*PluginConfig
  27. }
  28. // PluginConfig holds the configuration of a plugin
  29. type PluginConfig struct {
  30. Name string
  31. Args []string
  32. }
  33. // Load reads a configuration file and returns a Config object, or an error if
  34. // any.
  35. func Load() (*Config, error) {
  36. log.Print("Loading configuration")
  37. c := New()
  38. c.v.SetConfigType("yml")
  39. c.v.SetConfigName("config")
  40. c.v.AddConfigPath(".")
  41. c.v.AddConfigPath("$HOME/.coredhcp/")
  42. c.v.AddConfigPath("/etc/coredhcp/")
  43. if err := c.v.ReadInConfig(); err != nil {
  44. return nil, err
  45. }
  46. if err := c.parseV6Config(); err != nil {
  47. return nil, err
  48. }
  49. if err := c.parseV4Config(); err != nil {
  50. return nil, err
  51. }
  52. if c.Server6 == nil && c.Server4 == nil {
  53. return nil, ConfigErrorFromString("need at least one valid config for DHCPv6 or DHCPv4")
  54. }
  55. return c, nil
  56. }
  57. func parsePlugins(pluginList []interface{}) ([]*PluginConfig, error) {
  58. plugins := make([]*PluginConfig, 0)
  59. for idx, val := range pluginList {
  60. conf := cast.ToStringMap(val)
  61. if conf == nil {
  62. return nil, ConfigErrorFromString("dhcpv6: plugin #%d is not a string map", idx)
  63. }
  64. // make sure that only one item is specified, since it's a
  65. // map name -> args
  66. if len(conf) != 1 {
  67. return nil, ConfigErrorFromString("dhcpv6: exactly one plugin per item can be specified")
  68. }
  69. var (
  70. name string
  71. args []string
  72. )
  73. // only one item, as enforced above, so read just that
  74. for k, v := range conf {
  75. name = k
  76. args = strings.Fields(cast.ToString(v))
  77. break
  78. }
  79. plugins = append(plugins, &PluginConfig{Name: name, Args: args})
  80. }
  81. return plugins, nil
  82. }
  83. func (c *Config) parseV6Config() error {
  84. if exists := c.v.Get("server6"); exists == nil {
  85. // it is valid to have no DHCPv6 configuration defined, so no
  86. // server and no error are returned
  87. return nil
  88. }
  89. addr := c.v.GetString("server6.listen")
  90. if addr == "" {
  91. return ConfigErrorFromString("dhcpv6: missing `server6.listen` directive")
  92. }
  93. ipStr, portStr, err := net.SplitHostPort(addr)
  94. if err != nil {
  95. return ConfigErrorFromString("dhcpv6: %v", err)
  96. }
  97. ip := net.ParseIP(ipStr)
  98. if ip.To4() != nil {
  99. return ConfigErrorFromString("dhcpv6: missing or invalid `listen` address")
  100. }
  101. port, err := strconv.Atoi(portStr)
  102. if err != nil {
  103. return ConfigErrorFromString("dhcpv6: invalid `listen` port")
  104. }
  105. listener := net.UDPAddr{
  106. IP: ip,
  107. Port: port,
  108. }
  109. sc := ServerConfig{
  110. Listener: &listener,
  111. Plugins: nil,
  112. }
  113. // load plugins
  114. pluginList := cast.ToSlice(c.v.Get("server6.plugins"))
  115. if pluginList == nil {
  116. return ConfigErrorFromString("dhcpv6: invalid plugins section, not a list")
  117. }
  118. plugins, err := parsePlugins(pluginList)
  119. if err != nil {
  120. return err
  121. }
  122. for _, p := range plugins {
  123. log.Printf("DHCPv6: found plugin `%s` with %d args: %v", p.Name, len(p.Args), p.Args)
  124. }
  125. sc.Plugins = plugins
  126. c.Server6 = &sc
  127. return nil
  128. }
  129. func (c *Config) parseV4Config() error {
  130. if exists := c.v.Get("server4"); exists != nil {
  131. return errors.New("DHCPv4 config parser not implemented yet")
  132. }
  133. return nil
  134. }