dhcp.go 4.3 KB

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