coredhcp.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package coredhcp
  2. import (
  3. "errors"
  4. "net"
  5. "github.com/coredhcp/coredhcp/config"
  6. "github.com/coredhcp/coredhcp/handler"
  7. "github.com/coredhcp/coredhcp/logger"
  8. "github.com/coredhcp/coredhcp/plugins"
  9. "github.com/insomniacslk/dhcp/dhcpv4"
  10. "github.com/insomniacslk/dhcp/dhcpv6"
  11. )
  12. var log = logger.GetLogger()
  13. // Server is a CoreDHCP server structure that holds information about
  14. // DHCPv6 and DHCPv4 servers, and their respective handlers.
  15. type Server struct {
  16. Handlers6 []handler.Handler6
  17. Handlers4 []handler.Handler4
  18. Config *config.Config
  19. Server6 *dhcpv6.Server
  20. Server4 *dhcpv4.Server
  21. errors chan error
  22. }
  23. // LoadPlugins reads a Config object and loads the plugins as specified in the
  24. // `plugins` section, in order. For a plugin to be available, it must have been
  25. // previously registered with plugins.RegisterPlugin. This is normally done at
  26. // plugin import time.
  27. // This function returns the list of loaded v6 plugins, the list of loaded v4
  28. // plugins, and an error if any.
  29. func (s *Server) LoadPlugins(conf *config.Config) ([]*plugins.Plugin, []*plugins.Plugin, error) {
  30. log.Print("Loading plugins...")
  31. loadedPlugins6 := make([]*plugins.Plugin, 0)
  32. loadedPlugins4 := make([]*plugins.Plugin, 0)
  33. if conf.Server6 == nil && conf.Server4 == nil {
  34. return nil, nil, errors.New("no configuration found for either DHCPv6 or DHCPv4")
  35. }
  36. // now load the plugins. We need to call its setup function with
  37. // the arguments extracted above. The setup function is mapped in
  38. // plugins.RegisteredPlugins .
  39. // Load DHCPv6 plugins.
  40. if conf.Server6 != nil {
  41. for _, pluginConf := range conf.Server6.Plugins {
  42. if plugin, ok := plugins.RegisteredPlugins[pluginConf.Name]; ok {
  43. log.Printf("DHCPv6: loading plugin `%s`", pluginConf.Name)
  44. if plugin.Setup6 == nil {
  45. log.Warningf("DHCPv6: plugin `%s` has no setup function for DHCPv6", pluginConf.Name)
  46. continue
  47. }
  48. h6, err := plugin.Setup6(pluginConf.Args...)
  49. if err != nil {
  50. return nil, nil, err
  51. }
  52. loadedPlugins6 = append(loadedPlugins6, plugin)
  53. if h6 == nil {
  54. return nil, nil, config.ConfigErrorFromString("no DHCPv6 handler for plugin %s", pluginConf.Name)
  55. }
  56. s.Handlers6 = append(s.Handlers6, h6)
  57. } else {
  58. return nil, nil, config.ConfigErrorFromString("DHCPv6: unknown plugin `%s`", pluginConf.Name)
  59. }
  60. }
  61. }
  62. // Load DHCPv4 plugins. Yes, duplicated code, there's not really much that
  63. // can be deduplicated here.
  64. if conf.Server4 != nil {
  65. for _, pluginConf := range conf.Server4.Plugins {
  66. if plugin, ok := plugins.RegisteredPlugins[pluginConf.Name]; ok {
  67. log.Printf("DHCPv4: loading plugin `%s`", pluginConf.Name)
  68. if plugin.Setup4 == nil {
  69. log.Warningf("DHCPv4: plugin `%s` has no setup function for DHCPv4", pluginConf.Name)
  70. continue
  71. }
  72. h4, err := plugin.Setup4(pluginConf.Args...)
  73. if err != nil {
  74. return nil, nil, err
  75. }
  76. loadedPlugins4 = append(loadedPlugins4, plugin)
  77. if h4 == nil {
  78. return nil, nil, config.ConfigErrorFromString("no DHCPv4 handler for plugin %s", pluginConf.Name)
  79. }
  80. s.Handlers4 = append(s.Handlers4, h4)
  81. //s.Handlers4 = append(s.Handlers4, h4)
  82. } else {
  83. return nil, nil, config.ConfigErrorFromString("DHCPv4: unknown plugin `%s`", pluginConf.Name)
  84. }
  85. }
  86. }
  87. return loadedPlugins6, loadedPlugins4, nil
  88. }
  89. // MainHandler6 runs for every received DHCPv6 packet. It will run every
  90. // registered handler in sequence, and reply with the resulting response.
  91. // It will not reply if the resulting response is `nil`.
  92. func (s *Server) MainHandler6(conn net.PacketConn, peer net.Addr, req dhcpv6.DHCPv6) {
  93. var (
  94. resp dhcpv6.DHCPv6
  95. stop bool
  96. )
  97. for _, handler := range s.Handlers6 {
  98. resp, stop = handler(req, resp)
  99. if stop {
  100. break
  101. }
  102. }
  103. if resp != nil {
  104. if _, err := conn.WriteTo(resp.ToBytes(), peer); err != nil {
  105. log.Printf("conn.Write to %v failed: %v", peer, err)
  106. }
  107. } else {
  108. log.Print("Dropping request because response is nil")
  109. }
  110. }
  111. // MainHandler4 is like MainHandler6, but for DHCPv4 packets.
  112. func (s *Server) MainHandler4(conn net.PacketConn, peer net.Addr, d *dhcpv4.DHCPv4) {
  113. log.Print(d.Summary())
  114. }
  115. // Start will start the server asynchronously. See `Wait` to wait until
  116. // the execution ends.
  117. func (s *Server) Start() error {
  118. _, _, err := s.LoadPlugins(s.Config)
  119. if err != nil {
  120. return err
  121. }
  122. // listen
  123. if s.Config.Server6 != nil {
  124. log.Printf("Starting DHCPv6 listener on %v", s.Config.Server6.Listener)
  125. s.Server6 = dhcpv6.NewServer(*s.Config.Server6.Listener, s.MainHandler6)
  126. go func() {
  127. s.errors <- s.Server6.ActivateAndServe()
  128. }()
  129. }
  130. if s.Config.Server4 != nil {
  131. log.Printf("Starting DHCPv4 listener on %v", s.Config.Server6.Listener)
  132. s.Server4 = dhcpv4.NewServer(*s.Config.Server4.Listener, s.MainHandler4)
  133. go func() {
  134. s.errors <- s.Server4.ActivateAndServe()
  135. }()
  136. }
  137. return nil
  138. }
  139. // Wait waits until the end of the execution of the server.
  140. func (s *Server) Wait() error {
  141. log.Print("Waiting")
  142. if s.Server6 != nil {
  143. s.Server6.Close()
  144. }
  145. if s.Server4 != nil {
  146. s.Server4.Close()
  147. }
  148. return <-s.errors
  149. }
  150. // NewServer creates a Server instance with the provided configuration.
  151. func NewServer(config *config.Config) *Server {
  152. return &Server{Config: config, errors: make(chan error, 1)}
  153. }