summaryrefslogtreecommitdiff
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
Initial commit
-rw-r--r--.gitignore3
-rw-r--r--LICENSE201
-rw-r--r--README.md26
-rw-r--r--lombok.config3
-rw-r--r--pom.xml25
-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
28 files changed, 1078 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e5aa5b3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.idea
+*.iml
+target \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f49a4e1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f5b8172
--- /dev/null
+++ b/README.md
@@ -0,0 +1,26 @@
+# bgp-java
+BGP 4 Connector that can be used for network analysis.
+
+## Usage
+```java
+BGPServer server = new BGPServer();
+server.getSessionConfigurations().add(new BGPSessionConfiguration(
+ "demosession",
+ 1234,
+ ip("1.2.3.4"),
+ 4321,
+ ip("4.3.2.1"),
+ new BGPListener() {
+ public void onOpen(BGPSession session) {
+ // DO WHAT YOU WANT
+ }
+ public void onUpdate(BGPSession session, BGPUpdate update) {
+ // DO WHAT YOU WANT
+ }
+ public void onClose(BGPSession session) {
+ // NOT YET IMPLEMENTED
+ }
+ }
+));
+server.run();
+``` \ No newline at end of file
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 0000000..c075da7
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1,3 @@
+config.stopbubbling=true
+lombok.accessors.chain=true
+lombok.fielddefaults.defaultprivate=true \ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5a085ff
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,25 @@
+<?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>
+
+ <groupId>com.lumaserv</groupId>
+ <artifactId>bgp-java</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <maven.compiler.source>8</maven.compiler.source>
+ <maven.compiler.target>8</maven.compiler.target>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>1.18.16</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project> \ No newline at end of file
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);
+ }
+ }
+
+}