Python 如何绑定和发送来自谷歌云转发规则的IP地址?

Python 如何绑定和发送来自谷歌云转发规则的IP地址?,python,networking,google-compute-engine,google-cloud-platform,Python,Networking,Google Compute Engine,Google Cloud Platform,我已经按照谷歌云平台上的说明进行了操作。所以我现在有这样的东西: $ gcloud compute forwarding-rules list NAME REGION IP_ADDRESS IP_PROTOCOL TARGET x-fr-1 us-west1 104.198.?.?? TCP us-west1-a/targetInstances/x-target-instance x-fr-2 us-west1 104.198.?.??

我已经按照谷歌云平台上的说明进行了操作。所以我现在有这样的东西:

$ gcloud compute forwarding-rules list
NAME    REGION    IP_ADDRESS      IP_PROTOCOL  TARGET
x-fr-1  us-west1  104.198.?.??    TCP          us-west1-a/targetInstances/x-target-instance
x-fr-2  us-west1  104.198.?.??    TCP          us-west1-a/targetInstances/x-target-instance
x-fr-3  us-west1  104.198.??.???  TCP          us-west1-a/targetInstances/x-target-instance
x-fr-4  us-west1  104.198.??.???  TCP          us-west1-a/targetInstances/x-target-instance
x-fr-5  us-west1  104.198.?.???   TCP          us-west1-a/targetInstances/x-target-instance
(注意:姓名已更改,问号已替换。我不确定是否需要将这些信息保密,但最好是安全的。)

我的实例“x”在“x-target-instance”中,有五条转发规则“x-fr-1”到“x-fr-5”。我在“x”上运行nginx,我可以从它的6个外部IP地址中的任何一个访问它(实例+5转发规则为1)。到目前为止,一切顺利

我现在感兴趣的是将服务器绑定到这些外部IP地址。为了探索,我尝试使用Python:

import socket
import time

def serve(ip_address, port=80):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((ip_address, port))
    try:
        sock.listen(5)
        while True:
            con, _ = sock.accept()
            print con.getpeername(), con.getsockname()
            con.send(time.ctime())
            con.close()
    finally:
        sock.close()
现在我可以绑定“0.0.0.0”,并得到一些有趣的结果:

>>> serve("0.0.0.0")
('173.228.???.??', 57288) ('10.240.?.?', 80)
('173.228.???.??', 57286) ('104.198.?.??', 80)
当我在服务器的外部IP地址上与服务器通信时,“getsockname”方法返回实例的内部IP地址。但是,当我使用转发规则使用的外部IP地址与服务器通信时,“getsockname”方法返回外部IP地址

好的,现在我绑定实例的内部IP地址:

>>> serve("10.240.?.?")
('173.228.???.??', 57295) ('10.240.?.?', 80)
>>> serve("104.198.?.??")
error: [Errno 99] Cannot assign requested address
同样,我可以通过服务器的外部IP地址与服务器通信,“getsockname”方法返回实例的内部IP地址。这似乎有点奇怪

另外,如果我尝试绑定实例的外部IP地址:

>>> serve("10.240.?.?")
('173.228.???.??', 57295) ('10.240.?.?', 80)
>>> serve("104.198.?.??")
error: [Errno 99] Cannot assign requested address
然后我得到一个错误

但是,如果我尝试绑定转发规则使用的外部IP地址,然后发出请求:

>>> serve("104.198.??.???")
('173.228.???.??', 57313) ('104.198.??.???', 80)
它起作用了

最后我看一下“ifconfig”:

我只看到两个接口。很明显,谷歌云平台联网的能力已经超过了我在大学计算机联网课上的记忆。总结我的观察:

  • 如果我想绑定实例的外部IP地址,那么就绑定它的内部IP地址
  • 绑定到实例内部IP地址的进程无法区分实例内部或外部IP地址之间的目标IP
  • 单个网络适配器“ens4”正在接收绑定到实例6个外部IP地址中任何一个的数据包
  • 以下是我的问题:

  • 为什么我不能绑定实例的外部IP地址
  • 当我没有关联的网络适配器时,如何绑定转发规则使用的外部IP地址
  • 如果我想限制SSH对实例外部IP地址的访问,我应该配置SSH绑定内部IP地址吗
  • 如果我在转发规则使用的一个外部IP地址上设置HTTP代理,那么代理请求的源IP是什么
  • 最后,这可能是一个bug,当我可以用“gcloud计算转发规则列表”看到它们时,为什么web界面中的转发规则列表是空的
  • 它不在本地路由表中(“ip路由显示表本地”) [您当然可以添加它(例如“ip地址添加x.x.x.x/32 dev ens4”), 但是这样做不会对你有多大好处,因为不会有任何数据包 将其作为目标地址发送到您的虚拟机-请参阅 以下……]
  • 因为转发的地址已添加到本地路由表(“ip路由显示表本地”)
  • 您可以[但是请注意,这将限制ssh访问以外部IP地址为目标的外部客户端,或者限制访问以外部或内部IP地址为目标的虚拟网络中的客户端]。但是,正如已经指出的,限制允许的客户端地址(而不是服务器地址)可能更重要,因此防火墙将更有效
  • 它取决于代理请求的目的地。如果它是虚拟网络内部的,那么它将是虚拟机的内部IP地址,否则它将被NAT(在虚拟机外部)设置为虚拟机的外部IP地址
  • 该页面上有多个选项卡-其中两个选项卡列出了不同类别的转发规则(“全局转发规则”与“转发规则”)。无可否认,有些令人困惑:P
  • 另一件稍微令人困惑的事情是,当使用外部IP作为目标地址向VM发送数据包时,VM外部的实体(将其视为虚拟交换机/路由器/NAT设备)在数据包到达虚拟NIC的virtio驱动程序之前,自动将目标修改为内部IP,因此您无法修改该行为。但是,发送到转发规则的IP的数据包不会被NAT(如您所见)


    希望有帮助

    对于第三个问题,我们通常在tcp:22上创建一个防火墙,源IP范围为内部网络IP范围,这样只接受来自内部网络的连接。回答得很好,但外部IP和转发规则IP的实现方式不同的原因是什么?本地路由表是针对这台机器的IP目的地吗?因此,它应该转发到传输层(TCP/UDP),而不是转发到下一个跃点。我不能权威地解释为什么它们的实现方式不同——我只想说它们是这样,Google选择使用指定的外部IP地址为您进行NAT,但不使用转发规则IP。[事实上,它们没有NAT转发规则IP,这有助于区分给定客户机的目标]至于本地路由表-几乎是的。请注意,如果“ping”该表中的任何本地地址,它将被路由到环回接口。目前我能找到的最好的参考是Re:#5,无论是“全局转发规则”还是“转发规则”选项卡都没有列出任何规则。虽然我有六个,而且他们看起来都在工作。绝对是个虫子。你说得对。云控制台似乎列出了针对“目标池”的转发规则,而不是针对“目标实例”的转发规则。至少现在,如果您想让它们出现,请使用单个实例和target设置一个目标池