From 4f4bd8d7bc49239a4ddbd4e39a523c0cc58c2e9b Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sun, 13 Mar 2022 23:28:53 +0100 Subject: Add collision detection --- src/main/java/com/lumaserv/bgp/BGPServer.java | 93 +++++++++++++++++++++++++- src/main/java/com/lumaserv/bgp/BGPSession.java | 40 +++++++++-- 2 files changed, 127 insertions(+), 6 deletions(-) (limited to 'src/main/java/com') diff --git a/src/main/java/com/lumaserv/bgp/BGPServer.java b/src/main/java/com/lumaserv/bgp/BGPServer.java index 80ec7ff..e95caea 100644 --- a/src/main/java/com/lumaserv/bgp/BGPServer.java +++ b/src/main/java/com/lumaserv/bgp/BGPServer.java @@ -1,6 +1,7 @@ package com.lumaserv.bgp; import com.lumaserv.bgp.protocol.BGPPacket; +import com.lumaserv.bgp.protocol.message.BGPNotification; import com.lumaserv.bgp.protocol.message.BGPOpen; import lombok.Getter; @@ -39,6 +40,77 @@ public class BGPServer implements Runnable { return true; } + public boolean hasCollided(BGPSession session, BGPOpen msg) { + for (BGPSession otherSession : sessions) { + BGPFsm fsm = otherSession.getFsm(); + BGPFsm.State state = fsm.getCurrentState(); + + // May examine OPEN_SENT + if (state == fsm.OPEN_SENT + && otherSession.getConfiguration() == null) + continue; + + // Cannot detect collision + if (state == fsm.IDLE + || state == fsm.CONNECT + || state == fsm.ACTIVE) + continue; + + // Detect collision + if (session.getInetAddress() != otherSession.getLocalAddress() + || session.getLocalAddress() != otherSession.getInetAddress()) + continue; + + // Collision! + if (state == fsm.ESTABLISHED) { + // Close new connection + sessions.remove(session); + return true; + } + + byte[] remoteIdentifier; + byte[] localIdentifier = session.getConfiguration() + .getLocalIdentifier(); + + if (state == fsm.OPEN_SENT) { + remoteIdentifier = otherSession.getConfiguration() + .getRemoteIdentifier(); + } else { // state == BGPFsm.OPEN_CONFIRM + remoteIdentifier = otherSession.getRemoteIdentifier(); + } + + boolean isLocalIdLess = false; + + // Compare integer stored in network byte order + for (int i=0; i < 4; i++) { + if (localIdentifier[i] < remoteIdentifier[i]) { + isLocalIdLess = true; + break; + } + } + + if (isLocalIdLess) { + // Close existing connection + BGPNotification notification = new BGPNotification() + .setMajorErrorCode(BGPNotification.Error.CEASE.getCode()); + try { + otherSession.sendNotification(notification); + } catch(IOException ex) { + } + sessions.remove(otherSession); + otherSession.dropConnection(); + // Accept new connection + return false; + } else { + // Close new connection + sessions.remove(session); + return true; + } + } + + return false; + } + public void run() { while (true) { try { @@ -57,7 +129,7 @@ public class BGPServer implements Runnable { } BGPFsm fsm = new BGPFsm(); - BGPSession session = new BGPSession(socket, config, fsm); + BGPSession session = new BGPSession(this, socket, config, fsm); fsm.setSession(session); sessions.add(session); System.out.println("automaticStartPassive"); @@ -66,6 +138,8 @@ public class BGPServer implements Runnable { // System.out.println("tcpConnectionConfirmed in " + fsm.getCurrentState()); // fsm.getCurrentState().tcpConnectionConfirmed(); } catch (IOException ex) { + if (serverSocket.isClosed()) + break; ex.printStackTrace(); } } @@ -76,9 +150,16 @@ public class BGPServer implements Runnable { } public boolean connect(BGPSessionConfiguration config, String host, int port) throws IOException { + for (BGPSession session : sessions) { + if (session.getConfiguration().equals(config)) { + // Already connected + return false; + } + } + try { BGPFsm fsm = new BGPFsm(); - BGPSession session = new BGPSession(config, fsm, host, port); + BGPSession session = new BGPSession(this, config, fsm, host, port); fsm.setSession(session); sessions.add(session); fsm.getCurrentState().automaticStart(); @@ -93,5 +174,13 @@ public class BGPServer implements Runnable { for(BGPSession session : sessions) { session.automaticStop(); } + sessions.clear(); + if (serverSocket != null) { + try { + serverSocket.close(); + } 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 index bb38ebf..e785e3b 100644 --- a/src/main/java/com/lumaserv/bgp/BGPSession.java +++ b/src/main/java/com/lumaserv/bgp/BGPSession.java @@ -11,12 +11,15 @@ import lombok.Getter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; public class BGPSession implements Runnable { + @Getter + final BGPServer server; @Getter final BGPSessionConfiguration configuration; final String host; @@ -27,13 +30,17 @@ public class BGPSession implements Runnable { @Getter boolean closed; boolean outgoing; + @Getter BGPFsm fsm; Thread thread; boolean isAdvAS4Capability; @Getter boolean isAS4Capability; + @Getter + byte[] remoteIdentifier; - public BGPSession(Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException { + public BGPSession(BGPServer server, Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException { + this.server = server; this.configuration = configuration; this.socket = socket; this.inputStream = socket.getInputStream(); @@ -43,13 +50,26 @@ public class BGPSession implements Runnable { this.port = -1; } - public BGPSession(BGPSessionConfiguration configuration, BGPFsm fsm, String host, int port) throws IOException { + public BGPSession(BGPServer server, BGPSessionConfiguration configuration, BGPFsm fsm, String host, int port) throws IOException { + this.server = server; this.configuration = configuration; this.fsm = fsm; this.host = host; this.port = port; } + public InetAddress getInetAddress() { + return socket.getInetAddress(); + } + + public InetAddress getLocalAddress() { + return socket.getLocalAddress(); + } + + protected void finalize() throws Throwable { + System.out.println("Finalize BGPSession"); + } + public void automaticStop() { fsm.getCurrentState().automaticStop(); } @@ -78,8 +98,20 @@ public class BGPSession implements Runnable { break; case OPEN: BGPOpen open = new BGPOpen(packet.getMessage()); - isAS4Capability = isAdvAS4Capability && open.getAS4Capability().isPresent(); - fsm.getCurrentState().openMsg(open); + if (server.hasCollided(this, open)) { + BGPNotification notification = new BGPNotification() + .setMajorErrorCode(BGPNotification.Error.CEASE.getCode()); + try { + sendNotification(notification); + } catch(IOException ex) { + } + dropConnection(); + // TODO Break links between fsm and session! + } else { + isAS4Capability = isAdvAS4Capability && open.getAS4Capability().isPresent(); + remoteIdentifier = open.getIdentifier(); + fsm.getCurrentState().openMsg(open); + } break; case UPDATE: { BGPUpdate update = new BGPUpdate(this, packet.getMessage()); -- cgit v1.2.3