I'm trying to create a user space network stack for learning purposes.
What I'm trying to do is to set up a tap device on my VirtualBox machine with Windows 10 host. The VirtualBox is running Ubuntu 16.04 on a bridged network.
The way I'm setting up the tap device is by creating a tap in /dev/net
:
sudo mknod /dev/net/tap c 10 200
My program is running tun_alloc
:
/*
* Taken from Kernel Documentation/networking/tuntap.txt
*/
int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
/* Arguments taken by the function:
*
* char *dev: the name of an interface (or '\0'). MUST have enough
* space to hold the interface name if '\0' is passed
* int flags: interface flags (eg, IFF_TUN etc.)
*/
/* open the clone device */
if ((fd = open("/dev/net/tap", O_RDWR)) < 0)
{
printf("Cannot open TUN/TAP dev\n");
exit(1);
}
/* preparation of the struct ifr, of type "struct ifreq" */
memset(&ifr, 0, sizeof(struct ifreq));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (*dev)
{
/* if a device name was specified, put it in the structure; otherwise,
* the kernel will try to allocate the "next" device of the
* specified type */
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
/* try to create the device */
if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0)
{
printf("ERR: Could not ioctl tun: %s\n", strerror(errno));
close(fd);
return err;
}
/* if the operation was successful, write back the name of the
* interface to the variable "dev", so the caller can know
* it. Note that the caller MUST reserve space in *dev (see calling
* code below) */
strcpy(dev, ifr.ifr_name);
/* this is the special file descriptor that the caller will use to talk
* with the virtual interface */
return fd;
}
And then runs the following shell commands (from program):
ip link set dev tap0 up
ip route add dev tap0 192.168.1.0/24
ip address add dev tap0 local 192.168.1.21
When I run this, my ifconfig
shows:
enp0s3 Link encap:Ethernet HWaddr 08:00:27:2f:ba:f8
inet addr:192.168.1.36 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::445b:f137:4390:8b40/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:149 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1239 (1.2 KB) TX bytes:24836 (24.8 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:68 errors:0 dropped:0 overruns:0 frame:0
TX packets:68 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5351 (5.3 KB) TX bytes:5351 (5.3 KB)
tap0 Link encap:Ethernet HWaddr e2:c8:48:94:af:9c
inet addr:192.168.1.21 Bcast:0.0.0.0 Mask:255.255.255.255
inet6 addr: fe80::e0c8:48ff:fe94:af9c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1 errors:0 dropped:0 overruns:0 frame:0
TX packets:51 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:42 (42.0 B) TX bytes:6078 (6.0 KB)
When I don't run the program and don't have the tap0 interface, I can ping to my host machine, and it can ping me.
But when I run this program, and my tap device is up, I suddenly lose communication to my host.
Furthermore, when I ping from the host to my VM, I don't see any packets read by the tunnel, and in fact when check out the ARP table of my Windows host, I see that also the enp0s3
interface MAC address was deleted from this ARP table.
Just to be clear, I do see other packets received on the tap device, just not from outside my host.
This is what I see when I test ARP requests from inside my host machine:
arping -I tap0 192.168.1.21
ARPING 192.168.1.21 from 192.168.1.21 tap0
Unicast reply from 192.168.1.21 [00:0C:29:6D:50:25] 0.545ms
Unicast reply from 192.168.1.21 [00:0C:29:6D:50:25] 0.733ms
Now my questions are these:
Why, when running my tap device, I don't see any packets coming from outside?
Why I cant ping my other (enp0s3) interface as well? what is the relation?