1 /*
2     VTun - Virtual Tunnel over TCP/IP network.
3 
4     Copyright (C) 1998-2000  Maxim Krasnyansky <max_mk@yahoo.com>
5 
6     VTun has been derived from VPPP package by Maxim Krasnyansky.
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  */
18 
19 /*
20  * tun_dev.c,v 1.2.2.2.2.1 2006/11/16 04:05:18 mtbishop Exp
21  */
22 
23 /* #include "config.h" */
24 
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <syslog.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/ioctl.h>
39 #include <errno.h>
40 #include <signal.h>
41 #include <stropts.h>
42 #include <net/if.h>
43 #include <net/if_tun.h>
44 
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 
49 #ifdef HAVE_NETINET_IN_SYSTM_H
50 #include <netinet/in_systm.h>
51 #endif
52 
53 #ifdef HAVE_NETINET_IP_H
54 #include <netinet/ip.h>
55 #endif
56 
57 #ifdef HAVE_NETINET_TCP_H
58 #include <netinet/tcp.h>
59 #endif
60 
61 /* #include "vtun.h"
62 #include "lib.h" */
63 
64 static int ip_fd = -1;
65 
66 /*
67  * Allocate TUN device, returns opened fd.
68  * Stores dev name in the first arg(must be large enough).
69  */
tun_open(char * dev)70 int tun_open(char *dev)
71 {
72     int tun_fd, if_fd, muxid, ppa = -1;
73     struct ifreq ifr;
74     char *ptr;
75 
76     if( *dev ){
77        ptr = dev;
78        while( *ptr && !isdigit((int)*ptr) ) ptr++;
79        ppa = atoi(ptr);
80     }
81 
82     if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
83        syslog(LOG_ERR, "Can't open /dev/ip");
84        return -1;
85     }
86 
87     if( (tun_fd = open("/dev/tun", O_RDWR, 0)) < 0){
88        syslog(LOG_ERR, "Can't open /dev/tun");
89        return -1;
90     }
91 
92     /* Assign a new PPA and get its unit number. */
93     if( (ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0){
94        syslog(LOG_ERR, "Can't assign new interface");
95        return -1;
96     }
97 
98     if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
99        syslog(LOG_ERR, "Can't open /dev/tun (2)");
100        return -1;
101     }
102     if(ioctl(if_fd, I_PUSH, "ip") < 0){
103        syslog(LOG_ERR, "Can't push IP module");
104        return -1;
105     }
106 
107     /* Assign ppa according to the unit number returned by tun device */
108     if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
109        syslog(LOG_ERR, "Can't set PPA %d", ppa);
110        return -1;
111     }
112     if( (muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0){
113        syslog(LOG_ERR, "Can't link TUN device to IP");
114        return -1;
115     }
116     close(if_fd);
117 
118     sprintf(dev, "tun%d", ppa);
119 
120     memset(&ifr, 0, sizeof(ifr));
121     strcpy(ifr.ifr_name, dev);
122     ifr.ifr_ip_muxid = muxid;
123 
124     if( ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0 ){
125        ioctl(ip_fd, I_PUNLINK, muxid);
126        syslog(LOG_ERR, "Can't set multiplexor id");
127        return -1;
128     }
129 
130     return tun_fd;
131 }
132 
133 /*
134  * Close TUN device.
135  */
tun_close(int fd,char * dev)136 int tun_close(int fd, char *dev)
137 {
138     struct ifreq ifr;
139 
140     memset(&ifr, 0, sizeof(ifr));
141     strcpy(ifr.ifr_name, dev);
142     if( ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0 ){
143        syslog(LOG_ERR, "Can't get iface flags");
144        return 0;
145     }
146 
147     if( ioctl(ip_fd, SIOCGIFMUXID, &ifr) < 0 ){
148        syslog(LOG_ERR, "Can't get multiplexor id");
149        return 0;
150     }
151 
152     if( ioctl(ip_fd, I_PUNLINK, ifr.ifr_ip_muxid) < 0 ){
153        syslog(LOG_ERR, "Can't unlink interface");
154        return 0;
155     }
156 
157     close(ip_fd); close(fd);
158     return 0;
159 }
160 
tun_write(int fd,char * buf,int len)161 int tun_write(int fd, char *buf, int len)
162 {
163     struct strbuf sbuf;
164     sbuf.len = len;
165     sbuf.buf = buf;
166     return putmsg(fd, NULL, &sbuf, 0) >=0 ? sbuf.len : -1;
167 }
168 
tun_read(int fd,char * buf,int len)169 int tun_read(int fd, char *buf, int len)
170 {
171     struct strbuf sbuf;
172     int f = 0;
173 
174     sbuf.maxlen = len;
175     sbuf.buf = buf;
176     return getmsg(fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
177 }
178 
tun_last_error()179 const char *tun_last_error()
180 {
181     return strerror(errno);
182 }
183