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);
}