对于很多大学生而言,假期访问校园网是一个很重要的需求。这里介绍一种方便的使用 SOCKS 代理(v2ray)在校外访问校园网的方法——当然,需要一台校内机器和一台校外机器作为配合。此方法也可以用作内网穿透。

这种方法并不属于常规的内网穿透,通常意义上的内网穿透指的是利用公网服务器去直接访问内网资源,而本文提供的方法是利用公网服务器—内网服务器代理的方法去访问内网资源。这种方法的好处是,能够访问任意的内网资源而不需要根据暴露的内网资源调整内网穿透服务器的配置;而缺点是,需要客户端做出特殊的配置。

这种配置方法的教程,特别是利用 v2ray 进行配置的方法,在 v2ray 支持内网穿透后多了起来。但是网络上能够找到的教程通常表述不是十分清晰,因此在这里根据自己的理解重新描述一下。

在 v2ray 的文档中,将内网服务器称为 *Bridge*,而公网服务器称为 *Portal*。本文为了理解方便,沿用这种称法,但我个人认为,Bridge/Protal 的叫法并不利于用户理解。假定公网服务器的地址为 peek.example.com,VMess 协议暴露的端口为 5931

首先在 Bridge 上安装并配置 v2ray,配置文件如下:

{
  "reverse": {
    "bridges": [
      {
        "tag": "bridge",
        "domain": "anything.example.com"
      }
    ]
  },
  "outbounds": [
    {
      "tag": "tunnel",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "peek.example.com",
            "port": 5931,
            "users": [
              {
                "id": "6956ddd9-f3c3-4dc7-9cd2-3b41a8a5cc6a",
                "alterId": 16
              }
            ]
          }
        ]
      }
    },
    {
      "protocol": "freedom",
      "settings": {},
      "tag": "out"
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "inboundTag": ["bridge"],
        "domain": ["full:anything.example.com"],
        "outboundTag": "tunnel"
      },
      {
        "type": "field",
        "inboundTag": ["bridge"],
        "outboundTag": "out"
      }
    ]
  }
}

这里说明一下,使用的连接协议为 VMess,是出于我的实际环境中 Portal 服务器位于境外的原因。实际上这里使用的协议并不限于 VMess,利用其它协议同样可以达成目的。如果服务器位于境内,SOCKS 协议可能是一个更好的选择。修改协议时,只需要保证 tag 不发生改变就没有问题。

此外,此处用到的域名 anything.example.com 并不需要实际存在,亦不需要实际控制,仅作为标签使用。但是,使用已经存在的域名可能会带来混淆以及运行上的问题,因此建议编造并不存在的域名使用。

然后在 Portal 服务器上安装并运行 v2ray,配置文件如下:

{
  "reverse": {
    "portals": [
      {
        "tag": "portal",
        "domain": "anything.example.com"
      }
    ]
  },
  "inbounds": [
    {
      "tag": "tunnel",
      "port": 5931,
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "6956ddd9-f3c3-4dc7-9cd2-3b41a8a5cc6a",
            "alterId": 16
          }
        ]
      }
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "inboundTag": ["external"],
        "outboundTag": "portal"
      },
      {
        "type": "field",
        "inboundTag": ["tunnel"],
        "domain": ["full:anything.example.com"],
        "outboundTag": "portal"
      }
    ]
  }
}

这里同样是利用 VMess 协议对公网暴露服务,同理,如果服务器在境内,可以直接设置为 SOCKS 代理。

这里一个连接端点同时被用作 Bridge 服务器的连接以及客户端的连接。如有必要,也可以增加多个客户端连接配置,使得单一服务器可以为多人所用。如果客户端传入连接和 Bridge 连接的模式不同,对配置文件需要做以较大修改。

具体来说,路由部分需要修改为:

{
  "routing": {
    "rules": [{
      "type": "field",
      "inboundTag": ["external"],
      "outboundTag": "portal"
    },{
      "type": "field",
      "inboundTag": ["interconn"],
      "outboundTag": "portal"
    }]
  }
}

那么只要为用户连接的传入配置 external 的标签,同时为 Bridge 的传入配置 interconn 的标签,即可实现所需的功能。

此外,通过配置 Dokodemo-door,也可以实现传统的服务暴露型的内网穿透,例如:

{
  "tag": "external",
  "port": 80,
  "protocol": "dokodemo-door",
  "settings": {
    "address": "127.0.0.1",
    "port": 80,
    "network": "tcp"
  }
}

只要将所有外部传入打上对应的标签,并配置到利用 portal 传出,即可实现透传内网穿透。

那么配置的介绍就到这里,接下来瞎写一些没什么用的废话。

为什么我不去用学校的 VPN 而是自己折腾了一套反向代理呢?因为学校的 VPN 不能连接 80、443、3369 以外的任何端口。我也不是很懂学校为什么要这么做,无外乎是网络安全一类的废话,但实话说给学生还是带来了很大的不方便——我假期没有办法简单地去连接到校内服务器做维护。此外,学校用的 Cisco AnyConnect 设置了不允许保存密码的策略,可能也是为了安全,但是我的密码都是利用密码管理器生成,每次连接都要去复制一次,真的很麻烦。

我觉得,系统安全没必要太过于紧张,以致于连本来正常的操作都不允许开展。