Skip to content

反向代理

反向代理是代理服务的一种。服务器根据客户端的请求,从其关系的一组或多组后端服务器(如Web服务器)上获取资源,然后再将这些资源返回给客户端,客户端只会得知反向代理的IP地址,而不知道在代理服务器后面的服务器集群的存在。

GOST中的端口转发服务也可以被当作是一种功能受限的反向代理,因其只能转发到固定的一个或一组后端服务。

反向代理是端口转发服务的一个扩展,其依托于端口转发功能,并通过嗅探转发的数据来获取特定协议(目前支持HTTP/HTTPS)中的目标主机信息。

关于反向代理更详细的说明可以参考这篇博文

本地端口转发

services:
- name: https
  addr: :443
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: google
      addr: www.google.com:443
      filter:
        host: www.google.com
    - name: github
      addr: github.com:443
      filter:
        host: "*.github.com"
        # host: .github.com
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
    - name: example-org
      addr: example.org:80
      filter:
        host: example.org

通过sniffing选项来开启流量嗅探,并在forwarder.nodes中通过filter.host选项可以对每一个节点设置(虚拟)主机名过滤。

当开启流量嗅探后,转发服务会通过客户端的请求数据获取访问的目标主机,再通过转发器(forwarder)中的节点设置的虚拟主机名(filter.host)找到最终转发的目标地址(addr)。

Reverse Proxy - TCP Port Forwarding

filter.host也支持通配符,*.example.com或.example.com匹配example.com及其子域名:abc.example.com,def.abc.example.com等。

此时可以将对应的域名解析到本地通过反向代理来访问:

curl --resolve www.google.com:443:127.0.0.1 https://www.google.com
curl --resolve example.com:80:127.0.0.1 http://example.com

远程端口转发

远程端口转发服务同样也可以对流量进行嗅探。

services:
- name: https
  addr: :443
  handler:
    type: rtcp
    metadata:
      sniffing: true
  listener:
    type: rtcp
    chain: chain-0
  forwarder:
    nodes:
    - name: local-0
      addr: 192.168.1.1:443
      filter:
        host: srv-0.local
    - name: local-1
      addr: 192.168.1.2:443
      filter:
        host: srv-1.local
    - name: fallback
      addr: 192.168.2.1:443
- name: http
  addr: :80
  handler:
    type: rtcp
    metadata:
      sniffing: true
  listener:
    type: rtcp
    chain: chain-0
  forwarder:
    nodes:
    - name: local-0
      addr: 192.168.1.1:80
      filter:
        host: srv-0.local
    - name: local-1
      addr: 192.168.1.2:80
      filter:
        host: srv-1.local
chains:
- name: chain-0
  hops:
  - name: hop-0
    nodes:
    - name: node-0
      addr: SERVER_IP:8443 
      connector:
        type: relay
      dialer:
        type: wss

通过sniffing选项来开启流量嗅探,并在forwarder.nodes中通过filter.host选项对每一个节点设置(虚拟)主机名过滤。

Reverse Proxy - Remote TCP Port Forwarding

此时可以将对应的域名解析到服务器地址通过反向代理来访问内网服务:

curl --resolve srv-0.local:443:SERVER_IP https://srv-0.local
curl --resolve srv-1.local:80:SERVER_IP http://srv-1.local

如果访问的目标主机没有与转发器中的节点设定的主机名匹配上,当存在没有设置主机名的节点,则会在这些节点中选择一个使用。

curl --resolve srv-2.local:443:SERVER_IP https://srv-2.local

由于srv-2.local没有匹配到节点,因此会被转发到fallback节点(192.168.2.1:443)。

URL路径路由

通过filter.path选项为节点指定路径前缀。当嗅探到HTTP流量后,会使用URL路径通过最长前缀匹配模式来选择节点。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: target-0
      addr: 192.168.1.1:80
      filter:
        path: /
    - name: target-1
      addr: 192.168.1.2:80
      filter:
        path: /test

HTTP请求设置

当嗅探到HTTP流量时,可以在目标节点上通过forwarder.nodes.http选项对HTTP的请求信息进行设置,包括Host头重写,自定义头部信息,开启Basic Auth,URL路径重写。对本地和远程端口转发均适用。

重写Host头

通过设置http.host选项可以重写原始请求头中的Host。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        host: test.example.com
    - name: example-org
      addr: example.org:80
      filter:
        host: example.org
      http:
        host: test.example.org:80
curl --resolve example.com:80:127.0.0.1 http://example.com

当请求http://example.com时,最终发送给example.com:80的HTTP请求头中Host为test.example.com。

自定义请求头

通过设置http.header选项可以自定义请求头部信息,如果所设置的头部字段已存在则会被覆盖。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        header:
          User-Agent: gost/3.0.0
          foo: bar
          bar: 123
        # host: test.example.com
    - name: example-org
      addr: example.org:80
      filter:
        host: example.org
      http:
        header:
          User-Agent: curl/7.81.0
          foo: bar
          bar: baz
        # host: test.example.org:80

