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