48 lines
2.5 KiB
JavaScript
48 lines
2.5 KiB
JavaScript
import { isIP } from 'node:net'
|
|
import { matchesProxyRules, normalizeProxyRules } from './rules.mjs'
|
|
import { outboundProxyScopeEnabled } from '../../../../platform/lib/outbound-proxy.mjs'
|
|
|
|
const PLATFORM_RULES = normalizeProxyRules(['localhost', '127.0.0.1', '::1'], { label: 'platform NO_PROXY' })
|
|
|
|
function route(mode, reason, snapshot, fields = {}) {
|
|
return Object.freeze({ mode, reason, revision: snapshot.revision, ...fields })
|
|
}
|
|
|
|
export async function selectProxyRoute({ snapshot, scope, providerId, host, port, dnsCache, signal }) {
|
|
const configuration = snapshot.configuration
|
|
const userNoProxy = normalizeProxyRules(configuration.noProxy.user, {
|
|
allowWildcard: true,
|
|
label: 'NO_PROXY',
|
|
})
|
|
const bypass = normalizeProxyRules(configuration.bypass.additional, {
|
|
allowCidr: true,
|
|
label: 'proxy bypass',
|
|
})
|
|
const bypassHosts = bypass.filter(rule => rule.type !== 'cidr')
|
|
const bypassCidrs = bypass.filter(rule => rule.type === 'cidr')
|
|
if (matchesProxyRules(PLATFORM_RULES, host, port)) return route('direct', 'platform-forced-direct', snapshot)
|
|
if (matchesProxyRules(userNoProxy, host, port)) return route('direct', 'no-proxy', snapshot)
|
|
if (matchesProxyRules(bypassHosts, host, port)) return route('direct', 'bypass', snapshot)
|
|
if (isIP(host) !== 0 && matchesProxyRules(bypassCidrs, host, port)) return route('direct', 'bypass', snapshot)
|
|
if (!outboundProxyScopeEnabled(configuration, scope, providerId)) {
|
|
return route('direct', scope === 'modelApi' ? 'provider-direct' : 'scope-direct', snapshot)
|
|
}
|
|
const endpoint = Object.freeze({
|
|
host: configuration.proxy.host,
|
|
port: configuration.proxy.port,
|
|
remoteDns: configuration.proxy.remoteDns,
|
|
username: snapshot.credentials.username,
|
|
password: snapshot.credentials.password,
|
|
})
|
|
if (configuration.proxy.protocol !== 'socks5' || configuration.proxy.remoteDns || isIP(host) !== 0) {
|
|
const reason = scope === 'modelApi' ? 'provider-proxy' : 'scope-proxy'
|
|
return route(configuration.proxy.protocol, reason, snapshot, { endpoint })
|
|
}
|
|
if (dnsCache === undefined) throw new TypeError('SOCKS5 local DNS requires a ProxyDnsCache')
|
|
const targets = await dnsCache.resolve(host, snapshot.revision, { signal })
|
|
const directTargets = targets.filter(target => matchesProxyRules(bypassCidrs, target.address, port))
|
|
if (directTargets.length > 0) return route('direct', 'bypass-cidr', snapshot, { targets: Object.freeze(directTargets) })
|
|
const reason = scope === 'modelApi' ? 'provider-proxy' : 'scope-proxy'
|
|
return route('socks5', reason, snapshot, { endpoint, targets })
|
|
}
|