summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--acme.yaml4
-rw-r--r--out/phase-1.yaml49
-rw-r--r--out/vpn0.yaml41
-rw-r--r--pom.xml13
-rw-r--r--src/main/java/io/trygvis/rules/acme/IpCalc.java67
-rw-r--r--src/main/java/io/trygvis/rules/engine/Main.java11
-rw-r--r--src/main/java/io/trygvis/rules/network/Ipv4Address.java35
-rw-r--r--src/main/java/io/trygvis/rules/network/Ipv4Cidr.java40
-rw-r--r--src/main/resources/io/trygvis/rules/acme/vpn.drl23
-rw-r--r--src/test/java/io/trygvis/rules/acme/IpCalcTest.java27
10 files changed, 299 insertions, 11 deletions
diff --git a/acme.yaml b/acme.yaml
index 80517b7..818422a 100644
--- a/acme.yaml
+++ b/acme.yaml
@@ -34,8 +34,10 @@ type: io.trygvis.rules.machine.Machine
data:
name: ws-2
----
+--- # Wireguard VPN network
type: io.trygvis.rules.acme.WgNet
data:
name: vpn0
domain: vpn.acme.com
+ linkCidr: 192.168.10.0/29
+ networkCidr: 10.55.55.0/24
diff --git a/out/phase-1.yaml b/out/phase-1.yaml
index 0ec42e0..8c34f1a 100644
--- a/out/phase-1.yaml
+++ b/out/phase-1.yaml
@@ -74,6 +74,8 @@ type: "io.trygvis.rules.acme.WgNet"
data:
name: "vpn0"
domain: "vpn.acme.com"
+ linkCidr: "192.168.10.0/29"
+ networkCidr: "10.55.55.0/24"
---
type: "io.trygvis.rules.dba.Cluster"
data:
@@ -158,7 +160,7 @@ data:
type: "io.trygvis.rules.dba.Container"
data:
cluster:
- name: "acme-ci"
+ name: "acme-production"
name: "db"
machineRole: "mdb"
image: "mongodb"
@@ -167,7 +169,7 @@ data:
type: "io.trygvis.rules.dba.Container"
data:
cluster:
- name: "acme-production"
+ name: "acme-ci"
name: "db"
machineRole: "mdb"
image: "mongodb"
@@ -176,7 +178,7 @@ data:
type: "io.trygvis.rules.dba.Container"
data:
cluster:
- name: "acme-ci"
+ name: "acme-production"
name: "db"
machineRole: "pdb"
image: "postgresql"
@@ -185,7 +187,7 @@ data:
type: "io.trygvis.rules.dba.Container"
data:
cluster:
- name: "acme-production"
+ name: "acme-ci"
name: "db"
machineRole: "pdb"
image: "postgresql"
@@ -285,6 +287,45 @@ data:
name: "ws-2"
fqdn: null
---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.7"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.6"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.5"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.4"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.3"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.2"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.1"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.0"
+---
+type: "io.trygvis.rules.network.Ipv4Cidr"
+data:
+ network: -1062729216
+ netmask: -8
+ size: 8
+ bits: 29
+---
type: "io.trygvis.rules.terraform.ScalewayMachine"
data:
machine:
diff --git a/out/vpn0.yaml b/out/vpn0.yaml
index c4a798f..1c88e80 100644
--- a/out/vpn0.yaml
+++ b/out/vpn0.yaml
@@ -43,6 +43,8 @@ type: "io.trygvis.rules.acme.WgNet"
data:
name: "vpn0"
domain: "vpn.acme.com"
+ linkCidr: "192.168.10.0/29"
+ networkCidr: "10.55.55.0/24"
---
type: "io.trygvis.rules.dns.DnsEntry"
data:
@@ -108,3 +110,42 @@ type: "io.trygvis.rules.machine.Machine"
data:
name: "ws-2"
fqdn: null
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.7"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.6"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.5"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.4"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.3"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.2"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.1"
+---
+type: "io.trygvis.rules.network.Ipv4Address"
+data:
+ value: "192.168.10.0"
+---
+type: "io.trygvis.rules.network.Ipv4Cidr"
+data:
+ network: -1062729216
+ netmask: -8
+ size: 8
+ bits: 29
diff --git a/pom.xml b/pom.xml
index a8c44ee..47b1d04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -115,6 +115,19 @@
<version>2.8.0</version>
</dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.7.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <version>5.7.0</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
diff --git a/src/main/java/io/trygvis/rules/acme/IpCalc.java b/src/main/java/io/trygvis/rules/acme/IpCalc.java
new file mode 100644
index 0000000..5369d62
--- /dev/null
+++ b/src/main/java/io/trygvis/rules/acme/IpCalc.java
@@ -0,0 +1,67 @@
+package io.trygvis.rules.acme;
+
+import io.trygvis.rules.network.Ipv4Cidr;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class IpCalc {
+ private static final Pattern pattern = Pattern.compile("([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})/([0-9]{1,3})");
+
+ public static class FirstLast {
+ public final int first;
+ public final int last;
+
+ public FirstLast(int first, int last) {
+ this.first = first;
+ this.last = last;
+ }
+ }
+
+ public static Ipv4Cidr cidr(String cidr) {
+ var matcher = pattern.matcher(cidr);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Not a CIDR: " + cidr);
+ }
+
+ var b1 = matcher.group(1);
+ var b2 = matcher.group(2);
+ var b3 = matcher.group(3);
+ var b4 = matcher.group(4);
+
+ int network = parse(b1) << 24 |
+ parse(b2) << 16 |
+ parse(b3) << 8 |
+ parse(b4);
+
+// System.out.printf("network = %x%n", network);
+
+ var l = matcher.group(5);
+ var bits = Integer.parseInt(l);
+ var hostBits = 32 - bits;
+ int size = 1 << hostBits;
+
+ int netmask = (-1 >> hostBits) << hostBits;
+// System.out.printf("netmask = %08x%n", netmask);
+
+ int x = network & ~netmask;
+
+ if (x != 0) {
+ throw new IllegalArgumentException("Not a CIDR: " + cidr);
+ }
+
+ return new Ipv4Cidr(network, netmask, size, bits);
+ }
+
+ private static int parse(String s) {
+ var i = Integer.parseInt(s);
+ if (i > 255) {
+ throw new IllegalArgumentException("Not a CIDR");
+ }
+
+ return i;
+ }
+}
diff --git a/src/main/java/io/trygvis/rules/engine/Main.java b/src/main/java/io/trygvis/rules/engine/Main.java
index 5556db7..6f04a98 100644
--- a/src/main/java/io/trygvis/rules/engine/Main.java
+++ b/src/main/java/io/trygvis/rules/engine/Main.java
@@ -3,6 +3,8 @@ package io.trygvis.rules.engine;
import io.trygvis.rules.acme.AcmeIo;
import io.trygvis.rules.dns.DnsEntry;
import io.trygvis.rules.machine.Machine;
+import io.trygvis.rules.network.Ipv4Address;
+import io.trygvis.rules.network.Ipv4Cidr;
import org.drools.core.audit.WorkingMemoryConsoleLogger;
import org.kie.api.KieServices;
import org.kie.api.event.rule.AgendaEventListener;
@@ -38,9 +40,12 @@ public class Main {
io.dump("phase-1", session.getFactHandles());
- io.dump("vpn0", session.getFactHandles(), (Object o) -> {
- return o.getClass().getName().contains("Wg") || o instanceof Machine || o instanceof DnsEntry;
- });
+ io.dump("vpn0", session.getFactHandles(), (Object o) ->
+ o.getClass().getName().contains("Wg") ||
+ o instanceof Machine ||
+ o instanceof DnsEntry ||
+ o instanceof Ipv4Cidr ||
+ o instanceof Ipv4Address);
session.dispose();
}
diff --git a/src/main/java/io/trygvis/rules/network/Ipv4Address.java b/src/main/java/io/trygvis/rules/network/Ipv4Address.java
new file mode 100644
index 0000000..071bca9
--- /dev/null
+++ b/src/main/java/io/trygvis/rules/network/Ipv4Address.java
@@ -0,0 +1,35 @@
+package io.trygvis.rules.network;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import java.io.IOException;
+
+@JsonSerialize(using = Ipv4Address.Serializer.class)
+public class Ipv4Address {
+ public final int address;
+
+ public Ipv4Address(int address) {
+ this.address = address;
+ }
+
+ @Override
+ public String toString() {
+ return "%d.%d.%d.%d".formatted(
+ address >> 24 & 0xff,
+ address >> 16 & 0xff,
+ address >> 8 & 0xff,
+ address & 0xff);
+ }
+
+ public static class Serializer extends JsonSerializer<Ipv4Address> {
+ @Override
+ public void serialize(Ipv4Address value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+ gen.writeStartObject();
+ gen.writeObjectField("value", value.toString());
+ gen.writeEndObject();
+ }
+ }
+}
diff --git a/src/main/java/io/trygvis/rules/network/Ipv4Cidr.java b/src/main/java/io/trygvis/rules/network/Ipv4Cidr.java
new file mode 100644
index 0000000..34b3a0b
--- /dev/null
+++ b/src/main/java/io/trygvis/rules/network/Ipv4Cidr.java
@@ -0,0 +1,40 @@
+package io.trygvis.rules.network;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class Ipv4Cidr {
+ public final int network;
+ public final int netmask;
+ public final int size;
+ public final int bits;
+
+ public Ipv4Cidr(int network, int netmask, int size, int bits) {
+ this.network = network;
+ this.netmask = netmask;
+ this.size = size;
+ this.bits = bits;
+ }
+
+ @Override
+ public String toString() {
+ return "%d.%d.%d.%d/%d".formatted(
+ network >> 24 & 0xff,
+ network >> 16 & 0xff,
+ network >> 8 & 0xff,
+ network & 0xff,
+ bits);
+ }
+
+ public Collection<Ipv4Address> addresses() {
+ var end = network + size;
+ var addresses = new ArrayList<Ipv4Address>(size);
+ for (int address = network; address < end; address++) {
+ addresses.add(new Ipv4Address(address));
+ }
+
+ return addresses;
+ }
+}
diff --git a/src/main/resources/io/trygvis/rules/acme/vpn.drl b/src/main/resources/io/trygvis/rules/acme/vpn.drl
index 90cdce2..0f0b3c8 100644
--- a/src/main/resources/io/trygvis/rules/acme/vpn.drl
+++ b/src/main/resources/io/trygvis/rules/acme/vpn.drl
@@ -4,13 +4,30 @@ import java.util.ArrayList
import io.trygvis.rules.machine.Machine;
import io.trygvis.rules.dns.DnsEntry;
import io.trygvis.rules.acme.AcmeServer
-import io.trygvis.rules.acme.WgHost;
+import io.trygvis.rules.network.Ipv4Address
+import io.trygvis.rules.network.Ipv4Cidr
dialect "mvel"
declare WgNet
- name : String
- domain : String
+ name : String
+ domain : String
+ linkCidr : String
+ networkCidr : String
+end
+
+rule "Create link network" when
+ $net : WgNet()
+ not(Ipv4Cidr(network == IpCalc.cidr($net.linkCidr).network))
+then
+ insert(IpCalc.cidr($net.linkCidr))
+end
+
+rule "Create link network addresses" when
+ $cidr : Ipv4Cidr()
+ $addresses : Ipv4Address() from $cidr.addresses
+then
+ insert($addresses)
end
declare WgHost
diff --git a/src/test/java/io/trygvis/rules/acme/IpCalcTest.java b/src/test/java/io/trygvis/rules/acme/IpCalcTest.java
new file mode 100644
index 0000000..8b1e2c6
--- /dev/null
+++ b/src/test/java/io/trygvis/rules/acme/IpCalcTest.java
@@ -0,0 +1,27 @@
+package io.trygvis.rules.acme;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class IpCalcTest {
+
+ @Test
+ public void basic() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> IpCalc.cidr("192.168.1.1/24").addresses());
+ assertEquals(256, IpCalc.cidr("192.168.1.0/24").addresses().size());
+ assertEquals(128, IpCalc.cidr("192.168.1.128/25").addresses().size());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "192.168.1.0/24",
+ "192.168.1.128/25",
+ })
+ public void testParsing(String s) {
+ assertEquals(s, IpCalc.cidr(s).toString());
+ }
+}