-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtianji_TLS_worker.js
954 lines (942 loc) · 37.8 KB
/
tianji_TLS_worker.js
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
//1、天书版5.0终极版
//2、支持反代开关,私钥开关,全局分段开关,订阅隐藏开关功能,去除UUID限制,clash私钥防止被薅请求数
//3、又再重新修改了接口关闭逻辑,降低请求数(请求数大幅度降低)和错误率(worker引发异常为0,至少我测试的是)
//4、修改传输方式,增加分片传输,可提升传输稳定性
//5、支持SOCKS5,支持外部环境变量,变量名【SOCKS5】,只支持一个SOCKS5,并且SOCKS5和原始反代只能二选一,建议有稳定SOCKS5的人使用,白嫖玩家不建议使用,为了方便切换增加了一个外部变量【SOCKS5OPEN】,true打开和false关闭
//6、支持多反代,支持外部环境变量,变量名【PROXYIP】,每行一个,无限尝试逻辑(WORKER响应都是毫秒级的,几乎感觉不到反代切换的影响),直到连上了或者所有反代都无效,优先次序是【脚本内部定义的反代IP--外部环境变量定义的PROXYIP】
//7、多反代功能很方便,但前提是你的反代质量必须得好,可以把自己收集来的各路靠谱大佬的反代都丢进去,除非大佬全没了,不然几乎不用考虑反代问题,有VPS的同学就更方便了,一个VPS挂了还能备另一个^_^
//8、不用在意那些奇怪的变量名,根据后面注释的备注去改,大概也就前50行看一下备注就行,clash配置在底部,懂的可以根据自身需求修改
//9、纯手搓配置,去除任何API外链,直接改好了部署就行,这样安全性史无前例
//10、通用订阅不支持私钥功能,使用通用订阅需关闭私钥功能再订阅节点,CF不支持自身1.1.1.1的DNS解析,如果无法连通可以检查客户端DNS设置
//11、由于本人仅使用openclash和clash meta,其他平台软件均未测试,请自行测试研究,要是不能用就算了,不负责改进,继续概不负责^_^
//12、由于本人纯菜,很多代码解释都是根据自己的理解瞎编的,专业的无视就好,单纯为了帮助小白理解代码大致原理^_^
import { connect } from 'cloudflare:sockets';
let 哎呀呀这是我的ID啊 = "btpp"; //实际上这是你的订阅路径,支持任意大小写字母和数字,[域名/ID]进入订阅页面
let 哎呀呀这是我的VL密钥 = "2b5bb5a8-a33f-4df2-a715-9f805a7d8ca5"; //这是真实的UUID,会进行验证,建议修改为自己的规范化UUID
let 私钥开关 = false //是否启用私钥功能,true启用,false不启用,因为私钥功能只支持clash,如果打算使用通用订阅则需关闭私钥功能
let 咦这是我的私钥哎 = "123456"; //这是你的私钥,提高隐秘性安全性,就算别人扫到你的域名也无法链接,再也不怕别人薅请求数了^_^
let 隐藏订阅 = false //选择是否隐藏订阅页面,false不隐藏,true隐藏,当然隐藏后自己也无法订阅,因为配置固定,适合自己订阅后就隐藏,防止被爬订阅,并且可以到下方添加嘲讽语^_^
let 嘲讽语 = "哎呀你找到了我,但是我就是不给你看,气不气,嘿嘿嘿" //隐藏订阅后,真实的订阅页面就会显示这段话,想写啥写啥
let 我的优选 = '104.19.61.169' //CF的节点,填域名或IP,好的优选一个就够了,由于CFcdn常规13端口开放,可以生成全端口节点
let 我的优选IPV6 = '' //CF的IPV6节点,填域名或IP,好的优选一个就够了,由于CFcdn常规13端口开放,可以生成全端口节点
let 特殊优选 = '' //非CF的节点,填域名或IP,结合你的反代一起使用的话,这个节点可以完全的固定落地地区,例如同时都使用美国的
let 特殊优选的端口 = '443' //非CF的节点端口
let 非CF节点是否打开tls = 'true' //非CF的节点TLS开关,true,false,通用订阅此功能无效,默认使用tls
let 启用反代功能 = true //选择是否启用反代功能,false,true,现在你可以自由的选择是否启用反代功能了
let 反代IP = [
'ts.hpc.tw',
] //反代IP或域名,反代IP端口一般情况下不用填写,如果你非要用非标反代的话,可以填'ts.hpc.tw:443'这样
let 启用SOCKS5反代 = false //如果启用此功能,原始反代将失效
let 我的SOCKS5账号 = 'TG:[email protected]:35555' //格式'账号:密码@地址:端口'
let 我的节点名字 = 'btpp优选' //自己的节点名字
let 伪装网页 = '' //填入伪装网页,格式'www.youku.com',如果不填,脚本本身有个内置的简单代理页面,建议用小站伪装或者直接内置,比较靠谱
let 启用全局分段 = true //选择是否使用全局分段功能,试验功能,分段传输可以降低worker压力,提升传输稳定性。
let 分段大小 = 1*1024; //分段大小,建议不要随意修改,这是测试的比较适合的数值。
//////////////////////////////////////////////////////////////////////////网页入口////////////////////////////////////////////////////////////////////////
export default {
async fetch(访问请求, env) {
const 读取我的请求标头 = 访问请求.headers.get('Upgrade');
const url = new URL(访问请求.url);
if (!读取我的请求标头 || 读取我的请求标头 !== 'websocket') {
switch (url.pathname) {
case `/${哎呀呀这是我的ID啊}`: {
const 订阅页面 = 给我订阅页面(哎呀呀这是我的ID啊, 访问请求.headers.get('Host'));
return new Response(`${订阅页面}`, {
status: 200,
headers: {
"Content-Type": "text/plain;charset=utf-8",
}
});
}
case `/${哎呀呀这是我的ID啊}/${转码}${转码2}`: {
if (隐藏订阅) {
return new Response (`${嘲讽语}`, {
status: 200,
headers: {
"Content-Type": "text/plain;charset=utf-8",
}
});
} else {
const 通用配置文件 = 给我通用配置文件(访问请求.headers.get('Host'));
return new Response(`${通用配置文件}`, {
status: 200,
headers: {
"Content-Type": "text/plain;charset=utf-8",
}
});
}
}
case `/${哎呀呀这是我的ID啊}/${小猫}${咪}`: {
if (隐藏订阅) {
return new Response (`${嘲讽语}`, {
status: 200,
headers: {
"Content-Type": "text/plain;charset=utf-8",
}
});
} else {
const 小猫咪配置文件 = 给我小猫咪配置文件(访问请求.headers.get('Host'));
return new Response(`${小猫咪配置文件}`, {
status: 200,
headers: {
"Content-Type": "text/plain;charset=utf-8",
}
});
}
}
default:
if (伪装网页) {
url.hostname = 伪装网页;
url.protocol = 'https:';
访问请求 = new Request(url, 访问请求);
return fetch(访问请求);
} else {
访问请求 = new Request(url, 访问请求);
return 代理页面(访问请求);
}
}
} else if (读取我的请求标头 === 'websocket'){
FDIP = env.PROXYIP;
我的SOCKS5账号 = env.SOCKS5 || 我的SOCKS5账号;
启用SOCKS5反代 = (env.SOCKS5OPEN === 'true') ? true : (env.SOCKS5OPEN === 'false' ? false : 启用SOCKS5反代);
if (私钥开关) {
const 验证我的私钥 = 访问请求.headers.get('my-key')
if (验证我的私钥 === 咦这是我的私钥哎) {
return await 升级WS请求(访问请求);
}
}
if (!私钥开关) {
return await 升级WS请求(访问请求);
}
}
}
};
////////////////////////////////////////////////////////////////////////内置代理页面//////////////////////////////////////////////////////////////////////
async function 代理页面(request) {
const url = new URL(request.url);
if (url.pathname === '/' || url.pathname === '/proxy/') {
return createLandingPage();
}
let actualUrlStr = url.pathname.replace("/proxy/", "") + url.search + url.hash;
if (!actualUrlStr.startsWith('http://') && !actualUrlStr.startsWith('https://')) {
actualUrlStr = 'https://' + actualUrlStr;
}
try {
const actualUrl = new URL(actualUrlStr);
const modifiedRequest = new Request(actualUrl, {
headers: request.headers,
method: request.method,
body: (request.method === 'POST' || request.method === 'PUT') ? request.body : undefined,
redirect: 'follow'
});
const response = await fetch(modifiedRequest);
if (!response.ok) {
throw new Error(`Fetch request failed with status: ${response.status}`);
}
const clonedResponseBody = await response.clone().text();
const modifiedResponse = new Response(clonedResponseBody, response);
modifiedResponse.headers.set('Access-Control-Allow-Origin', '*');
modifiedResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
modifiedResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return modifiedResponse;
} catch (error) {
return new Response(`Error: ${error.message}`, { status: 500 });
}
}
function createLandingPage() {
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
background-color: #fbfbfb;
font-family: Arial, sans-serif;
}
h1 {
text-align: center;
color: #444;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
form {
background-color: white;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
padding: 2rem;
border-radius: 8px;
}
input {
display: block;
width: 100%;
font-size: 18px;
padding: 15px;
border: solid 1px #ccc;
border-radius: 4px;
margin: 1rem 0;
}
button {
padding: 15px;
background-color: #0288d1;
color: white;
font-size: 18px;
border: none;
border-radius: 4px;
cursor: pointer;
width: 100%;
}
button:hover {
background-color: #039BE5;
}
</style>
<meta charset="UTF-8">
<title>代理服务器</title>
</head>
<body>
<h1>输入您想访问的网址,本网页主要方便拉库用,并不能科学</h1>
<form id="proxy-form">
<input type="text" id="url" name="url" placeholder="https://示例.com" required />
<button type="submit">访问</button>
</form>
<script>
const form = document.getElementById('proxy-form');
form.addEventListener('submit', event => {
event.preventDefault();
const input = document.getElementById('url');
const actualUrl = input.value;
const proxyUrl = '/proxy/' + actualUrl;
location.href = proxyUrl;
});
</script>
</body>
</html>
`;
return new Response(html, {
headers: { 'Content-Type': 'text/html' }
});
}
////////////////////////////////////////////////////////////////////////脚本主要架构//////////////////////////////////////////////////////////////////////
//第一步,读取和构建基础访问结构
async function 升级WS请求(访问请求) {
const 创建WS接口 = new WebSocketPair();
const [客户端, WS接口] = Object.values(创建WS接口);
WS接口.accept();
const 读取我的加密访问内容数据头 = 访问请求.headers.get('sec-websocket-protocol') || '';
const 读取解密后的WS数据流 = await 创建我的WS服务(WS接口, 读取我的加密访问内容数据头);
let 远程传输 = { value: null, };
读取解密后的WS数据流.pipeTo(new WritableStream({
async write(VL数据) {
if (远程传输.value) {
const 传输数据 = 远程传输.value.writable.getWriter();
if (启用全局分段) {
await 发往TCP目标的分块传输(传输数据, VL数据);
} else {
await 传输数据.write(VL数据);
}
传输数据.releaseLock();
return;
}
const 解析VL数据 = await 解析VL标头(VL数据); //解析VL访问请求和数据,包括目标地址[如谷歌油管等],目标端口,数据内容等
if (解析VL数据 === null) {
await 读取解密后的WS数据流.cancel();
WS接口.close()
return new Response('Forbidden', { status: 403 });
}
const { 识别地址类型, 访问地址 = '', 访问端口 = '', 创建原始数据索引, } = 解析VL数据;
const 写入数据请求 = VL数据.slice(创建原始数据索引);
TCP握手协议(远程传输, 识别地址类型, 访问地址, 访问端口, 写入数据请求, WS接口);
},
}));
return new Response(null, {
status: 101,
webSocket: 客户端,
});
}
async function 发往TCP目标的分块传输(传输数据, VL数据, offset = 0) {
while (offset < VL数据.byteLength) {
const 分段数据块 = VL数据.slice(offset, offset + 分段大小);
await 传输数据.write(分段数据块);
await new Promise(resolve => setTimeout(resolve, 0));
offset += 分段大小;
}
}
//第二步,解密WS访问内容,建立WS服务监听状态
async function 创建我的WS服务(WS接口, 解密我的访问数据) {
const 数据流 = new ReadableStream({
async start(控制器) {
WS接口.addEventListener('message', (event) => { //监听WS接口数据并发送给目标服务器
const message = event.data
控制器.enqueue(message)
});
WS接口.addEventListener('close', () => { //监听客户端WS接口关闭信息,结束流传输
控制器.close();
return;
});
WS接口.addEventListener('error', () => { //监听客户端WS接口异常信息,结束流传输
控制器.close();
return;
});
const {earlyData} = await 使用64位加解密(解密我的访问数据); //解密目标访问数据,传递给TCP握手进程
if (earlyData) {
控制器.enqueue(earlyData);
};
}
});
return 数据流;
}
async function 使用64位加解密(还原混淆字符) {
还原混淆字符 = 还原混淆字符.replace(/-/g, '+').replace(/_/g, '/');
const 解密数据 = atob(还原混淆字符);
const 解密_你_个_丁咚_咙_咚呛 = Uint8Array.from(解密数据, (c) => c.charCodeAt(0));
return { earlyData: 解密_你_个_丁咚_咙_咚呛.buffer };
}
//第三步,解读VL协议数据,建立客户端VL--workers的完整索引通道
async function 解析VL标头(VL数据) {
if (验证VL的密钥(new Uint8Array(VL数据.slice(1, 17))) !== 哎呀呀这是我的VL密钥) {
return null;
}
const 获取数据定位 = new Uint8Array(VL数据.slice(17, 18))[0];
const 提取端口索引 = 18 + 获取数据定位 + 1;
const 建立端口缓存 = VL数据.slice(提取端口索引, 提取端口索引 + 2);
const 访问端口 = new DataView(建立端口缓存).getUint16(0);
const 提取地址索引 = 提取端口索引 + 2;
const 建立地址缓存 = new Uint8Array(VL数据.slice(提取地址索引, 提取地址索引 + 1));
const 识别地址类型 = 建立地址缓存[0];
let 地址长度 = 0;
let 地址信息 = '';
let 地址信息索引 = 提取地址索引 + 1;
switch (识别地址类型) {
case 1:
地址长度 = 4;
地址信息 = new Uint8Array(
VL数据.slice(地址信息索引, 地址信息索引 + 地址长度)
).join('.');
break;
case 2:
地址长度 = new Uint8Array(
VL数据.slice(地址信息索引, 地址信息索引 + 1)
)[0];
地址信息索引 += 1;
地址信息 = new TextDecoder().decode(
VL数据.slice(地址信息索引, 地址信息索引 + 地址长度)
);
break;
case 3:
地址长度 = 16;
const dataView = new DataView(
VL数据.slice(地址信息索引, 地址信息索引 + 地址长度)
);
const ipv6 = [];
for (let i = 0; i < 8; i++) {
ipv6.push(dataView.getUint16(i * 2).toString(16));
}
地址信息 = ipv6.join(':');
break;
default:
return null;
}
return {
识别地址类型,
访问地址: 地址信息,
访问端口,
创建原始数据索引: 地址信息索引 + 地址长度,
};
}
function 验证VL的密钥(arr, offset = 0) {
const uuid = 提取VL的密钥(arr, offset);
return uuid;
}
function 提取VL的密钥(arr, offset = 0) {
return (转换密钥格式[arr[offset + 0]] + 转换密钥格式[arr[offset + 1]] + 转换密钥格式[arr[offset + 2]] + 转换密钥格式[arr[offset + 3]] + "-" +
转换密钥格式[arr[offset + 4]] + 转换密钥格式[arr[offset + 5]] + "-" +
转换密钥格式[arr[offset + 6]] + 转换密钥格式[arr[offset + 7]] + "-" +
转换密钥格式[arr[offset + 8]] + 转换密钥格式[arr[offset + 9]] + "-" +
转换密钥格式[arr[offset + 10]] + 转换密钥格式[arr[offset + 11]] + 转换密钥格式[arr[offset + 12]] +
转换密钥格式[arr[offset + 13]] + 转换密钥格式[arr[offset + 14]] + 转换密钥格式[arr[offset + 15]]).toLowerCase();
}
const 转换密钥格式 = [];
for (let i = 0; i < 256; ++i) {
转换密钥格式.push((i + 256).toString(16).slice(1));
}
//第四步,建立VL--workers--外网的TCP握手协议
async function TCP握手协议(远程传输, 识别地址类型, 访问地址, 访问端口, 写入数据请求, WS接口) {
反代数组 = await 获取反代IP列表();
const 目标TCP接口 = await 创建TCP握手(访问地址, 访问端口);
TCP接口访问WS(目标TCP接口, WS接口, SOCKS5反代兜底, 原始反代兜底);
async function SOCKS5反代兜底(){
const 反代SOCKS5接口 = await 创建SOCKS5握手(访问地址, 访问端口);
if (反代SOCKS5接口 === null) {
WS接口.close(1006);
return;
}
TCP接口访问WS(反代SOCKS5接口, WS接口, SOCKS5反代兜底, 原始反代兜底);
return;
}
async function 原始反代兜底() {
let [反代IP地址, 反代IP端口] = 反代IP库.split(':');
const 反代TCP接口 = await 创建TCP握手(反代IP地址, 反代IP端口 || 访问端口);
TCP接口访问WS(反代TCP接口, WS接口, SOCKS5反代兜底, 原始反代兜底);
return;
}
async function 创建TCP握手(地址, 端口) {
const TCP接口 = connect({ hostname: 地址, port: 端口 });
远程传输.value = TCP接口;
const 传输数据 = TCP接口.writable.getWriter();
await 传输数据.write(写入数据请求);
传输数据.releaseLock();
return TCP接口;
}
async function 创建SOCKS5握手(地址, 端口) {
const SOCKS5接口 = await 创建SOCKS5接口(识别地址类型, 地址, 端口)
if (SOCKS5接口 === null){
return null;
}
远程传输.value = SOCKS5接口;
const 传输数据 = SOCKS5接口.writable.getWriter();
await 传输数据.write(写入数据请求);
传输数据.releaseLock();
return SOCKS5接口;
}
return;
}
//第五步,进行VL--workers--外网的WS数据传输,TCP握手成功后建立最终的WS数据传输通道
async function TCP接口访问WS(TCP接口, WS接口, SOCKS5反代兜底, 原始反代兜底) {
let VL标头 = new Uint8Array([0, 0]);
let 传入数据 = false;
await TCP接口.readable.pipeTo(new WritableStream({
async write(VL数据) {
传入数据 = true;
if (VL标头 && WS接口.readyState === 1) {
await WS接口.send(await new Blob([VL标头, VL数据]).arrayBuffer());
VL标头 = null;
} else {
if (启用全局分段) {
await WS回传的分块传输(WS接口, VL数据);
} else {
await WS接口.send(VL数据);
}
}
},
}));
if (启用反代功能 && 传入数据 === false) {
TCP接口.close();
if (启用SOCKS5反代) {
启用SOCKS5反代 = false;
SOCKS5反代兜底();
return;
}
if (反代数组.length > 0 && 反代IP库计数器 < 反代数组.length) {
反代IP库 = 反代数组[反代IP库计数器];
反代IP库计数器++;
原始反代兜底();
return;
}
}
TCP接口.close();
检查并关闭WS接口(WS接口)
return;
}
async function WS回传的分块传输(WS接口, VL数据, offset = 0) {
while (offset < VL数据.byteLength) {
const 分段数据块 = VL数据.slice(offset, offset + 分段大小);
await WS接口.send(分段数据块);
await new Promise(resolve => setTimeout(resolve, 0));
offset += 分段大小;
}
}
async function 检查并关闭WS接口(WS接口, 最大等待时间 = 1000, 检查间隔 = 50) {
if (WS接口.bufferedAmount === 0) {
WS接口.close(1000);
} else {
let 初始时间 = 0;
while (初始时间 < 最大等待时间) {
await new Promise(resolve => setTimeout(resolve, 检查间隔));
if (WS接口.bufferedAmount === 0) {
WS接口.close(1000);
return;
}
初始时间 += 检查间隔;
}
WS接口.close(1000);
}
return;
}
let FDIP, 反代IP库, 反代IP库计数器 = 0;
let 反代数组 = [];
async function 获取反代IP列表() {
if (FDIP) {
反代数组 = FDIP.split('\n').map(line => line.trim()).filter(line => line);
}
const 添加反代IP = Array.isArray(反代IP) ? 反代IP : [反代IP];
反代数组.unshift(...添加反代IP);
return 反代数组;
}
//////////////////////////////////////////////////////////////////////////SOCKS5部分//////////////////////////////////////////////////////////////////////
async function 创建SOCKS5接口(识别地址类型, 访问地址, 访问端口) {
const { username, password, hostname, port } = await 获取SOCKS5账号(我的SOCKS5账号);
const SOCKS5接口 = connect({ hostname, port });
const writer = SOCKS5接口.writable.getWriter();
const reader = SOCKS5接口.readable.getReader();
if (!writer || !reader) {
return 关闭接口并退出();
}
const socksGreeting = new Uint8Array([5, 2, 0, 2]);
await writer.write(socksGreeting);
const encoder = new TextEncoder();
let res = (await reader.read()).value;
if (res[0] !== 0x05) {
return 关闭接口并退出();
}
if (res[1] === 0xff) {
return 关闭接口并退出();
}
if (res[1] === 0x02) {
if (!username || !password) {
return 关闭接口并退出();
}
const authRequest = new Uint8Array([
1, // 认证子协议版本
username.length, // 用户名长度
...encoder.encode(username), // 用户名
password.length, // 密码长度
...encoder.encode(password) // 密码
]);
await writer.write(authRequest);
res = (await reader.read()).value;
if (res[0] !== 0x01 || res[1] !== 0x00) {
return 关闭接口并退出();
}
}
let DSTADDR; // DSTADDR = ATYP + DST.ADDR
switch (识别地址类型) {
case 1: // IPv4
DSTADDR = new Uint8Array(
[1, ...访问地址.split('.').map(Number)]
);
break;
case 2: // 域名
DSTADDR = new Uint8Array(
[3, 访问地址.length, ...encoder.encode(访问地址)]
);
break;
case 3: // IPv6
DSTADDR = new Uint8Array(
[4, ...访问地址.split(':').flatMap(x => [parseInt(x.slice(0, 2), 16), parseInt(x.slice(2), 16)])]
);
break;
default:
return 关闭接口并退出();
}
const socksRequest = new Uint8Array([5, 1, 0, ...DSTADDR, 访问端口 >> 8, 访问端口 & 0xff]);
await writer.write(socksRequest);
res = (await reader.read()).value;
writer.releaseLock();
reader.releaseLock();
return SOCKS5接口;
function 关闭接口并退出(){ //关闭SOCKS5接口,防止卡死
if (writer) {
writer.releaseLock();
}
if (reader) {
reader.releaseLock();
}
if (SOCKS5接口) {
SOCKS5接口.close();
}
return null;
}
}
async function 获取SOCKS5账号(SOCKS5) {
const [latter, former] = SOCKS5.split("@").reverse();
let username, password, hostname, port;
if (former) {
const formers = former.split(":");
username = formers[0];
password = formers[1];
}
const latters = latter.split(":");
port = Number(latters.pop());
hostname = latters.join(":");
return { username, password, hostname, port };
}
//////////////////////////////////////////////////////////////////////////订阅页面////////////////////////////////////////////////////////////////////////
let 转码 = 'vl', 转码2 = 'ess', 符号 = '://', 小猫 = 'cla', 咪 = 'sh', 我的私钥;
if (私钥开关) {
我的私钥 = `my-key: ${咦这是我的私钥哎}`
} else {
我的私钥 = ""
}
function 给我订阅页面(哎呀呀这是我的ID啊, hostName) {
return `
1、本worker的私钥功能只支持${小猫}${咪},仅open${小猫}${咪}和${小猫}${咪} meta测试过,其他${小猫}${咪}类软件自行测试
2、若使用通用订阅请关闭私钥功能
3、其他需求自行研究
通用的:https${符号}${hostName}/${哎呀呀这是我的ID啊}/${转码}${转码2}
猫咪的:https${符号}${hostName}/${哎呀呀这是我的ID啊}/${小猫}${咪}
`;
}
function 给我通用配置文件(hostName) {
const 特殊长链接Links = btoa(`
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:443?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:8443?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:2053?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:2083?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:2087?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选}:2096?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:443?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:8443?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:2053?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:2083?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:2087?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${我的优选IPV6}:2096?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${特殊优选}:${特殊优选的端口}?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
${转码}${转码2}${符号}${哎呀呀这是我的VL密钥}@${hostName}:443?encryption=none&security=tls&type=ws&host=${hostName}&path=%2F%3Fed%3D2560
`);
if (私钥开关) {
return `请先关闭私钥功能`
}else {
return `${特殊长链接Links}`
}
}
function 给我小猫咪配置文件(hostName) {
return `
dns:
nameserver:
- 119.29.29.29
- 223.5.5.5
fallback:
- 8.8.8.8
- tls://dns.google
- 2001:4860:4860::8888
proxies:
- name: ${我的节点名字}-tls-443
type: ${转码}${转码2}
server: ${我的优选}
port: 443
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-tls-8443
type: ${转码}${转码2}
server: ${我的优选}
port: 8443
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-tls-2053
type: ${转码}${转码2}
server: ${我的优选}
port: 2053
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-tls-2083
type: ${转码}${转码2}
server: ${我的优选}
port: 2083
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-tls-2087
type: ${转码}${转码2}
server: ${我的优选}
port: 2087
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-tls-2096
type: ${转码}${转码2}
server: ${我的优选}
port: 2096
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-443
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 443
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-8443
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 8443
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-2053
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 2053
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-2083
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 2083
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-2087
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 2087
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-IPV6-tls-2096
type: ${转码}${转码2}
server: ${我的优选IPV6}
port: 2096
ip-version: ipv6 # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-非CF节点
type: ${转码}${转码2}
server: ${特殊优选}
port: ${特殊优选的端口}
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: ${非CF节点是否打开tls}
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-备用IPV4节点
type: ${转码}${转码2}
server: ${hostName}
port: 443
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
- name: ${我的节点名字}-备用IPV6节点
type: ${转码}${转码2}
server: ${hostName}
port: 443
ip-version: ipv6-prefer # ip-version设置,可以自定义强制走ipv4或ipv6,ipv6-prefer则是双栈优先走ipv6
uuid: ${哎呀呀这是我的VL密钥}
udp: false
tls: true
network: ws
ws-opts:
path: "/?ed=2560"
headers:
Host: ${hostName}
${我的私钥}
proxy-groups:
- name: 🚀 节点选择
type: select
proxies:
- tls负载均衡
- IPV6-tls负载均衡
- 自动选择
- ${我的节点名字}-tls-443
- ${我的节点名字}-tls-8443
- ${我的节点名字}-tls-2053
- ${我的节点名字}-tls-2083
- ${我的节点名字}-tls-2087
- ${我的节点名字}-tls-2096
- ${我的节点名字}-IPV6-tls-443
- ${我的节点名字}-IPV6-tls-8443
- ${我的节点名字}-IPV6-tls-2053
- ${我的节点名字}-IPV6-tls-2083
- ${我的节点名字}-IPV6-tls-2087
- ${我的节点名字}-IPV6-tls-2096
- ${我的节点名字}-非CF节点
- ${我的节点名字}-备用IPV4节点
- ${我的节点名字}-备用IPV6节点
- name: 自动选择
type: url-test
url: http://www.gstatic.com/generate_204
interval: 300
tolerance: 50
proxies:
- ${我的节点名字}-tls-443
- ${我的节点名字}-tls-8443
- ${我的节点名字}-tls-2053
- ${我的节点名字}-tls-2083
- ${我的节点名字}-tls-2087
- ${我的节点名字}-tls-2096
- ${我的节点名字}-IPV6-tls-443
- ${我的节点名字}-IPV6-tls-8443
- ${我的节点名字}-IPV6-tls-2053
- ${我的节点名字}-IPV6-tls-2083
- ${我的节点名字}-IPV6-tls-2087
- ${我的节点名字}-IPV6-tls-2096
- ${我的节点名字}-非CF节点
- ${我的节点名字}-备用IPV4节点
- ${我的节点名字}-备用IPV6节点
- name: tls负载均衡
type: load-balance
url: http://www.gstatic.com/generate_204
interval: 300
proxies:
- ${我的节点名字}-tls-443
- ${我的节点名字}-tls-8443
- ${我的节点名字}-tls-2053
- ${我的节点名字}-tls-2083
- ${我的节点名字}-tls-2087
- ${我的节点名字}-tls-2096
- name: IPV6-tls负载均衡
type: load-balance
url: http://www.gstatic.com/generate_204
interval: 300
proxies:
- ${我的节点名字}-IPV6-tls-443
- ${我的节点名字}-IPV6-tls-8443
- ${我的节点名字}-IPV6-tls-2053
- ${我的节点名字}-IPV6-tls-2083
- ${我的节点名字}-IPV6-tls-2087
- ${我的节点名字}-IPV6-tls-2096
- name: 非CF节点
type: select
proxies:
- ${我的节点名字}-非CF节点
- name: 漏网之鱼
type: select
proxies:
- DIRECT
- 🚀 节点选择
- 非CF节点
rules:
# 策略规则,部分规则需打开${小猫}${咪} mate的使用geoip dat版数据库,比如TG规则就需要,或者自定义geoip的规则订阅
# 这是geoip的规则订阅链接,https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb
# GPT规则
- DOMAIN-KEYWORD,openai,🚀 节点选择
- DOMAIN-SUFFIX,AI.com,🚀 节点选择
- DOMAIN-SUFFIX,cdn.auth0.com,🚀 节点选择
- DOMAIN-SUFFIX,openaiapi-site.azureedge.net,🚀 节点选择
- DOMAIN-SUFFIX,opendns.com,🚀 节点选择
- DOMAIN-SUFFIX,bing.com,🚀 节点选择
- DOMAIN-SUFFIX,civitai.com,🚀 节点选择
- DOMAIN,bard.google.com,🚀 节点选择
- DOMAIN,ai.google.dev,🚀 节点选择
- DOMAIN,gemini.google.com,🚀 节点选择
- DOMAIN-SUFFIX,googleapis.com,🚀 节点选择
- DOMAIN-SUFFIX,sentry.io,🚀 节点选择
- DOMAIN-SUFFIX,intercom.io,🚀 节点选择
- DOMAIN-SUFFIX,featuregates.org,🚀 节点选择
- DOMAIN-SUFFIX,statsigapi.net,🚀 节点选择
- DOMAIN-SUFFIX,claude.ai,🚀 节点选择
- DOMAIN-SUFFIX,Anthropic.com,🚀 节点选择
- DOMAIN-SUFFIX,opera-api.com,🚀 节点选择
- DOMAIN-SUFFIX,aistudio.google.com,🚀 节点选择
- DOMAIN-SUFFIX,auth0.com,🚀 节点选择
- DOMAIN-SUFFIX,challenges.cloudflare.com,🚀 节点选择
- DOMAIN-SUFFIX,chatgpt.com,🚀 节点选择
- DOMAIN-SUFFIX,client-api.arkoselabs.com,🚀 节点选择
- DOMAIN-SUFFIX,events.statsigapi.net,🚀 节点选择
- DOMAIN-SUFFIX,identrust.com,🚀 节点选择
- DOMAIN-SUFFIX,intercomcdn.com,🚀 节点选择
- DOMAIN-SUFFIX,oaistatic.com,🚀 节点选择
- DOMAIN-SUFFIX,oaiusercontent.com,🚀 节点选择
- DOMAIN-SUFFIX,openai.com,🚀 节点选择
- DOMAIN-SUFFIX,stripe.com,🚀 节点选择
# GPT规则
# - GEOSITE,category-ads,REJECT #简单广告过滤规则,要增加规则数可使用category-ads-all
- GEOSITE,cn,DIRECT #国内域名直连规则
- GEOIP,CN,DIRECT,no-resolve #国内IP直连规则
- GEOSITE,cloudflare,DIRECT #CF域名直连规则
- GEOIP,CLOUDFLARE,DIRECT,no-resolve #CFIP直连规则
- GEOSITE,gfw,🚀 节点选择 #GFW域名规则
- GEOSITE,google,🚀 节点选择 #GOOGLE域名规则
- GEOIP,GOOGLE,🚀 节点选择,no-resolve #GOOGLE IP规则
- GEOSITE,netflix,🚀 节点选择 #奈飞域名规则
- GEOIP,NETFLIX,🚀 节点选择,no-resolve #奈飞IP规则
- GEOSITE,telegram,🚀 节点选择 #TG域名规则
- GEOIP,TELEGRAM,🚀 节点选择,no-resolve #TG IP规则
- MATCH,漏网之鱼
`
}