-
Notifications
You must be signed in to change notification settings - Fork 25
/
tap.c
73 lines (68 loc) · 2.16 KB
/
tap.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
#include "tap.h"
///
/// make_tap: try to create a TAP interface with given ifname, mtu.
/// return: 0 on success.
/// 1 on failed.
/// 2 on failed to set MTU.
/// 3 if we can't set ifname, in this case, read ifname back for name.
/// a errno will be set when returned value != 0 (linux)
///
int make_tap(int *fd, char *ifname, int mtu) {
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
#if defined(__APPLE__) || defined(__OpenBSD__)
ifr.ifr_flags |= IFF_LINK0;
char devpath[64];
for(int dev = 0; dev < TAP_COUNT; dev++) {
snprintf(devpath, 64, "/dev/tap%d", dev);
if((*fd = open(devpath, O_RDWR))) {
ioctl(*fd, SIOCGIFFLAGS, &ifr); // get old flags
ioctl(*fd, SIOCSIFFLAGS, &ifr); // set IFF_LINK0
snprintf(ifname, IFNAMSIZ, "tap%d", dev);
return 3;
}
}
return 1;
#else
*fd = open(TUNNEL_DEV, O_RDWR);
#endif
#if defined(__linux__)
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if(ioctl(*fd, TUNSETIFF, (void *) &ifr)) return 1;
ifr.ifr_mtu = mtu;
if(ioctl(socket(AF_INET, SOCK_STREAM, IPPROTO_IP), SIOCSIFMTU, (void *)&ifr))
return 2;
#elif defined(__FreeBSD__)
ioctl(*fd, TAPGIFNAME, &ifr);
strncpy(ifname, ifr.ifr_name, IFNAMSIZ);
return 3;
#endif
return 0;
}
///
/// tap_listen: receive data from a tap w/ given fd and write them to socket
/// w/ given sock_fd and sockaddr.
///
void tap_listen(sa_family_t af, int fd, int sock_fd, int tid,
const struct sockaddr *raddr, socklen_t raddrlen) {
uint8_t header[8];
union packet packet;
int len;
// pre-build the header
eoip_header(af, tid, &header);
// pre-fill headres
if(af == AF_INET) memcpy(&packet.header, &header, 8);
if(af == AF_INET6) memcpy(&packet.header, &header, 2);
do {
if (af == AF_INET) {
if((len = read(fd, packet.eoip.payload, BUFFER_SIZE - 8)) < 0) continue;
packet.eoip.len = htons(len);
len += 8;
} else {
if((len = read(fd, packet.eoip6.payload, BUFFER_SIZE - 4)) < 0) continue;
len += 2;
}
sendto(sock_fd, packet.buffer, len, 0, raddr, raddrlen);
} while (1);
}