mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 09:47:58 +01:00
Introduce an ASN-to-IP manager.
This commit is contained in:
committed by
Jon Chambers
parent
1160af9522
commit
f8c623074b
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.util;
|
||||
|
||||
import static com.codahale.metrics.MetricRegistry.name;
|
||||
|
||||
import com.amazonaws.services.s3.model.S3Object;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.configuration.MonitoredS3ObjectConfiguration;
|
||||
|
||||
public class AsnManager implements Managed {
|
||||
|
||||
private final S3ObjectMonitor asnTableMonitor;
|
||||
|
||||
private final AtomicReference<AsnTable> asnTable = new AtomicReference<>(AsnTable.EMPTY);
|
||||
|
||||
private static final Timer REFRESH_TIMER = Metrics.timer(name(AsnManager.class, "refresh"));
|
||||
private static final Counter REFRESH_ERRORS = Metrics.counter(name(AsnManager.class, "refreshErrors"));
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AsnManager.class);
|
||||
|
||||
public AsnManager(
|
||||
final ScheduledExecutorService scheduledExecutorService,
|
||||
final MonitoredS3ObjectConfiguration configuration) {
|
||||
|
||||
this.asnTableMonitor = new S3ObjectMonitor(
|
||||
configuration.getS3Region(),
|
||||
configuration.getS3Bucket(),
|
||||
configuration.getObjectKey(),
|
||||
configuration.getMaxSize(),
|
||||
scheduledExecutorService,
|
||||
configuration.getRefreshInterval(),
|
||||
this::handleAsnTableChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
try {
|
||||
handleAsnTableChanged(asnTableMonitor.getObject());
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to load initial IP-to-ASN map", e);
|
||||
}
|
||||
|
||||
asnTableMonitor.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
asnTableMonitor.stop();
|
||||
}
|
||||
|
||||
public Optional<Long> getAsn(final String address) {
|
||||
try {
|
||||
return asnTable.get().getAsn((Inet4Address) Inet4Address.getByName(address));
|
||||
} catch (final UnknownHostException e) {
|
||||
log.warn("Could not parse \"{}\" as an Inet4Address", address);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAsnTableChanged(final S3Object asnTableObject) {
|
||||
REFRESH_TIMER.record(() -> {
|
||||
try {
|
||||
handleAsnTableChanged(new GZIPInputStream(asnTableObject.getObjectContent()));
|
||||
} catch (final IOException e) {
|
||||
log.error("Retrieved object was not a gzip archive", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void handleAsnTableChanged(final InputStream inputStream) {
|
||||
try (final InputStreamReader reader = new InputStreamReader(inputStream)) {
|
||||
asnTable.set(new AsnTable(reader));
|
||||
} catch (final Exception e) {
|
||||
REFRESH_ERRORS.increment();
|
||||
log.warn("Failed to refresh IP-to-ASN table", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,8 @@ class AsnTable {
|
||||
}
|
||||
}
|
||||
|
||||
public static final AsnTable EMPTY = new AsnTable();
|
||||
|
||||
public AsnTable(final Reader tsvReader) throws IOException {
|
||||
final TreeMap<Long, AsnRange> treeMap = new TreeMap<>();
|
||||
|
||||
@@ -60,6 +62,10 @@ class AsnTable {
|
||||
asnBlocksByFirstIp = treeMap;
|
||||
}
|
||||
|
||||
private AsnTable() {
|
||||
asnBlocksByFirstIp = new TreeMap<>();
|
||||
}
|
||||
|
||||
public Optional<Long> getAsn(final Inet4Address address) {
|
||||
final long addressAsLong = ipToLong(address);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.configuration.TorExitNodeConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.MonitoredS3ObjectConfiguration;
|
||||
|
||||
/**
|
||||
* A utility for checking whether IP addresses belong to Tor exit nodes using the "bulk exit list."
|
||||
@@ -44,7 +44,7 @@ public class TorExitNodeManager implements Managed {
|
||||
|
||||
public TorExitNodeManager(
|
||||
final ScheduledExecutorService scheduledExecutorService,
|
||||
final TorExitNodeConfiguration configuration) {
|
||||
final MonitoredS3ObjectConfiguration configuration) {
|
||||
|
||||
this.exitListMonitor = new S3ObjectMonitor(
|
||||
configuration.getS3Region(),
|
||||
|
||||
Reference in New Issue
Block a user