-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnstx_tuntap.c
234 lines (203 loc) · 5.32 KB
/
nstx_tuntap.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#ifdef LINUX
#include <linux/if_tun.h>
#define TUNDEV "/dev/net/tun"
#else
#include <net/if_tun.h>
#define TUNDEV "/dev/tun"
#endif
#include "nstx.h"
#define TAPDEV "/dev/tap0"
#define MAXPKT 2000
int tfd = -1, nfd = -1;
static char dev[IFNAMSIZ+1];
int tun_alloc (char *path);
int tap_alloc (char *path);
void open_tuntap (void)
{
int tunerr, taperr;
fprintf(stderr, "Opening tun/tap-device... ");
if((tunerr = tun_alloc(TUNDEV)) && (taperr = tap_alloc(TAPDEV))) {
fprintf(stderr, "failed!\n"
"Diagnostics:\nTun ("TUNDEV"): ");
switch (tunerr) {
case EPERM:
fprintf(stderr, "Permission denied. You usually have to "
"be root to use nstx.\n");
break;
case ENOENT:
fprintf(stderr, TUNDEV " not found. Please create /dev/net/ and\n"
" mknod /dev/net/tun c 10 200 to use the tun-device\n");
break;
case ENODEV:
fprintf(stderr, "Device not available. Make sure you have "
"kernel-support\n for the tun-device. Under linux, you "
"need tun.o (Universal tun/tap-device)\n");
break;
default:
fprintf(stderr, "Unexpected error: %s\n", strerror(tunerr));
break;
}
fprintf(stderr, "Tap ("TAPDEV"): \n(only available under linux)\n");
switch (taperr) {
case EPERM:
fprintf(stderr, "Permission denied. You generally have to "
"be root to use nstx.\n");
break;
case ENOENT:
fprintf(stderr, TAPDEV " not found. Please\n"
" mknod /dev/tap0 c 36 16 to use the tap-device\n");
break;
case ENODEV:
fprintf(stderr, "Device not available. Make sure you have kernel-support\n"
" for the tap-device. Under linux, you need netlink_dev.o and ethertap.o\n");
break;
default:
fprintf(stderr, "Unexpected error: %s\n", strerror(taperr));
break;
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "using device %s\n"
"Please configure this device appropriately (IP, routes, etc.)\n", dev);
}
int tun_alloc (char *path)
{
#ifdef LINUX
struct ifreq ifr;
#else
struct stat st;
#endif
if ((tfd = open(path, O_RDWR)) < 0)
return errno;
#ifdef LINUX
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN|IFF_NO_PI;
if (ioctl(tfd, TUNSETIFF, (void *) &ifr) < 0)
{
close(tfd);
tfd = -1;
return errno;
}
strncpy(dev, ifr.ifr_name, IFNAMSIZ+1);
#else
fstat(tfd, &st);
strncpy(dev, devname(st.st_dev, S_IFCHR), IFNAMSIZ+1);
#endif
return 0;
}
int tap_alloc (char *path)
{
char *ptr;
if ((tfd = open(path, O_RDWR)) < 0)
return errno;
if ((ptr = strrchr(path, '/')))
strncpy(dev, ptr+1, IFNAMSIZ+1);
else
strncpy(dev, path, IFNAMSIZ+1);
return 0;
}
void open_ns (char *ip)
{
struct sockaddr_in sock;
fprintf(stderr, "Opening nameserver-socket... ");
if ((nfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "failed!\nUnexpected error creating socket: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
sock.sin_family = AF_INET;
sock.sin_port = htons(53);
if (!ip)
{
sock.sin_addr.s_addr = INADDR_ANY;
if (bind (nfd, (struct sockaddr *) &sock, sizeof(struct sockaddr_in))) {
fprintf(stderr, "failed!\n");
switch (errno) {
case EADDRINUSE:
fprintf(stderr, "Address is in use, please kill other processes "
"listening on UDP-Port 53\n");
break;
case EACCES:
case EPERM:
fprintf(stderr, "Permission denied binding port 53. You generally "
"have to be root to bind privileged ports.\n");
break;
default:
fprintf(stderr, "Unexpected error: bind: %s\n", strerror(errno));
break;
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "listening on 53/UDP\n");
}
else
{
sock.sin_addr.s_addr = inet_addr(ip);
connect(nfd, (struct sockaddr *)&sock, sizeof(struct sockaddr_in));
fprintf(stderr, "Using nameserver %s\n", ip);
}
}
struct nstxmsg *nstx_select (int timeout)
{
int peerlen;
fd_set set;
struct timeval tv;
static struct nstxmsg *ret = NULL;
FD_ZERO(&set);
if (nfd > 0)
FD_SET(nfd, &set);
if (tfd > 0)
FD_SET(tfd, &set);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (timeout < 0)
select(((tfd>nfd)?tfd:nfd)+1, &set, NULL, NULL, NULL);
else
select(((tfd>nfd)?tfd:nfd)+1, &set, NULL, NULL, &tv);
if (!ret)
ret = malloc(sizeof(struct nstxmsg));
if (FD_ISSET(tfd, &set)) {
ret->len = read(tfd, ret->data, MAXPKT);
if (ret->len > 0) {
ret->src = FROMTUN;
return ret;
}
}
if (FD_ISSET(nfd, &set)) {
peerlen = sizeof(struct sockaddr_in);
ret->len = recvfrom(nfd, ret->data, MAXPKT, 0,
(struct sockaddr *) &ret->peer, &peerlen);
if (ret->len > 0) {
ret->src = FROMNS;
return ret;
}
}
return NULL;
}
void sendtun (char *data, int len)
{
write(tfd, data, len);
}
void sendns (char *data, int len, struct sockaddr *peer)
{
if (peer)
sendto(nfd, data, len, 0, peer,
sizeof(struct sockaddr_in));
else
send(nfd, data, len, 0);
}