summaryrefslogtreecommitdiff
path: root/packages/backend/src
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-07-25 16:28:53 -0400
committerdakkar <dakkar@thenautilus.net>2025-07-27 19:39:20 +0100
commit25622b536c982f717c72b0cf039322d45c36a55b (patch)
tree440624975f32e96f9922c49cabe443a0f800d8e6 /packages/backend/src
parentallow HTTP connections to private IPs (diff)
downloadsharkey-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.ts30
-rw-r--r--packages/backend/src/core/activitypub/models/ApPersonService.ts1
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;