/[pearpc]/src/system/osapi/posix/sysethtun.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/system/osapi/posix/sysethtun.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (12 years, 8 months ago) by dpavlin
File size: 10819 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * sysethtun.cc
4 *
5 * POSIX/UN*X-specific ethernet-tunnel access
6 *
7 * Copyright (C) 2003 Stefan Weyergraf
8 *
9 * code taken from Mac-on-Linux 0.9.68:
10 * Copyright (C) 1999-2002 Samuel Rydh (samuel@ibrium.se)
11 *
12 * darwin code taken from tinc 1.0.2:
13 * Copyright (C) 2001-2003 Ivo Timmermans <ivo@o2w.nl>,
14 * 2001-2003 Guus Sliepen <guus@sliepen.eu.org>
15 *
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 as
18 * published by the Free Software Foundation.
19 *
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.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 #include <cerrno>
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 #include <unistd.h>
35 #include <sys/wait.h>
36
37 #include "system/sysethtun.h"
38 #include "tools/snprintf.h"
39 #include "tools/data.h"
40 #include "tools/str.h"
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include "tools/except.h"
47 #include "system/sysethtun.h"
48
49 #ifndef HAVE_SETENV
50 /*
51 * That is just to support BeOS R5, even Zeta has setenv() btw
52 * Note that leaks env, but we can't do anything about that
53 * (cf. glibc man page)
54 */
55 static int setenv(const char *name, const char *value, int overwrite)
56 {
57 String tmpenv;
58 tmpenv.assignFormat("%s=%s", name, value);
59 char *env = strdup(tmpenv); /* LEAK! */
60 putenv(env);
61 return 0;
62 }
63 #endif
64
65 /**
66 * Unix ethernet tunnel devices should work using a file descriptor
67 */
68 class UnixEthTunDevice: public EthTunDevice {
69 protected:
70 int mFD;
71 public:
72
73 UnixEthTunDevice()
74 {
75 // super-class constructor MUST set mFD!!!
76 // this is yet another case where C++ constructors suck
77 // (ohh lovely Borland Pascal, where art thou?)
78 mFD = -1;
79 }
80
81 virtual ~UnixEthTunDevice()
82 {
83 }
84
85 virtual uint recvPacket(void *buf, uint size)
86 {
87 ssize_t e = ::read(mFD, buf, size);
88 if (e < 0) return 0;
89 return e;
90 }
91
92 virtual int waitRecvPacket()
93 {
94 fd_set rfds;
95 fd_set zerofds;
96 FD_ZERO(&rfds);
97 FD_ZERO(&zerofds);
98 if (mFD < 0)
99 return ENODEV;
100 FD_SET(mFD, &rfds);
101
102 int e = select(mFD+1, &rfds, &zerofds, &zerofds, NULL);
103 if (e < 0) return errno;
104 return 0;
105 }
106
107 virtual uint sendPacket(void *buf, uint size)
108 {
109 ssize_t e = ::write(mFD, buf, size);
110 if (e < 0) return 0;
111 return e;
112 }
113
114 virtual const char *devicePath()
115 {
116 return NULL;
117 }
118
119 virtual const char *upScript()
120 {
121 return "scripts/ifppc_up.setuid";
122 }
123
124 virtual const char *downScript()
125 {
126 return "scripts/ifppc_down.setuid";
127 }
128
129 // FIXME: How shall we configure networking??? This thing can only be a temporary solution
130 virtual int execIFConfigScript(const char *action, const char *interface)
131 {
132 printf("UnixTun::execIFConfigScript(%s,%s)\n", action, interface);
133 int pid = fork();
134 if (pid < 0)
135 printf("fork = %d, 0x%08x\n", pid, errno);
136 if (pid == 0) {
137 const char *progname;
138 if (strcmp(action, "up") == 0) {
139 progname = upScript();
140 } else {
141 progname = downScript();
142 }
143 setenv("PPC_INTERFACE", interface, 1);
144 printf("executing '%s' ...\n"
145 "********************************************************************************\n", progname);
146 execl(progname, progname, (char*)NULL);
147 printf("couldn't exec '%s': %s\n", progname, strerror(errno));
148 exit(1);
149 } else if (pid != -1) {
150 int status;
151 waitpid(pid, &status, 0);
152 if (!WIFEXITED(status)) {
153 printf("program terminated abnormally...\n");
154 return 1;
155 }
156 if (WEXITSTATUS(status)) {
157 printf("program terminated with exit code %d\n", WEXITSTATUS(status));
158 return 1;
159 }
160 return 0;
161 }
162 return 1;
163 }
164
165 }; // end of UnixEthTunDevice
166
167 #if defined(HAVE_LINUX_TUN) || defined(HAVE_BEOS_TUN)
168 /*
169 * This is how it's done in Linux
170 */
171
172 #include <sys/ioctl.h>
173 #include <sys/socket.h>
174
175 #ifdef HAVE_LINUX_TUN
176 #include <asm/types.h>
177 #include <linux/netlink.h>
178 #include <linux/if.h>
179 #include <linux/if_tun.h>
180 #else /* BeOS */
181 #include <net/if.h>
182 #include <linux/if_tun.h> // should be moved to net/ someday too...
183 #include <image.h>
184 #endif /* HAVE_LINUX_TUN */
185
186 #include <sys/types.h>
187 #include <sys/stat.h>
188 #include <fcntl.h>
189
190 class LinuxLikeEthTunDevice: public UnixEthTunDevice {
191 protected:
192 String mIfName;
193 String mIfPrefix;
194 public:
195 LinuxLikeEthTunDevice(const char *netif_prefix)
196 : UnixEthTunDevice()
197 {
198 // We will allocate the next available interface name
199 // First, trim passed interface name down to 6 letters. To prevent
200 // overflow attacks and shell attacks.
201 String netif_buffer(netif_prefix);
202 netif_buffer.crop(6);
203 for (int i=0; i < netif_buffer.length(); i++) {
204 char c = netif_buffer[i];
205 // Delete all characters not suitable for below command
206 if (!(c >= 'a' && c <= 'z')
207 && !(c >= 'A' && c <= 'Z')
208 && !(c >= '0' && c <= '9')
209 && (c != '_')) {
210 netif_buffer[i] = '_';
211 }
212 }
213 mIfPrefix = netif_buffer;
214 }
215
216
217 int initDevice()
218 {
219
220 /* allocate tun device */
221 if ((mFD = ::open(devicePath(), O_RDWR)) < 0) {
222 const char *err = ::strerror(errno);
223 throw MsgfException("Failed to open %s (%s)", devicePath(), err);
224 }
225
226 struct ifreq ifr;
227 ::memset(&ifr, 0, sizeof(ifr));
228 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
229
230 if (::strlen(mIfName.contentChar())+1 > IFNAMSIZ) {
231 throw MsgfException("Interface name too long (%d > %d bytes)"
232 " in '%y'\n", ::strlen(mIfName.contentChar())+1, IFNAMSIZ, &mIfName);
233 }
234
235 ::strncpy(ifr.ifr_name, mIfName.contentChar(), IFNAMSIZ);
236 if (::ioctl(mFD, TUNSETIFF, &ifr) < 0) {
237 const char *err = ::strerror(errno);
238 ::close(mFD);
239 throw MsgfException("TUNSETIFF failed (%s).", err);
240 }
241
242 /* don't checksum */
243 ::ioctl(mFD, TUNSETNOCSUM, 1);
244
245 /* Configure device */
246 if (execIFConfigScript("up", mIfName.contentChar())) {
247 ::close(mFD);
248 throw MsgException("error executing ifconfig.");
249 }
250 return 0;
251 }
252
253 int shutdownDevice()
254 {
255 /* tear down the device */
256 execIFConfigScript("down", mIfName.contentChar());
257 ::close(mFD);
258 return 0;
259 }
260
261 virtual uint getWriteFramePrefix()
262 {
263 return 0;
264 }
265
266 virtual const char *devicePath()
267 {
268 return "/dev/net/tun";
269 }
270
271 }; // end of LinuxLikeEthTunDevice
272
273 #ifdef HAVE_LINUX_TUN
274
275 class LinuxEthTunDevice: public LinuxLikeEthTunDevice {
276 public:
277 LinuxEthTunDevice(const char *netif_prefix)
278 : LinuxLikeEthTunDevice(netif_prefix)
279 {
280 for (int counter = 0; counter < 10; counter++) {
281 String command;
282 command.assignFormat("ifconfig %y%d", &mIfPrefix, counter);
283 // FIXME: Is there anything else than command() that I can use here?
284 // Seems a fork&exec is a bit too much...
285 int ret = system(command.contentChar());
286 if (WEXITSTATUS(ret)) {
287 mIfName.assignFormat("%y%d", &mIfPrefix, counter);
288 ht_printf("mIfName = %y\n", &mIfName);
289 break;
290 }
291 }
292 // FIXME:There is more than 10 interfaces taken at this time. What should we do ?
293 if (mIfName == (String)"")
294 throw MsgfException("There are already 10 interfaces configured. We don't support more than that currently.");
295 }
296
297 }; // end of LinuxEthTunDevice
298
299 EthTunDevice *createEthernetTunnel()
300 {
301 return new LinuxEthTunDevice("ppc" /* FIXME: hardcoding */);
302 }
303
304 #else /* BeOS */
305
306 class BeOSEthTunDevice: public LinuxLikeEthTunDevice {
307 public:
308 BeOSEthTunDevice(const char *netif_name)
309 : LinuxLikeEthTunDevice(netif_name)
310 {
311 int s = socket(AF_INET, SOCK_DGRAM, 0);
312 if (s < 0)
313 throw MsgfException("Can't get a socket to enumerate interfaces.");
314 for (int counter = 0; counter < 10; counter++) {
315 String ifName;
316 ifreq_t ifr;
317 ifName.assignFormat("%y%d", &mIfPrefix, counter);
318
319 strncpy(ifr.ifr_name, ifName, IFNAMSIZ);
320 if (::ioctl(s, SIOCGIFADDR, &ifr, sizeof(ifr)) < 0) {
321 mIfName.assignFormat("%y%d", &mIfPrefix, counter); // is it safe ?
322 ht_printf("mIfName = %y\n", &mIfName);
323 break;
324 }
325 }
326 close(s);
327 // FIXME:There is more than 10 interfaces taken at this time. What should we do ?
328 if (mIfName == (String)"")
329 throw MsgfException("There are already 10 interfaces configured. We don't support more than that currently.");
330 }
331
332 virtual const char *devicePath()
333 {
334 return TUN_DEVICE;
335 }
336
337 virtual const char *upScript()
338 {
339 return "scripts/ifppc_up.beos";
340 }
341
342 virtual const char *downScript()
343 {
344 return "scripts/ifppc_down.beos";
345 }
346
347
348 #if 1
349 // FIXME: How shall we configure networking??? This thing can only be a temporary solution
350 // XXX: BeOS doesn't seem to like forking from PearPC... out of swap !?
351 // what you get from playing dirty tricks. :)
352 virtual int execIFConfigScript(const char *action, const char *interface)
353 {
354 thread_id tid;
355 status_t status;
356 const char *progname;
357 if (strcmp(action, "up") == 0) {
358 progname = upScript();
359 } else {
360 progname = downScript();
361 }
362 const char *sargv[] = { "/bin/sh", progname, NULL };
363 int sargc = 2;
364 setenv("PPC_INTERFACE", interface, 1);
365 printf("executing '%s' ...\n"
366 "********************************************************************************\n", progname);
367 //execl(progname, progname, 0);
368 tid = load_image(sargc, sargv, (const char **)environ);
369 if ((tid < B_OK) || (resume_thread(tid) < B_OK)) {
370 printf("couldn't exec '%s': %s\n", progname, strerror(tid));
371 return 1;
372 }
373 sleep(1);
374 wait_for_thread(tid, &status);
375 if (!WIFEXITED(status)) {
376 printf("program terminated abnormally...\n");
377 return 1;
378 }
379 if (WEXITSTATUS(status)) {
380 printf("program terminated with exit code %d\n", WEXITSTATUS(status));
381 return 1;
382 }
383 return 0;
384 }
385 #endif
386 }; // end of BeOSEthTunDevice
387
388 EthTunDevice *createEthernetTunnel()
389 {
390 return new BeOSEthTunDevice("ppc" /* FIXME: hardcoding */);
391 }
392
393 #endif /* HAVE_LINUX_TUN */
394
395 #elif (defined(__APPLE__) && defined(__MACH__)) || defined (__FreeBSD__)
396 /*
397 * This is how it's done in Darwin, Mac OS X or FreeBSD
398 */
399
400 /*
401 Interaction with Darwin/Mac OS X "tun" device driver
402
403 See http://chrisp.de/en/projects/tunnel.html,
404 for source code and binaries of tunnel.kext :
405
406 kextload /System/Library/Extensions/tunnel.kext
407 */
408
409 #include <fcntl.h>
410
411 #ifdef __FreeBSD__
412 #define DEFAULT_DEVICE "/dev/tap0"
413 #else
414 #define DEFAULT_DEVICE "/dev/tun0"
415 #endif
416
417 class SimpleEthTunDevice: public UnixEthTunDevice {
418 public:
419 SimpleEthTunDevice()
420 : UnixEthTunDevice()
421 {
422 }
423
424 int initDevice()
425 {
426 /* allocate tun device */
427 if ((mFD = ::open(DEFAULT_DEVICE, O_RDWR | O_NONBLOCK)) < 0) {
428 throw MsgException("Failed to open "DEFAULT_DEVICE"! Is tunnel.kext loaded?");
429 }
430 return 0;
431 }
432
433 int shutdownDevice()
434 {
435 }
436
437 virtual uint getWriteFramePrefix()
438 {
439 return 0;
440 }
441
442 }; // end of SimpleEthTunDevice
443
444 EthTunDevice *createEthernetTunnel()
445 {
446 return new SimpleEthTunDevice();
447 }
448
449 #else
450 /*
451 * System provides no ethernet tunnel
452 */
453
454 EthTunDevice *createEthernetTunnel()
455 {
456 throw MsgException("Your system has no support for ethernet tunnels.");
457 }
458
459 #endif

  ViewVC Help
Powered by ViewVC 1.1.26