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