proxy.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // Copyright 2023 The frp Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package legacy
  15. import (
  16. "fmt"
  17. "reflect"
  18. "gopkg.in/ini.v1"
  19. "github.com/fatedier/frp/pkg/config/types"
  20. )
  21. type ProxyType string
  22. const (
  23. ProxyTypeTCP ProxyType = "tcp"
  24. ProxyTypeUDP ProxyType = "udp"
  25. ProxyTypeTCPMUX ProxyType = "tcpmux"
  26. ProxyTypeHTTP ProxyType = "http"
  27. ProxyTypeHTTPS ProxyType = "https"
  28. ProxyTypeSTCP ProxyType = "stcp"
  29. ProxyTypeXTCP ProxyType = "xtcp"
  30. ProxyTypeSUDP ProxyType = "sudp"
  31. )
  32. // Proxy
  33. var (
  34. proxyConfTypeMap = map[ProxyType]reflect.Type{
  35. ProxyTypeTCP: reflect.TypeOf(TCPProxyConf{}),
  36. ProxyTypeUDP: reflect.TypeOf(UDPProxyConf{}),
  37. ProxyTypeTCPMUX: reflect.TypeOf(TCPMuxProxyConf{}),
  38. ProxyTypeHTTP: reflect.TypeOf(HTTPProxyConf{}),
  39. ProxyTypeHTTPS: reflect.TypeOf(HTTPSProxyConf{}),
  40. ProxyTypeSTCP: reflect.TypeOf(STCPProxyConf{}),
  41. ProxyTypeXTCP: reflect.TypeOf(XTCPProxyConf{}),
  42. ProxyTypeSUDP: reflect.TypeOf(SUDPProxyConf{}),
  43. }
  44. )
  45. type ProxyConf interface {
  46. // GetBaseConfig returns the BaseProxyConf for this config.
  47. GetBaseConfig() *BaseProxyConf
  48. // UnmarshalFromIni unmarshals a ini.Section into this config. This function
  49. // will be called on the frpc side.
  50. UnmarshalFromIni(string, string, *ini.Section) error
  51. }
  52. func NewConfByType(proxyType ProxyType) ProxyConf {
  53. v, ok := proxyConfTypeMap[proxyType]
  54. if !ok {
  55. return nil
  56. }
  57. cfg := reflect.New(v).Interface().(ProxyConf)
  58. return cfg
  59. }
  60. // Proxy Conf Loader
  61. // DefaultProxyConf creates a empty ProxyConf object by proxyType.
  62. // If proxyType doesn't exist, return nil.
  63. func DefaultProxyConf(proxyType ProxyType) ProxyConf {
  64. return NewConfByType(proxyType)
  65. }
  66. // Proxy loaded from ini
  67. func NewProxyConfFromIni(prefix, name string, section *ini.Section) (ProxyConf, error) {
  68. // section.Key: if key not exists, section will set it with default value.
  69. proxyType := ProxyType(section.Key("type").String())
  70. if proxyType == "" {
  71. proxyType = ProxyTypeTCP
  72. }
  73. conf := DefaultProxyConf(proxyType)
  74. if conf == nil {
  75. return nil, fmt.Errorf("invalid type [%s]", proxyType)
  76. }
  77. if err := conf.UnmarshalFromIni(prefix, name, section); err != nil {
  78. return nil, err
  79. }
  80. return conf, nil
  81. }
  82. // LocalSvrConf configures what location the client will to, or what
  83. // plugin will be used.
  84. type LocalSvrConf struct {
  85. // LocalIP specifies the IP address or host name to to.
  86. LocalIP string `ini:"local_ip" json:"local_ip"`
  87. // LocalPort specifies the port to to.
  88. LocalPort int `ini:"local_port" json:"local_port"`
  89. // Plugin specifies what plugin should be used for ng. If this value
  90. // is set, the LocalIp and LocalPort values will be ignored. By default,
  91. // this value is "".
  92. Plugin string `ini:"plugin" json:"plugin"`
  93. // PluginParams specify parameters to be passed to the plugin, if one is
  94. // being used. By default, this value is an empty map.
  95. PluginParams map[string]string `ini:"-"`
  96. }
  97. // HealthCheckConf configures health checking. This can be useful for load
  98. // balancing purposes to detect and remove proxies to failing services.
  99. type HealthCheckConf struct {
  100. // HealthCheckType specifies what protocol to use for health checking.
  101. // Valid values include "tcp", "http", and "". If this value is "", health
  102. // checking will not be performed. By default, this value is "".
  103. //
  104. // If the type is "tcp", a connection will be attempted to the target
  105. // server. If a connection cannot be established, the health check fails.
  106. //
  107. // If the type is "http", a GET request will be made to the endpoint
  108. // specified by HealthCheckURL. If the response is not a 200, the health
  109. // check fails.
  110. HealthCheckType string `ini:"health_check_type" json:"health_check_type"` // tcp | http
  111. // HealthCheckTimeoutS specifies the number of seconds to wait for a health
  112. // check attempt to connect. If the timeout is reached, this counts as a
  113. // health check failure. By default, this value is 3.
  114. HealthCheckTimeoutS int `ini:"health_check_timeout_s" json:"health_check_timeout_s"`
  115. // HealthCheckMaxFailed specifies the number of allowed failures before the
  116. // is stopped. By default, this value is 1.
  117. HealthCheckMaxFailed int `ini:"health_check_max_failed" json:"health_check_max_failed"`
  118. // HealthCheckIntervalS specifies the time in seconds between health
  119. // checks. By default, this value is 10.
  120. HealthCheckIntervalS int `ini:"health_check_interval_s" json:"health_check_interval_s"`
  121. // HealthCheckURL specifies the address to send health checks to if the
  122. // health check type is "http".
  123. HealthCheckURL string `ini:"health_check_url" json:"health_check_url"`
  124. // HealthCheckAddr specifies the address to connect to if the health check
  125. // type is "tcp".
  126. HealthCheckAddr string `ini:"-"`
  127. }
  128. // BaseProxyConf provides configuration info that is common to all types.
  129. type BaseProxyConf struct {
  130. // ProxyName is the name of this
  131. ProxyName string `ini:"name" json:"name"`
  132. // ProxyType specifies the type of this Valid values include "tcp",
  133. // "udp", "http", "https", "stcp", and "xtcp". By default, this value is
  134. // "tcp".
  135. ProxyType string `ini:"type" json:"type"`
  136. // UseEncryption controls whether or not communication with the server will
  137. // be encrypted. Encryption is done using the tokens supplied in the server
  138. // and client configuration. By default, this value is false.
  139. UseEncryption bool `ini:"use_encryption" json:"use_encryption"`
  140. // UseCompression controls whether or not communication with the server
  141. // will be compressed. By default, this value is false.
  142. UseCompression bool `ini:"use_compression" json:"use_compression"`
  143. // Group specifies which group the is a part of. The server will use
  144. // this information to load balance proxies in the same group. If the value
  145. // is "", this will not be in a group. By default, this value is "".
  146. Group string `ini:"group" json:"group"`
  147. // GroupKey specifies a group key, which should be the same among proxies
  148. // of the same group. By default, this value is "".
  149. GroupKey string `ini:"group_key" json:"group_key"`
  150. // ProxyProtocolVersion specifies which protocol version to use. Valid
  151. // values include "v1", "v2", and "". If the value is "", a protocol
  152. // version will be automatically selected. By default, this value is "".
  153. ProxyProtocolVersion string `ini:"proxy_protocol_version" json:"proxy_protocol_version"`
  154. // BandwidthLimit limit the bandwidth
  155. // 0 means no limit
  156. BandwidthLimit types.BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"`
  157. // BandwidthLimitMode specifies whether to limit the bandwidth on the
  158. // client or server side. Valid values include "client" and "server".
  159. // By default, this value is "client".
  160. BandwidthLimitMode string `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"`
  161. // meta info for each proxy
  162. Metas map[string]string `ini:"-" json:"metas"`
  163. LocalSvrConf `ini:",extends"`
  164. HealthCheckConf `ini:",extends"`
  165. }
  166. // Base
  167. func (cfg *BaseProxyConf) GetBaseConfig() *BaseProxyConf {
  168. return cfg
  169. }
  170. // BaseProxyConf apply custom logic changes.
  171. func (cfg *BaseProxyConf) decorate(_ string, name string, section *ini.Section) error {
  172. cfg.ProxyName = name
  173. // metas_xxx
  174. cfg.Metas = GetMapWithoutPrefix(section.KeysHash(), "meta_")
  175. // bandwidth_limit
  176. if bandwidth, err := section.GetKey("bandwidth_limit"); err == nil {
  177. cfg.BandwidthLimit, err = types.NewBandwidthQuantity(bandwidth.String())
  178. if err != nil {
  179. return err
  180. }
  181. }
  182. // plugin_xxx
  183. cfg.LocalSvrConf.PluginParams = GetMapByPrefix(section.KeysHash(), "plugin_")
  184. return nil
  185. }
  186. type DomainConf struct {
  187. CustomDomains []string `ini:"custom_domains" json:"custom_domains"`
  188. SubDomain string `ini:"subdomain" json:"subdomain"`
  189. }
  190. type RoleServerCommonConf struct {
  191. Role string `ini:"role" json:"role"`
  192. Sk string `ini:"sk" json:"sk"`
  193. AllowUsers []string `ini:"allow_users" json:"allow_users"`
  194. }
  195. // HTTP
  196. type HTTPProxyConf struct {
  197. BaseProxyConf `ini:",extends"`
  198. DomainConf `ini:",extends"`
  199. Locations []string `ini:"locations" json:"locations"`
  200. HTTPUser string `ini:"http_user" json:"http_user"`
  201. HTTPPwd string `ini:"http_pwd" json:"http_pwd"`
  202. HostHeaderRewrite string `ini:"host_header_rewrite" json:"host_header_rewrite"`
  203. Headers map[string]string `ini:"-" json:"headers"`
  204. RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"`
  205. }
  206. func (cfg *HTTPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  207. err := preUnmarshalFromIni(cfg, prefix, name, section)
  208. if err != nil {
  209. return err
  210. }
  211. // Add custom logic unmarshal if exists
  212. cfg.Headers = GetMapWithoutPrefix(section.KeysHash(), "header_")
  213. return nil
  214. }
  215. // HTTPS
  216. type HTTPSProxyConf struct {
  217. BaseProxyConf `ini:",extends"`
  218. DomainConf `ini:",extends"`
  219. }
  220. func (cfg *HTTPSProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  221. err := preUnmarshalFromIni(cfg, prefix, name, section)
  222. if err != nil {
  223. return err
  224. }
  225. // Add custom logic unmarshal if exists
  226. return nil
  227. }
  228. // TCP
  229. type TCPProxyConf struct {
  230. BaseProxyConf `ini:",extends"`
  231. RemotePort int `ini:"remote_port" json:"remote_port"`
  232. }
  233. func (cfg *TCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  234. err := preUnmarshalFromIni(cfg, prefix, name, section)
  235. if err != nil {
  236. return err
  237. }
  238. // Add custom logic unmarshal if exists
  239. return nil
  240. }
  241. // UDP
  242. type UDPProxyConf struct {
  243. BaseProxyConf `ini:",extends"`
  244. RemotePort int `ini:"remote_port" json:"remote_port"`
  245. }
  246. func (cfg *UDPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  247. err := preUnmarshalFromIni(cfg, prefix, name, section)
  248. if err != nil {
  249. return err
  250. }
  251. // Add custom logic unmarshal if exists
  252. return nil
  253. }
  254. // TCPMux
  255. type TCPMuxProxyConf struct {
  256. BaseProxyConf `ini:",extends"`
  257. DomainConf `ini:",extends"`
  258. HTTPUser string `ini:"http_user" json:"http_user,omitempty"`
  259. HTTPPwd string `ini:"http_pwd" json:"http_pwd,omitempty"`
  260. RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"`
  261. Multiplexer string `ini:"multiplexer"`
  262. }
  263. func (cfg *TCPMuxProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  264. err := preUnmarshalFromIni(cfg, prefix, name, section)
  265. if err != nil {
  266. return err
  267. }
  268. // Add custom logic unmarshal if exists
  269. return nil
  270. }
  271. // STCP
  272. type STCPProxyConf struct {
  273. BaseProxyConf `ini:",extends"`
  274. RoleServerCommonConf `ini:",extends"`
  275. }
  276. func (cfg *STCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  277. err := preUnmarshalFromIni(cfg, prefix, name, section)
  278. if err != nil {
  279. return err
  280. }
  281. // Add custom logic unmarshal if exists
  282. if cfg.Role == "" {
  283. cfg.Role = "server"
  284. }
  285. return nil
  286. }
  287. // XTCP
  288. type XTCPProxyConf struct {
  289. BaseProxyConf `ini:",extends"`
  290. RoleServerCommonConf `ini:",extends"`
  291. }
  292. func (cfg *XTCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  293. err := preUnmarshalFromIni(cfg, prefix, name, section)
  294. if err != nil {
  295. return err
  296. }
  297. // Add custom logic unmarshal if exists
  298. if cfg.Role == "" {
  299. cfg.Role = "server"
  300. }
  301. return nil
  302. }
  303. // SUDP
  304. type SUDPProxyConf struct {
  305. BaseProxyConf `ini:",extends"`
  306. RoleServerCommonConf `ini:",extends"`
  307. }
  308. func (cfg *SUDPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error {
  309. err := preUnmarshalFromIni(cfg, prefix, name, section)
  310. if err != nil {
  311. return err
  312. }
  313. // Add custom logic unmarshal if exists
  314. return nil
  315. }
  316. func preUnmarshalFromIni(cfg ProxyConf, prefix string, name string, section *ini.Section) error {
  317. err := section.MapTo(cfg)
  318. if err != nil {
  319. return err
  320. }
  321. err = cfg.GetBaseConfig().decorate(prefix, name, section)
  322. if err != nil {
  323. return err
  324. }
  325. return nil
  326. }