From 96f675abed4e73d57c38cd11fc7cc6950cf6743b Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Tue, 7 May 2019 17:49:25 +0900
Subject: [PATCH] =?UTF-8?q?Fix:=20IPv4=20only=E3=83=9B=E3=82=B9=E3=83=88?=
 =?UTF-8?q?=E3=81=8B=E3=82=89Dualstack=E3=83=9B=E3=82=B9=E3=83=88=E3=81=AB?=
 =?UTF-8?q?AP=20deliver=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=20(#4872)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .config/example.yml               |  3 +++
 src/config/types.ts               |  2 ++
 src/remote/activitypub/request.ts | 15 +++++++++++----
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/.config/example.yml b/.config/example.yml
index 2591066da5..8a626cc06d 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -149,3 +149,6 @@ autoAdmin: true
 
 # Clustering
 #clusterLimit: 1
+
+# IP address family used for outgoing request (ipv4, ipv6 or dual)
+#outgoingAddressFamily: ipv4
diff --git a/src/config/types.ts b/src/config/types.ts
index d1749c52f7..d312a5a181 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -44,6 +44,8 @@ export type Source = {
 	clusterLimit?: number;
 
 	id: string;
+
+	outgoingAddressFamily?: 'ipv4' | 'ipv6' | 'dual';
 };
 
 /**
diff --git a/src/remote/activitypub/request.ts b/src/remote/activitypub/request.ts
index da2113faea..3b69dd9ae4 100644
--- a/src/remote/activitypub/request.ts
+++ b/src/remote/activitypub/request.ts
@@ -101,11 +101,18 @@ export default async (user: ILocalUser, url: string, object: any) => {
  * Resolve host (with cached, asynchrony)
  */
 async function resolveAddr(domain: string) {
+	const af = config.outgoingAddressFamily || 'ipv4';
+	const useV4 = af == 'ipv4' || af == 'dual';
+	const useV6 = af == 'ipv6' || af == 'dual';
+
+	const promises = [];
+
+	if (!useV4 && !useV6) throw 'No usable address family available';
+	if (useV4) promises.push(resolveAddrInner(domain, { family: 4 }));
+	if (useV6) promises.push(resolveAddrInner(domain, { family: 6 }));
+
 	// v4/v6で先に取得できた方を採用する
-	return await promiseAny([
-		resolveAddrInner(domain, { family: 4 }),
-		resolveAddrInner(domain, { family: 6 })
-	]);
+	return await promiseAny(promises);
 }
 
 function resolveAddrInner(domain: string, options: IRunOptions = {}): Promise<string> {