#port #tcp #forward #tcp-server #proxy #tunnel #ip-address

app tobaru

使用Rust编写的端口转发CLI工具,具有允许列表、TLS SNI和ALPN路由、轮询转发(负载均衡)、IP到目标映射和iptables支持

5个版本 (3个破坏性更新)

0.9.0 2023年8月23日
0.7.1 2022年3月13日
0.7.0 2022年3月12日
0.5.0 2022年1月23日
0.4.0 2021年12月12日

#1530 in 网络编程

每月24次下载

MIT许可证

125KB
3K SLoC

tobaru

使用Rust编写的端口转发工具,具有以下高级功能:

  • 多个目标地址:根据IP和TLS SNI/ALPN转发到不同的目标地址
    • IPv4/IPv6允许列表:仅转发来自已知IP范围的连接
    • 支持TLS:
      • 在单个端口上允许TLS和非TLS客户端
      • 连接到TLS和非TLS端点
  • 热重载:更新后的配置会自动重新加载
  • iptables支持:自动配置iptables以丢弃来自不允许范围的包
  • IP组:可以在不同的服务器配置中重复使用的IP名称组

以下是一个快速示例

- address: 0.0.0.0:443
  transport: tcp
  targets:

    # target 1: non-TLS clients from any IP will be forwarded to 127.0.0.1:2999.
    - location: 127.0.0.1:2999
      allowlist: 0.0.0.0/0

    # target 2: TLS clients from specified IP masks asking for SNI example.com and
    # ALPN protocol http/1.1 will be forwarded to a listening UNIX domain socket.
    - location: /run/service.sock
      server_tls:
        cert: cert.pem
        key: key.pem
        sni_hostnames: example.com
        alpn_protocols: http/1.1
      allowlist:
        - 1.2.3.4
        - 2.3.0.0/16

    # target 3: TLS clients from ip 1.2.3.4 asking for SNI example.com or test.com,
    # and any other ALPN protocol, or no ALPN negotiation, will be forwarded here.
    - location: 127.0.0.1:3001
      server_tls:
        cert: cert.pem
        key: key.pem
        sni_hostnames:
          - example.com
          - test.com
        alpn_protocols:
          - any
          - none
      allowlist: 1.2.3.4

安装

GitHub发行版上提供了预编译的二进制文件,适用于x86_64和Apple aarch64。

否则,如果您在系统上安装了较新的Rust和cargo,可以使用cargo安装tobaru。

cargo install tobaru

用法

USAGE:

    tobaru [OPTIONS] <CONFIG PATH or CONFIG URL> [CONFIG PATH or CONFIG URL] [..]

OPTIONS:

    -t, --threads NUM
        Number of worker threads, defaults to an estimated amount of parallelism.

    --clear-iptables-all
        Clear all tobaru-created rules from iptables and exit immediately.

    --clear-iptables-matching
        Clear tobaru-created rules for the addresses specified in the specified
        config files and exit immediately.

    -h, --help
        Show this help screen.

IPTABLES PERMISSIONS:

    To run iptable commands, this binary needs to have CAP_NET_RAW and CAP_NET_ADMIN
    permissions, or else be invoked by root.

EXAMPLES:

    tobaru -t 1 config1.yaml config2.yaml

        Run servers from configs in config1.yaml and config2.yaml on a single thread.

    tobaru tcp://127.0.0.1:1000?target=127.0.0.1:2000

        Run a tcp server on 127.0.0.1 port 1000, forwarding to 127.0.0.1 port 2000.

    sudo tobaru --clear-iptables-matching config1.yaml

        Clear iptable configs only for the config addresses in config1.yaml.

基于URL的配置

可以使用配置URL格式执行简单的TCP转发

tcp://<bind ip>:<bind port>?target=<target ip>:<target port>

可以使用target-path键将TCP转发到UNIX域套接字

tcp://<bind ip>:<bind port>?target-path=<unix domain socket path>

基于文件的配置

