tun device is virtual network interface that can send raw IP packets to user space instead of link/phy layer. tun/tap devices are used with IPSec application like OpenVPN. more details in the wiki. This is a write up based on the answer in SO

in this example, we will use 3 to create tun, run application and capture pacp.

Shell 1 - How to create tun device Link to heading

create the tun0 interface and update the route table for that device.. and up to bring up the interface

sudo ip tuntap add mode tun dev tun0
sudo ip addr add 10.0.3.0/24 dev tun0 
sudo ip link set dev tun0 up

Then in the same shell, run ping to that IP

ping 10.0.3.50

Shell 2 -How can user-space read the virtual tun network interface Link to heading

From linux kernel docs, The application has to ioctl to register fd to that tun0 interface.

#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_TUN;
  strncpy(ifr.ifr_name, devname, IFNAMSIZ); // devname = "tun0" or "tun1", etc

  /* ioctl will use ifr.if_name as the name of TUN
   * interface to open: "tun0", etc. */
  if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
    perror("ioctl TUNSETIFF");close(fd);exit(1);
  }

  /* After the ioctl call the fd is "connected" to tun device specified
   * by devname ("tun0", "tun1", etc)*/

  return fd;
}


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

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

Shell 3 - Capture pcap Link to heading

we can see the network traffic using tcpdump

sudo tcpdump -i tun0 -w samepl.pcap

and using thark, we can that raw frame has IP and ICMP(the protocol for ping)..

Frame 1: 84 bytes on wire (672 bits), 84 bytes captured (672 bits)
    Encapsulation type: Raw IP (7)
    ....
    [Protocols in frame: raw:ip:icmp:data]
Raw packet data
Internet Protocol Version 4, Src: 10.0.3.0, Dst: 10.0.3.50
    ....
    Source: 10.0.3.0
    Destination: 10.0.3.50
Internet Control Message Protocol
    Type: 8 (Echo (ping) request)
    Code: 0
    ....