I'm writing a TCP/IP stack for embedded systems, but I wanted to test it on my host system.
Originally I tried with tap0 + a bridge. But I quickly realized it would make the most sense to bind to the ethernet device.
// devname is "eth0"
fd = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) ); // or AF_PACKET/IPPROTO_RAW / PF_PACKET/htons(ETH_P_ALL)
struct ifreq if_idx;
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, devname, IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0)
Error
struct sockaddr_ll socket_address = {
.sll_ifindex = if_idx.ifr_ifindex,
.sll_halen = 0,
.sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_ALL),
.sll_hatype = 0,
.sll_pkttype = PACKET_BROADCAST,
};
if ( bind( fd, (const struct sockaddr*)&socket_address, sizeof( socket_address ) ) < 0 )
Error
Then I also tried with this (These do not seem required, except to get the network card into promiscuous mode)
// https://stackoverflow.com/questions/10070008/reading-from-pf-packet-sock-raw-with-read-misses-packets MAYBE?
struct packet_mreq mr = {
.mr_ifindex = socket_address.sll_ifindex,
.mr_type = PACKET_MR_PROMISC,
};
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
FAIL( "Error setting packet membership\n" );
}
struct ifreq ifr = { 0 };
strncpy(ifr.ifr_name, devname, IFNAMSIZ-1);
if( ioctl( fd, SIOCGIFHWADDR, &ifr ) < 0 )
Error
memcpy( mymac, (char*)ifr.ifr_hwaddr.sa_data, 6 );
int rv = setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, devname, strlen(devname) );
I can easily receive packets, with read() and I can reply with write() or send() and everything works perfectly with other computers on the network. But when my local machine sends my IP stack packets, the stack receives the messages and tries sending back. I can see those replies in Wireshark as well when monitoring the device... but the system (userspace/kernel space) does not see the packets.
I tried specifically using sendto() with various sockaddr_ll addresses, and I can't seem to get it to fail, but still, my local system does not receive any of the packets locally.
What am I missing? How do I send packets from a C program to a local network interface and have my local system see them?
Right now, I can't even get my local system to see the arp replies.
EDIT: To clarify, my goal is to make it so my IP stack can reply to other computers on the same network or to the PC the app is running on, as though it were on a LAN.
EDIT: My issue with bridging was that I still gave my ethernet device an address, I should have only given my bridge device an address. With a bridge and code that connects to tap0, I could access the code from both sides and everything worked!
What am I missing?
Network interfaces work like a pipe. If you send a packet through one end, it always comes out through the other – a packet sent through the 'host' end will not be reflected back to the host regardless of its address.
Only the Wireshark packet capture merges both inbound and outbound packets into a single stream, but that does not mean they're all processed identically.
How do I send packets from a C program to a local network interface and have my local system see them?
Use a tap interface.
For communications only with the host, it doesn't need a bridge.
For communications with the host and an external network, use a bridge, and keep in mind that all interfaces that become "bridge ports" are detached from the host's networking stack and fully taken over by the bridge – which means that the host's IP address now needs to be configured on the bridge 'br0' interface, not anymore on the physical 'eth0' interface.