配置文件格式为YAML或JSON。tobaru期望读取一个对象数组,其中每个对象都是一个服务器配置或一个IP掩码组。

服务器对象配置

address:要监听的地址。

transport:传输协议,字符串为tcpudp

use_iptables(《可选》默认值:false):是否启用iptables支持。

  • 在目标中指定的允许列表中的IP掩码会被添加到iptables中,未指定的IP掩码会被拒绝。

targets(或target):指定转发到的目标位置对象或目标位置对象数组。

tcp_nodelay(《可选》默认值:true):指定是否在已接受的套接字上禁用Nagle算法。

  • 仅在 transporttcp 时才接受。

目标对象配置(TCP传输)

locations(或 location):单个TCP位置,或TCP位置的数组。

  • 当提供多个位置的数组时,连接将以轮询方式转发。

allowlist:单个IP掩码或IP组名称,或IP掩码或IP组名称的数组。

tcp_nodelay可选,默认:true):指定是否在目标连接套接字上禁用Nagle算法。

server_tls可选,默认:null):服务器TLS对象。当非空时,仅接受此目标的TLS连接。对象键为

  • cert:TLS证书的文件路径。
  • key:TLS私钥的文件路径。
  • optional可选,默认:false):指定TLS是否可选。当为真时,这意味着还将接受并转发非TLS流。
  • sni_hostnames可选,默认:any, none):SNI主机名,或SNI主机名的数组,具有特殊关键字
    • any:接受任何提供的SNI主机名。
    • none:接受没有SNI协商的手shake。
  • alpn_protocols可选:默认:any, none):接受的ALPN协议,或支持的ALPN协议的数组,具有特殊关键字
    • any:接受任何提供的ALPN协议。
    • none:接受没有ALPN协议选择的handshake。

TCP位置配置

TCP位置可以指定为

  • 地址字符串。例如:127.0.0.1:1234

  • UNIX域套接字路径。例如:/path/to/something.sock

  • 具有以下键的对象

    address:地址字符串。

    • 只能指定 addresspath 中的一个。

    path:UNIX域套接字路径。

    • 只能指定 addresspath 中的一个。

    client_tls可选,默认:false):指定是否在连接到此位置时处理TLS。支持的值是

    • true:启用客户端TLS处理,并进行证书验证。
    • no-verify:启用客户端TLS处理,不进行证书验证。
    • false:禁用客户端TLS处理。

目标对象配置(UDP传输)

addresses(或 address):单个地址字符串,或 host:port 地址字符串的数组

allowlist:单个IP掩码或IP组名称,或IP掩码或IP组名称的数组。

association_timeout_secs可选,默认:200):不活跃的UDP关联超时前的秒数。

IP组对象配置

group:IP组名称

ip_masks(或 ip_mask):单个IP掩码或IP组名称,或IP掩码或IP组名称的数组。

自动添加一个默认的IP组,名称为 all,IP掩码为 0.0.0.0/0

示例

TCP到TCP转发,允许所有IP

- address: 0.0.0.0:8080
  transport: tcp
  target:
    location: 192.168.8.1:80
    allowlist: all

或使用多个服务器和特定的IP范围

# Forward port 8080 to 192.168.8.1 port 80 for some IP ranges.
- address: 0.0.0.0:8080
  transport: tcp
  targets:
    - address: 192.168.8.1:80
      allowlist:
        # Some local IP ranges..
        - 192.168.9.0/24
        - 192.168.10.0/24

        # .. and some specific IPs
        - 12.34.56.78
        - fa71::e09d:92fa:beef:1234

    - address: 192.168.8.2:80
      allowlist:
        - 192.168.11.0/24
        - 192.168.12.0/24

# Forward port 8081 to 192.168.8.2 port 80 for all IPs.
- address: 0.0.0.0:8081
  transport: udp
  target:
    - address: 192.168.8.3:80
      allowlist:
        - all

来自未在 allowlist 中指定的地址的连接将被丢弃(如果 iptables 设置为 true),或者在接收后立即关闭。

