【问题标题】:why cannot bind socket to localhost for outgoing request为什么不能将套接字绑定到本地主机以进行传出请求
【发布时间】:2018-06-19 12:04:24
【问题描述】:

我有以下问题。我需要将我的应用程序发送的 DNS 数据包与来自其他应用程序的标准 DNS 查询区分开来,以便 iptables 进一步过滤。这些请求的源 IP 等于公共接口的 IP,我的想法是将套接字绑定到环回,然后触发请求。不幸的是,我得到了OSError: [Errno 22] Invalid argument 异常。看看这些例子:

import socket

# THIS WORKS FINE - PUBLIC -> PUBLIC
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('192.168.200.15', 7777))
s.sendto('test'.encode(),('192.168.200.16', 10000))

# THIS WORKS FINE - LOOPBACK -> LOOPBACK
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('127.0.0.1', 7777))
s.sendto('test'.encode(),('127.0.0.1', 10000))

# THIS WORKS FINE - PUBLIC -> LOOPBACK
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('192.168.200.15', 7777))
s.sendto('test'.encode(),('127.0.0.1', 10000))

# THIS THROWS ERROR - LOOPBACK -> PUBLIC
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('127.0.0.1', 7777))
s.sendto('test'.encode(),('192.168.200.16', 10000))
# RESULT:
# Traceback (most recent call last):
#  File "x.py", line 21, in <module>
#    s.sendto('test'.encode(),('192.168.200.16', 10000))
#OSError: [Errno 22] Invalid argument

为什么会这样?我虽然只是启用 net.ipv4.ip_forward 的问题,但事实并非如此。任何帮助表示赞赏。

【问题讨论】:

  • 来自@AndrewWinder(没有足够的代表发表评论):在我的接口上为我工作,你分配了正确的接口吗?在第 15 行,您绑定到本地 IP 192.168.200.15,然后在第 21 行发送到 192.168.200.16。
  • 抱歉,我可能没有提供足够的信息。 192.168.200.15 - 是我在公共接口上的本地 IP。 192.168.200.16 是我网络中的另一台主机。发生错误的数字也是错误的(现已修复)

标签: python sockets


【解决方案1】:

关于 Python 套接字的更多详细信息(它们只是原生实现的包装器):[Python]: socket - Low-level networking interface

这是范围(或可见性域,如果您愿意的话)的问题。有2个(简化):

  • 本地(当前机器):

    • 0 或更多公共接口(物理或虚拟)
    • 0 或更多loopback 接口(127.0.0.1 .. 127.0.0.254)
  • 全球(网络):

    • 0 或更多公共接口(来自连接到网络的每台主机),每个接口都是唯一可识别的

环回地址仅在本地范围内有意义。您的 4 个案例:

  • public -> publicOK - 通过网络
  • 回送 -> 回送OK - 本地
  • 公共 -> 回送OK - 本地
  • loopback -> publicFAILED - 无法通过网络访问环回地址

当 1stsendto 调用时(也发生在 connectSOCK_STREAMs 的情况下),套接字会自动绑定到所有本地地址(0.0.0.0)(尽管这可能是特定于套接字实现的)和一个临时端口(另外,请注意:一旦绑定了套接字,它就可以' t 不受约束或反弹)。 peer 套接字将使用这一对(封装在数据包中)来确定是谁发送了它们。认为如果 127.0.0.1 会在那里,那么对等套接字区分“你”(实际发送数据包的套接字)会非常混乱和他们自己的环回地址。
也许“无效参数”错误有点误导。在 Win 上,它更清晰一些(尽管有些人可能会对此争论):

>>> import sys
>>> import socket
>>> "Python {:s} on {:s}".format(sys.version, sys.platform)
'Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32'
>>>
>>> s4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4.sendto(b"Dummy", ("192.168.1.151", 3321))
5
>>> s4.getsockname()
('0.0.0.0', 61425)
>>> s4.bind(("127.0.0.1", 12345))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [WinError 10022] An invalid argument was supplied
>>> s4.close()
>>>
>>> s4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4.bind(("127.0.0.1", 12345))
>>> s4.sendto(b"Dummy", ("192.168.1.151", 3321))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [WinError 10051] A socket operation was attempted to an unreachable network
>>> s4.close()

参考文献Google 会产生大量其他参考文献):

【讨论】:

  • 这是您要找的吗?
猜你喜欢
  • 2011-01-28
  • 2017-01-11
  • 1970-01-01
  • 2011-11-25
  • 2012-07-15
  • 2022-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多