如何根据目标地址确定发送消息前的源地址?

1 投票
1 回答
531 浏览
提问于 2025-04-18 01:13

这个问题有点复杂,所以请耐心听我解释。

在Python中,我想发送一个UDP消息:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 5011))
dest = ('foo.horse', 5011)
# attact the source address to the message
...

sock.sendto(msg, dest)

但是在发送这个消息之前,我想根据目标地址来确定将要发送的接口地址,这样我就可以把它包含在消息里。

举个例子,如果目标是一个广域网(WAN)地址,那么我需要用局域网(LAN)接口的地址(因为我在NAT后面)。如果目标是“localhost”,那么地址就是“127.0.0.1”。如果是VPN上的地址,那就是我的VPN地址。

更新:

看起来我可以使用:$ ip route get <destination>,这样可以告诉我源地址
https://stackoverflow.com/a/5557459/334632

我最终查看了iproute2的源代码,但我没有找到可以直接使用的简便方法。https://git.kernel.org/cgit/linux/kernel/git/shemminger/iproute2.git/tree/ip/iproute.c#n1376

我可能最终会创建一个子进程来解析结果,但如果可以的话,我希望避免这样做。

1 个回答

3

如果你只关心Linux系统,可以使用pyroute2这个模块。比如,你可以用它来获取某个特定IP地址的路由信息:

>>> import pprint
>>> import pyroute2
>>> import socket
>>> ip = pyroute2.IPRoute()
>>> pprint.pprint(ip.get_routes(family=socket.AF_INET, dst='127.0.0.6'))
[{'attrs': [['RTA_TABLE', 254],
            ['RTA_DST', '127.0.0.6'],
            ['RTA_OIF', 1],
            ['RTA_PREFSRC', '127.0.0.1'],
            ['RTA_CACHEINFO',
             {'rta_clntref': 1,
              'rta_error': 0,
              'rta_expires': 0,
              'rta_id': 0,
              'rta_lastuse': 0,
              'rta_ts': 0,
              'rta_tsage': 0,
              'rta_used': 1}]],
  'dst_len': 32,
  'event': 'RTM_NEWROUTE',
  'family': 2,
  'flags': 2147484160,
  'proto': 0,
  'scope': 0,
  'src_len': 0,
  'table': 254,
  'tos': 0,
  'type': 2}]

不过,遗憾的是,这在最新版本的pyroute2上是无法使用的;我不得不从源代码安装才能得到这些结果。

撰写回答