当请求http://example.com时,最终发送给example.com:80的HTTP请求头中将会添加User-AgentFooBar三个字段。

自定义响应头

通过设置http.responseHeader选项可以自定义响应头部信息,如果所设置的头部字段已存在则会被覆盖。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        responseHeader:
          foo: bar
          bar: 123

当请求http://example.com时,最终来自example.com:80的HTTP响应头中将会添加FooBar两个字段。

Basic Authentication

通过设置http.auth选项为目标节点启用HTTP基本认证功能。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        auth:
          username: user
          password: pass

当直接请求http://example.com时,会返回HTTP状态码401要求认证。

URL路径重写

通过设置http.rewrite选项定义URL路径重写规则。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        rewrite:
        - match: /api/login
          replacement: /user/login
        - match: /api/(.*)
          replacement: /$1
rewrite.match (string)
指定路径匹配模式(支持正则表达式)。
rewrite.replacement (string)
设置路径替换内容。

http://example.com/api/login会被重写为http://example.com/user/login

http://example.com/api/logout会被重写为http://example.com/logout

重写响应体

通过设置http.rewriteBody选项定义响应体重写规则。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: example.com
      http:
        rewriteBody:
        - match: foo
          replacement: bar
          type: text/html
rewriteBody.match (string)
指定内容匹配模式(支持正则表达式)。
rewriteBody.replacement (string)
设置替换内容。
rewriteBody.type (string, default=text/html)
设置响应的内容类型,与Content-Type匹配。可以是,分割的多个类型或*代表匹配所有类型。

TLS请求设置

如果转发的目标节点启用了TLS,可以通过设置forwarder.nodes.tls来建立TLS连接。

services:
- name: http
  addr: :80
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:443
      filter:
        host: example.com
      tls:
        secure: true
        serverName: example.com
        options:
          minVersion: VersionTLS12
          maxVersion: VersionTLS13
          cipherSuites:
          - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
tls.secure (bool, default=false)
是否开启服务器证书和域名校验。
tls.serverName (string)
secure设置为true,则需要通过此参数指定服务器域名用于域名校验。
tls.options.minVersion (string)
TLS最小版本,可选值VersionTLS10VersionTLS11VersionTLS12VersionTLS13
tls.options.maxVersion (string)
TLS最大版本,可选值VersionTLS10VersionTLS11VersionTLS12VersionTLS13
tls.options.cipherSuites (list)
加密套件,可选值参考Cipher Suites

特定应用转发

本地和远程端口转发服务也支持对特定的应用流量嗅探。目前支持的应用协议有:

  • http - HTTP流量数据。
  • tls - TLS流量数据。
  • ssh - SSH数据。

在forwarder.nodes中通过filter.protocol选项指定节点协议类型,当嗅探到对应类型流量则会转发到此节点。

services:
- name: https
  addr: :443
  handler:
    type: tcp
    metadata:
      sniffing: true
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: http-server
      addr: example.com:80
      filter:
        host: example.com
        protocol: http
    - name: https-server
      addr: example.com:443
      filter:
        host: example.com
        protocol: tls
    - name: ssh-server
      addr: example.com:22
      filter:
        protocol: ssh
services:
- name: https
  addr: :443
  handler:
    type: rtcp
    metadata:
      sniffing: true
  listener:
    type: rtcp
    chain: chain-0
  forwarder:
    nodes:
    - name: local-http
      addr: 192.168.2.1:80
      filter:
        protocol: http
    - name: local-https
      addr: 192.168.2.1:443
      filter:
        protocol: tls
    - name: local-ssh
      addr: 192.168.2.1:22
      filter:
        protocol: ssh
chains:
- name: chain-0
  hops:
  - name: hop-0
    nodes:
    - name: node-0
      addr: SERVER_IP:8443 
      connector:
        type: relay
      dialer:
        type: wss

转发通道

除了原始TCP数据通道可以用来作为端口转发,其他数据通道也可以作为端口转发服务。

TLS转发通道

HTTPS-to-HTTP反向代理。

TLS转发通道可以动态的给后端HTTP服务添加TLS支持。

services:
- name: https
  addr: :443
  handler:
    type: forward
    metadata:
      sniffing: true
  listener:
    type: tls
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: .example.com
    - name: example-org
      addr: example.org:80
      filter:
        host: .example.org
curl -k --resolve example.com:443:127.0.0.1 https://example.com

HTTP3转发通道

HTTP3-to-HTTP反向代理。

HTTP3转发通道可以动态的给后端HTTP服务添加HTTP/3支持。

services:
- name: http3
  addr: :443
  handler:
    type: http3
  listener:
    type: http3
  forwarder:
    nodes:
    - name: example-com
      addr: example.com:80
      filter:
        host: .example.com
    - name: example-org
      addr: example.org:80
      filter:
        host: .example.org
curl -k --http3 --resolve example.com:443:127.0.0.1 https://example.com

Comments