我是一名程序员,正在尝试弄清楚一些超出我领域的东西:
假设我有一台机器,客户端将与其建立 tcp(但不是 http!)连接。我想根据客户端所连接的主机名将客户端重定向到它们自己的端口。例如,client1 连接到 client1.myserver.com 并连接到端口 1234。client2.myserver.com -> 1235,client3.myserver.com -> 1236,等等。
我想动态控制主机 y 的端口 x 如何实际指向我的物理机上的端口 z。
在谷歌搜索此信息时,我看到了对防火墙、代理、反向代理的引用。我实际上需要哪种软件?现有软件是否允许按需进行此类更改(我听说防火墙更改需要一天时间)?
如果我想自己编写这样一个层(因为它可能有点特定于应用程序),可以用 java 或 node.js 完成吗(我的意思是可以使用更高级别的 API 来完成吗,还是我必须开始分解 ip 数据包)?由于所有主机名都解析到同一台机器,我怎么知道客户端连接到哪个主机名?
我也会很感激任何阅读材料的指点。
答案1
在 IP 层,不存在主机名。主机名是 IP 地址在应用程序层上的抽象,在 Internet 层或传输层上没有任何意义。
在 HTTP 共享主机中,这个技巧在处理HTTP对话后TCP 对话已启动。正是由于这个原因,运行 SSL 服务器需要专用 IP 地址很长时间,因为 SSL 对话发生在 HTTP 对话之前(这个问题已在较新的 TLS 版本中得到修复,其中 HOSTNAME 现在可以作为 SSL 协商的一部分包含在内)。
对于共享主机 HTTP 实例,协议大致按以下顺序协商:
TCP -> SSL -> HTTP
每个协议只有在前面的协议完成后才能启动。直到最近,只有链中的最后一步才知道主机名,这就是为什么由网络服务器软件来处理主机名与 IP 的多对一关联。
对于动态端口转发,这只有在以下情况下才可行:应用程序协议以某种方式识别主机名。某些设备(无论是软件还是硬件)处理与客户端的初始 TCP 连接以及应用协议(无论是什么)的第一步,并根据收到的信息将连接转发到最终目的地。
所需的确切步骤因应用程序协议本身而异。有些协议(如 HTTP)包含一个 HOSTNAME 标头,指示客户端希望与之通信的主机名。其他协议(如某些 Microsoft 协议)利用基于 DNS 的 SRV 记录来确定精确的 IP和端口组合。由于听起来你可能正在从头开始设计自己的应用程序协议,我建议遵循 HTTP 的引导并在初始协议协商步骤中包含 HOSTNAME 标头。
答案2
您可以使用 DNS 中的 SRV 记录最轻松地实现此目的:
答案3
您能否更清楚地描述您要做什么以及为什么这样做?“为什么”将大有帮助。客户是什么?协议是什么?
根据协议和数据流,有很多方法可以做到这一点。
考虑 pf、iptables 或 ebtables 注入,请参阅“ssh 黑名单”示例。查看 LVS、HAproxy 和其他负载均衡器以进行常规重定向。
一个老办法是“唤醒”系统。这对于 SSH 或其他加密协议非常有用,因为这些协议需要更多的 CPU 来确定源域。(解码报头)当没有人连接时,这只会让一个端口运行。
- SSH 进入单个开放端口(无需终端支持)
- 以用户 X 身份登录系统(最好使用密钥),这将运行一个脚本,在端口 XXXXX 上启动服务器的另一个实例,并使用新的端口号回复客户端
- “端口 XXXXX 已打开”消息被传回给客户端,初始 ssh 会话关闭
- 然后客户端或客户端应用使用现在打开的端口 XXXXX 重新连接
- 当客户端断开连接时,端口 XXXXX 上的备用实例将关闭和/或端口 XXXXX 将关闭。
可以根据密钥/用户、反向查找、消息传递等分配特定端口。有些只是让实例运行,并使用 pf/iptables 防火墙注入打开/关闭。其他则使用防火墙规则来触发服务启动,并且在使用特定类型的数据包 ping 指定端口之前不运行初始 SSH(或其他服务)。我更喜欢“最近匹配”的自定义防火墙规则来阻止杂散数据包并停止/启动服务器实例,以减少与防火墙的动态交互。
这个想法可以适用于任何可以编码或脚本化的协议和服务。
TCP/IP 网络的阅读材料:W. Richard Stevens 撰写或推荐的任何材料。 http://www.kohala.com/start/
不要低估使用 SSH 隧道作为开发中的权宜之计。这些可以在没有代码的情况下实现您需要的一切。您的应用程序是什么?它的通信不应该是安全的吗?您如何将脚本小子黑客列入黑名单?这需要您编写和调试更多内容。无论如何,您都应该将代码划分为各个部分,因此使用 SSH 作为传输、端口转发、加密、使用记录、黑名单等来开发其他所有内容。然后,当其他所有事情都完成后,编写您自己的网络协议机制来替换 SSH。网关 SSH 服务器上的用户无需终端访问即可使用隧道。