same security fix for bsd device
[anytun.git] / src / bsd / tunDevice.cpp
blob5ad6ea7f56e6f8577115fc39055d331d8d06ec1e
1 /*
2 * anytun
4 * The secure anycast tunneling protocol (satp) defines a protocol used
5 * for communication between any combination of unicast and anycast
6 * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel
7 * mode and allows tunneling of every ETHER TYPE protocol (e.g.
8 * ethernet, ip, arp ...). satp directly includes cryptography and
9 * message authentication based on the methodes used by SRTP. It is
10 * intended to deliver a generic, scaleable and secure solution for
11 * tunneling and relaying of packets of any protocol.
14 * Copyright (C) 2007 anytun.org <satp@wirdorange.org>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2
18 * as published by the Free Software Foundation.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program (see the file COPYING included with this
27 * distribution); if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <sys/socket.h>
35 #include <net/if.h>
36 #include <net/if_tun.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/uio.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/in.h>
42 #include <netinet/ip.h>
44 #include <sstream>
46 #include "tunDevice.h"
47 #include "threadUtils.hpp"
48 #define DEVICE_FILE_MAX 255
50 #include <iostream>
52 TunDevice::TunDevice(const char* dev_name, const char* dev_type, const char* ifcfg_lp, const char* ifcfg_rnmp) : conf_(dev_name, dev_type, ifcfg_lp, ifcfg_rnmp)
54 std::string device_file = "/dev/";
55 bool dynamic = true;
56 if(dev_name) {
57 device_file.append(dev_name);
58 dynamic = false;
60 else if(conf_.type_ == TYPE_TUN) {
61 device_file.append("tun");
62 actual_name_ = "tun";
64 else if(conf_.type_ == TYPE_TAP) {
65 device_file.append("tap");
66 actual_name_ = "tap";
68 else
69 throw std::runtime_error("unable to recognize type of device (tun or tap)");
71 u_int32_t dev_id=0;
72 if(dynamic) {
73 for(; dev_id <= DEVICE_FILE_MAX; ++dev_id) {
74 std::ostringstream ds;
75 ds << device_file;
76 ds << dev_id;
77 fd_ = ::open(ds.str().c_str(), O_RDWR);
78 if(fd_ >= 0)
79 break;
82 else
83 fd_ = ::open(device_file.c_str(), O_RDWR);
85 if(fd_ < 0) {
86 std::string msg;
87 if(dynamic)
88 msg = "can't open device file dynamically: no unused node left";
89 else {
90 msg = "can't open device file (";
91 msg.append(device_file);
92 msg.append("): ");
93 msg.append(strerror(errno));
95 throw std::runtime_error(msg);
98 if(dynamic) {
99 std::stringstream s;
100 s << actual_name_;
101 s << dev_id;
102 actual_name_ = s.str();
104 else
105 actual_name_ = dev_name;
107 init_post();
109 if(ifcfg_lp && ifcfg_rnmp)
110 do_ifconfig();
113 TunDevice::~TunDevice()
115 if(fd_ > 0)
116 ::close(fd_);
119 #if defined(__GNUC__) && defined(__OpenBSD__)
121 void TunDevice::init_post()
123 with_type_ = true;
124 if(conf_.type_ == TYPE_TAP)
125 with_type_ = false;
127 struct tuninfo ti;
129 if (ioctl(fd_, TUNGIFINFO, &ti) < 0)
130 throw std::runtime_error("can't enable multicast for interface");
132 ti.flags |= IFF_MULTICAST;
134 if (ioctl(fd_, TUNSIFINFO, &ti) < 0)
135 throw std::runtime_error("can't enable multicast for interface");
138 #elif defined(__GNUC__) && defined(__FreeBSD__)
140 void TunDevice::init_post()
142 with_type_ = true;
143 if(conf_.type_ == TYPE_TAP)
144 with_type_ = false;
146 int arg = 0;
147 ioctl(fd_, TUNSLMODE, &arg);
148 arg = 1;
149 ioctl(fd_, TUNSIFHEAD, &arg);
152 #elif defined(__GNUC__) && defined(__NetBSD__)
154 void TunDevice::init_post()
156 with_type_ = false;
158 int arg = IFF_POINTOPOINT|IFF_MULTICAST;
159 ioctl(fd_, TUNSIFMODE, &arg);
160 arg = 0;
161 ioctl(fd_, TUNSLMODE, &arg);
164 #else
165 #error Target not supported
166 #endif
168 int TunDevice::fix_return(int ret, size_t type_length)
170 if(ret < 0)
171 return ret;
173 return (static_cast<size_t>(ret) > type_length ? (ret - type_length) : 0);
176 short TunDevice::read(u_int8_t* buf, u_int32_t len)
178 if(fd_ < 0)
179 return -1;
181 if(with_type_) {
182 struct iovec iov[2];
183 u_int32_t type;
185 iov[0].iov_base = &type;
186 iov[0].iov_len = sizeof(type);
187 iov[1].iov_base = buf;
188 iov[1].iov_len = len;
189 return(fix_return(::readv(fd_, iov, 2), sizeof(type)));
191 else
192 return(::read(fd_, buf, len));
195 int TunDevice::write(u_int8_t* buf, u_int32_t len)
197 if(fd_ < 0)
198 return -1;
200 if(with_type_) {
201 struct iovec iov[2];
202 u_int32_t type;
203 struct ip *hdr = reinterpret_cast<struct ip*>(buf);
205 type = 0;
206 if(hdr->ip_v == 4)
207 type = htonl(AF_INET);
208 else
209 type = htonl(AF_INET6);
211 iov[0].iov_base = &type;
212 iov[0].iov_len = sizeof(type);
213 iov[1].iov_base = buf;
214 iov[1].iov_len = len;
215 return(fix_return(::writev(fd_, iov, 2), sizeof(type)));
217 else
218 return(::write(fd_, buf, len));
221 const char* TunDevice::getActualName()
223 return actual_name_.c_str();
226 device_type_t TunDevice::getType()
228 return conf_.type_;
231 const char* TunDevice::getTypeString()
233 if(fd_ < 0)
234 return NULL;
236 switch(conf_.type_)
238 case TYPE_UNDEF: return "undef"; break;
239 case TYPE_TUN: return "tun"; break;
240 case TYPE_TAP: return "tap"; break;
242 return NULL;
245 void TunDevice::do_ifconfig()
247 // std::string command("/sbin/ifconfig ");
248 // command.append(actual_name_);
249 // command.append(" ");
250 // command.append(conf_.local_.toString());
251 // command.append(" ");
253 // if(conf_.type_ == TYPE_TUN)
254 // command.append("pointopoint ");
255 // else
256 // command.append("netmask ");
258 // command.append(conf_.remote_netmask_.toString());
259 // command.append(" mtu 1400");
261 // system(command.c_str());