Linux use interface for raw socket only - c

I'm having a OpenWrt Linux distribution for my embedded system. The device has 3 network interfaces: eth0, eth1 and wlan0.
One of the network interface (eth0) should be used for raw socket programming only. I'm able to create a socket with the parameters AF_PACKET, SOCK_RAW, ETH_P_ALL. The socket receives all network traffic, I can send packets and everything is OK.
But my problem is, that the OS is also using the interface for sending an reciving (e. g. ARP and ICMP requests/responses).
Is there any option that the interface is only used by my program and not by the OS itself?

This is not possible to achieve with a vanilla kernel. But this can come close:
First, ignore all arp requests on that interface:
echo 8 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
Then, disable IPv6:
echo 1 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6
Finally, filter all IPv4 packets coming on that interface
iptables -I INPUT -i eth0 -j DROP
And do not set an IP-address or routes on that interface. This is of course not perfect, certain packets will still be processed by the kernel, but I don't think there is a much better solution.

Related

How to send a packet to the kernel?

I have two interfaces in my Linux system - eth0 and eth1. I have opened a raw socket on eth0 and I am listening on it for incoming packets. When a packet comes from eth0, I forward it to eth1 after changing the ethernet header (specifically destination MAC to eth1's MAC address). The packet should now be accepted by the interface and sent to the kernel for further processing and eventually to the application waiting for it. But for some reason the packet reaches eth1 (as I can see from wireshark) but the application does not receive it (the application is ping and I don't see the ping reply).
How do I send the packet to eth1 such that it is accepted and sent upstream to the kernel?
There is probably a misunderstanding here:
If you send a packet through a raw socket on an interface, in your case eth1, it will not be treated as local to the kernel, regardless of its mac-address, but will leave the interface to the network (with its own mac-address as destination). This is what you observe with wireshark.
If you want the packet to be processed by your kernel, send it to the lo-interface (Loopback-interface), which is specifically for that purpose.

C RAW socket communication with custom ETH type

So I have two userspace applications (lets say app A and B) running on linux 2.6 kernel.
app A sends raw packet with a custom ethernet type (ETH_FOO) using the socket below
socket(PF_PACKET, SOCK_RAW, htons(ETH_FOO));
if app B opens a raw socket with ETH_P_ALL and listens to all interfaces without binding, it can successfully receive pkts sent by A with type ETH_FOO.
But if B opens the socket with type ETH_FOO, no packet is observed. I just want to capture ETH_FOO pkts. What may be the problem?
This is my first question here. Pardon my mistakes if there is any. Also I can not copy the entire code since it's not mine and somewhat propriatery.
When you use ETH_P_ALL, you are listening all packets, both ingoing and outgoing.
If you are in the same machine, using the same network interface, when you send a packet, there is no ingoing packet. Using ETH_P_ALL will get you the outgoing packet.
When you specify other value than ETH_P_ALL, only incoming packets are listened to. And you get nothing if using the Ethernet interface in the same machine.
You have two options here:
use different machines
in the same machine, use the loopback adapter (which creates an ingoing packet for every outgoing packet). The loopback adapter is listed together with the Ethernet adapter when you type ip a.
It took me some time to learn this, and I did it here, where you can learn a bit more.

Check incoming interface on TCP socket

In network programming (C & Linux) with a TCP socket, how can I check the interface that received the packet. I know this can be done very easily with a SOCK_DGRAM and the IP option IP_PKTINFO, but this option does not work on SOCK_STREAM. In this case (for what im programming) I must know the interface that received the packet (the respond that gives back the server depends on that).
One possible solution that I found is to use SOCK_RAW and IPPROTO_TCP (with SOCK_RAW I can set the IP_PKTINFO option) but that implies that i'll be receiving all the TCP traffic that arrives to the machine and i don't want that. Another possible solution that I'm thinking is to check the destination IP against the routing table and get the exit interface from there but what about IPv6? What if the destiny IP its IPv6 link-local?
If anyone has another solution or idea I'll be glad to read it. Thanks in advance
When your TCP server accepted a client connection, you will have a socket to represent the connection, you could call getsockname on the socket, it will give you the address associated on the socket, namely the ip addresses on your side.
Next step, you can call getifaddrs to get all the interfaces and their information on your system, including name(like eth0) and ip address. At this point, you can search this list with the ip obtained previously via getsockname, you can get the interface you want as a result.
reference:
http://linux.die.net/man/2/getsockname
http://linux.die.net/man/3/getifaddrs

How to receive a packet UDP with a known destination MAC different to that of the listening interface

I am trying to listen for a specific discovery packet that will be sent over UDP destined for a known MAC address. This MAC address will not be the same as the MAC address of the interface I am receiving on.
I have tried Beej's UDP listener but it only receives packets with the correct MAC.
When I listen with tcpdump I can see the packets are making it to the device.
It looks like I could receive on a raw socket (although haven't got that working yet) but would there be a way to filter only the destination MAC I want?
Can anyone give me any guidance with this?
Your interface does not normally receive packets that are not sent to its own address. It just ignores them.
You need to set your network interface in promiscuous mode and use a packet capture interface provided by Linux.
Have a look at libpcap, the manual page is here.
This is the same mechanism that tcpdump uses. It is a library which provides an interface and a filter to the packet capture mechanism in the kernel.

How do I send UDP packet from a specific interface on Linux?

How do I send UDP packet from a specific interface on Linux using C? Should I use bind? Is it possible to send UDP from the interface not having IP address?
Thanks.
Use bind. You cannot send UDP packets via an interface that does not have an IP address, because UDP uses the Internet Protocol and the Internet Protocol requires an IP address.
You can bind a socket to a specific interface by using the SO_BINDTODEVICE socket option, however this requires root privileges.
Alternately, you can set the IP_PKTINFO option, and use sendmsg for sending, setting the in_pktinfo's ipi_ifindex to the index of your interface.
You need to use socket option IP_MULTICAST_IF.
See here: Multicast-HOWTO-6.html

Resources