1 /*
2  *  Hans - IP over ICMP
3  *  Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "tun.h"
21 #include "exception.h"
22 #include "utility.h"
23 
24 #include <arpa/inet.h>
25 #include <sys/types.h>
26 #include <netinet/in_systm.h>
27 #include <netinet/in.h>
28 #include <netinet/ip.h>
29 #include <syslog.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 
34 #ifdef WIN32
35 #include <w32api/windows.h>
36 #endif
37 
38 typedef ip IpHeader;
39 
40 using namespace std;
41 
42 #ifdef WIN32
winsystem(char * cmd)43 static void winsystem(char *cmd)
44 {
45     STARTUPINFO info = { sizeof(info) };
46     PROCESS_INFORMATION processInfo;
47     if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
48     {
49         WaitForSingleObject(processInfo.hProcess, INFINITE);
50         CloseHandle(processInfo.hProcess);
51         CloseHandle(processInfo.hThread);
52     }
53 }
54 #endif
55 
Tun(const char * device,int mtu)56 Tun::Tun(const char *device, int mtu)
57 {
58     char cmdline[512];
59 
60     this->mtu = mtu;
61 
62     if (device != NULL)
63     {
64         strncpy(this->device, device, VTUN_DEV_LEN);
65         this->device[VTUN_DEV_LEN-1] = 0;
66     }
67     else
68         this->device[0] = 0;
69 
70     fd = tun_open(this->device);
71     if (fd == -1)
72         throw Exception(string("could not create tunnel device: ") + tun_last_error());
73 
74     syslog(LOG_INFO, "opened tunnel device: %s", this->device);
75 
76 #ifdef WIN32
77     snprintf(cmdline, sizeof(cmdline), "netsh interface ipv4 set subinterface \"%s\" mtu=%d", this->device, mtu);
78     winsystem(cmdline);
79 #else
80     snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu);
81     if (system(cmdline) != 0)
82         syslog(LOG_ERR, "could not set tun device mtu");
83 #endif
84 }
85 
~Tun()86 Tun::~Tun()
87 {
88     tun_close(fd, device);
89 }
90 
setIp(uint32_t ip,uint32_t destIp,bool includeSubnet)91 void Tun::setIp(uint32_t ip, uint32_t destIp, bool includeSubnet)
92 {
93     char cmdline[512];
94     string ips = Utility::formatIp(ip);
95     string destIps = Utility::formatIp(destIp);
96 
97 #ifdef WIN32
98     snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address name=\"%s\" "
99         "static %s 255.255.255.0", device, ips.c_str());
100     winsystem(cmdline);
101 
102     if (!tun_set_ip(fd, ip, ip & 0xffffff00, 0xffffff00))
103         syslog(LOG_ERR, "could not set tun device driver ip address: %s", tun_last_error());
104 #elif LINUX
105     snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str());
106     if (system(cmdline) != 0)
107         syslog(LOG_ERR, "could not set tun device ip address");
108 #else
109     snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
110     if (system(cmdline) != 0)
111         syslog(LOG_ERR, "could not set tun device ip address");
112 
113     if (includeSubnet)
114     {
115         snprintf(cmdline, sizeof(cmdline), "/sbin/route add %s/24 %s", destIps.c_str(), destIps.c_str());
116         if (system(cmdline) != 0)
117             syslog(LOG_ERR, "could not add route");
118     }
119 #endif
120 }
121 
write(const char * buffer,int length)122 void Tun::write(const char *buffer, int length)
123 {
124     if (tun_write(fd, (char *)buffer, length) == -1)
125         syslog(LOG_ERR, "error writing %d bytes to tun: %s", length, tun_last_error());
126 }
127 
read(char * buffer)128 int Tun::read(char *buffer)
129 {
130     int length = tun_read(fd, buffer, mtu);
131     if (length == -1)
132         syslog(LOG_ERR, "error reading from tun: %s", tun_last_error());
133     return length;
134 }
135 
read(char * buffer,uint32_t & sourceIp,uint32_t & destIp)136 int Tun::read(char *buffer, uint32_t &sourceIp, uint32_t &destIp)
137 {
138     int length = read(buffer);
139 
140     IpHeader *header = (IpHeader *)buffer;
141     sourceIp = ntohl(header->ip_src.s_addr);
142     destIp = ntohl(header->ip_dst.s_addr);
143 
144     return length;
145 }
146