summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorJanHolger <jan@bebendorf.eu>2021-07-06 17:01:33 +0200
committerJanHolger <jan@bebendorf.eu>2021-07-06 17:01:33 +0200
commit1d26c0a20d3c595d2846de31c2034e27595540b1 (patch)
treed19fb1f538c0c0cd5e0db55e45e1f16230782aac /src/main/java
Initial commit
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPListener.java11
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPServer.java70
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPSession.java54
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPSessionConfiguration.java19
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/BGPPacket.java76
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/IPPrefix.java27
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/AS4AggregatorAttribute.java30
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/AS4PathAttribute.java45
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java40
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathLimitAttribute.java29
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/AggregatorAttribute.java27
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/AtomicAggregateAttribute.java17
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/CommunitiesAttribute.java41
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/DevelopmentAttribute.java24
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/ExtendedCommuntiesAttribute.java33
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/LargeCommunityAttribute.java56
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/NextHopAttribute.java20
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/OriginAttribute.java24
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java38
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/UnknownAttribute.java23
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/message/BGPNotification.java18
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java35
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java63
23 files changed, 820 insertions, 0 deletions
diff --git a/src/main/java/com/lumaserv/bgp/BGPListener.java b/src/main/java/com/lumaserv/bgp/BGPListener.java
new file mode 100644
index 0000000..54f4fe5
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/BGPListener.java
@@ -0,0 +1,11 @@
+package com.lumaserv.bgp;
+
+import com.lumaserv.bgp.protocol.message.BGPUpdate;
+
+public interface BGPListener {
+
+ void onOpen(BGPSession session);
+ void onUpdate(BGPSession session, BGPUpdate update);
+ void onClose(BGPSession session);
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/BGPServer.java b/src/main/java/com/lumaserv/bgp/BGPServer.java
new file mode 100644
index 0000000..2e960fe
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/BGPServer.java
@@ -0,0 +1,70 @@
+package com.lumaserv.bgp;
+
+import com.lumaserv.bgp.protocol.BGPPacket;
+import com.lumaserv.bgp.protocol.message.BGPOpen;
+import lombok.Getter;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BGPServer implements Runnable {
+
+ final ServerSocket serverSocket;
+ @Getter
+ final List<BGPSessionConfiguration> sessionConfigurations = new ArrayList<>();
+
+ public BGPServer() throws IOException {
+ serverSocket = new ServerSocket(179);
+ }
+
+ private static boolean checkEqual(byte[] a, byte[] b) {
+ if(a == b)
+ return true;
+ if(a == null || b == null)
+ return false;
+ if(a.length != b.length)
+ return false;
+ for(int i=0; i<a.length; i++) {
+ if(a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ public void run() {
+ while (true) {
+ try {
+ Socket socket = serverSocket.accept();
+ BGPPacket packet = BGPPacket.read(socket.getInputStream());
+ if(packet.getType() != BGPPacket.Type.OPEN)
+ continue;
+ BGPOpen request = new BGPOpen(packet.getMessage());
+ BGPSessionConfiguration config = sessionConfigurations.stream()
+ .filter(c -> c.getRemoteAs() == request.getAsn() && checkEqual(c.getRemoteIdentifier(), request.getIdentifier()))
+ .findFirst()
+ .orElse(null);
+ if(config == null)
+ continue;
+ BGPOpen response = new BGPOpen()
+ .setAsn(config.getLocalAs())
+ .setHoldTime(request.getHoldTime())
+ .setVersion(request.getVersion())
+ .setIdentifier(config.getLocalIdentifier());
+ try {
+ socket.getOutputStream().write(new BGPPacket().setType(BGPPacket.Type.OPEN).setMessage(response.build()).build());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ BGPSession session = new BGPSession(socket, config);
+ session.keepAlive();
+ new Thread(session).start();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/BGPSession.java b/src/main/java/com/lumaserv/bgp/BGPSession.java
new file mode 100644
index 0000000..de1fc66
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/BGPSession.java
@@ -0,0 +1,54 @@
+package com.lumaserv.bgp;
+
+import com.lumaserv.bgp.protocol.BGPPacket;
+import com.lumaserv.bgp.protocol.message.BGPUpdate;
+import lombok.Getter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class BGPSession implements Runnable {
+
+ @Getter
+ final BGPSessionConfiguration configuration;
+ final InputStream inputStream;
+ final OutputStream outputStream;
+
+ public BGPSession(Socket socket, BGPSessionConfiguration configuration) throws IOException {
+ this.configuration = configuration;
+ this.inputStream = socket.getInputStream();
+ this.outputStream = socket.getOutputStream();
+ }
+
+ public void keepAlive() {
+ try {
+ outputStream.write(new BGPPacket().setType(BGPPacket.Type.KEEPALIVE).setMessage(new byte[0]).build());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void handle(BGPPacket packet) {
+ switch (packet.getType()) {
+ case KEEPALIVE:
+ keepAlive();
+ break;
+ case UPDATE: {
+ configuration.getListener().onUpdate(this, new BGPUpdate(packet.getMessage()));
+ break;
+ }
+ }
+ }
+
+ public void run() {
+ try {
+ while (true)
+ handle(BGPPacket.read(inputStream));
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/BGPSessionConfiguration.java b/src/main/java/com/lumaserv/bgp/BGPSessionConfiguration.java
new file mode 100644
index 0000000..8102f81
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/BGPSessionConfiguration.java
@@ -0,0 +1,19 @@
+package com.lumaserv.bgp;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Setter
+@Getter
+public class BGPSessionConfiguration {
+
+ String name;
+ int localAs;
+ byte[] localIdentifier;
+ int remoteAs;
+ byte[] remoteIdentifier;
+ BGPListener listener;
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/BGPPacket.java b/src/main/java/com/lumaserv/bgp/protocol/BGPPacket.java
new file mode 100644
index 0000000..e7cf66b
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/BGPPacket.java
@@ -0,0 +1,76 @@
+package com.lumaserv.bgp.protocol;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class BGPPacket {
+
+ Type type;
+ byte[] message;
+
+ public BGPPacket(byte[] packet) {
+ type = Type.fromValue(packet[18]);
+ message = new byte[packet.length-19];
+ System.arraycopy(packet, 19, message, 0, message.length);
+ }
+
+ public byte[] build() {
+ byte[] packet = new byte[message.length + 19];
+ Arrays.fill(packet, 0, 16, (byte) 0xFF);
+ packet[16] = (byte)(packet.length >> 8);
+ packet[17] = (byte)(packet.length & 0xFF);
+ packet[18] = type.getValue();
+ System.arraycopy(message, 0, packet, 19, message.length);
+ return packet;
+ }
+
+ public static BGPPacket read(InputStream stream) throws IOException {
+ byte[] packet = new byte[18];
+ int value;
+ for(int i=0; i<packet.length; i++) {
+ value = stream.read();
+ if(value == -1)
+ throw new IOException("Unexpected end of stream");
+ packet[i] = (byte) value;
+ }
+ int length = ((packet[16] & 0xFF) << 8) | (packet[17] & 0xFF);
+ byte[] newPacket = new byte[length];
+ System.arraycopy(packet, 0, newPacket, 0, packet.length);
+ packet = newPacket;
+ for(int i=18; i<packet.length; i++) {
+ value = stream.read();
+ if(value == -1)
+ throw new IOException("Unexpected end of stream");
+ packet[i] = (byte) value;
+ }
+ return new BGPPacket(packet);
+ }
+
+ @AllArgsConstructor
+ @Getter
+ public enum Type {
+ OPEN((byte) 1),
+ UPDATE((byte) 2),
+ NOTIFICATION((byte) 3),
+ KEEPALIVE((byte) 4),
+ ROUTE_REFRESH((byte) 5);
+ final byte value;
+ public static Type fromValue(byte value) {
+ for(Type t : values()) {
+ if(t.value == value)
+ return t;
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/IPPrefix.java b/src/main/java/com/lumaserv/bgp/protocol/IPPrefix.java
new file mode 100644
index 0000000..be70c4f
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/IPPrefix.java
@@ -0,0 +1,27 @@
+package com.lumaserv.bgp.protocol;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@NoArgsConstructor
+@Setter
+@Getter
+public class IPPrefix {
+
+ byte[] address;
+ byte length;
+
+ public String toString() {
+ try {
+ return InetAddress.getByAddress(address).getHostAddress() + "/" + length;
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4AggregatorAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4AggregatorAttribute.java
new file mode 100644
index 0000000..c579210
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4AggregatorAttribute.java
@@ -0,0 +1,30 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AS4AggregatorAttribute implements PathAttribute {
+
+ int as;
+ byte[] origin;
+
+ public AS4AggregatorAttribute(byte typeCode, byte[] data) {
+ as = ((data[0] & 0xFF) << 24) |
+ ((data[1] & 0xFF) << 16) |
+ ((data[2] & 0xFF) << 8) |
+ (data[3] & 0xFF);
+ origin = new byte[4];
+ System.arraycopy(data, 4, origin, 0, origin.length);
+ }
+
+ public byte getTypeCode() {
+ return 18;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4PathAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4PathAttribute.java
new file mode 100644
index 0000000..415dd5f
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/AS4PathAttribute.java
@@ -0,0 +1,45 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AS4PathAttribute implements PathAttribute {
+
+ List<Segment> segments = new ArrayList<>();
+
+ public AS4PathAttribute(byte typeCode, byte[] data) {
+ int offset = 0;
+ while (offset < data.length) {
+ Segment segment = new Segment().setType(data[offset]);
+ byte length = data[offset + 1];
+ for(int i=0; i<length; i++)
+ segment.asns.add(
+ ((data[offset + 2 + (i * 4)] & 0xFF) << 24) |
+ ((data[offset + 3 + (i * 4)] & 0xFF) << 16) |
+ ((data[offset + 4 + (i * 4)] & 0xFF) << 8) |
+ (data[offset + 5 + (i * 4)] & 0xFF)
+ );
+ offset += 2 + (length * 4);
+ segments.add(segment);
+ }
+ }
+
+ public byte getTypeCode() {
+ return 17;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+ @Getter
+ @Setter
+ public static class Segment {
+ byte type;
+ List<Integer> asns = new ArrayList<>();
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java
new file mode 100644
index 0000000..64be45b
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java
@@ -0,0 +1,40 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ASPathAttribute implements PathAttribute {
+
+ List<Segment> segments = new ArrayList<>();
+
+ public ASPathAttribute(byte typeCode, byte[] data) {
+ int offset = 0;
+ while (offset < data.length) {
+ Segment segment = new Segment().setType(data[offset]);
+ byte length = data[offset + 1];
+ for(int i=0; i<length; i++)
+ segment.asns.add(((data[offset + 2 + (i * 2)] & 0xFF) << 8) | (data[offset + 3 + (i * 2)] & 0xFF));
+ offset += 2 + (length * 2);
+ segments.add(segment);
+ }
+ }
+
+ public byte getTypeCode() {
+ return 2;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+ @Getter
+ @Setter
+ public static class Segment {
+ byte type;
+ List<Integer> asns = new ArrayList<>();
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathLimitAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathLimitAttribute.java
new file mode 100644
index 0000000..732b018
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathLimitAttribute.java
@@ -0,0 +1,29 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class ASPathLimitAttribute implements PathAttribute {
+
+ byte upperBound;
+ int as;
+
+ public ASPathLimitAttribute(byte typeCode, byte[] data) {
+ upperBound = data[0];
+ as = ((data[1] & 0xFF) << 24) |
+ ((data[2] & 0xFF) << 16) |
+ ((data[3] & 0xFF) << 8) |
+ (data[4] & 0xFF);
+ }
+
+ public byte getTypeCode() {
+ return 21;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/AggregatorAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/AggregatorAttribute.java
new file mode 100644
index 0000000..8a3dfdb
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/AggregatorAttribute.java
@@ -0,0 +1,27 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AggregatorAttribute implements PathAttribute {
+
+ int as;
+ byte[] origin;
+
+ public AggregatorAttribute(byte typeCode, byte[] data) {
+ as = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
+ origin = new byte[4];
+ System.arraycopy(data, 2, origin, 0, origin.length);
+ }
+
+ public byte getTypeCode() {
+ return 7;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/AtomicAggregateAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/AtomicAggregateAttribute.java
new file mode 100644
index 0000000..6f7e479
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/AtomicAggregateAttribute.java
@@ -0,0 +1,17 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+public class AtomicAggregateAttribute implements PathAttribute {
+
+ public AtomicAggregateAttribute(byte typeCode, byte[] data) {
+
+ }
+
+ public byte getTypeCode() {
+ return 6;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/CommunitiesAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/CommunitiesAttribute.java
new file mode 100644
index 0000000..7c7f060
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/CommunitiesAttribute.java
@@ -0,0 +1,41 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class CommunitiesAttribute implements PathAttribute {
+
+ List<Community> communities = new ArrayList<>();
+
+ public CommunitiesAttribute(byte typeCode, byte[] data) {
+ int offset = 0;
+ while (offset < data.length) {
+ communities.add(new Community()
+ .setValueA(((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF))
+ .setValueB(((data[offset + 2] & 0xFF) << 8) | (data[offset + 3] & 0xFF))
+ );
+ offset += 4;
+ }
+ }
+
+ public byte getTypeCode() {
+ return 8;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+ @Setter
+ @Getter
+ public static class Community {
+ int valueA;
+ int valueB;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/DevelopmentAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/DevelopmentAttribute.java
new file mode 100644
index 0000000..453f934
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/DevelopmentAttribute.java
@@ -0,0 +1,24 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DevelopmentAttribute implements PathAttribute {
+
+ byte[] data;
+
+ public DevelopmentAttribute(byte typeCode, byte[] data) {
+ this.data = data;
+ }
+
+ public byte[] build() {
+ return data;
+ }
+
+ public byte getTypeCode() {
+ return (byte) 255;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/ExtendedCommuntiesAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/ExtendedCommuntiesAttribute.java
new file mode 100644
index 0000000..759ae60
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/ExtendedCommuntiesAttribute.java
@@ -0,0 +1,33 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ExtendedCommuntiesAttribute implements PathAttribute {
+
+ byte type;
+ byte subType;
+ int as;
+ int an;
+
+ public ExtendedCommuntiesAttribute(byte typeCode, byte[] data) {
+ type = data[0];
+ subType = data[1];
+ as = ((data[2] & 0xFF) << 24) |
+ ((data[3] & 0xFF) << 16) |
+ ((data[4] & 0xFF) << 8) |
+ (data[5] & 0xFF);
+ an = ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
+ }
+
+ public byte getTypeCode() {
+ return 16;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/LargeCommunityAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/LargeCommunityAttribute.java
new file mode 100644
index 0000000..921d5a5
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/LargeCommunityAttribute.java
@@ -0,0 +1,56 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class LargeCommunityAttribute implements PathAttribute {
+
+ List<LargeCommunity> communities = new ArrayList<>();
+
+ public LargeCommunityAttribute(byte typeCode, byte[] data) {
+ for(int i=0; i<data.length; i+=12) {
+ communities.add(new LargeCommunity()
+ .setGlobalAdministrator(
+ ((data[i] & 0xFF) << 24) |
+ ((data[i+1] & 0xFF) << 16) |
+ ((data[i+2] & 0xFF) << 8) |
+ (data[i+3] & 0xFF)
+ )
+ .setLocalDataPart1(
+ ((data[i+4] & 0xFF) << 24) |
+ ((data[i+5] & 0xFF) << 16) |
+ ((data[i+6] & 0xFF) << 8) |
+ (data[i+7] & 0xFF)
+ )
+ .setLocalDataPart2(
+ ((data[i+8] & 0xFF) << 24) |
+ ((data[i+9] & 0xFF) << 16) |
+ ((data[i+10] & 0xFF) << 8) |
+ (data[i+11] & 0xFF)
+ )
+ );
+ }
+ }
+
+ public byte getTypeCode() {
+ return 32;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+ @Setter
+ @Getter
+ public static class LargeCommunity {
+ int globalAdministrator;
+ int localDataPart1;
+ int localDataPart2;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/NextHopAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/NextHopAttribute.java
new file mode 100644
index 0000000..f60d236
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/NextHopAttribute.java
@@ -0,0 +1,20 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+public class NextHopAttribute implements PathAttribute {
+
+ byte[] address;
+
+ public NextHopAttribute(byte typeCode, byte[] data) {
+ this.address = new byte[data.length];
+ System.arraycopy(data, 0, address, 0, address.length);
+ }
+
+ public byte getTypeCode() {
+ return 3;
+ }
+
+ public byte[] build() {
+ return address;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/OriginAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/OriginAttribute.java
new file mode 100644
index 0000000..2bf1208
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/OriginAttribute.java
@@ -0,0 +1,24 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class OriginAttribute implements PathAttribute {
+
+ byte origin;
+
+ public OriginAttribute(byte typeCode, byte[] data) {
+ origin = data[0];
+ }
+
+ public byte getTypeCode() {
+ return 1;
+ }
+
+ public byte[] build() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java
new file mode 100644
index 0000000..4a10daa
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java
@@ -0,0 +1,38 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+public interface PathAttribute {
+
+ byte getTypeCode();
+ byte[] build();
+
+ static PathAttribute from(byte typeCode, byte[] data) {
+ switch (typeCode & 0xFF) {
+ case 1:
+ return new OriginAttribute(typeCode, data);
+ case 2:
+ return new ASPathAttribute(typeCode, data);
+ case 3:
+ return new NextHopAttribute(typeCode, data);
+ case 6:
+ return new AtomicAggregateAttribute(typeCode, data);
+ case 7:
+ return new AggregatorAttribute(typeCode, data);
+ case 8:
+ return new CommunitiesAttribute(typeCode, data);
+ case 16:
+ return new ExtendedCommuntiesAttribute(typeCode, data);
+ case 17:
+ return new AS4PathAttribute(typeCode, data);
+ case 18:
+ return new AS4AggregatorAttribute(typeCode, data);
+ case 21:
+ return new ASPathLimitAttribute(typeCode, data);
+ case 32:
+ return new LargeCommunityAttribute(typeCode, data);
+ case 255:
+ return new DevelopmentAttribute(typeCode, data);
+ }
+ return new UnknownAttribute(typeCode, data);
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/UnknownAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/UnknownAttribute.java
new file mode 100644
index 0000000..9dbe0f9
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/UnknownAttribute.java
@@ -0,0 +1,23 @@
+package com.lumaserv.bgp.protocol.attribute;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Getter
+@Setter
+public class UnknownAttribute implements PathAttribute {
+
+ byte typeCode;
+ byte[] data;
+
+ public byte[] build() {
+ return data;
+ }
+
+ public byte getTypeCode() {
+ return typeCode;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/message/BGPNotification.java b/src/main/java/com/lumaserv/bgp/protocol/message/BGPNotification.java
new file mode 100644
index 0000000..54ee9bd
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/message/BGPNotification.java
@@ -0,0 +1,18 @@
+package com.lumaserv.bgp.protocol.message;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class BGPNotification {
+
+ byte majorErrorCode;
+ byte minorErrorCode;
+
+ public BGPNotification(byte[] message) {
+ this.majorErrorCode = message[0];
+ this.minorErrorCode = message[1];
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java b/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java
new file mode 100644
index 0000000..875f7bc
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java
@@ -0,0 +1,35 @@
+package com.lumaserv.bgp.protocol.message;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class BGPOpen {
+
+ byte version;
+ int asn;
+ int holdTime;
+ byte[] identifier;
+
+ public BGPOpen(byte[] message) {
+ version = message[0];
+ asn = ((message[1] & 0xFF) << 8) | (message[2] & 0xFF);
+ holdTime = ((message[3] & 0xFF) << 8) | (message[4] & 0xFF);
+ identifier = new byte[4];
+ }
+
+ public byte[] build() {
+ byte[] message = new byte[6 + identifier.length];
+ message[0] = version;
+ message[1] = (byte) (asn >> 8);
+ message[2] = (byte) (asn & 0xFF);
+ message[3] = (byte) (holdTime >> 8);
+ message[4] = (byte) (holdTime & 0xFF);
+ System.arraycopy(identifier, 0, message, 5, identifier.length);
+ return message;
+ }
+
+}
diff --git a/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java b/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java
new file mode 100644
index 0000000..fa23432
--- /dev/null
+++ b/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java
@@ -0,0 +1,63 @@
+package com.lumaserv.bgp.protocol.message;
+
+import com.lumaserv.bgp.protocol.IPPrefix;
+import com.lumaserv.bgp.protocol.attribute.PathAttribute;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class BGPUpdate {
+
+ List<IPPrefix> withdrawnPrefixes = new ArrayList<>();
+ List<PathAttribute> attributes = new ArrayList<>();
+ List<IPPrefix> prefixes = new ArrayList<>();
+
+ public BGPUpdate(byte[] message) {
+ int routesLength = ((message[0] & 0xFF) << 8) | (message[1] & 0xFF);
+ int offset = 2;
+ int offsetOffset = 2;
+ while ((offset - offsetOffset) < routesLength) {
+ IPPrefix prefix = new IPPrefix()
+ .setLength(message[offset])
+ .setAddress(new byte[4]);
+ offset++;
+ int addressLen = (int) Math.ceil(prefix.getLength() / 8d);
+ System.arraycopy(message, offset, prefix.getAddress(), 0, addressLen);
+ offset += addressLen;
+ withdrawnPrefixes.add(prefix);
+ }
+ int attributesLength = ((message[offset] & 0xFF) << 8) | (message[offset + 1] & 0xFF);
+ offset += 2;
+ offsetOffset = offset;
+ while ((offset - offsetOffset) < attributesLength) {
+ byte flags = message[offset];
+ byte typeCode = message[offset + 1];
+ int length = message[offset + 2] & 0xFF;
+ offset += 3;
+ if((flags & 0b0001_0000) > 0) {
+ length <<= 8;
+ length |= message[offset] & 0xFF;
+ offset++;
+ }
+ byte[] data = new byte[length];
+ System.arraycopy(message, offset, data, 0, length);
+ offset += length;
+ attributes.add(PathAttribute.from(typeCode, data));
+ }
+ while (offset < message.length) {
+ IPPrefix prefix = new IPPrefix()
+ .setLength(message[offset])
+ .setAddress(new byte[4]);
+ offset++;
+ int addressLen = (int) Math.ceil(prefix.getLength() / 8d);
+ System.arraycopy(message, offset, prefix.getAddress(), 0, addressLen);
+ offset += addressLen;
+ prefixes.add(prefix);
+ }
+ }
+
+}