Twisted:出站连接的源 IP 地址

发布于 2024-08-09 02:00:28 字数 682 浏览 5 评论 0原文

我正在实现一项服务——使用 Twisted 框架用 Python 编写,在 Debian GNU/Linux 上运行——检查 SIP 服务器的可用性。为此,我使用 OPTIONS 方法(SIP 协议功能),因为这似乎是一种常见的做法。为了构造正确且符合 RFC 的标头,我需要知道要建立的连接的源 IP 地址和源端口。 [如何]使用 Twisted 来完成此操作?

这是我尝试过的: 我对 protocol.DatagramProtocol 进行了子类化并在 < code>startProtocol(self) 我使用了 self.transport.getHost().hostself.transport.getHost().port。后者确实是要使用的端口,而前者仅产生 0.0.0.0。

我猜此时 Twisted 还不知道将使用哪个接口以及哪个源 IP 地址。 Twisted 是否提供了可以帮助我解决此问题的工具,或者我是否需要以不同的方式与操作系统(路由)进行交互?或者我只是错误地使用了 self.transport.getHost().host ?

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. For this I use the OPTIONS method (a SIP protocol feature), as this seems to be a commonplace practice. 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. [How] can this be done with 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. The latter is indeed the port that's going to be used, whereas the former only yields 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. 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? Or did I just use self.transport.getHost().host incorrectly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

踏月而来 2024-08-16 02:00:28

您是否认为通过 Twisted 一部分的 SIP 实现是否可以实现您想要的功能?

无论如何,在 Twisted 中设置 UDP 的源地址和端口的方式与在没有 Twisted 的情况下设置它们的方式非常相似。在 Twisted 中,reactor.listenUDP(port,protocol,interface) 将 UDP 套接字绑定到特定端口和接口,并将接收到的数据报处理为您的协议。在协议内部,self.transport.write(msg, addr) 使用协议绑定的地址作为源地址向 addr 发送数据报。

再次阅读您的问题,我认为您唯一缺少的部分是将 interface 传递给 reactor.listenUDP(...)

Did you see if that you want to do is possible with the SIP implementation that is part of Twisted?

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. 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. 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.

Reading your question again, I think the only part you were missing was passing interface to reactor.listenUDP(...).

絕版丫頭 2024-08-16 02:00:28

为了完整起见,我回答我自己的问题:

在尝试确定主机的源 IP 地址之前,请确保在传输上使用 connect() 。以下摘录显示了协议实现的相关部分:

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

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. 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
貪欢 2024-08-16 02:00:28

如果您使用 UDP,则端点由以下任一方式确定:

  1. 在套接字上调用 bind() 并显式为其提供
  2. 发送数据包的

地址如果您需要更多详细信息,检查此响应

问题是我对扭曲不太熟悉。通过快速浏览源代码,我可以看出,您可能想要使用像 tidSelectReactor 代替。这就是 tndDNSDatagramProtocol 在幕后工作

如果您将 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)

如果您需要支持多个网络接口或 IPv4 和 IPv6,则获取主机名会有点棘手。如果您可以使所使用的接口可配置,则将其作为元组的第一个成员传递给 socket.bind() 即可。

现在最困难的部分是在twisted 提供的抽象范围内做到这一点。不幸的是,我不能在那里提供很多帮助。我建议寻找有关如何访问底层套接字或找到将套接字信息传递到框架的方法的示例。

祝你好运。

If you are using UDP then the endpoint is determined by either:

  1. calling bind() on the socket and explicitly giving it an address
  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 t.i.d.SelectReactor instead. This is what t.n.d.DNSDatagramProtocol does under the hood.

If you take twisted out of the picture, then the following snippet shows what is going on:

>>> 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. 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文