udpforwarding.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
  6. "github.com/go-nunu/nunu-layout-advanced/internal/model"
  7. "github.com/go-nunu/nunu-layout-advanced/internal/repository"
  8. "golang.org/x/sync/errgroup"
  9. "strconv"
  10. "strings"
  11. )
  12. type UdpForWardingService interface {
  13. GetUdpForWarding(ctx context.Context,req v1.GetForwardingRequest) (v1.UdpForwardingDataRequest, error)
  14. AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error
  15. EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error
  16. DeleteUdpForwarding(ctx context.Context, Id int) error
  17. }
  18. func NewUdpForWardingService(
  19. service *Service,
  20. udpForWardingRepository repository.UdpForWardingRepository,
  21. required RequiredService,
  22. parser ParserService,
  23. crawler CrawlerService,
  24. globalRep repository.GlobalLimitRepository,
  25. hostRep repository.HostRepository,
  26. wafformatter WafFormatterService,
  27. ) UdpForWardingService {
  28. return &udpForWardingService{
  29. Service: service,
  30. udpForWardingRepository: udpForWardingRepository,
  31. required: required,
  32. parser: parser,
  33. crawler: crawler,
  34. globalRep: globalRep,
  35. hostRep: hostRep,
  36. wafformatter: wafformatter,
  37. }
  38. }
  39. type udpForWardingService struct {
  40. *Service
  41. udpForWardingRepository repository.UdpForWardingRepository
  42. required RequiredService
  43. parser ParserService
  44. crawler CrawlerService
  45. globalRep repository.GlobalLimitRepository
  46. hostRep repository.HostRepository
  47. wafformatter WafFormatterService
  48. }
  49. func (s *udpForWardingService) require(ctx context.Context,req v1.GlobalRequire) (v1.GlobalRequire, error) {
  50. res, err := s.wafformatter.require(ctx, req, "udp")
  51. if err != nil {
  52. return v1.GlobalRequire{}, err
  53. }
  54. return res, nil
  55. }
  56. func (s *udpForWardingService) GetUdpForWarding(ctx context.Context,req v1.GetForwardingRequest) (v1.UdpForwardingDataRequest, error) {
  57. var udpForWarding model.UdpForWarding
  58. var backend model.UdpForwardingRule
  59. var err error
  60. g, gCtx := errgroup.WithContext(ctx)
  61. g.Go(func() error {
  62. res, e := s.udpForWardingRepository.GetUdpForWarding(gCtx, int64(req.Id))
  63. if e != nil {
  64. return fmt.Errorf("GetUdpForWarding failed: %w", e)
  65. }
  66. if res != nil {
  67. udpForWarding = *res
  68. }
  69. return nil
  70. })
  71. g.Go(func() error {
  72. res, e := s.udpForWardingRepository.GetTcpForwardingByID(gCtx, req.Id)
  73. if e != nil {
  74. return fmt.Errorf("GetUdpForWardingByID failed: %w", e)
  75. }
  76. if res != nil {
  77. backend = *res
  78. }
  79. return nil
  80. })
  81. if err = g.Wait(); err != nil {
  82. return v1.UdpForwardingDataRequest{}, err
  83. }
  84. portInt, err := strconv.Atoi(udpForWarding.Port)
  85. if err != nil {
  86. return v1.UdpForwardingDataRequest{}, err
  87. }
  88. return v1.UdpForwardingDataRequest{
  89. Id: udpForWarding.Id,
  90. WafUdpId: udpForWarding.WafUdpId,
  91. Tag: udpForWarding.Tag,
  92. Port: portInt,
  93. WafGatewayGroupId: udpForWarding.WafGatewayGroupId,
  94. WafUdpLimitId: udpForWarding.UdpLimitRuleId,
  95. CcPacketCount: udpForWarding.CcPacketCount,
  96. CcPacketDuration: udpForWarding.CcPacketDuration,
  97. CcCount: udpForWarding.CcCount,
  98. CcDuration: udpForWarding.CcDuration,
  99. CcBlockCount: udpForWarding.CcBlockCount,
  100. CcBlockDuration: udpForWarding.CcBlockDuration,
  101. SessionTimeout: udpForWarding.SessionTimeout,
  102. BackendList: backend.BackendList,
  103. AllowIpList: backend.AllowIpList,
  104. DenyIpList: backend.DenyIpList,
  105. AccessRule: backend.AccessRule,
  106. Comment: udpForWarding.Comment,
  107. }, nil
  108. }
  109. func (s *udpForWardingService) buildWafFormData(req *v1.UdpForwardingDataSend, require v1.GlobalRequire) map[string]interface{} {
  110. return map[string]interface{}{
  111. "waf_udp_id": req.WafUdpId,
  112. "tag": require.Tag,
  113. "port": req.Port,
  114. "waf_gateway_group_id": require.WafGatewayGroupId,
  115. "waf_udp_limit_id": require.LimitRuleId,
  116. "cc_packet_count": req.CcPacketCount,
  117. "cc_packet_duration": req.CcPacketDuration,
  118. "cc_count": req.CcCount,
  119. "cc_duration": req.CcDuration,
  120. "cc_block_count": req.CcBlockCount,
  121. "cc_block_duration": req.CcBlockDuration,
  122. "session_timeout": req.SessionTimeout,
  123. "backend_list": req.BackendList,
  124. "allow_ip_list": req.AllowIpList,
  125. "deny_ip_list": req.DenyIpList,
  126. "access_rule": req.AccessRule,
  127. "comment": req.Comment,
  128. }
  129. }
  130. func (s *udpForWardingService) buildUdpForwardingModel(req *v1.UdpForwardingDataRequest, ruleId int, require v1.GlobalRequire) *model.UdpForWarding {
  131. return &model.UdpForWarding{
  132. HostId: require.HostId,
  133. WafUdpId: ruleId,
  134. Tag: require.Tag,
  135. Port: strconv.Itoa(req.Port),
  136. WafGatewayGroupId: require.WafGatewayGroupId,
  137. UdpLimitRuleId: require.LimitRuleId,
  138. CcPacketCount: req.CcPacketCount,
  139. CcPacketDuration: req.CcPacketDuration,
  140. CcPacketBlockCount: req.CcBlockCount,
  141. CcPacketBlockDuration: req.CcBlockDuration,
  142. CcCount: req.CcCount,
  143. CcDuration: req.CcDuration,
  144. CcBlockCount: req.CcBlockCount,
  145. CcBlockDuration: req.CcBlockDuration,
  146. SessionTimeout: req.SessionTimeout,
  147. Comment: req.Comment,
  148. }
  149. }
  150. func (s *udpForWardingService) buildUdpRuleModel(reqData *v1.UdpForwardingDataRequest, require v1.GlobalRequire, localDbId int) *model.UdpForwardingRule {
  151. return &model.UdpForwardingRule{
  152. Uid: require.Uid,
  153. HostId: require.HostId,
  154. UdpId: localDbId, // 关联到本地数据库的主记录 ID
  155. BackendList: reqData.BackendList,
  156. AllowIpList: reqData.AllowIpList,
  157. DenyIpList: reqData.DenyIpList,
  158. AccessRule: reqData.AccessRule,
  159. }
  160. }
  161. func (s *udpForWardingService) prepareWafData(ctx context.Context, req *v1.UdpForwardingRequest) (v1.GlobalRequire, map[string]interface{}, error) {
  162. // 1. 获取必要的全局信息
  163. require, err := s.require(ctx, v1.GlobalRequire{
  164. HostId: req.HostId,
  165. Uid: req.Uid,
  166. Comment: req.UdpForwardingData.Comment,
  167. })
  168. if err != nil {
  169. return v1.GlobalRequire{}, nil, err
  170. }
  171. if require.LimitRuleId == 0 || require.WafGatewayGroupId == 0 {
  172. return v1.GlobalRequire{}, nil, fmt.Errorf("请先配置实例")
  173. }
  174. // 2. 将字符串切片拼接成字符串,用于 WAF API
  175. backendListStr := strings.Join(req.UdpForwardingData.BackendList, "\n")
  176. allowIpListStr := strings.Join(req.UdpForwardingData.AllowIpList, "\n")
  177. denyIpListStr := strings.Join(req.UdpForwardingData.DenyIpList, "\n")
  178. // 3. 创建用于构建 WAF 表单的数据结构
  179. formDataBase := v1.UdpForwardingDataSend{
  180. Tag: require.Tag,
  181. WafUdpId: req.UdpForwardingData.WafUdpId,
  182. WafGatewayGroupId: require.WafGatewayGroupId,
  183. WafUdpLimitId: require.LimitRuleId,
  184. Port: req.UdpForwardingData.Port,
  185. CcPacketCount: req.UdpForwardingData.CcPacketCount,
  186. CcPacketDuration: req.UdpForwardingData.CcPacketDuration,
  187. CcCount: req.UdpForwardingData.CcCount,
  188. CcDuration: req.UdpForwardingData.CcDuration,
  189. CcBlockCount: req.UdpForwardingData.CcBlockCount,
  190. CcBlockDuration: req.UdpForwardingData.CcBlockDuration,
  191. SessionTimeout: req.UdpForwardingData.SessionTimeout,
  192. BackendList: backendListStr,
  193. AllowIpList: allowIpListStr,
  194. DenyIpList: denyIpListStr,
  195. AccessRule: req.UdpForwardingData.AccessRule,
  196. Comment: req.UdpForwardingData.Comment,
  197. }
  198. // 4. 构建 WAF 表单数据映射
  199. formData := s.buildWafFormData(&formDataBase, require)
  200. return require, formData, nil
  201. }
  202. func (s *udpForWardingService) AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error {
  203. require, formData, err := s.prepareWafData(ctx, req)
  204. if err != nil {
  205. return err
  206. }
  207. err = s.wafformatter.validateWafPortCount(ctx, require.HostId)
  208. if err != nil {
  209. return err
  210. }
  211. wafUdpId, err := s.wafformatter.sendFormData(ctx, "admin/info/waf_udp/new", "admin/new/waf_udp", formData)
  212. if err != nil {
  213. return err
  214. }
  215. udpModel := s.buildUdpForwardingModel(&req.UdpForwardingData, wafUdpId, require)
  216. id, err := s.udpForWardingRepository.AddUdpForwarding(ctx, udpModel)
  217. if err != nil {
  218. return err
  219. }
  220. udpRuleModel := s.buildUdpRuleModel(&req.UdpForwardingData, require, id)
  221. if _, err = s.udpForWardingRepository.AddUdpForwardingIps(ctx, *udpRuleModel); err != nil {
  222. return err
  223. }
  224. return nil
  225. }
  226. func (s *udpForWardingService) EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error {
  227. WafUdpId, err := s.udpForWardingRepository.GetUdpForwardingWafUdpIdById(ctx, req.UdpForwardingData.Id)
  228. if err != nil {
  229. return err
  230. }
  231. req.UdpForwardingData.WafUdpId = WafUdpId
  232. require, formData, err := s.prepareWafData(ctx, req)
  233. if err != nil {
  234. return err
  235. }
  236. _, err = s.wafformatter.sendFormData(ctx, "admin/info/waf_udp/edit?&__goadmin_edit_pk="+strconv.Itoa(req.UdpForwardingData.WafUdpId), "admin/edit/waf_udp", formData)
  237. if err != nil {
  238. return err
  239. }
  240. udpModel := s.buildUdpForwardingModel(&req.UdpForwardingData, req.UdpForwardingData.WafUdpId, require)
  241. udpModel.Id = req.UdpForwardingData.Id
  242. if err = s.udpForWardingRepository.EditUdpForwarding(ctx, udpModel); err != nil {
  243. return err
  244. }
  245. udpRuleModel := s.buildUdpRuleModel(&req.UdpForwardingData, require, req.UdpForwardingData.Id)
  246. if err = s.udpForWardingRepository.EditUdpForwardingIps(ctx, *udpRuleModel); err != nil {
  247. return err
  248. }
  249. return nil
  250. }
  251. func (s *udpForWardingService) DeleteUdpForwarding(ctx context.Context, Id int) error {
  252. wafUdpId, err := s.udpForWardingRepository.GetUdpForwardingWafUdpIdById(ctx, Id)
  253. if err != nil {
  254. return err
  255. }
  256. _, err = s.crawler.DeleteRule(ctx, wafUdpId, "admin/delete/waf_udp?page=1&__pageSize=10&__sort=waf_udp_id&__sort_type=desc")
  257. if err != nil {
  258. return err
  259. }
  260. if err = s.udpForWardingRepository.DeleteUdpForwarding(ctx, int64(Id)); err != nil {
  261. return err
  262. }
  263. return nil
  264. }