dhcp.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package service
  2. import (
  3. "context"
  4. "dhcp/api/request"
  5. "dhcp/code"
  6. "dhcp/internal/backend"
  7. "dhcp/internal/handler/proxy"
  8. "dhcp/internal/ip"
  9. "dhcp/internal/server"
  10. "dhcp/result"
  11. "fmt"
  12. "github.com/go-logr/logr"
  13. "github.com/insomniacslk/dhcp/dhcpv4/server4"
  14. "net"
  15. "net/netip"
  16. )
  17. var DHCPServiceMap = map[string]*DHCPService{}
  18. var DHCPServiceInfoMap = map[string]request.DHCPService{}
  19. type DhcpConfig struct {
  20. Mode string `yaml:"mode"` // 模式
  21. BindAddr string `yaml:"bind_addr"` // 绑定地址
  22. BindInterface string `yaml:"bind_interface"` // 绑定接口
  23. IpForPacket string `yaml:"ip_for_packet"` // 包的ip
  24. SyslogIP string `yaml:"syslog_ip"` // syslog ip
  25. TftpIP string `yaml:"tftp_ip"` // tftp ip
  26. HttpIpxeBinaryURL string `yaml:"http_ipxe_binary_url"` // http ipxe二进制url
  27. }
  28. func StartDHCPService(ctx context.Context, log logr.Logger, req request.DHCPService) result.Result {
  29. dhcp := DhcpConfig{
  30. Mode: req.Mode,
  31. BindAddr: "0.0.0.0:67",
  32. BindInterface: req.BindInterface,
  33. IpForPacket: ip.DetectPublicIPv4(""),
  34. SyslogIP: ip.DetectPublicIPv4(""),
  35. TftpIP: ip.DetectPublicIPv4(":69"),
  36. }
  37. var dhcpService = &DHCPService{}
  38. dhcpService.StartDHCP(ctx, dhcp, log)
  39. DHCPServiceMap[req.BindInterface] = dhcpService
  40. req.Status = true
  41. DHCPServiceInfoMap[req.BindInterface] = req
  42. return result.Result{
  43. Status: true,
  44. Code: code.SUCCESS,
  45. Msg: "启动成功",
  46. }
  47. }
  48. func StopDHCPService(ctx context.Context, log logr.Logger, req request.DHCPService) result.Result {
  49. if dhcpService, ok := DHCPServiceMap[req.BindInterface]; ok {
  50. err := dhcpService.server.Close()
  51. if err != nil {
  52. return result.Result{
  53. Status: false,
  54. Code: code.SystemException,
  55. Msg: "关闭失败",
  56. }
  57. }
  58. delete(DHCPServiceMap, req.BindInterface)
  59. DHCPServiceInfo := DHCPServiceInfoMap[req.BindInterface]
  60. DHCPServiceInfo.Status = false
  61. DHCPServiceInfo.Info = "自主关闭"
  62. DHCPServiceInfoMap[req.BindInterface] = DHCPServiceInfo
  63. }
  64. return result.Result{
  65. Status: true,
  66. Code: code.SUCCESS,
  67. Msg: "关闭成功",
  68. }
  69. }
  70. func DeleteDHCPService(ctx context.Context, log logr.Logger, req request.DHCPService) result.Result {
  71. if dhcpService, ok := DHCPServiceMap[req.BindInterface]; ok {
  72. _ = dhcpService.server.Close()
  73. delete(DHCPServiceMap, req.BindInterface)
  74. delete(DHCPServiceInfoMap, req.BindInterface)
  75. } else {
  76. return result.Result{
  77. Status: false,
  78. Code: code.SystemException,
  79. Msg: "删除失败",
  80. }
  81. }
  82. return result.Result{
  83. Status: true,
  84. Code: code.SUCCESS,
  85. Msg: "删除成功",
  86. }
  87. }
  88. type DHCPService struct {
  89. server *server.DHCP
  90. }
  91. func (dhcp *DHCPService) StartDHCP(ctx context.Context, d DhcpConfig, log logr.Logger) {
  92. dh, err := dhcpHandler(ctx, &d, log)
  93. if err != nil {
  94. log.Error(err, "failed to create dhcpServer listener")
  95. panic(fmt.Errorf("failed to create dhcpServer listener: %w", err))
  96. }
  97. log.Info("starting dhcpServer server", "bind_addr", d.BindAddr)
  98. go func(ctx context.Context) {
  99. bindAddr, err := netip.ParseAddrPort(d.BindAddr)
  100. if err != nil {
  101. panic(fmt.Errorf("invalid tftp address for dhcpServer server: %w", err))
  102. }
  103. conn, err := server4.NewIPv4UDPConn(d.BindInterface, net.UDPAddrFromAddrPort(bindAddr))
  104. if err != nil {
  105. log.Info("failed to create dhcpServer listener", "error", err)
  106. panic(err)
  107. }
  108. defer conn.Close()
  109. dhcp.server = &server.DHCP{Logger: log, Conn: conn, Handlers: []server.Handler{dh}}
  110. err = dhcp.server.Serve(ctx)
  111. if err != nil {
  112. delete(DHCPServiceMap, d.BindInterface)
  113. DHCPServiceInfo := DHCPServiceInfoMap[d.BindInterface]
  114. DHCPServiceInfo.Status = false
  115. DHCPServiceInfo.Info = err.Error()
  116. DHCPServiceInfoMap[d.BindInterface] = DHCPServiceInfo
  117. }
  118. }(ctx)
  119. }
  120. func (dhcp *DHCPService) StopDHCP(ctx context.Context) {
  121. dhcp.server.Close()
  122. }
  123. func dhcpHandler(ctx context.Context, c *DhcpConfig, log logr.Logger) (server.Handler, error) {
  124. // 1. create the handler
  125. // 2. create the macAndIPXE
  126. // 3. add the macAndIPXE to the handler
  127. pktIP, err := netip.ParseAddr(c.IpForPacket)
  128. if err != nil {
  129. return nil, fmt.Errorf("invalid bind address: %w", err)
  130. }
  131. br := backend.NewBackend()
  132. dh := &proxy.Handler{
  133. Backend: br,
  134. IPAddr: pktIP,
  135. Log: log,
  136. }
  137. return dh, nil
  138. }