tcpprox.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package tcpprox
  2. import (
  3. "errors"
  4. "net"
  5. "sync"
  6. "sync/atomic"
  7. "github.com/google/uuid"
  8. "imuslab.com/zoraxy/mod/database"
  9. )
  10. /*
  11. TCP Proxy
  12. Forward port from one port to another
  13. Also accept active connection and passive
  14. connection
  15. */
  16. const (
  17. ProxyMode_Listen = 0
  18. ProxyMode_Transport = 1
  19. ProxyMode_Starter = 2
  20. ProxyMode_UDP = 3
  21. )
  22. type ProxyRelayOptions struct {
  23. Name string
  24. PortA string
  25. PortB string
  26. Timeout int
  27. Mode int
  28. }
  29. type ProxyRelayConfig struct {
  30. UUID string //A UUIDv4 representing this config
  31. Name string //Name of the config
  32. Running bool //If the service is running
  33. PortA string //Ports A (config depends on mode)
  34. PortB string //Ports B (config depends on mode)
  35. Mode int //Operation Mode
  36. Timeout int //Timeout for connection in sec
  37. stopChan chan bool //Stop channel to stop the listener
  38. aTobAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from A to B
  39. bToaAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from B to A
  40. udpClientMap sync.Map //map storing the UDP client-server connections
  41. parent *Manager `json:"-"`
  42. }
  43. type Options struct {
  44. Database *database.Database
  45. DefaultTimeout int
  46. AccessControlHandler func(net.Conn) bool
  47. }
  48. type Manager struct {
  49. //Config and stores
  50. Options *Options
  51. Configs []*ProxyRelayConfig
  52. //Realtime Statistics
  53. Connections int //currently connected connect counts
  54. }
  55. func NewTCProxy(options *Options) *Manager {
  56. options.Database.NewTable("tcprox")
  57. //Load relay configs from db
  58. previousRules := []*ProxyRelayConfig{}
  59. if options.Database.KeyExists("tcprox", "rules") {
  60. options.Database.Read("tcprox", "rules", &previousRules)
  61. }
  62. //Check if the AccessControlHandler is empty. If yes, set it to always allow access
  63. if options.AccessControlHandler == nil {
  64. options.AccessControlHandler = func(conn net.Conn) bool {
  65. //Always allow access
  66. return true
  67. }
  68. }
  69. //Create a new proxy manager for TCP
  70. thisManager := Manager{
  71. Options: options,
  72. Connections: 0,
  73. }
  74. //Inject manager into the rules
  75. for _, rule := range previousRules {
  76. rule.parent = &thisManager
  77. }
  78. thisManager.Configs = previousRules
  79. return &thisManager
  80. }
  81. func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
  82. //Generate two zero value for atomic int64
  83. aAcc := atomic.Int64{}
  84. bAcc := atomic.Int64{}
  85. aAcc.Store(0)
  86. bAcc.Store(0)
  87. //Generate a new config from options
  88. configUUID := uuid.New().String()
  89. thisConfig := ProxyRelayConfig{
  90. UUID: configUUID,
  91. Name: config.Name,
  92. Running: false,
  93. PortA: config.PortA,
  94. PortB: config.PortB,
  95. Mode: config.Mode,
  96. Timeout: config.Timeout,
  97. stopChan: nil,
  98. aTobAccumulatedByteTransfer: aAcc,
  99. bToaAccumulatedByteTransfer: bAcc,
  100. udpClientMap: sync.Map{},
  101. parent: m,
  102. }
  103. m.Configs = append(m.Configs, &thisConfig)
  104. m.SaveConfigToDatabase()
  105. return configUUID
  106. }
  107. func (m *Manager) GetConfigByUUID(configUUID string) (*ProxyRelayConfig, error) {
  108. // Find and return the config with the specified UUID
  109. for _, config := range m.Configs {
  110. if config.UUID == configUUID {
  111. return config, nil
  112. }
  113. }
  114. return nil, errors.New("config not found")
  115. }
  116. // Edit the config based on config UUID, leave empty for unchange fields
  117. func (m *Manager) EditConfig(configUUID string, newName string, newPortA string, newPortB string, newMode int, newTimeout int) error {
  118. // Find the config with the specified UUID
  119. foundConfig, err := m.GetConfigByUUID(configUUID)
  120. if err != nil {
  121. return err
  122. }
  123. // Validate and update the fields
  124. if newName != "" {
  125. foundConfig.Name = newName
  126. }
  127. if newPortA != "" {
  128. foundConfig.PortA = newPortA
  129. }
  130. if newPortB != "" {
  131. foundConfig.PortB = newPortB
  132. }
  133. if newMode != -1 {
  134. if newMode > 2 || newMode < 0 {
  135. return errors.New("invalid mode given")
  136. }
  137. foundConfig.Mode = newMode
  138. }
  139. if newTimeout != -1 {
  140. if newTimeout < 0 {
  141. return errors.New("invalid timeout value given")
  142. }
  143. foundConfig.Timeout = newTimeout
  144. }
  145. /*
  146. err = foundConfig.ValidateConfigs()
  147. if err != nil {
  148. return err
  149. }
  150. */
  151. m.SaveConfigToDatabase()
  152. return nil
  153. }
  154. func (m *Manager) RemoveConfig(configUUID string) error {
  155. // Find and remove the config with the specified UUID
  156. for i, config := range m.Configs {
  157. if config.UUID == configUUID {
  158. m.Configs = append(m.Configs[:i], m.Configs[i+1:]...)
  159. m.SaveConfigToDatabase()
  160. return nil
  161. }
  162. }
  163. return errors.New("config not found")
  164. }
  165. func (m *Manager) SaveConfigToDatabase() {
  166. m.Options.Database.Write("tcprox", "rules", m.Configs)
  167. }