/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 10819 byte(s)
import upstream CVS
1 dpavlin 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