00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "config.h"
00012
00013 #include <sys/ioctl.h>
00014 #include <sys/socket.h>
00015 #include <sys/sockio.h>
00016
00017 #include <net/if.h>
00018 #include <net/if_tun.h>
00019
00020 #include <fcntl.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <stropts.h>
00025 #include <unistd.h>
00026
00027 #include "dnet.h"
00028
00029 #define DEV_TUN "/dev/tun"
00030 #define DEV_IP "/dev/ip"
00031
00032 struct tun {
00033 int fd;
00034 int ip_fd;
00035 int if_fd;
00036 char name[16];
00037 };
00038
00039 tun_t *
00040 tun_open(struct addr *src, struct addr *dst, int mtu)
00041 {
00042 tun_t *tun;
00043 char cmd[512];
00044 int ppa;
00045
00046 if ((tun = calloc(1, sizeof(*tun))) == NULL)
00047 return (NULL);
00048
00049 tun->fd = tun->ip_fd = tun->if_fd = -1;
00050
00051 if ((tun->fd = open(DEV_TUN, O_RDWR, 0)) < 0)
00052 return (tun_close(tun));
00053
00054 if ((tun->ip_fd = open(DEV_IP, O_RDWR, 0)) < 0)
00055 return (tun_close(tun));
00056
00057 if ((ppa = ioctl(tun->fd, TUNNEWPPA, ppa)) < 0)
00058 return (tun_close(tun));
00059
00060 if ((tun->if_fd = open(DEV_TUN, O_RDWR, 0)) < 0)
00061 return (tun_close(tun));
00062
00063 if (ioctl(tun->if_fd, I_PUSH, "ip") < 0)
00064 return (tun_close(tun));
00065
00066 if (ioctl(tun->if_fd, IF_UNITSEL, (char *)&ppa) < 0)
00067 return (tun_close(tun));
00068
00069 if (ioctl(tun->ip_fd, I_LINK, tun->if_fd) < 0)
00070 return (tun_close(tun));
00071
00072 snprintf(tun->name, sizeof(tun->name), "tun%d", ppa);
00073
00074 snprintf(cmd, sizeof(cmd), "ifconfig %s %s/32 %s mtu %d up",
00075 tun->name, addr_ntoa(src), addr_ntoa(dst), mtu);
00076
00077 if (system(cmd) < 0)
00078 return (tun_close(tun));
00079
00080 return (tun);
00081 }
00082
00083 const char *
00084 tun_name(tun_t *tun)
00085 {
00086 return (tun->name);
00087 }
00088
00089 int
00090 tun_fileno(tun_t *tun)
00091 {
00092 return (tun->fd);
00093 }
00094
00095 ssize_t
00096 tun_send(tun_t *tun, const void *buf, size_t size)
00097 {
00098 struct strbuf sbuf;
00099
00100 sbuf.buf = buf;
00101 sbuf.len = size;
00102 return (putmsg(tun->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1);
00103 }
00104
00105 ssize_t
00106 tun_recv(tun_t *tun, void *buf, size_t size)
00107 {
00108 struct strbuf sbuf;
00109 int flags = 0;
00110
00111 sbuf.buf = buf;
00112 sbuf.maxlen = size;
00113 return (getmsg(tun->fd, NULL, &sbuf, &flags) >= 0 ? sbuf.len : -1);
00114 }
00115
00116 tun_t *
00117 tun_close(tun_t *tun)
00118 {
00119 if (tun->if_fd >= 0)
00120 close(tun->if_fd);
00121 if (tun->ip_fd >= 0)
00122 close(tun->ip_fd);
00123 if (tun->fd >= 0)
00124 close(tun->fd);
00125 free(tun);
00126 return (NULL);
00127 }