Is there a way to get the destination MAC address, if the destination IP is known, using ANSI C? I would preferably do it with a system call so the kernel deals with it all and I can take advantage of the ARP cache. I know I can build and send my own ARP request, but then I would not have the caching functionality etc unless I implement it myself so it feels like letting the kernel handling it is the way to go.
Not an exact answer, because it's not ANSI C, but you can read the arp table from /proc/net/arp (in Linux, that is). That's where arp looks. For any other OS, the easiest way is to use strace or an equivalent on the equivalent arp-cache-showing utility.
What I decided to do was to send my own ARP packets and caching it internaly in my application. If the destination is outside my local network I parse /proc/net/route and extract the gateway for the given interface and send an arp packet to the gateway to get it's macaddress (since that is the destination macaddress of packets destined outside the local network).
Related
I want to send a packet to another machine but with a different MAC address in the ethernet header. For this I am using raw sockets in C and creating my own ethernet header so that I can set the source MAC as desired. The trouble is that I am not sure what destination MAC address to fill in the header. I know the IP of the destination machine but not the MAC. Even if I knew, I don't want to hardcode this MAC.
One option I see is that my machine would know the MAC in its ARP table and I could read it and get the MAC address and fill it in. But doing this before sending each packet is overhead. I could read it once and keep using but what if some day the destination machine gets replaced. The admin would assign the same IP address to the new machine but the MAC address would be different. Probably when the new machine boots up, it would send a Gratuitous ARP and my machine would update its ARP table. But my program wouldn't know this. My program would keep sending packets with old MAC.
I feel I am missing something very basic. Thoughts?
What you are seeing here is the same problem that everyone faces, who tries to implement a network stack.
You have several options:
If the packet is a reply packet, then just use the MAC address of the from address
You can maintain an own arp-table and send a arp request if the entry in your table is missing or outdated. Parse arp replies and update your table accordingly. Packets to be sent without a valid arp table entry have to be queued. This is the most elegant, but also a very demanding option.
You can simply send the packet to the MAC of your local router. It will forward the packet to the correct host specified in the IP header. If your local router employs protocols like vrrp, hsrp or gblp, then the MAC address is always the same and doesn't change, even if your router is replaced.
You can read the MAC address from /proc/net/arp or with ioctl(SIOCGARP, ...);, but the entry for the IP you are looking for might not be present, if your host hasn't tried to communicate with it recently. You could, of course, send a dummy packet with sendto(); to that host before reading the arp table.
If you describe in more detail what you are planning to do, the suggestions might get better.
You can set the MAC address for the device with SIOCSIFHWADDR ioctl request. The manual for netdevice is a good starting point for this.
Is there a way to view all the IPv4 packets sent to a Linux computer?
I know I can capture the packets at the ethernet level using libpcap. This can work, but I don't really want to defragment the IPv4 packets. Does libpcap provide this functionality and I'm just missing it?
One thing that kinda works is using a tun device. I can capture all the IPv4 traffic by routing all traffic to the tun device via something like ip route add default via $TUN_IP dev $TUNID. This also stops outbound traffic though, which is not what I want.
I just want to see the IPv4 packets, not intercept them. (Or, even better, optionally intercept them.)
Edit: I'm specifically looking for a programmatic interface to do this. E.g. something I can use from within a C program.
Yes, you can see all the packets that arrive at your network interface. There are several options to access or view them. Here a small list of possible solutions, where the first one is the easiest and the last one the hardest to utilize:
Wireshark
I'd say this is pretty much the standard when it comes to protocol analyzers with a GUI (uses libpcap). It has tons of options, a nice GUI, great filtering capabilities and reassembles IP datagrams. It uses libpcap and can also show the raw ethernet frame data. For example it allows you to see layer 2 packets like ARP. Furthermore you can capture the complete data arriving at your network interface in a file that can later be analyzed (also in Wireshark).
tcpdump
Very powerful, similar features like Wireshark but a command line utility, which also uses libpcap. Can also capture/dump the complete interface traffic to a file. You can view the dumped data in Wireshark since the format is compatible.
ngrep
This is known as the "network grep" and is similar to tcpdump but supports regular expressions (regex) to filter the payload data. It allows to save captured data in the file format supported by Wireshark and tcpdump (also uses libpcap).
libnids
Quotation from the official git repository:
"Libnids is a library that provides a functionality of one of NIDS
(Network Intrusion Detection System) components, namely E-component. It means
that libnids code watches all local network traffic [...] and provides convenient information on them to
analyzing modules of NIDS. Libnids performs:
assembly of TCP segments into TCP streams
IP defragmentation
TCP port scan detection"
libpcap
Of course you can also write your own programs by using the library directly. Needless to say, this requires more efforts.
Raw or Packet Sockets
In case you want to do all the dirty work yourself, this is the low level option, which of course also allows you to do everything you want. The tools listed above use them as a common basis. Raw sockets operate on OSI layer 3 and packet sockets on layer 2.
Note: This is not meant to be a complete list of available tools or options. I'm sure there are much more but these are the most common ones I can think of.
Technically you have to make a copy of the received packet via libpcap. To be more specific, what you can do is to get packets with libpcap, that way the packets will be kind of blocked, so you need to re send them to the destination. Lets say that you want to make a Fire-Wall or something, what you should do is to have a layer that can work like getting the package and then send it to the destination, in between you can make a copy of what you got for further processes. In order to make the intercept option, you need to create some predefined rules, i.e. the ones that violates the rules will not be send again to their destination.
But that needs a lot of efforts and I don't think you want to waist your life on it.
Wire-shark as mentioned by #Barmar can do the job already.
If you need some kind of command line interface option I would say that "tcpdump" is one of the best monitoring tools. for example for capturing all ipv4 HTTP packets to and from port 80 the command will be:
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
for more information and options see tcpdump
Please be specific if you need to write a program for it, then we can help about how to do it.
just as title says.
Let's assume this situation:
I have a network and I need to know IP adresses and everything else related of all computers connected to mantain socket sending via Winsock under Windows.
Is there better way than looping throught IP Adresses range and sending something like:
"Are You there?" and waiting for answer from client?
Performing an ARP scan would tell you which devices are active on the network, regardless of device type or operating system. So this would include PCs, laptops, phones, routers, and any other devices with a NIC. This is the most reliable way of scanning for live hosts on a network.
ARP is the protocol that translates IP addresses into MAC addresses, or vice versa. It allows routing devices to translate between the logical network and the physical network. When you send a packet to, say, 192.168.1.99, your system first sends out an ARP request for 192.168.1.99, saying something along the lines of "Who has 192.168.1.99? Tell [my MAC]". Other devices on the network see this packet, and the owner of that IP address will reply "Hi [MAC], I'm 192.168.1.99, my MAC is 00:12:34:56:78:90".
You can (ab)use this protocol to discover network devices. If you know you're on 192.168.1.x, you send ARP requests for 192.168.1.1 through 192.168.1.254, and record the results. Every reply you get indicates a live system at the defined IP address.
Keep in mind that not all your users will be on 192.168.1.0/24, so you'll need to check the current network configuration first.
As far as doing this in C goes, it's not a simple task. However, you can take a look at this example which implements ARP scanning.
An alternative to the ARP scan suggested by #Polynomial is the PING scan.
Same concept, PING each address in your subnet, and record the results.
Just as an ARP scan may give you false positives (because there is a router saying "I'll deal what that address" whether there is a device on it or not), so too, PING can give you false negatives (as some systems disable the ICMP/PING command).
There is a tool called fping that implements this kind of PING scan in a massively parallel way. Fping is originally a *NIX program, but there are Windows versions out there. You should be able to find the source to peruse if you want to learn the gory details.
This is a follow-up to my previous question: ARP reply packet does not update ARP cache on Ubuntu. It turned out that my problem was that I was using an arbitrary MAC address as my source MAC (ie. one that doesn't exist on my network, say aa:bb:cc:dd:ee:ff). I could send ARP replies to poison my cache with no problem as long as my source MAC matches with the MAC of my NIC. I tried to manually set my NIC to have an arbitrary MAC address, then send ARP replies using that as my ARP packet's source MAC - also worked.
I am wondering if anybody knows the inner workings of this. Was there some kind of check that prevents packets with mismatched source MAC from being sent? Was it a check between the source MAC of the Ethernet frame vs. the source MAC of the ARP packet? And for the purpose of an experiment that I'm running, is there a way to bypass this restriction?
JY
Various optimizations are possible to make ARP work more efficiently.
To start with, once a machine has run ARP, it caches the result in
case it needs to contact the same machine shortly. Next time it will
find the mapping it its own cache, thus eliminating the need for a
second broadcast. In many cases, host 2(receiver) will need to send
back a reply, forcing it, too, to run ARP to determine the sender's
Ethernet address. This ARP broadcast can be avoided by having sender
include its IP-to-Ethernet mapping in the ARP packet.
Quoted from Tanenbaum's Computer Networks, fifth Edition p486-487
So it looks like your receiver fails to resolve MAC of the sender. And Tanenbaum presented a solution to you to avoid this failure.
Was there some kind of check that prevents packets with mismatched
source MAC from being sent? Was it a check between the source MAC of
the Ethernet frame vs. the source MAC of the ARP packet?
You mention Ubuntu. In Linux, you can send any Ethernet frame (see examples), so internally there is no any kind of such check. But you did not tell how do you attempt to send the spoofed ARP messages; maybe the way you are doing it is limiting your options for the source MAC address.
If I use arp and arping on machines in my local network I get the mac addresses from them. In the same way I can construct and send a ARP request and collect the response to these machines. This is used since I build raw packets completely from scratchy (to allow spoofing of every possible field, including mac addresses if needed). But, when I try arping or arp on external ip's and hosts such as google.com it doesn't get any reply. What should the destination mac address be set to when sending packets to targets outside my local network? I guess the router since that's what passes it on... am I correct? Is there a quick way in ANSI C to collect the mac address of the router in use by the computer? Or at least the IP so I can send a ARP request to it.
Thanx in advance
MAC operations are limited to machines directly connected within your subnet. So you should use the router's MAC address for packets intended for hosts outside your subnet.
There are numerous ways to obtain the router's IP address.
You can parse the configuration files on your local host if the interface is statically configured.
You can see if your compute platform has an API that lets you access the interface configuration information directly. This would work in both static and dhcp cases.
You can write socket code to send an ICMP message to an outside address then parse the incoming responses. They will be from the router. The stack will, in this case, find the router for you.
It should be set to the gateway (assuming ethernet on that link...).