Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir/Erlang:gen_udp伪头_Erlang_Elixir - Fatal编程技术网

Elixir/Erlang:gen_udp伪头

Elixir/Erlang:gen_udp伪头,erlang,elixir,Erlang,Elixir,我想在Elixir中接收UDP消息,并需要获取数据包发送到的目标IP 在iex中,我可以使用以下命令打开套接字: {:ok, socket} = :gen_udp.open(19_999, [{:active, true}]) 当我收到一条消息时,我将以以下格式收到它: {:udp, port, source_ip, source_port, data} 目标IP不是消息的一部分。根据UDP规范,源IP不是UDP数据包的一部分,而是IP伪报头的一部分。当我使用tcpdump时,我可以看到数据

我想在Elixir中接收UDP消息,并需要获取数据包发送到的目标IP

在iex中,我可以使用以下命令打开套接字:

{:ok, socket} = :gen_udp.open(19_999, [{:active, true}])
当我收到一条消息时,我将以以下格式收到它:

{:udp, port, source_ip, source_port, data}
目标IP不是消息的一部分。根据UDP规范,源IP不是UDP数据包的一部分,而是IP伪报头的一部分。当我使用tcpdump时,我可以看到数据包的目标IP


是否有任何方法/参数可以获取UDP数据包的IP或伪报头?

目标端口肯定是
19\u 999

要确定哪个IP正在接收当前数据包,您需要知道所有网络适配器(包括虚拟适配器)的配置。之后,您可以从源IP和网络配置获取目标IP,因为只有同一网络中的设备才能相互通信。您只需要在所有网络适配器中找到与源IP位于同一网络中的IP。您可以通过将网络掩码应用于2个IP地址来判断2个设备是否在同一网络中,并查看结果是否相同

顺便说一句,如果您的服务器位于NAT之后,那么如果客户端与服务器不在同一网络中,您就无法获得它的真实源IP地址。您只能获得最后一个跃点的源IP地址(通常是网络网关的IP地址)

获取网络配置

{:ok, ifaddrs} = :inet.getifaddrs()
您将得到一个如下列表:

[
  {'lo', [addr: {127, 0, 0, 1}, netmask: {255, 0, 0, 0}, ...]},
  {'eth0', [addr: {192, 168, 0, 10}, netmask: {255, 255, 255, 0}, ...]},
  {'docker_gwbridge', [addr: {172, 18, 0, 1}, netmask: {255, 255, 0, 0}, ...]}
]
由于我们只需要
addr
netmask
,因此我们可以在列表上进一步执行
Enum.map

ifaddrs = Enum.map(ifaddrs, fn{_, opts}-> {opts[:addr], opts[:netmask]} end)
将网络掩码应用于IP地址

只需按位将它们放在一起

defp apply_netmask({a1, b1, c1, d1} = _ip, {a2, b2, c2, d2} = _netmask) do
  # Don't forget `use Bitwise`
  {
    a1 &&& a2,
    b1 &&& b2,
    c1 &&& c2,
    d1 &&& d2
  }
end
查找目标IP

dest_ip = ifaddrs
          |> Enum.find(fn{addr, netmask}-> 
               apply_netmask(addr, netmask) == apply_netmask(source_ip, netmask) 
          end)
          |> elem(0)
更新 如果可能,我建议您只在一个网络适配器上打开UDP套接字。您可以使用
{ifaddr,inet:socket\u address()}
选项来实现这一点,例如:

{:ok, socket} = :gen_udp.open(19_999, [active: true, ifaddr: {192, 168, 0, 10}])

通过这种方式,您可以100%确保目标IP是192.168.0.10。此外,它还增加了一点安全性。

我在某个地方读到一条评论,说伪头永远不会发送,而是用来计算校验和,这意味着你无法得到伪头。这里是:我对你的问题有点困惑。如果应用程序正在接收数据包,那么数据包的目标地址就是主机的地址。您是否希望找到接收数据包时回复的目标地址?我本人从未使用过它,但
套接字
模块似乎支持获取有关接收数据包的更多信息:目标端口是您在
:gen_udp.open
(代码中为19_999)中设置的端口。但是,目标IP有点棘手,因为默认情况下,
:gen_udp.open
侦听
0.0.0
,它引用所有可用的网络适配器,包括虚拟适配器,如
lo
。由于不同网络中的设备无法相互通信,也许您可以通过查看源IP来确定哪个IP地址正在接收当前数据包。谢谢您的回答。我最终做了你在更新中建议的事情。似乎不可能使用:gen_udp获取伪头。