tap network interface is a way to forward data layer packets (ethernet) to user space. it is very similar to tun(actually they share command and /dev). note that run works on network layer (forwards IP packets to user space).

We will use 3 shells in this examples

Shell 1 Link to heading

Create interface and start a ping

sudo ip tuntap add mode tap dev tap0
sudo ip addr add 10.0.3.0/24 dev tap0
sudo ip link set dev tap0 up
ip route get 10.0.3.50
ping 10.0.3.30

Shell 2 Link to heading

Start tcp capture.

sudo tcpdump -i tap0 -w samepl.pcap
tcpdump: listening on tap0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C5 packets captured
5 packets received by filter

Note, the message says is waiting on link-type Ethernet. but in case of tun it would be

tcpdump: listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes

Shell 3 Link to heading

The user space program is similar to tun but but with difference flags(IFF_TAP)

#include <fcntl.h>  /* O_RDWR */
#include <string.h> /* memset(), memcpy() */
#include <stdio.h> /* perror(), printf(), fprintf() */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <sys/ioctl.h> /* ioctl() */
#include <unistd.h> /* read(), close() */

/* includes for struct ifreq, etc */
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int tun_open(char *devname)
{
  struct ifreq ifr;
  int fd, err;

  if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) { perror("open /dev/net/tun");exit(1); }

  memset(&ifr, 0, sizeof(ifr));
  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
  strncpy(ifr.ifr_name, devname, IFNAMSIZ);

  if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
    perror("ioctl TUNSETIFF");close(fd);exit(1);
  }

  return fd;
}

int main(int argc, char *argv[])
{
  int fd, nbytes;
  char buf[1600];

  fd = tun_open("tap0"); /* devname = ifr.if_name = "tun0" */
  printf("Device tap0 opened\n");
  while(1) {
    nbytes = read(fd, buf, sizeof(buf));
    printf("Read %d bytes from tap0\n", nbytes);
  }
  return 0;
}

When i compile and run the program above. It would print the following capture ethernet packet.

$ ./a.out
Device tap0 opened
Read 110 bytes from tap0

cleanup Link to heading

These commands remove the tap interface

sudo ip link set dev tap0 down
sudo ip tuntap del mode tun dev tap0