промежуточный коммит
This commit is contained in:
parent
08c8fe2f7c
commit
47bd3ef9d6
|
|
@ -38,3 +38,4 @@ build/
|
|||
.DS_Store
|
||||
/.idea/
|
||||
/.mvn/
|
||||
/config.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>ru.kirillius</groupId>
|
||||
<artifactId>pf-sdn</artifactId>
|
||||
<version>0.1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>app</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>24</maven.compiler.source>
|
||||
<maven.compiler.target>24</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ru.kirillius</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>0.1.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package ru.kirillius.pf.sdn;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import ru.kirillius.pf.sdn.External.API.HENetBGPInfoProvider;
|
||||
import ru.kirillius.pf.sdn.core.Auth.AuthManager;
|
||||
import ru.kirillius.pf.sdn.core.Config;
|
||||
import ru.kirillius.pf.sdn.core.Context;
|
||||
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInformationService;
|
||||
import ru.kirillius.pf.sdn.core.Networking.NetworkManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class App implements Context {
|
||||
public static void main(String[] args) {
|
||||
new App();
|
||||
}
|
||||
|
||||
private final static File configFile = new File("config.json");
|
||||
|
||||
public App() {
|
||||
try {
|
||||
config = Config.load(configFile);
|
||||
} catch (IOException e) {
|
||||
config = new Config();
|
||||
try {
|
||||
Config.store(config, configFile);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
authManager = new AuthManager(this);
|
||||
server = new Server();
|
||||
autonomousSystemInformationService = new AutonomousSystemInformationService();
|
||||
autonomousSystemInformationService.setProvider(new HENetBGPInfoProvider());
|
||||
networkManager = new NetworkManager(this);
|
||||
var inputResources = networkManager.getInputResources();
|
||||
inputResources.add(config.getCustomResources());
|
||||
networkManager.triggerUpdate();
|
||||
|
||||
while (networkManager.isUpdatingNow()) {
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final NetworkManager networkManager;
|
||||
@Getter
|
||||
private Config config;
|
||||
@Getter
|
||||
private final AuthManager authManager;
|
||||
@Getter
|
||||
private final Server server;
|
||||
@Getter
|
||||
private final AutonomousSystemInformationService autonomousSystemInformationService;
|
||||
|
||||
|
||||
}
|
||||
56
app/src/main/java/ru/kirillius/pf/sdn/External/API/HENetBGPInfoProvider.java
vendored
Normal file
56
app/src/main/java/ru/kirillius/pf/sdn/External/API/HENetBGPInfoProvider.java
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package ru.kirillius.pf.sdn.External.API;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInfoProvider;
|
||||
import ru.kirillius.pf.sdn.core.Networking.IPv4Subnet;
|
||||
import ru.kirillius.utils.logging.SystemLogger;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HENetBGPInfoProvider implements AutonomousSystemInfoProvider {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public List<IPv4Subnet> getPrefixes(int as) {
|
||||
try (var client = HttpClient.newHttpClient()) {
|
||||
var request = HttpRequest.newBuilder().uri(URI.create("https://bgp.he.net/super-lg/report/api/v1/prefixes/originated/" + as)).header("Accept", "application/json").GET().build();
|
||||
var response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
if (response.statusCode() == 200) {
|
||||
try (var inputStream = response.body()) {
|
||||
return getIPv4Subnets(inputStream);
|
||||
}
|
||||
} else {
|
||||
SystemLogger.error("Unable to get info about AS" + as, CTX);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull ArrayList<IPv4Subnet> getIPv4Subnets(InputStream inputStream) {
|
||||
var json = new JSONObject(new JSONTokener(inputStream));
|
||||
var array = json.getJSONArray("prefixes");
|
||||
var list = new ArrayList<IPv4Subnet>();
|
||||
array.forEach(obj -> {
|
||||
var jo = (JSONObject) obj;
|
||||
|
||||
var prefix = jo.getString("Prefix");
|
||||
if (prefix.indexOf('.') == -1) {
|
||||
return;
|
||||
}
|
||||
list.add(new IPv4Subnet(prefix));
|
||||
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
private final static String CTX = HENetBGPInfoProvider.class.getSimpleName();
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import ru.kirillius.json.JSONProperty;
|
|||
import ru.kirillius.json.JSONSerializable;
|
||||
import ru.kirillius.json.JSONUtility;
|
||||
import ru.kirillius.pf.sdn.core.Auth.AuthToken;
|
||||
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
|
|
@ -39,13 +40,33 @@ public class Config {
|
|||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private String passwordHash = null;
|
||||
private String passwordHash = "";
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private int httpPort = 8081;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private boolean mergeSubnets = true;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private int mergeSubnetsCount = 10;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private NetworkResourceBundle customResources = new NetworkResourceBundle();
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@JSONProperty
|
||||
private NetworkResourceBundle filteredResources = new NetworkResourceBundle();
|
||||
|
||||
public void update() {
|
||||
try {
|
||||
store(this, loadedConfigFile);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package ru.kirillius.pf.sdn.core;
|
|||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import ru.kirillius.pf.sdn.core.Auth.AuthManager;
|
||||
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInformationService;
|
||||
import ru.kirillius.pf.sdn.core.Networking.NetworkManager;
|
||||
|
||||
public interface Context {
|
||||
Config getConfig();
|
||||
|
|
@ -10,4 +12,8 @@ public interface Context {
|
|||
|
||||
Server getServer();
|
||||
|
||||
AutonomousSystemInformationService getAutonomousSystemInformationService();
|
||||
|
||||
NetworkManager getNetworkManager();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package ru.kirillius.pf.sdn.core.Networking;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AutonomousSystemInfoProvider {
|
||||
List<IPv4Subnet> getPrefixes(int as);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package ru.kirillius.pf.sdn.core.Networking;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class AutonomousSystemInformationService implements Closeable {
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private AutonomousSystemInfoProvider provider = null;
|
||||
|
||||
|
||||
public Future<List<IPv4Subnet>> getPrefixes(int as) {
|
||||
return executor.submit(() -> provider.getPrefixes(as));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,18 +1,46 @@
|
|||
package ru.kirillius.pf.sdn.core.Networking;
|
||||
|
||||
import lombok.Getter;
|
||||
import ru.kirillius.json.JSONSerializer;
|
||||
import ru.kirillius.json.SerializationException;
|
||||
import ru.kirillius.pf.sdn.core.Util.IPv4Util;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public class IPv4Subnet {
|
||||
|
||||
public final static class Serializer implements JSONSerializer<IPv4Subnet> {
|
||||
|
||||
@Override
|
||||
public Object serialize(IPv4Subnet subnet) throws SerializationException {
|
||||
return subnet.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPv4Subnet deserialize(Object o, Class<?> aClass) throws SerializationException {
|
||||
return new IPv4Subnet((String) o);
|
||||
}
|
||||
}
|
||||
|
||||
private final long address;
|
||||
@Getter
|
||||
private final int prefixLength;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
IPv4Subnet that = (IPv4Subnet) o;
|
||||
return address == that.address && prefixLength == that.prefixLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(address, prefixLength);
|
||||
}
|
||||
|
||||
public IPv4Subnet(String subnet) {
|
||||
var split = subnet.split(Pattern.quote("/"));
|
||||
if (split.length != 2) {
|
||||
|
|
@ -45,7 +73,7 @@ public class IPv4Subnet {
|
|||
public boolean overlaps(IPv4Subnet subnet) {
|
||||
var minPrefixLength = Math.min(prefixLength, subnet.prefixLength);
|
||||
var commonMask = IPv4Util.calculateMask(minPrefixLength);
|
||||
if (commonMask != prefixLength) {
|
||||
if (minPrefixLength != prefixLength) {
|
||||
return false; //can't overlap larger prefix
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
package ru.kirillius.pf.sdn.core.Networking;
|
||||
|
||||
import lombok.Getter;
|
||||
import ru.kirillius.pf.sdn.core.Context;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class NetworkManager implements Closeable {
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private Context context;
|
||||
|
||||
public NetworkManager(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private final AtomicReference<Future<?>> updateProcess = new AtomicReference<>();
|
||||
private final AtomicBoolean cacheInvalid = new AtomicBoolean(true);
|
||||
@Getter
|
||||
private final NetworkResourceBundle inputResources = new NetworkResourceBundle();
|
||||
@Getter
|
||||
private final NetworkResourceBundle outputResources = new NetworkResourceBundle();
|
||||
|
||||
public boolean isUpdatingNow() {
|
||||
var future = updateProcess.get();
|
||||
return future != null && !future.isDone() && !future.isCancelled();
|
||||
}
|
||||
|
||||
private final Map<Integer, List<IPv4Subnet>> prefixCache = new ConcurrentHashMap<>();
|
||||
|
||||
public synchronized void triggerUpdate() {
|
||||
if (isUpdatingNow()) {
|
||||
return;
|
||||
}
|
||||
updateProcess.set(executor.submit(() -> {
|
||||
var config = context.getConfig();
|
||||
var filteredResources = config.getFilteredResources();
|
||||
var asn = new ArrayList<>(inputResources.getASN());
|
||||
asn.removeAll(filteredResources.getASN());
|
||||
|
||||
|
||||
if (cacheInvalid.get()) {
|
||||
fetchPrefixes(asn);
|
||||
}
|
||||
|
||||
var subnets = new HashSet<>(inputResources.getSubnets());
|
||||
prefixCache.values().forEach(subnets::addAll);
|
||||
filteredResources.getSubnets().forEach(subnets::remove);
|
||||
|
||||
var domains = new HashSet<>(inputResources.getDomains());
|
||||
filteredResources.getDomains().forEach(domains::remove);
|
||||
//check overlaps
|
||||
|
||||
var domainsToRemove = new HashSet<String>();
|
||||
for (var domainToMatch : domains) {
|
||||
var pattern = "." + domainToMatch;
|
||||
for (var domain : domains) {
|
||||
if (domain.endsWith(pattern)) {
|
||||
domainsToRemove.add(domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
domains.removeAll(domainsToRemove);
|
||||
|
||||
outputResources.setASN(Collections.unmodifiableList(asn));
|
||||
outputResources.setSubnets(subnets.stream().toList());
|
||||
outputResources.setDomains(domains.stream().toList());
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
cacheInvalid.set(true);
|
||||
}
|
||||
|
||||
private void fetchPrefixes(List<Integer> systems) {
|
||||
systems.forEach(as -> {
|
||||
var service = context.getAutonomousSystemInformationService();
|
||||
var future = service.getPrefixes(as);
|
||||
|
||||
while (!future.isDone() && !future.isCancelled()) {
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
try {
|
||||
var iPv4Subnets = future.get();
|
||||
prefixCache.put(as, iPv4Subnets);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package ru.kirillius.pf.sdn.core.Networking;
|
||||
|
||||
import lombok.*;
|
||||
import ru.kirillius.json.JSONArrayProperty;
|
||||
import ru.kirillius.json.JSONSerializable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@JSONSerializable
|
||||
public class NetworkResourceBundle {
|
||||
@Getter
|
||||
@Setter
|
||||
@JSONArrayProperty(type = Integer.class)
|
||||
private List<Integer> ASN = new ArrayList<>();
|
||||
@Getter
|
||||
@Setter
|
||||
@JSONArrayProperty(type = IPv4Subnet.class, serializer = IPv4Subnet.Serializer.class)
|
||||
private List<IPv4Subnet> subnets = new ArrayList<>();
|
||||
@Getter
|
||||
@Setter
|
||||
@JSONArrayProperty(type = String.class)
|
||||
private List<String> domains = new ArrayList<>();
|
||||
|
||||
public void clear() {
|
||||
ASN.clear();
|
||||
subnets.clear();
|
||||
domains.clear();
|
||||
}
|
||||
|
||||
public void add(NetworkResourceBundle networkResourceBundle) {
|
||||
ASN.addAll(networkResourceBundle.getASN());
|
||||
subnets.addAll(networkResourceBundle.getSubnets());
|
||||
domains.addAll(networkResourceBundle.getDomains());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package ru.kirillius.pf.sdn.core.Util;
|
||||
|
||||
public class BGPUtility {
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ class IPv4SubnetTest {
|
|||
var validPrefixes = List.of(0, 5, 20, 32);
|
||||
var invalidPrefixes = List.of(-1, 33, 800);
|
||||
var validAddresses = List.of("1.2.3.4", "0.0.0.0", "255.255.255.255");
|
||||
var invalidAddresses = List.of("1.2.3.04", "0.0.0", "255.255.255.255.255", "1.2.3.256", "-1.0.0.0");
|
||||
var invalidAddresses = List.of("1", "0.0.0", "255.255.255.255.255", "1.2.3.256", "-1.0.0.0");
|
||||
|
||||
|
||||
validPrefixes.forEach(prefix -> {
|
||||
|
|
@ -27,7 +27,7 @@ class IPv4SubnetTest {
|
|||
try {
|
||||
var subnet = new IPv4Subnet(address, prefix);
|
||||
throw new AssertionError();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
assertThat(e).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
});
|
||||
|
|
@ -38,7 +38,7 @@ class IPv4SubnetTest {
|
|||
try {
|
||||
var subnet = new IPv4Subnet(address, prefix);
|
||||
throw new AssertionError();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
assertThat(e).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
});
|
||||
|
|
@ -49,7 +49,7 @@ class IPv4SubnetTest {
|
|||
try {
|
||||
var subnet = new IPv4Subnet(address, prefix);
|
||||
throw new AssertionError();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
assertThat(e).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>ru.kirillius</groupId>
|
||||
<artifactId>pf-sdn</artifactId>
|
||||
<version>0.1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>launcher</artifactId>
|
||||
|
||||
</project>
|
||||
12
pom.xml
12
pom.xml
|
|
@ -10,9 +10,9 @@
|
|||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>web-client</module>
|
||||
<module>launcher</module>
|
||||
<module>core</module>
|
||||
<module>web-server</module>
|
||||
<module>app</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
@ -94,12 +94,7 @@
|
|||
<artifactId>hibernate-commons</artifactId>
|
||||
<version>2.2.0.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>3.29.2-GA</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-server -->
|
||||
<dependency>
|
||||
|
|
@ -112,9 +107,10 @@
|
|||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
<version>1.18.40</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Loading…
Reference in New Issue