简体   繁体   English

扭曲:出站连接的源IP地址

[英]Twisted: source IP address for outbound connections

I'm in the process of implementing a service -- written in Python with the Twisted framework, running on Debian GNU/Linux -- that checks the availability of SIP servers. 我正在实施一项服务-用Twisted框架用Python编写,在Debian GNU / Linux上运行-检查SIP服务器的可用性。 For this I use the OPTIONS method (a SIP protocol feature), as this seems to be a commonplace practice. 为此,我使用了OPTIONS方法(SIP协议功能),因为这似乎是司空见惯的做法。 In order to construct correct and RFC compliant headers, I need to know the source IP address and the source port for the connection that is going to be established. 为了构造正确且符合RFC的标头,我需要知道将要建立的连接的源IP地址和源端口。 [How] can this be done with Twisted? [如何]可以用Twisted完成?

This is what I tried: I subclassed protocol.DatagramProtocol and within startProtocol(self) I used self.transport.getHost().host and self.transport.getHost().port . 这是我尝试的方法:我将protocol.DatagramProtocol子类化,并在startProtocol(self)使用了self.transport.getHost().hostself.transport.getHost().port The latter is indeed the port that's going to be used, whereas the former only yields 0.0.0.0. 后者确实是将要使用的端口,而前者仅产生0.0.0.0。

I guess that at this point Twisted doesn't [yet?] know which interface and as such which source IP address will be used. 我猜在这一点上,Twisted还不知道要使用哪个接口以及哪个源IP地址。 Does Twisted provide a facility that could help me with this or do I need to interface with the OS (routing) in a different way? Twisted是否提供可以帮助我解决此问题的功能,还是需要以其他方式与OS(路由)交互? Or did I just use self.transport.getHost().host incorrectly? 还是我只是错误地使用了self.transport.getHost().host

For the sake of completeness I answer my own question: 为了完整起见,我回答我自己的问题:

Make sure you use connect() on the transport before trying to determine the host's source IP address. 在尝试确定主机的源IP地址之前,请确保在传输上使用connect()。 The following excerpt shows the relevant part of a protocol implementation: 以下摘录显示了协议实现的相关部分:

class FooBarProtocol(protocol.DatagramProtocol):
    def startProtocol(self):
        self.transport.getHost().host   # => 0.0.0.0
        self.transport.connect(self.dstHost, self.dstPort)
        self.transport.getHost().host   # => 192.168.1.102

If you are using UDP then the endpoint is determined by either: 如果您使用的是UDP,则终结点取决于以下任一情况:

  1. calling bind() on the socket and explicitly giving it an address 在套接字上调用bind()并显式为其指定地址
  2. sending a packet 发送数据包

If you want a few more details, check this response . 如果您需要更多详细信息, 请查看此回复

The problem is that I'm not that familiar with twisted. 问题是我对扭曲不那么熟悉。 From what I can tell by a quick perusal of the source, it looks like you might want to use a reactor like tidSelectReactor instead. 通过快速浏览源代码可以看出,您似乎想要使用像tidSelectReactor这样的反应堆。 This is what tndDNSDatagramProtocol does under the hood . 这就是tndDNSDatagramProtocoltndDNSDatagramProtocol执行的操作

If you take twisted out of the picture, then the following snippet shows what is going on: 如果您将图片twisted了,那么以下代码片段将说明正在发生的情况:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
<socket._socketobject object at 0x10025d670>
>>> s.getsockname()           # this is an unbound or unnamed socket
('0.0.0.0', 0)
>>> s.bind( ('0.0.0.0', 0) )  # 0.0.0.0 is INADDR_ANY, 0 means pick a port
>>> s.getsockname()           # IP is still zero, but it has picked a port
('0.0.0.0', 56814)

Get the host name is a little trickier if you need to support multiple network interfaces or IPv4 and IPv6. 如果需要支持多个网络接口或IPv4和IPv6,则获取主机名会有些棘手。 If you can make the interface used configurable, then pass it in as the first member of the tuple to socket.bind() and you are set. 如果您可以使使用的接口可配置,则将其作为元组的第一个成员传递给socket.bind()进行设置。

Now the hard part is doing this within the confines of the abstractions that twisted provides. 现在,最困难的部分是在扭曲提供的抽象范围内进行此操作。 Unfortunately, I can't help a whole lot there. 不幸的是,我在那里无能为力。 I would recommend looking for examples on how you can get access to the underlying socket or find a way to pass the socket information into the framework. 我建议您寻找有关如何访问底层套接字或找到将套接字信息传递到框架中的方法的示例。

Good luck. 祝好运。

Did you see if that you want to do is possible with the SIP implementation that is part of Twisted? 您是否知道Twisted的SIP实现是否可以实现您的目标?

In any case, how you set the source address and port for UDP in Twisted is quite similar to how you set them without Twisted. 无论如何,在Twisted中设置UDP的源地址和端口的方式与在没有Twisted的情况下设置它们的方式非常相似。 In Twisted, reactor.listenUDP(port, protocol, interface) binds an UDP socket to a specific port and interface and handles the received datagrams to your protocol. 在Twisted中, reactor.listenUDP(port, protocol, interface)将UDP套接字绑定到特定的端口和接口,并根据协议处理接收到的数据报。 Inside the protocol, self.transport.write(msg, addr) sends a datagram to addr using the address that the protocol is bound to as source address. 在协议内部, self.transport.write(msg, addr)使用协议绑定的地址作为源地址self.transport.write(msg, addr)将数据报发送到addr

Reading your question again, I think the only part you were missing was passing interface to reactor.listenUDP(...) . 再次阅读您的问题,我认为您唯一缺少的部分是将interface传递给reactor.listenUDP(...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM