使用 UDP 从特定端口向特定端口发送单个 RIPv2 数据报?

Send a single RIPv2 datagram using UDP from and to a specific port?

我有一项任务是制作路由信息协议嗅探器和 C/C++ 中的一个程序,该程序能够使用从嗅探器收集的信息发送自定义 RIP 条目。

我 运行 都在一所学校提供 Ubuntu Virtualbox 映像,它通过 "Internal Network" 选项连接到 BSD 映像 运行 一个生成 RIP 的路由守护进程交通.

我到达了需要将自定义数据包发送到 "router" 的部分,但是在尝试从端口 520 发送它时遇到了问题。

从描述 RIP 协议的 RFC 1058 中我了解到,为了让路由器确认新路由,RIP 消息必须来自和到达端口 520。

我可以将我的数据包发送到路由器的 520 端口,但源端口始终是我绑定失败并显示错误消息后系统分配的随机端口 "Cannot assign requested address"。

数据包本身在 WireShark 中看起来很好,但源端口除外,例如 60818。

我在响应程序中执行以下操作:

#define ROUTERADDR "10.0.0.1"

int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in router;
router.sin_family      = AF_INET;
router.sin_port        = htons(520);
router.sin_addr.s_addr = inet_addr(ROUTERADDR);

bind    (fd, (struct sockaddr*)&router, sizeof(router));
connect (fd, (struct sockaddr*)&router, sizeof(router));

send(fd, &payload, sizeof(payload), 0);
close(fd);

绑定到小于 1024 的端口需要 root 权限,除非您将可执行文件添加到 CAP_NET_BIND_SERVICE 能力,如下所示。

setcap 'cap_net_bind_service=+ep' /path/to/executable

您的代码中还有另一个问题,您正在尝试绑定到路由器的地址。您需要绑定到特定的本地地址或INADDR_ANY,如下所示。

struct sockaddr_in local, router;
local.sin_family = AF_INET;
local.sin_port = htons(520);
local.sin_addr.s_addr = htonl(INADDR_ANY);
bind    (fd, (struct sockaddr*)&local, sizeof(local));

router.sin_family      = AF_INET;
router.sin_port        = htons(520);
router.sin_addr.s_addr = inet_addr(ROUTERADDR);
connect (fd, (struct sockaddr*)&router, sizeof(router));

您应该检查系统调用的 return 值,这样您就知道什么时候不工作了,在您的情况下 bind() 调用可能会失败。

在你的情况下,bind() 会失败,因为你试图绑定到你正在发送 的远程地址上的端口,你不能这样做。

bind() 指定您要使用的本地端点,因此您应该指定要发送的本地 IP 地址之一 from。 或者您可以使用 INADDR_ANY 将套接字绑定到任何本地地址。所以你可能想创建另一个 struct sockaddr_in 并像这样:

struct sockaddr_in my_addr;
my_addr.sin_family      = AF_INET;
my_addr.sin_port        = htons(520);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if (bind(fd, (struct sockaddr*)&my_addr, sizeof(my_addr)) != 0) {
   perror("bind() failed");
}