关于 TCP 打洞的一些问题,有尝试过的请教一下

2019-10-02 18:14:46 +08:00
 myqoo

最近发现家里的垃圾宽带(华数网通)居然支持 TCP 打洞,并成功将内网的 HTTP 服务暴露到公网上。

原理很简单。先连接一个公网服务,获得该连接的公网 IP 和公网端口。然后开启一个 HTTP 服务,端口指定为之前连接的本地端口(端口重用)。然后用其他设备测试,例如手机 4G 访问 http://公网 IP:公网端口,成功显示出 HTTP 服务。(实现超简单,结尾附上 nodejs 演示)

目前遇到几个疑惑,不知是否为正常现象:

1.每个 http://公网 IP:公网端口 访问几次后就不能再访问了,需要重新打洞更换公网端口才可以。

并且每个连接时间不能太久,否则会被断开。我测试大文件下载,速度不错有 2MB/s (对于¥ 200/年的宽带也算满意了),但大约 10 分钟左右下了一个多 GB 就被断开了。

这是因为该公网 IP 有很多人在用,导致端口被其他人占用了吗?假如我同时发起成千上万的 TCP 连接,是不是也会把同个公网 IP 下其他人正在使用的端口给抢占呢。

2.当其他设备访问 http://公网 IP:公网端口 时,原先的 TCP 连接不再可用(演示中的心跳包无法收到)。

TCP 打洞成功后,原先的连接就不可用了?这意味着,本地任何一个 TCP 连接都可以被恶意者破坏(假如恶意者知道该连接的公网端口)。事实上我用服务器扫了下自己公网 IP 的所有端口,发现确实可以把本地开着的 TCP 连接都断开!!!感觉这是运营商配置的问题,不是正常现象吧,要不然安全性也太低了。

3.OSX 和 Windows 上支持端口重用,但 Linux 却不支持,报端口被占用的错。

我搜了下 nodejs 官网关于 net 模块的介绍 https://nodejs.org/api/net.html 其中提到 All net.Socket are set to SO_REUSEADDR (see socket(7) for details). 不明白为什么 Linux 系统不支持端口重用?

最后贴上 nodejs 的演示代码。我试了很多运营商都不行,但华数宽带可以实现(最好是直接在电脑上拨号,因为有些路由器也会影响打洞):

const net = require('net')
const http = require('http')

function runHttpSvr(port) {
  http.createServer((req, res) => {
    const ip = req.connection.remoteAddress.replace('::ffff:', '')
    const addr = ip + ':' + req.connection.remotePort
    console.log('client:', addr)
    res.end('Hello: ' + addr + '\n')
  }).listen(port, _ => {
    console.log('server running...')
  })
}

const conn = net.createConnection(50000, '106.75.17.52', () => {
  const localPort = conn.localPort
  console.log('localPort:', localPort)

  let pong = 0

  conn.on('data', data => {
    if (data == 'PONG') {
      console.log('PONG:', pong++)
      setTimeout(ping, 1000)
      return
    }
    console.log('curl http://' + data)
    runHttpSvr(localPort)
  })
  conn.on('end', _ => {
    console.log('end')
  })
  conn.on('error', err => {
    console.log('error:', err)
  })
  conn.setEncoding('utf8')

  function ping() {
    conn.write('PING')
  }
  ping()
})

11661 次点击
所在节点    程序员
21 条回复
ofblyt
2019-12-26 14:13:49 +08:00
推荐博客
http://www.cnblogs.com/pannengzhi/p/4800526.html
这上面的打洞可以说是很清楚了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/606042

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX