Re: Kernel tunnel driver and routing?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi!

> I have attached a changed version of tuntest1.c which seems to run on my pc.

trying to resend the attachment...

	-Michi
-- 
programing a layer 3+4 network protocol for mesh networks
see http://michaelblizek.twilightparadox.com
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <fcntl.h>
#include <memory.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>

#include <linux/if.h>
#include <linux/if_tun.h>

#include <linux/if_tunnel.h>


extern int errno;

#define MAX_SIZE 2048
#define IF_TYPE_TUN 4

struct message
{
   int length;                  /* number of characters in packet  */
   unsigned char msg[MAX_SIZE]; /* the packet itself               */
};


/*
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * open and initialize the IO interface.  Return -1 for error.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */
int
tun_open (char *name)
{
   struct ifreq ifr;
   int err, fd;
//   struct ip_tunnel_parm p;

   if ((fd = open ("/dev/net/tun", O_RDWR)) < 0)
   {
      printf ("%s\n", name);
      return -1;
   }

   memset (&ifr, 0, sizeof (ifr));

   /* Flags: IFF_TUN   - TUN device (no Ethernet headers) 
    *        IFF_TAP   - TAP device  
    *
    *        IFF_NO_PI - Do not provide packet information  
    */
   ifr.ifr_flags = IFF_TUN;
   if (*name)
      strncpy (ifr.ifr_name, name, IFNAMSIZ);

   if ((err = ioctl (fd, TUNSETIFF, (void *) &ifr)) < 0)
   {
      close (fd);
      printf ("ioctl on TUNSETIFF failed %d\n", err);
      return err;
   }
   strncpy (name, ifr.ifr_name, IFNAMSIZ);      // the name actually allocated

   printf ("Opened %s\n", name);
   return fd;
}

int
set_flag (int fd, char *name, short flag)
{
   struct ifreq ifr;
   fd = socket (AF_INET, SOCK_DGRAM, 0);
   if (fd < 0)
   {
      printf ("tunnel_ioctl: socket: %s\n", strerror (errno));
      return fd;
   }


   strncpy (ifr.ifr_name, name, IFNAMSIZ);
   if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
   {
      printf ("%s: unknown interface: %s\n", name, strerror (errno));
      return (-1);
   }
   strncpy (ifr.ifr_name, name, IFNAMSIZ);
   ifr.ifr_flags |= flag;
   if (ioctl (fd, SIOCSIFFLAGS, &ifr) < 0)
   {
      perror ("SIOCSIFFLAGS");
      return -1;
   }
   return (0);
}


int
do_ioctl_get_ifindex (const char *dev)
{
   struct ifreq ifr;
   int fd;
   int err;

   strncpy (ifr.ifr_name, dev, IFNAMSIZ);
   fd = socket (AF_INET, SOCK_DGRAM, 0);
   err = ioctl (fd, SIOCGIFINDEX, &ifr);
   if (err)
   {
      perror ("ioctl");
      return 0;
   }
   close (fd);
   return ifr.ifr_ifindex;
}


unsigned int
get_addr (char *name)
{
   int i;
   unsigned int addr = 0;
   char *cp;
   unsigned char *ap = (unsigned char *) &addr;

   for (cp = name, i = 0; *cp; cp++)
   {
      if (*cp <= '9' && *cp >= '0')
      {
         ap[i] = 10 * ap[i] + (*cp - '0');
         continue;
      }
      if (*cp == '.' && ++i <= 3)
         continue;
      return -1;
   }
   return addr;
}


int
set_addresses (int fd, char *name, unsigned int remote, unsigned int local)
{
   struct ifreq ifr;
   struct ip_tunnel_parm p;

   memset (&p, 0, sizeof (p));
   p.iph.version = 4;
   p.iph.ihl = 5;
   p.iph.frag_off = htons (IP_DF);      /* Flag: Don't Fragment */
   p.iph.ttl = 64;              /* fixed TTL for the outer IP header to make the
                                 * tunnel transparent for traceroute like applications
                                 */
   strncpy (p.name, name, IFNAMSIZ);

   p.iph.protocol = IPPROTO_IPIP;
   p.iph.daddr = htonl (remote);
   p.iph.saddr = htonl (local);

   p.link = do_ioctl_get_ifindex ("eth0");
   if (p.link == 0)
   {
      printf ("get_ifindex: eth0: %s\n", strerror (errno));
      return -1;
   }

   memset (&ifr, 0, sizeof (ifr));
   strncpy (ifr.ifr_name, name, IFNAMSIZ);
   ifr.ifr_ifru.ifru_data = (void *) &p;

   if (ioctl (fd, SIOCCHGTUNNEL, &ifr) < 0)
   {
      printf ("tunnel_ioctl: SIOCCHGTUNNEL %s\n", strerror (errno));
      return -1;
   }

   close (fd);
   return 0;
}


