1
0

tcpprox.go 4.7 KB

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