summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/HttpRequestService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/core/HttpRequestService.ts')
-rw-r--r--packages/backend/src/core/HttpRequestService.ts68
1 files changed, 27 insertions, 41 deletions
diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts
index 12047346fb..7c086c9976 100644
--- a/packages/backend/src/core/HttpRequestService.ts
+++ b/packages/backend/src/core/HttpRequestService.ts
@@ -12,7 +12,7 @@ import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import type { Config } from '@/config.js';
+import type { Config, PrivateNetwork } from '@/config.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
@@ -20,12 +20,36 @@ import type { IObject, IObjectWithId } from '@/core/activitypub/type.js';
import { ApUtilityService } from './activitypub/ApUtilityService.js';
import type { Response } from 'node-fetch';
import type { URL } from 'node:url';
+import type { Socket } from 'node:net';
export type HttpRequestSendOptions = {
throwErrorWhenResponseNotOk: boolean;
validators?: ((res: Response) => void)[];
};
+export function isPrivateIp(allowedPrivateNetworks: PrivateNetwork[] | undefined, ip: string, port?: number): boolean {
+ const parsedIp = ipaddr.parse(ip);
+
+ for (const { cidr, ports } of allowedPrivateNetworks ?? []) {
+ if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(cidr)) {
+ if (port == null || ports == null || ports.includes(port)) {
+ return false;
+ }
+ }
+ }
+
+ return parsedIp.range() !== 'unicast';
+}
+
+export function validateSocketConnect(allowedPrivateNetworks: PrivateNetwork[] | undefined, socket: Socket): void {
+ const address = socket.remoteAddress;
+ if (address && ipaddr.isValid(address)) {
+ if (isPrivateIp(allowedPrivateNetworks, address, socket.remotePort)) {
+ socket.destroy(new Error(`Blocked address: ${address}`));
+ }
+ }
+}
+
declare module 'node:http' {
interface Agent {
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket;
@@ -44,31 +68,12 @@ class HttpRequestServiceAgent extends http.Agent {
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
const socket = super.createConnection(options, callback)
.on('connect', () => {
- const address = socket.remoteAddress;
if (process.env.NODE_ENV === 'production') {
- if (address && ipaddr.isValid(address)) {
- if (this.isPrivateIp(address)) {
- socket.destroy(new Error(`Blocked address: ${address}`));
- }
- }
+ validateSocketConnect(this.config.allowedPrivateNetworks, socket);
}
});
return socket;
}
-
- @bindThis
- private isPrivateIp(ip: string): boolean {
- const parsedIp = ipaddr.parse(ip);
-
- for (const net of this.config.allowedPrivateNetworks ?? []) {
- const cidr = ipaddr.parseCIDR(net);
- if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
- return false;
- }
- }
-
- return parsedIp.range() !== 'unicast';
- }
}
class HttpsRequestServiceAgent extends https.Agent {
@@ -83,31 +88,12 @@ class HttpsRequestServiceAgent extends https.Agent {
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
const socket = super.createConnection(options, callback)
.on('connect', () => {
- const address = socket.remoteAddress;
if (process.env.NODE_ENV === 'production') {
- if (address && ipaddr.isValid(address)) {
- if (this.isPrivateIp(address)) {
- socket.destroy(new Error(`Blocked address: ${address}`));
- }
- }
+ validateSocketConnect(this.config.allowedPrivateNetworks, socket);
}
});
return socket;
}
-
- @bindThis
- private isPrivateIp(ip: string): boolean {
- const parsedIp = ipaddr.parse(ip);
-
- for (const net of this.config.allowedPrivateNetworks ?? []) {
- const cidr = ipaddr.parseCIDR(net);
- if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
- return false;
- }
- }
-
- return parsedIp.range() !== 'unicast';
- }
}
@Injectable()