-
Notifications
You must be signed in to change notification settings - Fork 11
/
tun2proxy.mm
137 lines (118 loc) · 4.48 KB
/
tun2proxy.mm
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
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2023-2024 Chilledheart */
#include "tun2proxy.h"
#import <NetworkExtension/NetworkExtension.h>
#include <fcntl.h>
#include <unistd.h>
#include <base/check.h>
#include <base/posix/eintr_wrapper.h>
struct Tun2Proxy_InitContext {
__weak NEPacketTunnelFlow* packetFlow;
int read_fd;
void* tun2proxy_ptr;
};
struct ReadPacketContext {
NSData* data;
};
static const void* GetReadPacketContextData(void* context, void* packet) {
NSData* data = reinterpret_cast<ReadPacketContext*>(packet)->data;
return data.bytes;
}
static size_t GetReadPacketContextSize(void* context, void* packet) {
NSData* data = reinterpret_cast<ReadPacketContext*>(packet)->data;
return data.length;
}
static void FreeReadPacketContext(void* context, void* packet) {
auto packet_context = reinterpret_cast<ReadPacketContext*>(packet);
packet_context->data = nil;
delete packet_context;
}
static NEPacket* packetFromData(NSData* data) {
uint8_t version_ih = 0;
[data getBytes:&version_ih length:sizeof(version_ih)];
uint8_t version = version_ih >> 4;
DCHECK(version == 4 || version == 6) << "unsupported ip hdr version: " << version;
return [[NEPacket alloc] initWithData:data protocolFamily:version == 6 ? AF_INET6 : AF_INET];
}
static void WritePackets(void* context, void* const* packets, const size_t* packetLengths, int packetsCount) {
Tun2Proxy_InitContext* c = reinterpret_cast<Tun2Proxy_InitContext*>(context);
NEPacketTunnelFlow* packetFlow = c->packetFlow;
NSMutableArray* packetsArray = [NSMutableArray arrayWithCapacity:packetsCount];
for (int i = 0; i < packetsCount; ++i) {
NSData* data = [NSData dataWithBytesNoCopy:packets[i] length:packetLengths[i] freeWhenDone:NO];
NEPacket* packet = packetFromData(data);
[packetsArray addObject:packet];
}
if (![packetFlow writePacketObjects:packetsArray]) {
NSLog(@"writePacketObjects failed");
}
}
extern "C" void* tun2proxy_init(void* context,
int fd,
decltype(GetReadPacketContextData),
decltype(GetReadPacketContextSize),
decltype(FreeReadPacketContext),
decltype(WritePackets),
const char* proxy_url,
int tun_mtu,
int log_level,
int dns_over_tcp);
extern "C" int tun2proxy_run(void* ptr);
extern "C" int tun2proxy_shutdown(void* ptr);
extern "C" void tun2proxy_destroy(void* ptr);
Tun2Proxy_InitContext* Tun2Proxy_Init(NEPacketTunnelFlow* packetFlow,
const std::string& proxy_url,
int tun_mtu,
int log_level,
bool dns_over_tcp) {
auto context = new Tun2Proxy_InitContext;
context->packetFlow = packetFlow;
int fds[2] = {-1, -1};
if (pipe(fds) < 0) {
delete context;
return nullptr;
}
fcntl(fds[0], F_SETFD, FD_CLOEXEC); // read end
fcntl(fds[1], F_SETFD, FD_CLOEXEC); // write end
fcntl(fds[0], F_SETFL, O_NONBLOCK | fcntl(fds[0], F_GETFL));
context->read_fd = fds[1]; // save write end
context->tun2proxy_ptr =
tun2proxy_init(context, fds[0], GetReadPacketContextData, GetReadPacketContextSize, FreeReadPacketContext,
WritePackets, proxy_url.c_str(), tun_mtu, log_level, dns_over_tcp ? 1 : 0);
if (context->tun2proxy_ptr == nullptr) {
IGNORE_EINTR(close(fds[0]));
IGNORE_EINTR(close(fds[1]));
delete context;
return nullptr;
}
return context;
}
int Tun2Proxy_Run(Tun2Proxy_InitContext* context) {
DCHECK(context);
return tun2proxy_run(context->tun2proxy_ptr);
}
void Tun2Proxy_ForwardReadPackets(Tun2Proxy_InitContext* context, NSArray<NEPacket*>* packets) {
DCHECK(context);
for (NEPacket* packet in packets) {
ReadPacketContext* p = new ReadPacketContext;
p->data = packet.data;
int ret = HANDLE_EINTR(write(context->read_fd, &p, sizeof(p)));
if (ret < 0) {
break;
}
}
}
void Tun2Proxy_Shutdown(Tun2Proxy_InitContext* context) {
DCHECK(context);
tun2proxy_shutdown(context->tun2proxy_ptr);
IGNORE_EINTR(close(context->read_fd));
}
void Tun2Proxy_Destroy(Tun2Proxy_InitContext* context) {
if (context == nullptr) {
return;
}
tun2proxy_destroy(context->tun2proxy_ptr);
context->packetFlow = nil;
context->tun2proxy_ptr = nullptr;
delete context;
}