I want to receive UDP messages in Elixir and need to get the destination IP where the packets have been sent to.
In iex i can open a socket with this command:
{:ok, socket} = :gen_udp.open(19_999, [{:active, true}])
When i receive a message i will get it in the following format:
{:udp, port, source_ip, source_port, data}
The destination IP is not part of the message. According to UDP specification the source IP is not part of the UDP packet, but it is part of the IP pseudo header. When i use tcpdump i can see the target IPs of the packets.
Is there any way/parameter to get the IP or Pseudo header of the UDP packet?
The destination port is 19_999 for sure.
To figure out which IP is receiving the current packet, you need to know the configuration of all your network adapters, including the virtual ones. After that, you can get the destination IP from the source IP and network configuration because only the devices in the same network can talk to each other. You just need to find the IP that is in the same network as the source IP, among all the network adapters. You can judge whether 2 devices are in the same network by applying the netmask to the 2 IP addresses, and see if the results are the same.
By the way, if your server is behind NAT, you can't get the real source IP address of the client if it's not in the same network as the server. You only get the source IP address of the last hop (which is usually the IP address of your network gateway).
Getting the network configuration
{:ok, ifaddrs} = :inet.getifaddrs()
You'll get a list that looks like
[
{'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}, ...]}
]
Since we only need the addr and the netmask, we can just do a further Enum.map on the list:
ifaddrs = Enum.map(ifaddrs, fn{_, opts}-> {opts[:addr], opts[:netmask]} end)
Apply a netmask to an IP address
Just bitwise and them together.
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
Find the destination IP
dest_ip = ifaddrs
|> Enum.find(fn{addr, netmask}->
apply_netmask(addr, netmask) == apply_netmask(source_ip, netmask)
end)
|> elem(0)
UPDATE
If possible I suggest that you open the UDP socket on only one of your network adapters. You can use the {ifaddr, inet:socket_address()} option to achieve that, for example:
{:ok, socket} = :gen_udp.open(19_999, [active: true, ifaddr: {192, 168, 0, 10}])
In this way, you can 100% be sure that the destination IP is 192.168.0.10. Besides, it also adds a little bit of security.
Related
I want to capture some network traffic with the filter like "src x.x.x.x and dst x.x.x.x".
Ususally it works, but it doesn't work when the network traffic is encapsulated by protocls like Gre or Vxlan.
For example, the Gre encapsulate a message like this:
Ethernet II, Src: VMware_91:f6:ad (00:0c:29:91:f6:ad), Dst: VMware_dc:c7:71 (00:0c:29:dc:c7:71)
Internet Protocol Version 4, Src: 10.75.2.161, Dst: 10.75.2.140
Generic Routing Encapsulation (Transparent Ethernet bridging)
Ethernet II, Src: Micro-St_e3:51:57 (4c:cc:6a:e3:51:57), Dst: VMware_91:f6:ad (00:0c:29:91:f6:ad)
Internet Protocol Version 4, Src: 10.75.2.11, Dst: 10.75.2.160
So what should I do to capture those inner traffic?
I use "src 10.75.2.160" to capture but it tcpdump captured nothing.
tcpdump -i eth0 "src 10.75.2.11"
It doesn't work.
I use "ip[54:4]" to capture, it works, but my leader tell me it's not accurate.
So what else can I try?
I don't know how accurate your leader wants the filter, but if we can make a few assumptions about the outer IP and GRE headers, then the filter isn't too complicated. So here are the 2 assumptions:
The outer IP header is a standard 20 bytes. If this isn't the case or can't be relied upon, then everywhere I use 20 in the filter will need to be replaced with the IP header length calculation, which is (ip[0] & 0x0f) * 4.
The GRE header is a standard size of 4 bytes. If options are present and you can guarantee that all GRE headers are exactly the same size, then you can substitute 4 for the actual GRE header length, but if GRE options could vary, then it should still be possible to specify a capture filter that works with any size GRE header, but it will be much more complicated and hard to follow. I leave that as an exercise for the reader.
With those assumptions out of the way, here's a filter that would be the equivalent of "src 10.75.2.11" but for the inner source IP address of a IP/GRE/IP packet:
(ip proto 47) && (ip[20 + 2:2] = 0x0800) && (ip[20 + 4 + 12:4] = 0x0a4b0x0b)
Explanation:
ip proto 47: This captures only IP/GRE packets as GRE is assigned protocol number 47.
ip[20 + 2:2] = 0x0800: Since 0x0800 is the assigned Ethertype for IPv4, this captures only GRE packets where the Protocol Type field is IP, so only IP/GRE/IP packets. (NOTE: RFC 1701 states, "The Protocol Type field contains the protocol type of the payload packet. In general, the value will be the Ethernet protocol type field for the packet.")
ip[20 + 4 + 12:4] = 0x0a4b020b: This captures only the IP/GRE/IP packets where the source IP address field of the inner IP header is 10.75.2.11. (NOTE: To get 0x0a4b020b from 10.75.2.11, you just need to convert each decimal octet to hexadecimal and combine them into a single 4 byte value.)
To verify the resulting BPF code, you can run tcpdump with the -d option to check that the filter meets your expectations, for example:
tcpdump -i eth0 "(ip proto 47) && (ip[20 + 2:2] = 0x0800) && (ip[20 + 4 + 12:4] = 0x0a4b020b)"
You should see output of the following form:
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 9
(002) ldb [23]
(003) jeq #0x2f jt 4 jf 9
(004) ldh [36]
(005) jeq #0x800 jt 6 jf 9
(006) ld [50]
(007) jeq #0xa4b020b jt 8 jf 9
(008) ret #262144
(009) ret #0
If you're not familiar with BPF code, then I would suggest further reading elsewhere, as providing a BPF tutorial here is beyond the scope of this answer.
Finally, if you need to filter for the source IP address whether it's in the outer IP header or the inner IP header, then you can basically just combine the 2 filters, i.e.:
"(ip src 10.75.2.11) || ((ip proto 47) && (ip[20 + 2:2] = 0x0800) && (ip[20 + 4 + 12:4] = 0x0a4b020b))"
I'm trying to get my IP address using Erlang.
I found this example from here: Erlang: Finding my IP Address
local_ip_v4() ->
{ok, Addrs} = inet:getifaddrs(),
hd([Addr || {_, Opts} <- Addrs, {addr, Addr} <- Opts, size(Addr) == 4, Addr =/= {127,0,0,1}]).
But it returns a value like this: {127,0,0,1}
I want it to return a value like this: "{127,0,0,1}" with double quotes ("") because I want to use re:replace to change , to ..
How can I do that?
If you want to convert the IP address to a string, you can use the function inet:ntoa/1:
> inet:ntoa({127, 0, 0, 1}).
"127.0.0.1"
As a bonus, it handles IPv6 addresses as well:
> inet:ntoa({0,0,0,0,0,0,0,1}).
"::1"
The function returns the tuple because this is something that erlang code can handle natively. What you might want to do is transform this tuple to a string and then apply string operations. Details on how to do that can be found e.g. at Convert erlang terms to string, or decode erlang binary
When erlang module communicates with a c program via a port it sends a packet to the c program my question is when i create a port using this configuration
Port = open_port({spawn, ExtPrg}, [{packet, 2}]).
what are the parameters sent in the packet ?
what is the length of each parameter?
Erlang module and C program communicate via stdin and stdout by sending byte stream(sequence of bytes).
Creating a port with
Port = open_port({spawn, ExtPrg}, [{packet, N}]).
(valid values for N are 1,2,4)
tells erlang that the packets sent will be in this format :
N bytes : data length of the packet (we can conclude the data length)
data length bytes : data
I am setting up a peer 2 peer network and i cant find if my 2 subnets will both have a network and broadcast?
x.x.x.0 and x.x.x.127 will be my first subnet's broadcast/network.
x.x.x.128 and x.x.x.255 will be the second subnet broadcast/network addresses.
or is it just x.x.x.0 and x.x.x.255 that are the broadcast/network addresses?
This is defined by the subnetmask, which is why you normally write IP addresses as:
192.168.1.24/24
This means the network address is 192.168.1.0 and the broadcast address 192.168.1.255. The network part of the is /24 bits, and host id is 8 bits. For the broadcast address you always set all the host id bits to 1 (8 bits set to one = 255), and for the network address you set it to 0.
Both subnet's will have the broadcast/network ip's so there will be -4 ip in the total amount of valip ip addresses in the entire subnet.
I was told to ask this here:
10:53:04.042608 IP 172.17.2.12.42654 > 172.17.2.6.6000: Flags [FPU], seq 3891587770, win 1024, urg 0, length 0
10:53:04.045939 IP 172.17.2.6.6000 > 172.17.2.12.42654: Flags [R.], seq 0, ack 3891587770, win 0, length 0
This states that the flags set are FPU and R. What flags do these stand for and what kind of exchange is this?
The flags are:
F - FIN, used to terminate an active TCP connection from one end.
P - PUSH, asks that any data the receiving end is buffering be sent to the receiving process.
U - URGENT, indicating that there is data referenced by the urgent "pointer."
R - RESET, indicating that a packet was received that was NOT part of an existing connection.
It looks like the first packet was manufactured, or possibly delayed. The argument for it being manufactured is the urgent flag being set, with no urgent data. If it was delayed, it indicates the normal end of a connection between .12 and .6 on port 6000, along with a request that the last of any pending data sent across the wire be flushed to the service on .6.
.6 has clearly forgotten about this connection, if it even existed. .6 is indicating that while it got the FIN packet, it believes that the connection that FIN packet refers to did not exist.
If .6 had a current matching connection, it would have replied with a FIN-ACK instead of RST, acknowledging the termination of the connection.