Add support for dynamic DNS in IP Allowlist

Affects issues:
- Close #1502
This commit is contained in:
Aurora Lahtela 2023-05-06 15:54:17 +03:00
parent 93c10ccdcd
commit b2d78bb491
10 changed files with 133 additions and 7 deletions

View File

@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
import com.djrapitops.plan.gathering.ShutdownHook;
@ -108,4 +109,8 @@ public interface BukkitTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindPlaceholderWarmupTask(PlaceholderCacheRefreshTask placeholderCacheRefreshTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}

View File

@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.timed.BungeePingCounter;
import com.djrapitops.plan.gathering.timed.ProxyTPSCounter;
@ -87,4 +88,8 @@ public interface BungeeTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}

View File

@ -0,0 +1,96 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.delivery.webserver.configuration;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* Maintains Dynamic IP and other IPs in IP Allowlist.
* <p>
* If the allowlist is disabled this task is not registered.
*
* @author AuroraLS3
*/
@Singleton
public class AddressAllowList extends TaskSystem.Task {
private final PlanConfig config;
private List<String> addresses = new ArrayList<>();
@Inject
public AddressAllowList(PlanConfig config) {
this.config = config;
}
private static List<String> resolveIpAddress(String host) {
try {
InetAddress[] foundIps = InetAddress.getAllByName(host);
return Arrays.stream(foundIps)
.map(InetAddress::getHostAddress)
.collect(Collectors.toList());
} catch (UnknownHostException e) {
return Collections.emptyList();
}
}
@Override
public void register(RunnableFactory runnableFactory) {
if (config.isFalse(WebserverSettings.IP_WHITELIST)) {
return;
}
runnableFactory.create(this).runTaskTimerAsynchronously(0, 60, TimeUnit.SECONDS);
}
@Override
public void run() {
updateDnsEntries();
}
private void updateDnsEntries() {
List<String> configuredAddresses = config.get(WebserverSettings.WHITELIST);
List<String> allowedAddresses = new ArrayList<>();
for (String configuredAddress : configuredAddresses) {
if (configuredAddress.startsWith("dns:")) {
allowedAddresses.addAll(resolveIpAddress(configuredAddress.substring(4)));
} else {
allowedAddresses.add(configuredAddress);
}
}
addresses = allowedAddresses;
}
public List<String> getAllowedAddresses() {
return addresses;
}
}

View File

@ -18,8 +18,6 @@ package com.djrapitops.plan.delivery.webserver.configuration;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.exceptions.LibraryLoadingException;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
import com.djrapitops.plan.storage.file.PlanFiles;
import com.djrapitops.plan.utilities.dev.Untrusted;
import dev.vankka.dependencydownload.DependencyManager;
@ -46,15 +44,15 @@ public class IpAllowListMatcher {
private final PluginLogger logger;
private final PlanFiles files;
private final PlanConfig config;
private final AddressAllowList addressAllowList;
private final AtomicBoolean failedDownload = new AtomicBoolean(false);
private ClassLoader libraryClassLoader;
@Inject
public IpAllowListMatcher(PluginLogger logger, PlanFiles files, PlanConfig config) {
public IpAllowListMatcher(PluginLogger logger, PlanFiles files, AddressAllowList addressAllowList) {
this.logger = logger;
this.files = files;
this.config = config;
this.addressAllowList = addressAllowList;
}
public synchronized void prepare() {
@ -95,7 +93,7 @@ public class IpAllowListMatcher {
}
try {
List<String> addresses = config.get(WebserverSettings.WHITELIST);
List<String> addresses = addressAllowList.getAllowedAddresses();
IPLibraryAccessor libraryAccessor = new IPLibraryAccessor(libraryClassLoader);
return libraryAccessor.isAllowed(accessAddress, addresses);
} catch (LibraryLoadingException e) {
@ -105,7 +103,7 @@ public class IpAllowListMatcher {
}
private boolean exactMatchAllowCheck(@Untrusted String accessAddress) {
List<String> allowed = config.get(WebserverSettings.WHITELIST);
List<String> allowed = addressAllowList.getAllowedAddresses();
return allowed.isEmpty() || allowed.contains(accessAddress);
}

View File

@ -78,6 +78,7 @@ Webserver:
# IPv4 exact: "192.168.0.1", wildcard: "192.168.*.*", cidr: "192.168.0.0/16"
# IPv6 exact: "0:0:0:0:0:0:0:1", compressed: "1::1", cidr: "1234:db8:1234:1a:20::/64"
# More: https://seancfoley.github.io/IPAddress/ipaddress.html#supported-ip-address-parsing-formats
# Dynamic DNS hostname: "dns:intranet.example.com", updated once per minute
Whitelist:
- "192.168.0.0"
- "0:0:0:0:0:0:0:1"

View File

@ -79,6 +79,7 @@ Webserver:
# IPv4 exact: "192.168.0.1", wildcard: "192.168.*.*", cidr: "192.168.0.0/16"
# IPv6 exact: "0:0:0:0:0:0:0:1", compressed: "1::1", cidr: "1234:db8:1234:1a:20::/64"
# More: https://seancfoley.github.io/IPAddress/ipaddress.html#supported-ip-address-parsing-formats
# Dynamic DNS hostname: "dns:intranet.example.com", updated once per minute
Whitelist:
- "192.168.0.0"
- "0:0:0:0:0:0:0:1"

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
import com.djrapitops.plan.gathering.ShutdownHook;
@ -93,4 +94,8 @@ public interface FabricTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}

View File

@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
import com.djrapitops.plan.gathering.ShutdownHook;
@ -98,4 +99,8 @@ public interface NukkitTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}

View File

@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
import com.djrapitops.plan.gathering.ShutdownHook;
@ -98,4 +99,8 @@ public interface SpongeTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}

View File

@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.delivery.webserver.configuration.AddressAllowList;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.timed.ProxyTPSCounter;
import com.djrapitops.plan.gathering.timed.SystemUsageBuffer;
@ -87,4 +88,8 @@ public interface VelocityTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
@Binds
@IntoSet
TaskSystem.Task bindAddressAllowListUpdateTask(AddressAllowList addressAllowList);
}