diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-07-25 16:28:53 -0400 |
|---|---|---|
| committer | dakkar <dakkar@thenautilus.net> | 2025-07-27 19:39:20 +0100 |
| commit | 25622b536c982f717c72b0cf039322d45c36a55b (patch) | |
| tree | 440624975f32e96f9922c49cabe443a0f800d8e6 /packages/backend/src | |
| parent | allow HTTP connections to private IPs (diff) | |
| download | sharkey-25622b536c982f717c72b0cf039322d45c36a55b.tar.gz sharkey-25622b536c982f717c72b0cf039322d45c36a55b.tar.bz2 sharkey-25622b536c982f717c72b0cf039322d45c36a55b.zip | |
resolve domain names when checking for private URLs
Diffstat (limited to 'packages/backend/src')
| -rw-r--r-- | packages/backend/src/core/HttpRequestService.ts | 30 | ||||
| -rw-r--r-- | packages/backend/src/core/activitypub/models/ApPersonService.ts | 1 |
2 files changed, 22 insertions, 9 deletions
diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index bbc127fa86..34aaada9f2 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -27,16 +27,27 @@ export type HttpRequestSendOptions = { validators?: ((res: Response) => void)[]; }; -export function isPrivateUrl(url: URL): boolean { - if (!ipaddr.isValid(url.hostname)) { - return false; +export async function isPrivateUrl(url: URL, lookup: net.LookupFunction): Promise<boolean> { + const ip = await resolveIp(url, lookup); + return ip.range() !== 'unicast'; +} + +export async function resolveIp(url: URL, lookup: net.LookupFunction) { + if (ipaddr.isValid(url.hostname)) { + return ipaddr.parse(url.hostname); } - const ip = ipaddr.parse(url.hostname); - return ip.range() !== 'unicast'; + const resolvedIp = await new Promise<string>((resolve, reject) => { + lookup(url.hostname, {}, (err, address) => { + if (err) reject(err); + else resolve(address as string); + }); + }); + + return ipaddr.parse(resolvedIp); } -export function isPrivateIp(allowedPrivateNetworks: PrivateNetwork[] | undefined, ip: string, port?: number): boolean { +export function isAllowedPrivateIp(allowedPrivateNetworks: PrivateNetwork[] | undefined, ip: string, port?: number): boolean { const parsedIp = ipaddr.parse(ip); for (const { cidr, ports } of allowedPrivateNetworks ?? []) { @@ -53,7 +64,7 @@ export function isPrivateIp(allowedPrivateNetworks: PrivateNetwork[] | undefined export function validateSocketConnect(allowedPrivateNetworks: PrivateNetwork[] | undefined, socket: Socket): void { const address = socket.remoteAddress; if (address && ipaddr.isValid(address)) { - if (isPrivateIp(allowedPrivateNetworks, address, socket.remotePort)) { + if (isAllowedPrivateIp(allowedPrivateNetworks, address, socket.remotePort)) { socket.destroy(new Error(`Blocked address: ${address}`)); } } @@ -142,6 +153,7 @@ export class HttpRequestService { private config: Config, private readonly apUtilityService: ApUtilityService, private readonly utilityService: UtilityService, + private readonly lookup: net.LookupFunction, ) { const cache = new CacheableLookup({ maxTtl: 3600, // 1hours @@ -149,6 +161,8 @@ export class HttpRequestService { lookup: false, // nativeのdns.lookupにfallbackしない }); + this.lookup = cache.lookup as unknown as net.LookupFunction; + const agentOption = { keepAlive: true, keepAliveMsecs: 30 * 1000, @@ -321,7 +335,7 @@ export class HttpRequestService { const timeout = args.timeout ?? 5000; const parsedUrl = new URL(url); - const allowHttp = args.allowHttp || isPrivateUrl(parsedUrl); + const allowHttp = args.allowHttp || await isPrivateUrl(parsedUrl, this.lookup); this.utilityService.assertUrl(parsedUrl, allowHttp); const controller = new AbortController(); diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index b3fd17e7a0..30124949bb 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -56,7 +56,6 @@ import type { ApLoggerService } from '../ApLoggerService.js'; import type { ApImageService } from './ApImageService.js'; import type { IActor, ICollection, IObject, IOrderedCollection } from '../type.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; const nameLength = 128; const summaryLength = 2048; |