轮询转发

{
  // Listen on all interfaces, port 8080.
  "bindAddress": "0.0.0.0:8080",
  "transport": "tcp",
  "target": {
    // Round-robin forward to different addresses.
    "addresses": [
      "192.168.8.1:80",
      "192.168.8.2:80",
      "192.168.8.3:80",
      "192.168.8.4:80"
    ],
    "allowlist": "all"
  }
}

基于IP地址的多重目的地

{
  // Listen on port 8080
  "bindAddress": "0.0.0.0:8080",
  "transport": "tcp",
  "targets": [
    // Forward some IP ranges to 192.168.8.1 port 80.
    {
      "address": "192.168.8.1:80",
      "allowlist": [
        "192.168.1.0/24",
        "192.168.2.0/24"
      ]
    },
    // Forward other IP ranges to 192.168.8.2 port 80.
    {
      "address": "192.168.8.2:80",
      "allowlist": [
        "192.168.3.0/24",
        "192.168.4.0/24"
      ]
    }
  ]
}

支持TLS

[
    // Server listening on port 443 (HTTPS).
    {
      "bindAddress": "192.168.0.1:443",
      "target": {
        // All connections need to use TLS.
        // Enable TLS by specifying the path to the certificate and private key.
        "serverTls": {
          "cert": "/path/to/cert.pem",
          "key": "/path/to/key.pem",
          // Allow clients to connect without TLS.
          "optional": true
        },

        // Also connect to the destination HTTPS server using TLS.
        // '+' (plus sign) means to use TLS.
        "address": "192.168.2.1:+443",
        "allowlist": "all"
      }
    },

    // Server listening on port 443 (HTTPS).
    // Forward in a round-robin manner to various HTTP servers that do not have
    // TLS enabled.
    {
      "bindAddress": "192.168.0.2:443",
      "target": {
        "serverTls": {
          "cert": "/path/to/cert.pem",
          "key": "/path/to/key.pem"
        },
        "addresses": [
          "192.168.2.1:80",
          "192.168.2.2:80",
          "192.168.2.3:80"
        ],
        "allowlist": "all"
      }
    }
]

iptables支持

请注意,tobaru需要root权限才能配置iptables。可能可以通过使用 setcap(8) 来不使用root权限完成此操作。如果您能够这样做,请提交一个带有说明的pull request。

{
  "bindAddress": "0.0.0.0:8080",
  // Enable iptables auto-configuration.
  "iptables": true,
  "target": {
    "address": "192.168.8.1:80",
    // Allow only the following IP ranges. Packets from other IPs will be dropped.
    "allowlist": [
      "192.168.2.2/24",
      "192.168.2.3/24",
      "192.168.100.50"
    ]
  }
}

IP组

IP组可以用于在多个服务器中快速指定IP组。请注意,IP范围可以指定在任何文件中,并且可以在不同的文件中重复使用,例如,可以方便地在一个单独的文件中调用所有IP组:tobaru ip_groups.json http_servers.json ssh_servers.json

{
  "ipGroups": {
    "local": [
      "192.168.0.0/24",
      "192.168.1.0/24",
      "192.168.2.0/24",
      "192.168.3.0/24"
    ],
    "friends": [
      "1.2.3.4",
      "2.3.4.5"
    ]
  },

  "servers": [
    {
      "bindAddress": "0.0.0.0:8080",
      "target": {
        "address": "192.168.5.1:8080",
        // Only allow IP ranges from 'local' and 'friends' to connect.
        "allowlist": [
          "local",
          "friends"
        ]
      }
    },
    {
      "bindAddress": "0.0.0.0:8081",
      "target": {
        "address": "192.168.5.2:8080",
        // Only allow IP ranges from 'local'.
        "allowlist": "@local"
      }
    }
  ]
}

从0.7.1或更低版本升级

请参阅 UPGRADING.md

依赖项

~18–30MB
~557K SLoC