/*
 * Read data from the specified interface. Return a complete IP datagram.
 * If the packet is not complete, then don't return anything.
 * By experiment the packet returned has the ethernet and outer IP header attached still so skip them (32 bytes)
 */
int
tun_read (int fd, struct message *m)
{
   int n;
   char buf[MAX_SIZE];

   n = read (fd, (char *) buf, MAX_SIZE);
   if (n < 0)
   {
      m->length = 0;
      if (errno == EINTR)
         return 0;
      if (errno == EWOULDBLOCK)
         return 0;
      printf ("read from tunnel device");
      return -1;
   }
   memcpy ((char *) m->msg, buf, n);
   m->length = n;
   return n - 32;
}

/*
 * write data to the specified interface. Return as soon as possible.
 * The buffer provided will be a complete IP datagram.
 */
int
tun_send (int fd, struct message *m)
{
   int n;
   char buf[MAX_SIZE];


   if (m->length <= 0)
      return 0;

   memcpy (buf, (char *) m->msg, m->length);
   n = write (fd, buf, m->length);
   if (n < 0)
   {
      if (errno == EINTR)
      {
         printf ("Send: eintr\n");
         return 0;
      }
      if (errno == EWOULDBLOCK)
      {
         printf ("Send: wouldblock\n");
         return 0;
      }
      printf ("write to tunnel device");
      return -1;
   }
   return n;
}


int
main (int argc, char *argv[])
{
   int tun_fd, nread, i;
   struct message m;
   unsigned int srcip, dstip;
   char name[10] = "tun%d";

   if (argc < 3)
   {
      printf ("%s: ipaddr encap_route\n", argv[0]);
      printf ("eg. %s: 172.25.1.2 10.0.0.0/8\n", argv[0]);
      exit (1);
   }

   tun_fd = tun_open (name);    /* tun interface */
   if (tun_fd < 0)
   {
      perror ("Allocating interface");
      exit (1);
   }

   if (fcntl (tun_fd, F_SETFL, FNDELAY) < 0)
   {
      perror ("setting non-blocking I/O on tunnel device");
      exit (1);
   }

   if (set_flag (tun_fd, name, IFF_UP | IFF_RUNNING) < 0)
   {
      perror ("setting link up on tunnel device");
      exit (1);
   }

   if (set_flag (tun_fd, name, IFF_POINTOPOINT) < 0)
   {
      perror ("setting PTP on tunnel device");
      exit (1);
   }

#if 0
   {
   unsigned int remote, local;
   remote = get_addr (argv[1]);
   local = get_addr (argv[2]);
   set_addresses (tun_fd, name, remote, local);
   }
#else
   {
   char cmd[100];
   sprintf (cmd, "ip addr add %s dev %s", argv[1], name);
   system (cmd);
   sprintf (cmd, "ip route add %s dev %s", argv[2], name);
   system (cmd);
   }
#endif

   /* Now read data coming from the kernel */
   while (1)
   {
      /* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
      sleep (1);
      nread = tun_read (tun_fd, &m);
      if (nread < 0)
      {
         if (errno == EINTR)
            continue;
         if (errno == EWOULDBLOCK)
         {
            printf ("Reading\n");
            continue;
         }
         perror ("Reading from interface");
         close (tun_fd);
         exit (1);
      }

      if (nread > 0)
      {
         printf ("\nRead %d bytes from %d.%d.%d.%d to %d.%d.%d.%d\n", nread, m.msg[16], m.msg[17], m.msg[18], m.msg[19],
                 m.msg[20], m.msg[21], m.msg[22], m.msg[23]);
         for (i = 0; i < nread; i++)
         {
            if ((i & 15) == 0)
               printf ("\n");
            printf (" %02x", m.msg[i]);
         }
         printf ("\n");

         // swap source and destination IP addresses and send the packet back
         (void) memcpy ((char *) &srcip, (char *) m.msg + 16, 4);
         (void) memcpy ((char *) &dstip, (char *) m.msg + 20, 4);
         (void) memcpy ((char *) m.msg + 20, (char *) &srcip, 4);
         (void) memcpy ((char *) m.msg + 16, (char *) &dstip, 4);

         tun_send (tun_fd, &m);
      }
   }
   exit (0);
}

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux