├── README.md ├── test_v0.3.1.js ├── test_v0.3.js ├── testmax_v0.2.js ├── testmax_v0.1.js ├── test_v4.0养老版.js ├── test_v0.1.js ├── test_v0.2.js └── _worker.js /README.md: -------------------------------------------------------------------------------- 1 | 提供可以fork的狂暴代码地址 2 | -------------------------------------------------------------------------------- /test_v0.3.1.js: -------------------------------------------------------------------------------- 1 | import{connect}from'cloudflare:sockets'; 2 | const d=new TextDecoder(),e=new TextEncoder(),i='123456',u='5aba5b77-48eb-4ae2-b60d-5bfee7ac169e',p=['1.1.1.1'],r='sjc.o00o.ooo:443',n='狂暴'; 3 | const U=((h,a=new Uint8Array(16))=>{for(let i=0;i<32;i+=2)a[i>>1]=parseInt(h.substr(i,2),16);return a})(u.replace(/-/g,'')); 4 | const c=b=>{for(let i=0;i<16;i++)if(b[i]!==U[i])return 0;return 1}; 5 | const t=async(h,o,a)=>{try{const s=await connect({hostname:h,port:o});return await s.opened,{tcpSocket:s,initialData:a}}catch{}if(r){const[H,P]=r.split(':');return t(H,+P||o,a)}throw new Error('连接失败')}; 6 | const v=async b=>{b=new Uint8Array(b);let j=18+b[17],P=(b[j+1]<<8)|b[j+2],H='',i=j+4;switch(b[j+3]){case 1:H=`${b[i++]}.${b[i++]}.${b[i++]}.${b[i++]}`;break;case 2:{const l=b[i++];H=d.decode(b.subarray(i,i+l));i+=l}break;case 3:H=Array.from({length:8},(_,k)=>((b[i+2*k]<<8)|b[i+2*k+1]).toString(16)).join(':');i+=16}return t(H,P,b.slice(i))}; 7 | const m=(w,s,a)=>{const x=s.writable.getWriter();w.send(new Uint8Array([0,0]));a&&x.write(a);let b=[],y,z=0;const q=()=>{z||(z=1,y&&clearTimeout(y),x.releaseLock().catch(()=>{}),s.close().catch(()=>{}),w.close().catch(()=>{}),b=null)};w.onmessage=({data})=>{if(z)return;const l=data instanceof ArrayBuffer?new Uint8Array(data):e.encode(data);b.push(l),y||(y=setTimeout(()=>{if(z)return;const o=b.length===1?b[0]:(()=>{let l=0;b.forEach(c=>l+=c.length);const d=new Uint8Array(l);let p=0;return b.forEach(c=>(d.set(c,p),p+=c.length)),d})();x.write(o).catch(q),b.length=0,y=null},5))};s.readable.pipeTo(new WritableStream({write:d=>w.send(d),close:q,abort:q})).catch(q);w.onclose=q}; 8 | const f=h=>{const t=(a,b=n)=>{const[H,P=443]=a.split(':');return`vless://${u}@${H}:${P}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${encodeURIComponent(b)}`};return p.map(a=>{const[c,d]=a.split('#');return t(c,d)}).join('\n')+`\n`+t(h)}; 9 | export default{async fetch(req,env){const{headers,url}=req,host=headers.get('Host');if(headers.get('Upgrade')!=='websocket'){const{pathname}=new URL(url);return new Response(pathname===`/${i}`?`订阅地址: https://${host}/${i}/vless`:pathname===`/${i}/vless`?f(host):'Hello Worker!')}try{const p=headers.get('sec-websocket-protocol'),d=Uint8Array.from(atob(p.replace(/-/g,'+').replace(/_/g,'/')),c=>c.charCodeAt(0));if(!c(d.subarray(1,17)))return new Response('无效UUID',{status:403});const{tcpSocket:s,initialData:a}=await v(d.buffer),[C,S]=Object.values(new WebSocketPair);return S.accept(),m(S,s,a),new Response(null,{status:101,webSocket:C})}catch(e){return new Response('连接失败: '+e.message,{status:502})}}} 10 | -------------------------------------------------------------------------------- /test_v0.3.js: -------------------------------------------------------------------------------- 1 | /*@__PURE__*/import{connect}from'cloudflare:sockets'; 2 | const d=new TextDecoder(),e=new TextEncoder(); 3 | const I='123456',UUID='5aba5b77-48eb-4ae2-b60d-5bfee7ac169e',P=['1.1.1.1','8.8.8.8','1.0.0.1'],R='sjc.o00o.ooo',N=0,N2='狂暴'; 4 | const U=((u,a=new Uint8Array(16),j=0)=>{for(let i=0;i(b[0]^U[0])|(b[1]^U[1])|(b[2]^U[2])|(b[3]^U[3])|(b[4]^U[4])|(b[5]^U[5])|(b[6]^U[6])|(b[7]^U[7])|(b[8]^U[8])|(b[9]^U[9])|(b[10]^U[10])|(b[11]^U[11])|(b[12]^U[12])|(b[13]^U[13])|(b[14]^U[14])|(b[15]^U[15])?0:1; 6 | const to64=ip=>'2001:67c:2960:6464::'+((o,p)=>{for(let i=0;i<4;i++)o[i]=+p[i];return((o[0]<<8)|o[1]).toString(16).padStart(4,'0')+':'+((o[2]<<8)|o[3]).toString(16).padStart(4,'0')})(new Uint8Array(4),ip.split('.')); 7 | const tryConn=async(h,p,c,init)=>{try{const s=await connect({hostname:h,port:p});return await s.opened,{tcpSocket:s,initialData:init}}catch{}if(N&&((c=h.charCodeAt(0))>47&&c<58))try{return await tryConn(to64(h),p,{...c,N:0},init)}catch{}const[h2,p2]=R.split(':');return await tryConn(h2,+p2||p,{...c},init)}; 8 | const parseV=async(buf,c)=>{const a=new Uint8Array(buf),t=a[17],p=(a[18+t+1]<<8)|a[18+t+2];let o=18+t+4,h='',x,l;switch(a[o-1]){case 1:h=`${a[o++]}.${a[o++]}.${a[o++]}.${a[o++]}`;break;case 2:l=a[o++];h=d.decode(a.subarray(o,o+l));o+=l;break;case 3:for(x=0;x<8;x++)h+=(x?':':'')+((a[o+2*x]<<8)|a[o+2*x+1]).toString(16);o+=16}return await tryConn(h,p,c,buf.slice(o))}; 9 | const tunnel=(ws,tcp,init)=>{const w=tcp.writable.getWriter();ws.send(new Uint8Array([0,0]));init&&w.write(init);let b=[],t,c=0;const cleanup=()=>c?0:(c=1,t&&clearTimeout(t),b=null,w.releaseLock(),tcp.close());ws.addEventListener('message',({data})=>{if(c)return;const chunk=data instanceof ArrayBuffer?new Uint8Array(data):typeof data==='string'?e.encode(data):data;b.push(chunk),t||(t=setTimeout(()=>{if(c)return;const total=b.length===1?b[0]:((len=b.reduce((s,x)=>s+x.length,0),o=new Uint8Array(len),pos=0)=>{for(const x of b)o.set(x,pos),pos+=x.length;return o})();w.write(total).catch(cleanup),b.length=0,t=null},5))});tcp.readable.pipeTo(new WritableStream({write:d=>ws.send(d),close:cleanup,abort:cleanup})).catch(cleanup);ws.addEventListener('close',cleanup)}; 10 | const conf=h=>P.concat([`${h}:443`]).map(x=>{const[raw,name=N2]=x.split('#'),[addr,port=443]=raw.split(':');return`vless://${UUID}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`}).join('\n'); 11 | export default{async fetch(req,env){const url=new URL(req.url),h=req.headers.get('Host');if(req.headers.get('Upgrade')!=='websocket'){const path=url.pathname;return path===`/${I}`?new Response(`订阅地址: https://${h}/${I}/vless`):path===`/${I}/vless`?new Response(conf(h)):new Response('Hello Worker!')}try{const proto=req.headers.get('sec-websocket-protocol'),data=Uint8Array.from(atob(proto.replace(/-/g,'+').replace(/_/g,'/')),c=>c.charCodeAt(0));if(!chk(data.subarray(1,17)))return new Response('无效UUID',{status:403});const{tcpSocket,initialData}=await parseV(data.buffer,{N}),[client,server]=new WebSocketPair();return server.accept(),tunnel(server,tcpSocket,initialData),new Response(null,{status:101,webSocket:client})}catch(e){return new Response('连接失败: '+e.message,{status:502})}}}; 12 | -------------------------------------------------------------------------------- /testmax_v0.2.js: -------------------------------------------------------------------------------- 1 | import{connect}from'cloudflare:sockets'; 2 | const I='123456',UUID='5aba5b77-48eb-4ae2-b60d-5bfee7ac169e',P=['1.1.1.1','8.8.8.8','1.0.0.1'],R='sjc.o00o.ooo:443',F=1,N=0,N2='狂暴'; 3 | const[d,e,U,C,PS,S,A]=[new TextDecoder(),new TextEncoder(),[],{I,U:UUID,P,R,F,N,N2},new Map(),new Set(),new ArrayBuffer(8192)]; 4 | let W,T,B=new Uint8Array(A),O=0; 5 | const init=()=>{if(C.done)return C;const u=C.U.replace(/-/g,'');for(let i=0;i<32;i+=2)U[i>>1]=parseInt(u.substr(i,2),16);return C.done=1,C}; 6 | const chk=a=>{let i=0;do{if(a[i+1]!==U[i])return!1;}while(++i<16);return!0}; 7 | const tryConn=async(h,p,c,init)=>{const k=h+':'+p;if(PS.has(k)&&!S.has(k))return{...PS.get(k),initialData:init};try{const s=await connect({hostname:h,port:p});await s.opened;const r={tcpSocket:s,initialData:init};PS.set(k,r);S.delete(k);return r}catch{S.add(k)}if(c.N&&/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h))try{return await tryConn('2001:67c:2960:6464::'+h.split('.').map(x=>(+x).toString(16).padStart(2,'0')).join('').match(/.{4}/g).join(':'),p,{...c,N:0},init)}catch{}if(c.F&&c.R){const i=c.R.lastIndexOf(':');if(i>0&&!/^\[.*\]$/.test(c.R.substring(0,i)))return await tryConn(c.R.substring(0,i),+c.R.substring(i+1)||443,{...c,F:0},init);return await tryConn(c.R,443,{...c,F:0},init)}throw Error('连接失败')}; 8 | const parseV=async(buf,c)=>{const a=new Uint8Array(buf),t=a[17],p=(a[18+t+1]<<8)|a[18+t+2];let o=18+t+4,h='';const at=a[o-1];if(at===1){h=a[o]+'.'+a[o+1]+'.'+a[o+2]+'.'+a[o+3];o+=4}else if(at===2){const l=a[o];h=d.decode(a.subarray(o+1,o+1+l));o+=l+1}else if(at===3){h=Array.from({length:8},(_,i)=>((a[o+2*i]<<8)|a[o+2*i+1]).toString(16)).join(':');o+=16}return await tryConn(h,p,c,buf.slice(o))}; 9 | const tunnel=(ws,tcp,init)=>{const w=tcp.writable.getWriter(),r=tcp.readable.getReader(),cleanup=()=>{try{r.releaseLock();w.releaseLock();tcp.close()}catch{}};ws.send(new Uint8Array([0,0]));init&&w.write(init);let b=[],t,len=0;ws.onmessage=({data})=>{const chunk=data instanceof ArrayBuffer?new Uint8Array(data):typeof data==='string'?e.encode(data):data;b.push(chunk);len+=chunk.length;t||(t=setTimeout(()=>{if(!len)return;try{if(b.length===1)w.write(b[0]);else{if(len<=8192){O=0;for(const x of b){B.set(x,O);O+=x.length}w.write(B.subarray(0,len))}else{const o=new Uint8Array(len);let pos=0;for(const x of b){o.set(x,pos);pos+=x.length}w.write(o)}}}catch{cleanup()}b=[];len=0;t=null},0))};(async()=>{try{for(;;){const{value,done}=await r.read();if(done)break;ws.send(value)}}catch{}finally{ws.close()}})();ws.onclose=ws.onerror=cleanup}; 10 | const conf=(h,c)=>W||(W=c.P.concat([h+':443']).map(x=>{const[raw,name=c.N2]=x.split('#'),[addr,port=443]=raw.split(':');return`vless://${c.U}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`}).join('\n')); 11 | export default{async fetch(req,env){const c=init();if(req.headers.get('Upgrade')==='websocket'){try{const proto=req.headers.get('sec-websocket-protocol');if(!proto)return new Response('Missing protocol',{status:400});const data=Uint8Array.from(atob(proto.replace(/-/g,'+').replace(/_/g,'/')),c=>c.charCodeAt(0));if(data.length<17||!chk(data))return new Response('无效UUID',{status:403});const{tcpSocket,initialData}=await parseV(data.buffer,c),[client,server]=new WebSocketPair();server.accept();tunnel(server,tcpSocket,initialData);return new Response(null,{status:101,webSocket:client})}catch(e){return new Response('连接失败: '+e.message,{status:502})}}T||(T=req.headers.get('Host'));const p=new URL(req.url).pathname;return p===`/${c.I}`?new Response(`订阅地址: https://${T}/${c.I}/vless`):p===`/${c.I}/vless`?new Response(conf(T,c)):new Response('Hello Worker!')}}; 12 | -------------------------------------------------------------------------------- /testmax_v0.1.js: -------------------------------------------------------------------------------- 1 | import{connect}from'cloudflare:sockets'; 2 | const[d,e,U,C,P,S,A]=[new TextDecoder(),new TextEncoder(),[],{},new Map(),new Set(),new ArrayBuffer(8192)]; 3 | let W,T,B=new Uint8Array(A),O=0; 4 | const g=(k,f,n)=>{const v=import.meta?.env?.[k]??n?.[k];return!v?f:typeof v!=='string'?v:(t=>t==='true'||t!=='false'&&(t[0]==='\n'?t.split('\n').map(x=>x.trim()).filter(Boolean):+t||t))(v.trim())}; 5 | const init=n=>{if(C.done)return C;[['I','ID','123456'],['U','UUID','5aba5b77-48eb-4ae2-b60d-5bfee7ac169e'],['P','IP',['104.16.160.145']],['T','TXT',[]],['R','PROXYIP','sjc.o00o.ooo:443'],['F','启用反代功能',!0],['N','NAT64',!1],['N2','我的节点名字','狂暴']].forEach(([k,k2,d])=>C[k]=g(k2,d,n));const u=C.U.replace(/-/g,'');for(let i=0;i<32;i+=2)U[i>>1]=parseInt(u.substr(i,2),16);return C.done=1,C}; 6 | const chk=a=>{for(let i=0;i<16;i++)if(a[i+1]!==U[i])return!1;return!0}; 7 | const tryConn=async(h,p,c,init)=>{const k=h+':'+p;if(P.has(k)&&!S.has(k))return{...P.get(k),initialData:init};try{const s=await connect({hostname:h,port:p});await s.opened;const r={tcpSocket:s,initialData:init};P.set(k,r);S.delete(k);return r}catch{S.add(k)}if(c.N&&/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h))try{return await tryConn('2001:67c:2960:6464::'+h.split('.').map(x=>(+x).toString(16).padStart(2,'0')).join('').match(/.{4}/g).join(':'),p,{...c,N:0},init)}catch{}if(c.F&&c.R){const[h2,p2]=c.R.split(':');return await tryConn(h2,+p2||p,{...c,F:0},init)}throw Error('连接失败')}; 8 | const parseV=async(buf,c)=>{const a=new Uint8Array(buf),t=a[17],p=(a[18+t+1]<<8)|a[18+t+2];let o=18+t+4,h='';const at=a[o-1];if(at===1){h=a[o]+'.'+a[o+1]+'.'+a[o+2]+'.'+a[o+3];o+=4}else if(at===2){const l=a[o];h=d.decode(a.subarray(o+1,o+1+l));o+=l+1}else if(at===3){h=Array.from({length:8},(_,i)=>((a[o+2*i]<<8)|a[o+2*i+1]).toString(16)).join(':');o+=16}return await tryConn(h,p,c,buf.slice(o))}; 9 | const tunnel=(ws,tcp,init)=>{const w=tcp.writable.getWriter(),r=tcp.readable.getReader(),cleanup=()=>{try{r.releaseLock();w.releaseLock();tcp.close()}catch{}};ws.send(new Uint8Array([0,0]));init&&w.write(init);let b=[],t,len=0;ws.onmessage=({data})=>{const chunk=data instanceof ArrayBuffer?new Uint8Array(data):typeof data==='string'?e.encode(data):data;b.push(chunk);len+=chunk.length;t||(t=setTimeout(()=>{if(!len)return;if(b.length===1)w.write(b[0]);else{if(len<=8192){O=0;for(const x of b){B.set(x,O);O+=x.length}w.write(B.subarray(0,len))}else{const o=new Uint8Array(len);let pos=0;for(const x of b){o.set(x,pos);pos+=x.length}w.write(o)}}b=[];len=0;t=null},0))};(async()=>{try{for(;;){const{value,done}=await r.read();if(done)break;ws.send(value)}}catch{}finally{ws.close()}})();ws.onclose=cleanup}; 10 | const conf=(h,c)=>W||(W=c.P.concat([h+':443']).map(x=>{const[raw,name=c.N2]=x.split('#'),[addr,port=443]=raw.split(':');return`vless://${c.U}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`}).join('\n')); 11 | export default{async fetch(req,env){const c=init(env);if(req.headers.get('Upgrade')==='websocket'){try{const proto=req.headers.get('sec-websocket-protocol');if(!proto)return new Response('Missing protocol',{status:400});const data=Uint8Array.from(atob(proto.replace(/-/g,'+').replace(/_/g,'/')),c=>c.charCodeAt(0));if(!chk(data))return new Response('无效UUID',{status:403});const{tcpSocket,initialData}=await parseV(data.buffer,c),[client,server]=new WebSocketPair();server.accept();tunnel(server,tcpSocket,initialData);return new Response(null,{status:101,webSocket:client})}catch(e){return new Response('连接失败: '+e.message,{status:502})}}T||(T=req.headers.get('Host'));const p=new URL(req.url).pathname;return p===`/${c.I}`?new Response(`订阅地址: https://${T}/${c.I}/vless`):p===`/${c.I}/vless`?new Response(conf(T,c)):new Response('Hello Worker!')}}; 12 | -------------------------------------------------------------------------------- /test_v4.0养老版.js: -------------------------------------------------------------------------------- 1 | import{connect}from'cloudflare:sockets' 2 | const C={sub:'222222',uuid:'36d33e1d-d02c-447f-9472-99cff13b79d2',fallback:'sjc.o00o.ooo',hdrs:{'cache-control':'public,max-age=14400','content-type':'text/plain'}}, 3 | uuidBytes=new Uint8Array(16),decoder=new TextDecoder(),bufferPool=[],urlCache=Object.create(null) 4 | for(let i=0,hex=C.uuid.replace(/-/g,'');i<32;i+=2)uuidBytes[i>>1]=parseInt(hex.substr(i,2),16) 5 | let ERR4,ERR5,redirect,nodeList=['www.visa.cn:443'],stmt,cacheSize=0 6 | const acquireBuffer=len=>{const buf=bufferPool.pop();return buf?.length>=len?buf:new Uint8Array(len)}, 7 | releaseBuffer=buf=>{if(bufferPool.length<8)bufferPool.push(buf)}, 8 | validateProtocol=buf=>{for(let i=16;i--;)if(buf[i+1]!==uuidBytes[i])return false;return true}, 9 | parseTarget=(buf,offset)=>{ 10 | const port=buf[offset]<<8|buf[offset+1],type=buf[offset+2],start=offset+3 11 | if(type&1)return{host:`${buf[start]}.${buf[start+1]}.${buf[start+2]}.${buf[start+3]}`,port,end:start+4} 12 | if(type&4){let addr='[';for(let i=0;i<8;i++)addr+=(i?':':'')+((buf[start+i*2]<<8)|buf[start+i*2+1]).toString(16);return{host:addr+']',port,end:start+16}} 13 | const len=buf[start];return{host:decoder.decode(buf.subarray(start+1,start+1+len)),port,end:start+1+len} 14 | }, 15 | buildVless=(ip,name,host)=>{ 16 | const sepIdx=ip.indexOf('#'),endpoint=sepIdx>-1?ip.substring(0,sepIdx):ip,tag=sepIdx>-1?ip.substring(sepIdx+1):name||'' 17 | let displayIp,port='443' 18 | if(endpoint[0]==='['){const bracket=endpoint.indexOf(']');displayIp=endpoint.substring(0,bracket+1);const match=endpoint.substring(bracket+1).match(/^:(\d+)/);if(match)port=match[1]} 19 | else{const colon=endpoint.indexOf(':');displayIp=colon>-1?endpoint.substring(0,colon):endpoint;if(colon>-1)port=endpoint.substring(colon+1)} 20 | return`vless://${C.uuid}@${displayIp}:${port}?encryption=none&security=tls&type=ws&host=${host}&path=%2F%3Fed%3D2560&sni=${host}#${encodeURIComponent(tag||displayIp.replace(/\./g,'-')+'-'+port)}` 21 | }, 22 | createQueue=()=>{let queue=Promise.resolve();return fn=>queue=queue.then(fn).catch(()=>{})} 23 | export default{ 24 | async fetch(req,env,ctx){ 25 | if(!ERR4){ERR4=new Response(null,{status:400});ERR5=new Response(null,{status:502});redirect=Response.redirect('https://github.com/Meibidi/kuangbao',302)} 26 | let url=urlCache[req.url];if(!url){if(cacheSize>=64){for(const k in urlCache){delete urlCache[k];cacheSize--;break}}url=new URL(req.url);urlCache[req.url]=url;cacheSize++} 27 | const{host,pathname}=url 28 | if(req.headers.get('upgrade')==='websocket'){ 29 | const proto=req.headers.get('sec-websocket-protocol');if(!proto)return ERR4 30 | const bin=atob(proto.replace(/[-_]/g,c=>c<'.'?'+':'/')),len=bin.length,buf=acquireBuffer(len) 31 | for(let i=0;iend){const payload=buf.subarray(end,len);writeQueue(async()=>{const w=socket.writable.getWriter();await w.write(payload);w.releaseLock()})} 38 | releaseBuffer(buf) 39 | server.addEventListener('message',e=>writeQueue(async()=>{const w=socket.writable.getWriter();await w.write(e.data);w.releaseLock()})) 40 | socket.readable.pipeTo(new WritableStream({write(chunk){server.send(chunk)}})).catch(()=>{}) 41 | return new Response(null,{status:101,webSocket:client}) 42 | } 43 | if(pathname===`/${C.sub}/vless`){ 44 | try{stmt??=env.DB.prepare('SELECT ip,name FROM ips WHERE active=1 ORDER BY id ASC');const{results}=await stmt.all();if(results[0])nodeList=results.map(r=>r.ip+(r.name?'#'+r.name:''))}catch{} 45 | return new Response(nodeList.map(ip=>buildVless(ip,'',host)).join('\n'),{headers:C.hdrs}) 46 | } 47 | return pathname===`/${C.sub}`?new Response(`订阅: https://${host}/${C.sub}/vless`,{headers:C.hdrs}):redirect 48 | }} 49 | -------------------------------------------------------------------------------- /test_v0.1.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'cloudflare:sockets'; 2 | const d = new TextDecoder(), e = new TextEncoder(); 3 | let U = null, C = {}; 4 | 5 | const g = (k, f, env) => { 6 | const v = import.meta?.env?.[k] ?? env?.[k]; 7 | if (!v) return f; 8 | if (typeof v !== 'string') return v; 9 | const t = v.trim(); 10 | if (t === 'true') return true; 11 | if (t === 'false') return false; 12 | if (t.includes('\n')) return t.split('\n').map(x => x.trim()).filter(Boolean); 13 | const n = Number(t); 14 | return isNaN(n) ? t : n; 15 | }; 16 | 17 | const init = env => { 18 | if (C.done) return C; 19 | const m = { 20 | I: ['ID', '123456'], 21 | U: ['UUID', '5aba5b77-48eb-4ae2-b60d-5bfee7ac169e'], 22 | P: ['IP', ['1.1.1.1']], 23 | T: ['TXT', []], 24 | R: ['PROXYIP', 'sjc.o00o.ooo:443'], 25 | F: ['启用反代功能', true], 26 | N: ['NAT64', false], 27 | N2: ['我的节点名字', '狂暴'] 28 | }; 29 | for (const [k, [k2, d]] of Object.entries(m)) C[k] = g(k2, d, env); 30 | C.B = U = Uint8Array.from(C.U.replace(/-/g, '').match(/.{2}/g).map(x => parseInt(x, 16))); 31 | return C.done = 1, C; 32 | }; 33 | 34 | const chk = b => U.every((x, i) => b[i] === x); 35 | 36 | const to64 = ip => '2001:67c:2960:6464::' + ip.split('.').map(x => (+x).toString(16).padStart(2, '0')).join('').match(/.{4}/g).join(':'); 37 | 38 | const tryConn = async (h, p, c, init) => { 39 | try { 40 | const s = await connect({ hostname: h, port: p }); 41 | await s.opened; 42 | return { tcpSocket: s, initialData: init }; 43 | } catch {} 44 | if (c.N && /^\d+\.\d+\.\d+\.\d+$/.test(h)) try { 45 | return await tryConn(to64(h), p, { ...c, N: 0 }, init); 46 | } catch {} 47 | if (c.F && c.R) { 48 | const [h2, p2] = c.R.split(':'); 49 | return await tryConn(h2, +p2 || p, { ...c, F: 0 }, init); 50 | } 51 | throw new Error('连接失败'); 52 | }; 53 | 54 | const parseV = async (buf, c) => { 55 | const a = new Uint8Array(buf), t = a[17], p = (a[18 + t + 1] << 8) | a[18 + t + 2]; 56 | let o = 18 + t + 4, h = ''; 57 | switch (a[o - 1]) { 58 | case 1: h = `${a[o++]}.${a[o++]}.${a[o++]}.${a[o++]}`; break; 59 | case 2: { const l = a[o++]; h = d.decode(a.subarray(o, o + l)); o += l; break; } 60 | case 3: h = Array.from({ length: 8 }, (_, i) => ((a[o + 2*i] << 8) | a[o + 2*i + 1]).toString(16)).join(':'); o += 16; 61 | } 62 | return await tryConn(h, p, c, buf.slice(o)); 63 | }; 64 | 65 | const tunnel = (ws, tcp, init) => { 66 | const w = tcp.writable.getWriter(); 67 | ws.send(new Uint8Array([0, 0])); 68 | if (init) w.write(init); 69 | let b = [], t; 70 | ws.addEventListener('message', ({ data }) => { 71 | const c = data instanceof ArrayBuffer ? new Uint8Array(data) : typeof data === 'string' ? e.encode(data) : data; 72 | b.push(c); 73 | if (!t) t = setTimeout(() => { 74 | const total = b.length === 1 ? b[0] : (() => { 75 | const len = b.reduce((s, x) => s + x.length, 0), o = new Uint8Array(len); 76 | let pos = 0; for (const x of b) o.set(x, pos), pos += x.length; 77 | return o; 78 | })(); 79 | w.write(total); b = []; t = null; 80 | }, 5); 81 | }); 82 | 83 | tcp.readable.pipeTo(new WritableStream({ 84 | write: d => ws.send(d), 85 | close: () => ws.close(), 86 | abort: () => ws.close() 87 | })).catch(() => ws.close()); 88 | 89 | ws.addEventListener('close', () => { 90 | try { w.releaseLock(); tcp.close(); } catch {} 91 | }); 92 | }; 93 | 94 | const conf = (h, c) => c.P.concat([`${h}:443`]).map(x => { 95 | const [raw, name = c.N2] = x.split('#'), [addr, port = 443] = raw.split(':'); 96 | return `vless://${c.U}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`; 97 | }).join('\n'); 98 | 99 | export default { 100 | async fetch(req, env) { 101 | const c = init(env), url = new URL(req.url), h = req.headers.get('Host'); 102 | if (req.headers.get('Upgrade') !== 'websocket') { 103 | const path = url.pathname; 104 | if (path === `/${c.I}`) return new Response(`订阅地址: https://${h}/${c.I}/vless`); 105 | if (path === `/${c.I}/vless`) return new Response(conf(h, c)); 106 | return new Response('Hello Worker!'); 107 | } 108 | 109 | try { 110 | const proto = req.headers.get('sec-websocket-protocol'), data = Uint8Array.from(atob(proto.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); 111 | if (!chk(data.subarray(1, 17))) return new Response('无效UUID', { status: 403 }); 112 | const { tcpSocket, initialData } = await parseV(data.buffer, c); 113 | const [client, server] = new WebSocketPair(); server.accept(); 114 | tunnel(server, tcpSocket, initialData); 115 | return new Response(null, { status: 101, webSocket: client }); 116 | } catch (e) { 117 | return new Response('连接失败: ' + e.message, { status: 502 }); 118 | } 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /test_v0.2.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'cloudflare:sockets'; 2 | const d = new TextDecoder(), e = new TextEncoder(); 3 | let U = null, C = {}; 4 | 5 | const g = (k, f, env) => { 6 | const v = import.meta?.env?.[k] ?? env?.[k]; 7 | if (!v) return f; 8 | if (typeof v !== 'string') return v; 9 | const t = v.trim(); 10 | if (t === 'true') return true; 11 | if (t === 'false') return false; 12 | if (t.includes('\n')) return t.split('\n').map(x => x.trim()).filter(Boolean); 13 | const n = Number(t); 14 | return isNaN(n) ? t : n; 15 | }; 16 | 17 | const init = env => { 18 | if (C.done) return C; 19 | const m = { 20 | I: ['ID', '123456'], 21 | U: ['UUID', '5aba5b77-48eb-4ae2-b60d-5bfee7ac169e'], 22 | P: ['IP', ['1.1.1.1']], 23 | T: ['TXT', []], 24 | R: ['PROXYIP', 'sjc.o00o.ooo:443'], 25 | F: ['启用反代功能', true], 26 | N: ['NAT64', false], 27 | N2: ['我的节点名字', '狂暴'] 28 | }; 29 | for (const [k, [k2, d]] of Object.entries(m)) C[k] = g(k2, d, env); 30 | C.B = U = Uint8Array.from(C.U.replace(/-/g, '').match(/.{2}/g).map(x => parseInt(x, 16))); 31 | return C.done = 1, C; 32 | }; 33 | 34 | const chk = b => U.every((x, i) => b[i] === x); 35 | 36 | const to64 = ip => '2001:67c:2960:6464::' + ip.split('.').map(x => (+x).toString(16).padStart(2, '0')).join('').match(/.{4}/g).join(':'); 37 | 38 | const tryConn = async (h, p, c, init) => { 39 | try { 40 | const s = await connect({ hostname: h, port: p }); 41 | await s.opened; 42 | return { tcpSocket: s, initialData: init }; 43 | } catch {} 44 | if (c.N && /^\d+\.\d+\.\d+\.\d+$/.test(h)) try { 45 | return await tryConn(to64(h), p, { ...c, N: 0 }, init); 46 | } catch {} 47 | if (c.F && c.R) { 48 | const [h2, p2] = c.R.split(':'); 49 | return await tryConn(h2, +p2 || p, { ...c, F: 0 }, init); 50 | } 51 | throw new Error('连接失败'); 52 | }; 53 | 54 | const parseV = async (buf, c) => { 55 | const a = new Uint8Array(buf), t = a[17], p = (a[18 + t + 1] << 8) | a[18 + t + 2]; 56 | let o = 18 + t + 4, h = ''; 57 | switch (a[o - 1]) { 58 | case 1: h = `${a[o++]}.${a[o++]}.${a[o++]}.${a[o++]}`; break; 59 | case 2: { const l = a[o++]; h = d.decode(a.subarray(o, o + l)); o += l; break; } 60 | case 3: h = Array.from({ length: 8 }, (_, i) => ((a[o + 2*i] << 8) | a[o + 2*i + 1]).toString(16)).join(':'); o += 16; 61 | } 62 | return await tryConn(h, p, c, buf.slice(o)); 63 | }; 64 | 65 | const tunnel = (ws, tcp, init) => { 66 | const w = tcp.writable.getWriter(); 67 | ws.send(new Uint8Array([0, 0])); 68 | if (init) w.write(init); 69 | let b = [], t, closed = false; 70 | 71 | const cleanup = () => { 72 | if (closed) return; 73 | closed = true; 74 | if (t) clearTimeout(t); 75 | b = null; 76 | try { w.releaseLock(); tcp.close(); } catch {} 77 | }; 78 | 79 | ws.addEventListener('message', ({ data }) => { 80 | if (closed) return; 81 | const c = data instanceof ArrayBuffer ? new Uint8Array(data) : typeof data === 'string' ? e.encode(data) : data; 82 | b.push(c); 83 | if (!t) t = setTimeout(() => { 84 | if (closed) return; 85 | const total = b.length === 1 ? b[0] : (() => { 86 | const len = b.reduce((s, x) => s + x.length, 0), o = new Uint8Array(len); 87 | let pos = 0; for (const x of b) o.set(x, pos), pos += x.length; 88 | return o; 89 | })(); 90 | w.write(total).catch(cleanup); 91 | b.length = 0; t = null; 92 | }, 5); 93 | }); 94 | 95 | tcp.readable.pipeTo(new WritableStream({ 96 | write: d => ws.send(d), 97 | close: cleanup, 98 | abort: cleanup 99 | })).catch(cleanup); 100 | 101 | ws.addEventListener('close', cleanup); 102 | }; 103 | 104 | const conf = (h, c) => c.P.concat([`${h}:443`]).map(x => { 105 | const [raw, name = c.N2] = x.split('#'), [addr, port = 443] = raw.split(':'); 106 | return `vless://${c.U}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`; 107 | }).join('\n'); 108 | 109 | export default { 110 | async fetch(req, env) { 111 | const c = init(env), url = new URL(req.url), h = req.headers.get('Host'); 112 | if (req.headers.get('Upgrade') !== 'websocket') { 113 | const path = url.pathname; 114 | if (path === `/${c.I}`) return new Response(`订阅地址: https://${h}/${c.I}/vless`); 115 | if (path === `/${c.I}/vless`) return new Response(conf(h, c)); 116 | return new Response('Hello Worker!'); 117 | } 118 | 119 | try { 120 | const proto = req.headers.get('sec-websocket-protocol'), data = Uint8Array.from(atob(proto.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); 121 | if (!chk(data.subarray(1, 17))) return new Response('无效UUID', { status: 403 }); 122 | const { tcpSocket, initialData } = await parseV(data.buffer, c); 123 | const [client, server] = new WebSocketPair(); server.accept(); 124 | tunnel(server, tcpSocket, initialData); 125 | return new Response(null, { status: 101, webSocket: client }); 126 | } catch (e) { 127 | return new Response('连接失败: ' + e.message, { status: 502 }); 128 | } 129 | } 130 | }; 131 | -------------------------------------------------------------------------------- /_worker.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'cloudflare:sockets'; 2 | const d = new TextDecoder(), e = new TextEncoder(); 3 | let U = null, C = {}; 4 | 5 | const g = (n, f, env) => { 6 | const v = import.meta?.env?.[n] ?? env?.[n]; 7 | if (!v) return f; 8 | if (typeof v !== 'string') return v; 9 | const t = v.trim(); 10 | if (t === 'true') return true; 11 | if (t === 'false') return false; 12 | if (t.includes('\n')) return t.split('\n').map(x => x.trim()).filter(Boolean); 13 | const num = Number(t); 14 | return isNaN(num) ? t : num; 15 | }; 16 | 17 | const b16 = s => Uint8Array.from(s.replace(/-/g, '').match(/.{2}/g).map(x => parseInt(x, 16))); 18 | 19 | const init = env => { 20 | if (C.done) return C; 21 | const m = { 22 | I: ['ID', '123456'], 23 | U: ['UUID', '5aba5b77-48eb-4ae2-b60d-5bfee7ac169e'], 24 | P: ['IP', ['1.1.1.1']], 25 | T: ['TXT', []], 26 | R: ['PROXYIP', 'sjc.o00o.ooo:443'], 27 | F: ['启用反代功能', true], 28 | N: ['NAT64', false], 29 | N2: ['我的节点名字', '狂暴'] 30 | }; 31 | for (const [k, [k2, d]] of Object.entries(m)) C[k] = g(k2, d, env); 32 | C.B = U = b16(C.U); 33 | C.done = 1; 34 | return C; 35 | }; 36 | 37 | const chk = b => U.every((x, i) => b[i] === x); 38 | 39 | const to64 = ip => '2001:67c:2960:6464::' + ip.split('.').map(x => (+x).toString(16).padStart(2, '0')).join('').match(/.{4}/g).join(':'); 40 | 41 | const dns6 = async d => { 42 | const r = await fetch(`https://1.1.1.1/dns-query?name=${d}&type=A`, { headers: { Accept: 'application/dns-json' } }); 43 | const j = await r.json(), ip = j.Answer?.find(x => x.type === 1)?.data; 44 | return ip ? to64(ip) : null; 45 | }; 46 | 47 | const base64 = s => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)).buffer; 48 | 49 | const tryConn = async (h, p, cfg, init) => { 50 | try { 51 | const s = await connect({ hostname: h, port: p }); 52 | await s.opened; 53 | return { tcpSocket: s, initialData: init }; 54 | } catch {} 55 | 56 | if (cfg.N && /^\d+\.\d+\.\d+\.\d+$/.test(h)) { 57 | try { 58 | return await tryConn(to64(h), p, { ...cfg, N: 0 }, init); 59 | } catch {} 60 | } 61 | 62 | if (cfg.F && cfg.R) { 63 | const [h2, p2] = cfg.R.split(':'); 64 | return await tryConn(h2, Number(p2 || p), { ...cfg, F: 0 }, init); 65 | } 66 | 67 | throw new Error('连接失败'); 68 | }; 69 | 70 | const parseVless = async (buf, cfg) => { 71 | const c = new Uint8Array(buf), t = c[17], p = (c[18 + t + 1] << 8) | c[18 + t + 2]; 72 | let o = 18 + t + 4, h = ''; 73 | switch (c[o - 1]) { 74 | case 1: h = `${c[o++]}.${c[o++]}.${c[o++]}.${c[o++]}`; break; 75 | case 2: { const l = c[o++]; h = d.decode(c.subarray(o, o + l)); o += l; break; } 76 | case 3: h = Array.from({ length: 8 }, (_, i) => ((c[o + 2*i] << 8) | c[o + 2*i + 1]).toString(16)).join(':'); o += 16; break; 77 | } 78 | return await tryConn(h, p, cfg, buf.slice(o)); 79 | }; 80 | 81 | const tunnel = (ws, tcp, init) => { 82 | const w = tcp.writable.getWriter(); 83 | ws.send(new Uint8Array([0, 0])); 84 | if (init) w.write(init); 85 | let b = [], t; 86 | ws.addEventListener('message', ({ data }) => { 87 | const c = data instanceof ArrayBuffer ? new Uint8Array(data) 88 | : typeof data === 'string' ? e.encode(data) 89 | : data; 90 | b.push(c); 91 | if (!t) t = setTimeout(() => { 92 | w.write(b.length === 1 ? b[0] : b.reduce((a, b) => { 93 | const o = new Uint8Array(a.length + b.length); 94 | o.set(a); o.set(b, a.length); return o; 95 | })); 96 | b = []; t = null; 97 | }, 5); 98 | }); 99 | 100 | tcp.readable.pipeTo(new WritableStream({ 101 | write: c => ws.send(c), 102 | close: () => ws.close(), 103 | abort: () => ws.close() 104 | })).catch(() => ws.close()); 105 | 106 | ws.addEventListener('close', () => { 107 | try { w.releaseLock(); tcp.close(); } catch {} 108 | }); 109 | }; 110 | 111 | const genConf = (h, cfg) => 112 | cfg.P.concat([`${h}:443`]).map(x => { 113 | const [raw, name = cfg.N2] = x.split('#'); 114 | const [addr, port = 443] = raw.split(':'); 115 | return `vless://${cfg.U}@${addr}:${port}?encryption=none&security=tls&type=ws&host=${h}&sni=${h}&path=%2F%3Fed%3D2560#${name}`; 116 | }).join('\n'); 117 | 118 | export default { 119 | async fetch(req, env) { 120 | const cfg = init(env), url = new URL(req.url); 121 | const up = req.headers.get('Upgrade'), proto = req.headers.get('sec-websocket-protocol'); 122 | const host = req.headers.get('Host'); 123 | 124 | if (up !== 'websocket') { 125 | if (url.pathname === `/${cfg.I}`) 126 | return new Response(`订阅地址: https://${host}/${cfg.I}/vless`, { status: 200 }); 127 | if (url.pathname === `/${cfg.I}/vless`) 128 | return new Response(genConf(host, cfg), { status: 200 }); 129 | return new Response('Hello Worker!', { status: 200 }); 130 | } 131 | 132 | try { 133 | const d = base64(proto), id = new Uint8Array(d, 1, 16); 134 | if (!chk(id)) return new Response('无效UUID', { status: 403 }); 135 | 136 | const { tcpSocket, initialData } = await parseVless(d, cfg); 137 | const [client, server] = new WebSocketPair(); 138 | server.accept(); tunnel(server, tcpSocket, initialData); 139 | return new Response(null, { status: 101, webSocket: client }); 140 | 141 | } catch (e) { 142 | return new Response(`连接失败: ${e.message}`, { status: 502 }); 143 | } 144 | } 145 | }; 146 | --------------------------------------------------------------------------------