@@ -78,7 +78,7 @@ let fakeHostName;
7878let subProtocol = 'https' ;
7979let subConverter = atob ( 'dXJsLnYxLm1r' ) ; // Subscription conversion backend using Sheep's function
8080let subConfig = atob ( 'aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2FtY2x1YnMvQUNMNFNTUi9tYWluL0NsYXNoL2NvbmZpZy9BQ0w0U1NSX09ubGluZV9GdWxsX011bHRpTW9kZS5pbmk=' ) ; // Subscription profile
81- let fileName = atob ( '5pWw5a2X5aWX5Yip' ) ;
81+ let fileName = atob ( '5pWw5a2X5aWX5Yip' ) ;
8282let isBase64 = true ;
8383
8484let botToken = '' ;
@@ -97,9 +97,14 @@ let nat64Domain = [
9797 // 'twitch.tv'
9898] ;
9999let nat64 = false ;
100+ let nat64Prefix ;
101+ let nat64Prefixs = [
102+ '2602:fc59:b0:64::'
103+ ] ;
104+
100105let hostRemark = false ;
101106
102- const ENABLE_LOG = true ;
107+ const ENABLE_LOG = true ;
103108
104109if ( ! isValidUUID ( userID ) ) {
105110 throw new Error ( 'uuid is invalid' ) ;
@@ -138,6 +143,7 @@ export default {
138143 ADDRESSESAPI ,
139144 NAT64 ,
140145 NAT64_DOM_URL_TXT ,
146+ NAT64_PREFIX ,
141147 HOST_REAMRK ,
142148 } = env ;
143149 const kvCheckResponse = await checkKVNamespaceBinding ( env ) ;
@@ -249,6 +255,23 @@ export default {
249255 let proxyDomainAll = await getIpUrlTxtAndCsv ( noTLS , proxyDomainTxt , null ) ;
250256 proxyDomain = [ ...new Set ( [ ...proxyDomainAll . txt ] ) ] ;
251257 }
258+ nat64Prefix = url . searchParams . get ( 'NAT64_PREFIX' ) || NAT64_PREFIX ;
259+ if ( NAT64_PREFIX ) {
260+ if ( httpPattern . test ( NAT64_PREFIX ) ) {
261+ let proxyIpTxt = await addIpText ( NAT64_PREFIX ) ;
262+ let ipUrlTxtAndCsv ;
263+ if ( NAT64_PREFIX . endsWith ( '.csv' ) ) {
264+ ipUrlTxtAndCsv = await getIpUrlTxtAndCsv ( noTLS , null , proxyIpTxt ) ;
265+ } else {
266+ ipUrlTxtAndCsv = await getIpUrlTxtAndCsv ( noTLS , proxyIpTxt , null ) ;
267+ }
268+ const uniqueIpTxt = [ ...new Set ( [ ...ipUrlTxtAndCsv . txt , ...ipUrlTxtAndCsv . csv ] ) ] ;
269+ nat64Prefix = uniqueIpTxt [ Math . floor ( Math . random ( ) * uniqueIpTxt . length ) ] ;
270+ } else {
271+ nat64Prefixs = await addIpText ( NAT64_PREFIX ) ;
272+ nat64Prefix = nat64Prefixs [ Math . floor ( Math . random ( ) * nat64Prefixs . length ) ] ;
273+ }
274+ }
252275
253276 // Unified protocol for handling subconverters
254277 const [ subProtocol , subConverterWithoutProtocol ] = ( subConverter . startsWith ( "http://" ) || subConverter . startsWith ( "https://" ) )
@@ -410,11 +433,11 @@ async function resolveProxyIP(PROXYIP, noTLS, proxyIpTxt, fallbackIPs = []) {
410433/** ---------------------Tools------------------------------ */
411434
412435function log ( ...args ) {
413- if ( ENABLE_LOG ) console . log ( ...args ) ;
436+ if ( ENABLE_LOG ) console . log ( ...args ) ;
414437}
415438
416439function error ( ...args ) {
417- if ( ENABLE_LOG ) console . error ( ...args ) ;
440+ if ( ENABLE_LOG ) console . error ( ...args ) ;
418441}
419442
420443export async function hashHex_f ( string ) {
@@ -1124,86 +1147,86 @@ function getRandomItems(arr, count) {
11241147} ) ( ) ;
11251148
11261149async function resolveDomainToNAT64IPv6 ( domain ) {
1127- try {
1128- log ( `[DNS] Starting domain resolution: ${ domain } ` ) ;
1150+ try {
1151+ log ( `[DNS] Starting domain resolution: ${ domain } ` ) ;
11291152
1130- const response = await fetch ( `${ dnsResolver } ?name=${ domain } &type=A` , {
1131- headers : {
1132- Accept : "application/dns-json" ,
1133- } ,
1134- } ) ;
1153+ const response = await fetch ( `${ dnsResolver } ?name=${ domain } &type=A` , {
1154+ headers : {
1155+ Accept : "application/dns-json" ,
1156+ } ,
1157+ } ) ;
11351158
1136- if ( ! response . ok ) {
1137- throw new Error ( `DNS request failed with status code: ${ response . status } ` ) ;
1138- }
1159+ if ( ! response . ok ) {
1160+ throw new Error ( `DNS request failed with status code: ${ response . status } ` ) ;
1161+ }
11391162
1140- const result = await response . json ( ) ;
1141- log ( `[DNS] Query result: ${ JSON . stringify ( result , null , 2 ) } ` ) ;
1163+ const result = await response . json ( ) ;
1164+ log ( `[DNS] Query result: ${ JSON . stringify ( result , null , 2 ) } ` ) ;
11421165
1143- const aRecord = result ?. Answer ?. find ( record => record . type === 1 && record . data ) ;
1144- if ( ! aRecord ) {
1145- throw new Error ( "No valid A record found" ) ;
1146- }
1166+ const aRecord = result ?. Answer ?. find ( record => record . type === 1 && record . data ) ;
1167+ if ( ! aRecord ) {
1168+ throw new Error ( "No valid A record found" ) ;
1169+ }
11471170
1148- const ipv4 = aRecord . data ;
1149- log ( `[DNS] Found IPv4 address: ${ ipv4 } ` ) ;
1171+ const ipv4 = aRecord . data ;
1172+ log ( `[DNS] Found IPv4 address: ${ ipv4 } ` ) ;
11501173
1151- const ipv6 = convertIPv4ToNAT64IPv6 ( ipv4 ) ;
1152- log ( `[NAT64] Converted IPv6 address: ${ ipv6 } ` ) ;
1174+ const ipv6 = convertIPv4ToNAT64IPv6 ( ipv4 ) ;
1175+ log ( `[NAT64] Converted IPv6 address: ${ ipv6 } ` ) ;
11531176
1154- return ipv6 ;
1177+ return ipv6 ;
11551178
1156- } catch ( err ) {
1157- error ( `[Error] Failed to get NAT64 address: ${ err . message } ` ) ;
1158- throw new Error ( `DNS resolution failed: ${ err . message } ` ) ;
1159- }
1179+ } catch ( err ) {
1180+ error ( `[Error] Failed to get NAT64 address: ${ err . message } ` ) ;
1181+ throw new Error ( `DNS resolution failed: ${ err . message } ` ) ;
1182+ }
11601183}
11611184
11621185function convertIPv4ToNAT64IPv6 ( ipv4Address , options = { } ) {
1163- const {
1164- prefixType = 'custom' , // Options: 'standard', 'custom', 'private', 'random', 'manual'
1165- withBrackets = true ,
1166- prefix = '' // Used only when prefixType is 'manual'
1167- } = options ;
1168-
1169- // Validate and parse IPv4 address
1170- const parts = ipv4Address . trim ( ) . split ( '.' ) ;
1171- if ( parts . length !== 4 ) throw new Error ( 'Invalid IPv4 address' ) ;
1172- const hexParts = parts . map ( part => {
1173- const num = Number ( part ) ;
1174- if ( ! / ^ \d + $ / . test ( part ) || isNaN ( num ) || num < 0 || num > 255 ) {
1175- throw new Error ( `Invalid IPv4 segment: ${ part } ` ) ;
1176- }
1177- return num . toString ( 16 ) . padStart ( 2 , '0' ) ;
1178- } ) ;
1179-
1180- // Built-in NAT64 prefixes
1181- const predefinedPrefixes = {
1182- standard : [ '64:ff9b::' ] ,
1183- custom : [ '2001:67c:2960:6464 ::' ] ,
1184- private : [ 'fd00:abcd::' , 'fd00:1234::' ] ,
1185- random : [ '64:ff9b::' , '2001:67c:2960:6464::' , 'fd00:abcd::' ]
1186- } ;
1187-
1188- // Select prefix
1189- let selectedPrefix ;
1190- if ( prefixType === 'manual' ) {
1191- if ( ! prefix || typeof prefix !== 'string' || ! prefix . includes ( '::' ) ) {
1192- throw new Error ( 'Invalid manual prefix; must be a valid IPv6 prefix' ) ;
1193- }
1194- selectedPrefix = prefix ;
1195- } else if ( predefinedPrefixes [ prefixType ] ) {
1196- const prefixList = predefinedPrefixes [ prefixType ] ;
1197- selectedPrefix = prefixList [ Math . floor ( Math . random ( ) * prefixList . length ) ] ;
1198- } else {
1199- throw new Error ( `Unsupported prefixType: ${ prefixType } ` ) ;
1200- }
1201-
1202- // Construct IPv6 suffix
1203- const ipv6Tail = `${ hexParts [ 0 ] } ${ hexParts [ 1 ] } :${ hexParts [ 2 ] } ${ hexParts [ 3 ] } ` . toLowerCase ( ) ;
1204- const fullIPv6 = `${ selectedPrefix } ${ ipv6Tail } ` ;
1205-
1206- return withBrackets ? `[${ fullIPv6 } ]` : fullIPv6 ;
1186+ const {
1187+ prefixType = nat64Prefix ? 'manual' : 'custom' , // Options: 'standard', 'custom', 'private', 'random', 'manual'
1188+ prefix = nat64Prefix || '' , // Used only when prefixType is 'manual'
1189+ withBrackets = true
1190+ } = options ;
1191+
1192+ // Validate and parse IPv4 address
1193+ const parts = ipv4Address . trim ( ) . split ( '.' ) ;
1194+ if ( parts . length !== 4 ) throw new Error ( 'Invalid IPv4 address' ) ;
1195+ const hexParts = parts . map ( part => {
1196+ const num = Number ( part ) ;
1197+ if ( ! / ^ \d + $ / . test ( part ) || isNaN ( num ) || num < 0 || num > 255 ) {
1198+ throw new Error ( `Invalid IPv4 segment: ${ part } ` ) ;
1199+ }
1200+ return num . toString ( 16 ) . padStart ( 2 , '0' ) ;
1201+ } ) ;
1202+
1203+ // Built-in NAT64 prefixes
1204+ const predefinedPrefixes = {
1205+ standard : [ '64:ff9b::' ] ,
1206+ custom : [ '2602:fc59:b0:64 ::' ] ,
1207+ private : [ 'fd00:abcd::' , 'fd00:1234::' ] ,
1208+ random : [ '64:ff9b::' , '2001:67c:2960:6464::' , 'fd00:abcd::' ]
1209+ } ;
1210+
1211+ // Select prefix
1212+ let selectedPrefix ;
1213+ if ( prefixType === 'manual' ) {
1214+ if ( ! prefix || typeof prefix !== 'string' || ! prefix . includes ( '::' ) ) {
1215+ throw new Error ( 'Invalid manual prefix; must be a valid IPv6 prefix' ) ;
1216+ }
1217+ selectedPrefix = prefix ;
1218+ } else if ( predefinedPrefixes [ prefixType ] ) {
1219+ const prefixList = predefinedPrefixes [ prefixType ] ;
1220+ selectedPrefix = prefixList [ Math . floor ( Math . random ( ) * prefixList . length ) ] ;
1221+ } else {
1222+ throw new Error ( `Unsupported prefixType: ${ prefixType } ` ) ;
1223+ }
1224+
1225+ // Construct IPv6 suffix
1226+ const ipv6Tail = `${ hexParts [ 0 ] } ${ hexParts [ 1 ] } :${ hexParts [ 2 ] } ${ hexParts [ 3 ] } ` . toLowerCase ( ) ;
1227+ const fullIPv6 = `${ selectedPrefix } ${ ipv6Tail } ` ;
1228+
1229+ return withBrackets ? `[${ fullIPv6 } ]` : fullIPv6 ;
12071230}
12081231
12091232/**
@@ -1218,33 +1241,33 @@ function convertIPv4ToNAT64IPv6(ipv4Address, options = {}) {
12181241 * @returns {boolean } Whether the hostname matches the pattern
12191242 */
12201243function matchesDomainPattern ( hostname , pattern ) {
1221- if ( ! hostname || ! pattern ) return false ;
1244+ if ( ! hostname || ! pattern ) return false ;
12221245
1223- // Normalize to lowercase; domain names are case-insensitive
1224- hostname = hostname . toLowerCase ( ) ;
1225- pattern = pattern . toLowerCase ( ) ;
1246+ // Normalize to lowercase; domain names are case-insensitive
1247+ hostname = hostname . toLowerCase ( ) ;
1248+ pattern = pattern . toLowerCase ( ) ;
12261249
1227- // Exclude IP addresses (both IPv4 and IPv6)
1228- // IPv4: consists of digits and dots; IPv6: contains colons and may be wrapped in brackets
1229- const ipv4Regex = / ^ ( \d { 1 , 3 } \. ) { 3 } \d { 1 , 3 } $ / ;
1230- const ipv6Regex = / ^ \[ ? ( [ a - f 0 - 9 : ] + ) \] ? $ / i;
1231- if ( ipv4Regex . test ( hostname ) || ipv6Regex . test ( hostname ) ) {
1232- return false ;
1233- }
1250+ // Exclude IP addresses (both IPv4 and IPv6)
1251+ // IPv4: consists of digits and dots; IPv6: contains colons and may be wrapped in brackets
1252+ const ipv4Regex = / ^ ( \d { 1 , 3 } \. ) { 3 } \d { 1 , 3 } $ / ;
1253+ const ipv6Regex = / ^ \[ ? ( [ a - f 0 - 9 : ] + ) \] ? $ / i;
1254+ if ( ipv4Regex . test ( hostname ) || ipv6Regex . test ( hostname ) ) {
1255+ return false ;
1256+ }
12341257
1235- const hostParts = hostname . split ( '.' ) ;
1236- const patternParts = pattern . split ( '.' ) ;
1258+ const hostParts = hostname . split ( '.' ) ;
1259+ const patternParts = pattern . split ( '.' ) ;
12371260
1238- if ( hostParts . length < patternParts . length ) return false ;
1261+ if ( hostParts . length < patternParts . length ) return false ;
12391262
1240- // Match segments from right to left; all corresponding segments must match
1241- for ( let i = 1 ; i <= patternParts . length ; i ++ ) {
1242- if ( hostParts [ hostParts . length - i ] !== patternParts [ patternParts . length - i ] ) {
1243- return false ;
1244- }
1245- }
1263+ // Match segments from right to left; all corresponding segments must match
1264+ for ( let i = 1 ; i <= patternParts . length ; i ++ ) {
1265+ if ( hostParts [ hostParts . length - i ] !== patternParts [ patternParts . length - i ] ) {
1266+ return false ;
1267+ }
1268+ }
12461269
1247- return true ;
1270+ return true ;
12481271}
12491272
12501273/**
@@ -1261,17 +1284,17 @@ async function resolveNAT64IfNeeded(address, addressRemote, port, nat64, forceNA
12611284 log ( `resolveNAT64IfNeeded: address = ${ address } , addressRemote = ${ addressRemote } , port = ${ port } , nat64 = ${ nat64 } ` ) ;
12621285 log ( `resolveNAT64IfNeeded: proxyDomain = ${ proxyDomain } , nat64Domain = ${ nat64Domain } ` ) ;
12631286
1264- if ( proxyDomain . some ( domain => matchesDomainPattern ( address , domain ) ) ) {
1287+ if ( proxyDomain . some ( domain => matchesDomainPattern ( address , domain ) ) ) {
12651288 log ( `resolveNAT64IfNeeded: proxyIP = ${ proxyIP } ` ) ;
12661289 return proxyIP ;
12671290 }
12681291
12691292 const shouldUseNAT64 = nat64 && ( forceNAT64 || nat64Domain . some ( domain => matchesDomainPattern ( address , domain ) ) ) ;
12701293 if ( shouldUseNAT64 ) {
1271- const nat64IP = await resolveDomainToNAT64IPv6 ( addressRemote ) ;
1272- log ( `resolveNAT64IfNeeded Using NAT64 IPv6: nat64IP = ${ nat64IP } ` ) ;
1273- return nat64IP ;
1274- }
1294+ const nat64IP = await resolveDomainToNAT64IPv6 ( addressRemote ) ;
1295+ log ( `resolveNAT64IfNeeded Using NAT64 IPv6: nat64IP = ${ nat64IP } ` ) ;
1296+ return nat64IP ;
1297+ }
12751298
12761299 return address ;
12771300}
@@ -1862,7 +1885,7 @@ function splitNodeData(uniqueIpTxt, noTLS, host, uuid, userAgent, protType, nat6
18621885 if ( match && ! ipTxt . includes ( '@am_clubs' ) ) {
18631886 address = match [ 1 ] ;
18641887 port = match [ 2 ] || port ;
1865- remarks = hostRemark ? host : ( match [ 3 ] || address || host ) ;
1888+ remarks = hostRemark ? host : ( match [ 3 ] || address || host ) ;
18661889 proxyip = match [ 4 ] || '' ;
18671890 // console.log(`splitNodeData--match-> \n address: ${address} \n port: ${port} \n remarks: ${remarks} \n proxyip: ${proxyip}`);
18681891 } else {
@@ -1886,7 +1909,7 @@ function splitNodeData(uniqueIpTxt, noTLS, host, uuid, userAgent, protType, nat6
18861909
18871910 address = ip ;
18881911 port = newPort || port ;
1889- remarks = hostRemark ? host : ( extra || address || host ) ;
1912+ remarks = hostRemark ? host : ( extra || address || host ) ;
18901913 // console.log(`splitNodeData---> \n address: ${address} \n port: ${port} \n remarks: ${remarks} \n proxyip: ${proxyip}`);
18911914 }
18921915
@@ -2422,7 +2445,7 @@ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawCli
24222445 */
24232446 async function connectAndWrite ( address , port , socks = false ) {
24242447 //
2425- address = await resolveNAT64IfNeeded ( address , addressRemote , port , nat64 ) ;
2448+ address = await resolveNAT64IfNeeded ( address , addressRemote , port , nat64 ) ;
24262449
24272450 /** @type {import("@cloudflare/workers-types").Socket } */
24282451 const tcpSocket = socks ? await socks5Connect ( addressType , address , port , log )
@@ -2444,12 +2467,12 @@ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawCli
24442467 */
24452468 async function retry ( ) {
24462469 //
2447- const resolvedTarget = await resolveNAT64IfNeeded ( proxyIP , addressRemote , portRemote , nat64 , true ) ;
2470+ const resolvedTarget = await resolveNAT64IfNeeded ( proxyIP , addressRemote , portRemote , nat64 , true ) ;
24482471 const finalTargetHost = resolvedTarget || addressRemote ;
24492472 const finalTargetPort = proxyPort || portRemote ;
24502473
2451- const tcpSocket = socks5Enable
2452- ? await connectAndWrite ( addressRemote , portRemote , true )
2474+ const tcpSocket = socks5Enable
2475+ ? await connectAndWrite ( addressRemote , portRemote , true )
24532476 : await connectAndWrite ( finalTargetHost , finalTargetPort ) ;
24542477
24552478 log ( `retry-${ socks5Enable } connected to ${ addressRemote } :${ portRemote } ` ) ;
@@ -3079,4 +3102,4 @@ async function nginx() {
30793102 </html>
30803103 `
30813104 return text ;
3082- }
3105+ }
0 commit comments