-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathQTap.cpp
119 lines (96 loc) · 2.74 KB
/
QTap.cpp
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
#include "QTap.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_tun.h>
#include <net/ethernet.h>
#include <fcntl.h>
#include <string.h>
#include <stdbool.h>
#include <limits.h>
struct tap_packet {
struct tun_pi packet_info;
union _data {
struct ether_header eth_hdr;
char raw[TAP_MAX_MTU];
} data;
} __attribute__((packed));
QTap::QTap(const QString &pref_name, const QByteArray &mac, QObject *parent, int resume): QObject(parent) {
struct ifreq ifr;
tap_fd = -1;
if (resume > 0) {
// already got a fd? make sure it is a valid tap
if (ioctl(resume, TUNGETIFF, (void*)&ifr) == 0) {
// oh oh ?
tap_fd = resume;
name = QString::fromLatin1(ifr.ifr_name);
}
}
if (tap_fd == -1) {
tap_fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
if (tap_fd < 0) {
qDebug("failed to open tun port, make sure module is loaded and you can access it");
return;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP;
if (!pref_name.isEmpty()) {
strncpy(ifr.ifr_name, pref_name.toLatin1().constData(), IFNAMSIZ);
}
if (ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0) {
qDebug("tap: unable to set tunnel. Make sure you have the appropriate privileges");
close(tap_fd);
tap_fd = -1;
return;
}
name = QString::fromLatin1(ifr.ifr_name);
}
notifier = new QSocketNotifier(tap_fd, QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), this, SLOT(activity(int)));
if (!mac.isEmpty())
setMac(mac);
}
bool QTap::isValid() const {
return tap_fd > 0;
}
const QString &QTap::getName() const {
return name;
}
int QTap::getFd() const {
return tap_fd;
}
void QTap::activity(int fd) {
if (fd != tap_fd) return;
struct tap_packet buffer;
int len = read(tap_fd, &buffer, sizeof(buffer));
// we actually don't care about the tun_pi part, strip down to what's below ethernet (only keep proto)
QByteArray data(buffer.data.raw+12, len-4-12);
QByteArray src_hw(buffer.data.raw+6, 6);
QByteArray dst_hw(buffer.data.raw, 6);
packet(src_hw, dst_hw, data);
}
void QTap::setMac(const QByteArray &mac) {
if (tap_fd <= 0) return;
struct ifreq ifhw;
memset(&ifhw, 0, sizeof(ifhw));
strncpy(ifhw.ifr_name, name.toLatin1().constData(), IFNAMSIZ);
ifhw.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy(&ifhw.ifr_hwaddr.sa_data, mac.constData(), ETH_ALEN);
if (ioctl(tap_fd, SIOCSIFHWADDR, (void*) &ifhw) < 0) {
qDebug("SIOCSIFHWADDR failed");
return;
}
}
void QTap::write(const QByteArray &dat) {
if (tap_fd <= 0) return;
QByteArray cp(4, '\x00');
cp.append(dat);
int res = ::write(tap_fd, cp.constData(), cp.size());
if (res != cp.size()) {
qDebug("QTap::write: failed to write");
}
}