Enhance local provider URL detection for IPv6 and loopback ranges
This commit is contained in:
@@ -6,6 +6,10 @@ test('treats localhost endpoints as local', () => {
|
|||||||
expect(isLocalProviderUrl('http://localhost:11434/v1')).toBe(true)
|
expect(isLocalProviderUrl('http://localhost:11434/v1')).toBe(true)
|
||||||
expect(isLocalProviderUrl('http://127.0.0.1:11434/v1')).toBe(true)
|
expect(isLocalProviderUrl('http://127.0.0.1:11434/v1')).toBe(true)
|
||||||
expect(isLocalProviderUrl('http://0.0.0.0:11434/v1')).toBe(true)
|
expect(isLocalProviderUrl('http://0.0.0.0:11434/v1')).toBe(true)
|
||||||
|
// Full 127.0.0.0/8 loopback range should be treated as local
|
||||||
|
expect(isLocalProviderUrl('http://127.0.0.2:11434/v1')).toBe(true)
|
||||||
|
expect(isLocalProviderUrl('http://127.1.2.3:11434/v1')).toBe(true)
|
||||||
|
expect(isLocalProviderUrl('http://127.255.255.255:11434/v1')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('treats private IPv4 endpoints as local', () => {
|
test('treats private IPv4 endpoints as local', () => {
|
||||||
@@ -18,7 +22,14 @@ test('treats .local hostnames as local', () => {
|
|||||||
expect(isLocalProviderUrl('http://ollama.local:11434/v1')).toBe(true)
|
expect(isLocalProviderUrl('http://ollama.local:11434/v1')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('treats private IPv6 endpoints as local', () => {
|
||||||
|
expect(isLocalProviderUrl('http://[fd00::1]:11434/v1')).toBe(true)
|
||||||
|
expect(isLocalProviderUrl('http://[fe80::1]:11434/v1')).toBe(true)
|
||||||
|
expect(isLocalProviderUrl('http://[::1]:11434/v1')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
test('treats public hosts as remote', () => {
|
test('treats public hosts as remote', () => {
|
||||||
expect(isLocalProviderUrl('http://203.0.113.1:11434/v1')).toBe(false)
|
expect(isLocalProviderUrl('http://203.0.113.1:11434/v1')).toBe(false)
|
||||||
expect(isLocalProviderUrl('https://example.com/v1')).toBe(false)
|
expect(isLocalProviderUrl('https://example.com/v1')).toBe(false)
|
||||||
|
expect(isLocalProviderUrl('http://[2001:4860:4860::8888]:11434/v1')).toBe(false)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -210,7 +210,19 @@ function isCodexAlias(model: string): boolean {
|
|||||||
export function isLocalProviderUrl(baseUrl: string | undefined): boolean {
|
export function isLocalProviderUrl(baseUrl: string | undefined): boolean {
|
||||||
if (!baseUrl) return false
|
if (!baseUrl) return false
|
||||||
try {
|
try {
|
||||||
const hostname = new URL(baseUrl).hostname.toLowerCase()
|
let hostname = new URL(baseUrl).hostname.toLowerCase()
|
||||||
|
|
||||||
|
// Strip IPv6 brackets added by the URL parser (e.g. "[::1]" -> "::1")
|
||||||
|
if (hostname.startsWith('[') && hostname.endsWith(']')) {
|
||||||
|
hostname = hostname.slice(1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip RFC6874 IPv6 zone identifiers (e.g. "fe80::1%25en0" -> "fe80::1")
|
||||||
|
const zoneIdIndex = hostname.indexOf('%25')
|
||||||
|
if (zoneIdIndex !== -1) {
|
||||||
|
hostname = hostname.slice(0, zoneIdIndex)
|
||||||
|
}
|
||||||
|
|
||||||
if (LOCALHOST_HOSTNAMES.has(hostname) || hostname === '0.0.0.0') {
|
if (LOCALHOST_HOSTNAMES.has(hostname) || hostname === '0.0.0.0') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -220,7 +232,9 @@ export function isLocalProviderUrl(baseUrl: string | undefined): boolean {
|
|||||||
|
|
||||||
const ipVersion = isIP(hostname)
|
const ipVersion = isIP(hostname)
|
||||||
if (ipVersion === 4) {
|
if (ipVersion === 4) {
|
||||||
return isPrivateIpv4Address(hostname)
|
// Treat the full 127.0.0.0/8 loopback range as local
|
||||||
|
const firstOctet = Number.parseInt(hostname.split('.', 1)[0] ?? '', 10)
|
||||||
|
return firstOctet === 127 || isPrivateIpv4Address(hostname)
|
||||||
}
|
}
|
||||||
if (ipVersion === 6) {
|
if (ipVersion === 6) {
|
||||||
return isPrivateIpv6Address(hostname)
|
return isPrivateIpv6Address(hostname)
|
||||||
|
|||||||
Reference in New Issue
Block a user