config.go 3.4 KB

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