Added ability to firewall (TCP/UDP) connections and to specify connection types (NOTHING, COMPRESS, COMPRESS_AND_ENCRYPT)
This commit is contained in:
parent
78d42e985a
commit
8010005323
|
@ -24,6 +24,7 @@ import dorkbox.network.connection.BootstrapWrapper;
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPoint;
|
||||||
import dorkbox.network.connection.EndPointClient;
|
import dorkbox.network.connection.EndPointClient;
|
||||||
|
import dorkbox.network.connection.RegistrationWrapperClient;
|
||||||
import dorkbox.network.connection.idle.IdleBridge;
|
import dorkbox.network.connection.idle.IdleBridge;
|
||||||
import dorkbox.network.connection.idle.IdleSender;
|
import dorkbox.network.connection.idle.IdleSender;
|
||||||
import dorkbox.network.connection.registration.local.RegistrationLocalHandlerClient;
|
import dorkbox.network.connection.registration.local.RegistrationLocalHandlerClient;
|
||||||
|
@ -150,7 +151,7 @@ class Client<C extends Connection> extends EndPointClient implements Connection
|
||||||
localBootstrap.group(newEventLoop(LOCAL, 1, threadName + "-JVM-BOSS"))
|
localBootstrap.group(newEventLoop(LOCAL, 1, threadName + "-JVM-BOSS"))
|
||||||
.channel(LocalChannel.class)
|
.channel(LocalChannel.class)
|
||||||
.remoteAddress(new LocalAddress(config.localChannelName))
|
.remoteAddress(new LocalAddress(config.localChannelName))
|
||||||
.handler(new RegistrationLocalHandlerClient(threadName, registrationWrapper));
|
.handler(new RegistrationLocalHandlerClient(threadName, (RegistrationWrapperClient) registrationWrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ class Client<C extends Connection> extends EndPointClient implements Connection
|
||||||
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
||||||
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
||||||
.remoteAddress(config.host, config.tcpPort)
|
.remoteAddress(config.host, config.tcpPort)
|
||||||
.handler(new RegistrationRemoteHandlerClientTCP(threadName, registrationWrapper, workerEventLoop));
|
.handler(new RegistrationRemoteHandlerClientTCP(threadName, (RegistrationWrapperClient) registrationWrapper, workerEventLoop));
|
||||||
|
|
||||||
// android screws up on this!!
|
// android screws up on this!!
|
||||||
tcpBootstrap.option(ChannelOption.TCP_NODELAY, !OS.isAndroid())
|
tcpBootstrap.option(ChannelOption.TCP_NODELAY, !OS.isAndroid())
|
||||||
|
@ -217,7 +218,7 @@ class Client<C extends Connection> extends EndPointClient implements Connection
|
||||||
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
||||||
.localAddress(new InetSocketAddress(0)) // bind to wildcard
|
.localAddress(new InetSocketAddress(0)) // bind to wildcard
|
||||||
.remoteAddress(new InetSocketAddress(config.host, config.udpPort))
|
.remoteAddress(new InetSocketAddress(config.host, config.udpPort))
|
||||||
.handler(new RegistrationRemoteHandlerClientUDP(threadName, registrationWrapper, workerEventLoop));
|
.handler(new RegistrationRemoteHandlerClientUDP(threadName, (RegistrationWrapperClient) registrationWrapper, workerEventLoop));
|
||||||
|
|
||||||
// Enable to READ and WRITE MULTICAST data (ie, 192.168.1.0)
|
// Enable to READ and WRITE MULTICAST data (ie, 192.168.1.0)
|
||||||
// in order to WRITE: write as normal, just make sure it ends in .255
|
// in order to WRITE: write as normal, just make sure it ends in .255
|
||||||
|
|
|
@ -19,11 +19,14 @@ import static dorkbox.network.pipeline.ConnectionType.LOCAL;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPoint;
|
||||||
import dorkbox.network.connection.EndPointServer;
|
import dorkbox.network.connection.EndPointServer;
|
||||||
|
import dorkbox.network.connection.RegistrationWrapperServer;
|
||||||
|
import dorkbox.network.connection.connectionType.ConnectionRule;
|
||||||
import dorkbox.network.connection.registration.local.RegistrationLocalHandlerServer;
|
import dorkbox.network.connection.registration.local.RegistrationLocalHandlerServer;
|
||||||
import dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerServerTCP;
|
import dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerServerTCP;
|
||||||
import dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerServerUDP;
|
import dorkbox.network.connection.registration.remote.RegistrationRemoteHandlerServerUDP;
|
||||||
|
@ -49,6 +52,10 @@ import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.channel.socket.oio.OioDatagramChannel;
|
import io.netty.channel.socket.oio.OioDatagramChannel;
|
||||||
import io.netty.channel.socket.oio.OioServerSocketChannel;
|
import io.netty.channel.socket.oio.OioServerSocketChannel;
|
||||||
|
import io.netty.handler.ipfilter.IpFilterRule;
|
||||||
|
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||||
|
import io.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||||
|
import io.netty.util.NetUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server can only be accessed in an ASYNC manner. This means that the server can only be used in RESPONSE to events. If you access the
|
* The server can only be accessed in an ASYNC manner. This means that the server can only be used in RESPONSE to events. If you access the
|
||||||
|
@ -59,6 +66,10 @@ import io.netty.channel.socket.oio.OioServerSocketChannel;
|
||||||
public
|
public
|
||||||
class Server<C extends Connection> extends EndPointServer {
|
class Server<C extends Connection> extends EndPointServer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that will always allow LOCALHOST to connect to the server. This is not added by default
|
||||||
|
*/
|
||||||
|
public static final IpFilterRule permitLocalHostRule = new IpSubnetFilterRule(NetUtil.LOCALHOST, 32, IpFilterRuleType.ACCEPT);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the version number.
|
* Gets the version number.
|
||||||
|
@ -158,7 +169,7 @@ class Server<C extends Connection> extends EndPointServer {
|
||||||
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
||||||
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFF_LOW, WRITE_BUFF_HIGH))
|
||||||
.localAddress(new LocalAddress(localChannelName))
|
.localAddress(new LocalAddress(localChannelName))
|
||||||
.childHandler(new RegistrationLocalHandlerServer(threadName, registrationWrapper));
|
.childHandler(new RegistrationLocalHandlerServer(threadName, (RegistrationWrapperServer) registrationWrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,7 +206,7 @@ class Server<C extends Connection> extends EndPointServer {
|
||||||
|
|
||||||
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
||||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||||
.childHandler(new RegistrationRemoteHandlerServerTCP(threadName, registrationWrapper, workerEventLoop));
|
.childHandler(new RegistrationRemoteHandlerServerTCP(threadName, (RegistrationWrapperServer) registrationWrapper, workerEventLoop));
|
||||||
|
|
||||||
// have to check options.host for "0.0.0.0". we don't bind to "0.0.0.0", we bind to "null" to get the "any" address!
|
// have to check options.host for "0.0.0.0". we don't bind to "0.0.0.0", we bind to "null" to get the "any" address!
|
||||||
if (hostName.equals("0.0.0.0")) {
|
if (hostName.equals("0.0.0.0")) {
|
||||||
|
@ -244,7 +255,7 @@ class Server<C extends Connection> extends EndPointServer {
|
||||||
// TODO: move broadcast to it's own handler, and have UDP server be able to be bound to a specific IP
|
// TODO: move broadcast to it's own handler, and have UDP server be able to be bound to a specific IP
|
||||||
// OF NOTE: At the end in my case I decided to bind to .255 broadcast address on Linux systems. (to receive broadcast packets)
|
// OF NOTE: At the end in my case I decided to bind to .255 broadcast address on Linux systems. (to receive broadcast packets)
|
||||||
.localAddress(udpPort) // if you bind to a specific interface, Linux will be unable to receive broadcast packets! see: http://developerweb.net/viewtopic.php?id=5722
|
.localAddress(udpPort) // if you bind to a specific interface, Linux will be unable to receive broadcast packets! see: http://developerweb.net/viewtopic.php?id=5722
|
||||||
.childHandler(new RegistrationRemoteHandlerServerUDP(threadName, registrationWrapper, workerEventLoop));
|
.childHandler(new RegistrationRemoteHandlerServerUDP(threadName, (RegistrationWrapperServer) registrationWrapper, workerEventLoop));
|
||||||
|
|
||||||
// // have to check options.host for null. we don't bind to 0.0.0.0, we bind to "null" to get the "any" address!
|
// // have to check options.host for null. we don't bind to 0.0.0.0, we bind to "null" to get the "any" address!
|
||||||
// if (hostName.equals("0.0.0.0")) {
|
// if (hostName.equals("0.0.0.0")) {
|
||||||
|
@ -365,6 +376,37 @@ class Server<C extends Connection> extends EndPointServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an IP+subnet rule that defines if that IP+subnet is allowed/denied connectivity to this server.
|
||||||
|
* <p>
|
||||||
|
* If there are any IP+subnet added to this list - then ONLY those are permitted (all else are denied)
|
||||||
|
* <p>
|
||||||
|
* If there is nothing added to this list - then ALL are permitted
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void addIpFilter(IpFilterRule... rules) {
|
||||||
|
ipFilterRules.addAll(Arrays.asList(rules));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an IP+subnet rule that defines what type of connection this IP+subnet should have.
|
||||||
|
* - NOTHING : Nothing happens to the in/out bytes
|
||||||
|
* - COMPRESS: The in/out bytes are compressed with LZ4-fast
|
||||||
|
* - COMPRESS_AND_ENCRYPT: The in/out bytes are compressed (LZ4-fast) THEN encrypted (AES-256-GCM)
|
||||||
|
*
|
||||||
|
* If no rules are defined, then for LOOPBACK, it will always be `COMPRESS` and for everything else it will always be `COMPRESS_AND_ENCRYPT`.
|
||||||
|
*
|
||||||
|
* If rules are defined, then everything by default is `COMPRESS_AND_ENCRYPT`.
|
||||||
|
*
|
||||||
|
* The compression algorithm is LZ4-fast, so there is a small performance impact for a very large gain
|
||||||
|
* Compress : 6.210 micros/op; 629.0 MB/s (output: 55.4%)
|
||||||
|
* Uncompress : 0.641 micros/op; 6097.9 MB/s
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void addConnectionTypeFilter(ConnectionRule... rules) {
|
||||||
|
connectionRules.addAll(Arrays.asList(rules));
|
||||||
|
}
|
||||||
|
|
||||||
// called when we are stopped/shut down
|
// called when we are stopped/shut down
|
||||||
@Override
|
@Override
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import dorkbox.network.Configuration;
|
import dorkbox.network.Configuration;
|
||||||
|
import dorkbox.network.Server;
|
||||||
import dorkbox.network.connection.bridge.ConnectionBridgeBase;
|
import dorkbox.network.connection.bridge.ConnectionBridgeBase;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.wrapper.ChannelLocalWrapper;
|
import dorkbox.network.connection.wrapper.ChannelLocalWrapper;
|
||||||
|
@ -214,8 +215,11 @@ class EndPoint extends Shutdownable {
|
||||||
// The registration wrapper permits the registration process to access protected/package fields/methods, that we don't want
|
// The registration wrapper permits the registration process to access protected/package fields/methods, that we don't want
|
||||||
// to expose to external code. "this" escaping can be ignored, because it is benign.
|
// to expose to external code. "this" escaping can be ignored, because it is benign.
|
||||||
//noinspection ThisEscapedInObjectConstruction
|
//noinspection ThisEscapedInObjectConstruction
|
||||||
registrationWrapper = new RegistrationWrapper(this,
|
if (type == Server.class) {
|
||||||
logger);
|
registrationWrapper = new RegistrationWrapperServer(this, logger);
|
||||||
|
} else {
|
||||||
|
registrationWrapper = new RegistrationWrapperClient(this, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// we have to be able to specify WHAT property store we want to use, since it can change!
|
// we have to be able to specify WHAT property store we want to use, since it can change!
|
||||||
|
|
|
@ -15,13 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package dorkbox.network.connection;
|
package dorkbox.network.connection;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import dorkbox.network.Configuration;
|
import dorkbox.network.Configuration;
|
||||||
import dorkbox.network.Server;
|
import dorkbox.network.Server;
|
||||||
import dorkbox.network.connection.bridge.ConnectionBridgeServer;
|
import dorkbox.network.connection.bridge.ConnectionBridgeServer;
|
||||||
import dorkbox.network.connection.registration.UpgradeType;
|
import dorkbox.network.connection.connectionType.ConnectionRule;
|
||||||
|
import dorkbox.network.connection.connectionType.ConnectionType;
|
||||||
import dorkbox.util.exceptions.SecurityException;
|
import dorkbox.util.exceptions.SecurityException;
|
||||||
|
import io.netty.handler.ipfilter.IpFilterRule;
|
||||||
|
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||||
|
import io.netty.util.NetUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This serves the purpose of making sure that specific methods are not available to the end user.
|
* This serves the purpose of making sure that specific methods are not available to the end user.
|
||||||
|
@ -29,6 +35,16 @@ import dorkbox.util.exceptions.SecurityException;
|
||||||
public
|
public
|
||||||
class EndPointServer extends EndPoint {
|
class EndPointServer extends EndPoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a thread-safe collection of rules to allow/deny connectivity to this server.
|
||||||
|
*/
|
||||||
|
protected final CopyOnWriteArrayList<IpFilterRule> ipFilterRules = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a thread-safe collection of rules used to define the connection type with this server.
|
||||||
|
*/
|
||||||
|
protected final CopyOnWriteArrayList<ConnectionRule> connectionRules = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
public
|
public
|
||||||
EndPointServer(final Configuration config) throws SecurityException {
|
EndPointServer(final Configuration config) throws SecurityException {
|
||||||
super(Server.class, config);
|
super(Server.class, config);
|
||||||
|
@ -108,8 +124,74 @@ class EndPointServer extends EndPoint {
|
||||||
connectionManager.removeConnection(connection);
|
connectionManager.removeConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void shutdownChannelsPre() {
|
||||||
|
// Sometimes there might be "lingering" connections (ie, halfway though registration) that need to be closed.
|
||||||
|
registrationWrapper.clearSessions();
|
||||||
|
|
||||||
|
// this calls connectionManager.stop()
|
||||||
|
super.shutdownChannelsPre();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no rules, then always yes
|
||||||
|
// if rules, then default no unless a rule says yes. ACCEPT rules take precedence over REJECT (so if you have both rules, ACCEPT will happen)
|
||||||
|
boolean acceptRemoteConnection(final InetSocketAddress remoteAddress) {
|
||||||
|
int size = ipFilterRules.size();
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress address = remoteAddress.getAddress();
|
||||||
|
|
||||||
|
// it's possible for a remote address to match MORE than 1 rule.
|
||||||
|
boolean isAllowed = false;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final IpFilterRule rule = ipFilterRules.get(i);
|
||||||
|
if (rule == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.matches(remoteAddress)) {
|
||||||
|
isAllowed = rule.ruleType() == IpFilterRuleType.ACCEPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Validating {} Connection allowed: {}", address, isAllowed);
|
||||||
|
return isAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// after the handshake, what sort of connection do we want (NONE, COMPRESS, ENCRYPT+COMPRESS)
|
||||||
byte getConnectionUpgradeType(final InetSocketAddress remoteAddress) {
|
byte getConnectionUpgradeType(final InetSocketAddress remoteAddress) {
|
||||||
// TODO, crypto/compression based on ip/range of remote address
|
InetAddress address = remoteAddress.getAddress();
|
||||||
return UpgradeType.ENCRYPT;
|
|
||||||
|
int size = connectionRules.size();
|
||||||
|
|
||||||
|
// if it's unknown, then by default we encrypt the traffic
|
||||||
|
ConnectionType connectionType = ConnectionType.COMPRESS_AND_ENCRYPT;
|
||||||
|
if (size == 0 && address.equals(NetUtil.LOCALHOST)) {
|
||||||
|
// if nothing is specified, then by default localhost is compression and everything else is encrypted
|
||||||
|
connectionType = ConnectionType.COMPRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final ConnectionRule rule = connectionRules.get(i);
|
||||||
|
if (rule == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.matches(remoteAddress)) {
|
||||||
|
connectionType = rule.ruleType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Validating {} Permitted type is: {}", remoteAddress, connectionType);
|
||||||
|
return connectionType.getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,7 +425,6 @@ class Shutdownable {
|
||||||
synchronized (shutdownInProgress) {
|
synchronized (shutdownInProgress) {
|
||||||
shutdownChannelsPre();
|
shutdownChannelsPre();
|
||||||
shutdownAllChannels();
|
shutdownAllChannels();
|
||||||
|
|
||||||
shutdownEventLoops();
|
shutdownEventLoops();
|
||||||
|
|
||||||
logger.info("Stopping endpoint.");
|
logger.info("Stopping endpoint.");
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package dorkbox.network.connection.connectionType;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import io.netty.util.internal.SocketUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class ConnectionRule {
|
||||||
|
|
||||||
|
private final IpConnectionTypeRule filterRule;
|
||||||
|
|
||||||
|
public
|
||||||
|
ConnectionRule(String ipAddress, int cidrPrefix, ConnectionType ruleType) {
|
||||||
|
try {
|
||||||
|
filterRule = selectFilterRule(SocketUtils.addressByName(ipAddress), cidrPrefix, ruleType);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new IllegalArgumentException("ipAddress", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
ConnectionRule(InetAddress ipAddress, int cidrPrefix, ConnectionType ruleType) {
|
||||||
|
filterRule = selectFilterRule(ipAddress, cidrPrefix, ruleType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
|
return filterRule.matches(remoteAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
ConnectionType ruleType() {
|
||||||
|
return filterRule.ruleType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static
|
||||||
|
IpConnectionTypeRule selectFilterRule(InetAddress ipAddress, int cidrPrefix, ConnectionType ruleType) {
|
||||||
|
if (ipAddress == null) {
|
||||||
|
throw new NullPointerException("ipAddress");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ruleType == null) {
|
||||||
|
throw new NullPointerException("ruleType");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipAddress instanceof Inet4Address) {
|
||||||
|
return new Ip4SubnetFilterRule((Inet4Address) ipAddress, cidrPrefix, ruleType);
|
||||||
|
} else if (ipAddress instanceof Inet6Address) {
|
||||||
|
return new Ip6SubnetFilterRule((Inet6Address) ipAddress, cidrPrefix, ruleType);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Ip4SubnetFilterRule implements IpConnectionTypeRule {
|
||||||
|
private final int networkAddress;
|
||||||
|
private final int subnetMask;
|
||||||
|
private final ConnectionType ruleType;
|
||||||
|
|
||||||
|
private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, ConnectionType ruleType) {
|
||||||
|
if (cidrPrefix < 0 || cidrPrefix > 32) {
|
||||||
|
throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of " +
|
||||||
|
"[0,32]. The prefix was: %d", cidrPrefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
subnetMask = prefixToSubnetMask(cidrPrefix);
|
||||||
|
networkAddress = ipToInt(ipAddress) & subnetMask;
|
||||||
|
this.ruleType = ruleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
|
final InetAddress inetAddress = remoteAddress.getAddress();
|
||||||
|
if (inetAddress instanceof Inet4Address) {
|
||||||
|
int ipAddress = ipToInt((Inet4Address) inetAddress);
|
||||||
|
return (ipAddress & subnetMask) == networkAddress;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConnectionType ruleType() {
|
||||||
|
return ruleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ipToInt(Inet4Address ipAddress) {
|
||||||
|
byte[] octets = ipAddress.getAddress();
|
||||||
|
assert octets.length == 4;
|
||||||
|
|
||||||
|
return (octets[0] & 0xff) << 24 |
|
||||||
|
(octets[1] & 0xff) << 16 |
|
||||||
|
(octets[2] & 0xff) << 8 |
|
||||||
|
octets[3] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int prefixToSubnetMask(int cidrPrefix) {
|
||||||
|
/**
|
||||||
|
* Perform the shift on a long and downcast it to int afterwards.
|
||||||
|
* This is necessary to handle a cidrPrefix of zero correctly.
|
||||||
|
* The left shift operator on an int only uses the five least
|
||||||
|
* significant bits of the right-hand operand. Thus -1 << 32 evaluates
|
||||||
|
* to -1 instead of 0. The left shift operator applied on a long
|
||||||
|
* uses the six least significant bits.
|
||||||
|
*
|
||||||
|
* Also see https://github.com/netty/netty/issues/2767
|
||||||
|
*/
|
||||||
|
return (int) ((-1L << 32 - cidrPrefix) & 0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Ip6SubnetFilterRule implements IpConnectionTypeRule {
|
||||||
|
private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
|
||||||
|
|
||||||
|
private final BigInteger networkAddress;
|
||||||
|
private final BigInteger subnetMask;
|
||||||
|
private final ConnectionType ruleType;
|
||||||
|
|
||||||
|
private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, ConnectionType ruleType) {
|
||||||
|
if (cidrPrefix < 0 || cidrPrefix > 128) {
|
||||||
|
throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of " +
|
||||||
|
"[0,128]. The prefix was: %d", cidrPrefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
subnetMask = prefixToSubnetMask(cidrPrefix);
|
||||||
|
networkAddress = ipToInt(ipAddress).and(subnetMask);
|
||||||
|
this.ruleType = ruleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
|
final InetAddress inetAddress = remoteAddress.getAddress();
|
||||||
|
if (inetAddress instanceof Inet6Address) {
|
||||||
|
BigInteger ipAddress = ipToInt((Inet6Address) inetAddress);
|
||||||
|
return ipAddress.and(subnetMask).equals(networkAddress);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConnectionType ruleType() {
|
||||||
|
return ruleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger ipToInt(Inet6Address ipAddress) {
|
||||||
|
byte[] octets = ipAddress.getAddress();
|
||||||
|
assert octets.length == 16;
|
||||||
|
|
||||||
|
return new BigInteger(octets);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger prefixToSubnetMask(int cidrPrefix) {
|
||||||
|
return MINUS_ONE.shiftLeft(128 - cidrPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package dorkbox.network.connection.connectionType;
|
||||||
|
|
||||||
|
import dorkbox.network.connection.registration.UpgradeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in {@link IpConnectionTypeRule} to decide what kind of connection a matching IP Address should have.
|
||||||
|
*/
|
||||||
|
public enum ConnectionType {
|
||||||
|
/**
|
||||||
|
* No compression, no encryption
|
||||||
|
*/
|
||||||
|
NOTHING(UpgradeType.NONE),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only compression
|
||||||
|
*/
|
||||||
|
COMPRESS(UpgradeType.COMPRESS),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compression + encryption
|
||||||
|
*/
|
||||||
|
COMPRESS_AND_ENCRYPT(UpgradeType.ENCRYPT)
|
||||||
|
;
|
||||||
|
|
||||||
|
private final byte type;
|
||||||
|
|
||||||
|
ConnectionType(byte type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
byte getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package dorkbox.network.connection.connectionType;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to create new rules.
|
||||||
|
*/
|
||||||
|
public interface IpConnectionTypeRule {
|
||||||
|
/**
|
||||||
|
* @return This method should return true if remoteAddress is valid according to your criteria. False otherwise.
|
||||||
|
*/
|
||||||
|
boolean matches(InetSocketAddress remoteAddress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return This method should return {@link IpFilterRuleType#ACCEPT} if all
|
||||||
|
* {@link IpConnectionTypeRule#matches(InetSocketAddress)} for which {@link #matches(InetSocketAddress)}
|
||||||
|
* returns true should the accepted. If you want to exclude all of those IP addresses then
|
||||||
|
* {@link IpFilterRuleType#REJECT} should be returned.
|
||||||
|
*/
|
||||||
|
ConnectionType ruleType();
|
||||||
|
}
|
|
@ -24,10 +24,10 @@ import io.netty.channel.EventLoopGroup;
|
||||||
|
|
||||||
@Sharable
|
@Sharable
|
||||||
public abstract
|
public abstract
|
||||||
class RegistrationHandler extends ChannelInboundHandlerAdapter {
|
class RegistrationHandler<T extends RegistrationWrapper> extends ChannelInboundHandlerAdapter {
|
||||||
protected static final String CONNECTION_HANDLER = "connection";
|
protected static final String CONNECTION_HANDLER = "connection";
|
||||||
|
|
||||||
protected final RegistrationWrapper registrationWrapper;
|
protected final T registrationWrapper;
|
||||||
protected final org.slf4j.Logger logger;
|
protected final org.slf4j.Logger logger;
|
||||||
protected final String name;
|
protected final String name;
|
||||||
protected final EventLoopGroup workerEventLoop;
|
protected final EventLoopGroup workerEventLoop;
|
||||||
|
@ -38,7 +38,7 @@ class RegistrationHandler extends ChannelInboundHandlerAdapter {
|
||||||
* @param workerEventLoop can be null for local JVM connections
|
* @param workerEventLoop can be null for local JVM connections
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
RegistrationHandler(final String name, RegistrationWrapper registrationWrapper, final EventLoopGroup workerEventLoop) {
|
RegistrationHandler(final String name, T registrationWrapper, final EventLoopGroup workerEventLoop) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.workerEventLoop = workerEventLoop;
|
this.workerEventLoop = workerEventLoop;
|
||||||
this.logger = org.slf4j.LoggerFactory.getLogger(this.name);
|
this.logger = org.slf4j.LoggerFactory.getLogger(this.name);
|
||||||
|
|
|
@ -23,28 +23,13 @@ import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
|
||||||
public abstract
|
public abstract
|
||||||
class RegistrationLocalHandler extends RegistrationHandler {
|
class RegistrationLocalHandler<T extends RegistrationWrapper> extends RegistrationHandler<T> {
|
||||||
public static final AttributeKey<MetaChannel> META_CHANNEL = AttributeKey.valueOf(RegistrationLocalHandler.class, "MetaChannel.local");
|
public static final AttributeKey<MetaChannel> META_CHANNEL = AttributeKey.valueOf(RegistrationLocalHandler.class, "MetaChannel.local");
|
||||||
|
|
||||||
RegistrationLocalHandler(String name, RegistrationWrapper registrationWrapper) {
|
RegistrationLocalHandler(String name, T registrationWrapper) {
|
||||||
super(name, registrationWrapper, null);
|
super(name, registrationWrapper, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* STEP 1: Channel is first created
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected
|
|
||||||
void initChannel(Channel channel) {
|
|
||||||
MetaChannel metaChannel = registrationWrapper.createSessionServer();
|
|
||||||
metaChannel.localChannel = channel;
|
|
||||||
|
|
||||||
channel.attr(META_CHANNEL)
|
|
||||||
.set(metaChannel);
|
|
||||||
|
|
||||||
logger.trace("New LOCAL connection.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void channelActive(final ChannelHandlerContext context) throws Exception {
|
void channelActive(final ChannelHandlerContext context) throws Exception {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
package dorkbox.network.connection.registration.local;
|
package dorkbox.network.connection.registration.local;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperClient;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -25,13 +25,28 @@ import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
|
||||||
public
|
public
|
||||||
class RegistrationLocalHandlerClient extends RegistrationLocalHandler {
|
class RegistrationLocalHandlerClient extends RegistrationLocalHandler<RegistrationWrapperClient> {
|
||||||
|
|
||||||
public
|
public
|
||||||
RegistrationLocalHandlerClient(String name, RegistrationWrapper registrationWrapper) {
|
RegistrationLocalHandlerClient(String name, RegistrationWrapperClient registrationWrapper) {
|
||||||
super(name, registrationWrapper);
|
super(name, registrationWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 1: Channel is first created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void initChannel(Channel channel) {
|
||||||
|
MetaChannel metaChannel = registrationWrapper.createSession(0);
|
||||||
|
metaChannel.localChannel = channel;
|
||||||
|
|
||||||
|
channel.attr(META_CHANNEL)
|
||||||
|
.set(metaChannel);
|
||||||
|
|
||||||
|
logger.trace("New LOCAL connection.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STEP 2: Channel is now active. Start the registration process
|
* STEP 2: Channel is now active. Start the registration process
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
package dorkbox.network.connection.registration.local;
|
package dorkbox.network.connection.registration.local;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
|
||||||
import dorkbox.network.connection.RegistrationWrapper.STATE;
|
import dorkbox.network.connection.RegistrationWrapper.STATE;
|
||||||
|
import dorkbox.network.connection.RegistrationWrapperServer;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -26,14 +26,29 @@ import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
|
||||||
public
|
public
|
||||||
class RegistrationLocalHandlerServer extends RegistrationLocalHandler {
|
class RegistrationLocalHandlerServer extends RegistrationLocalHandler<RegistrationWrapperServer> {
|
||||||
|
|
||||||
|
|
||||||
public
|
public
|
||||||
RegistrationLocalHandlerServer(String name, RegistrationWrapper registrationWrapper) {
|
RegistrationLocalHandlerServer(String name, RegistrationWrapperServer registrationWrapper) {
|
||||||
super(name, registrationWrapper);
|
super(name, registrationWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 1: Channel is first created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void initChannel(Channel channel) {
|
||||||
|
MetaChannel metaChannel = registrationWrapper.createSession();
|
||||||
|
metaChannel.localChannel = channel;
|
||||||
|
|
||||||
|
channel.attr(META_CHANNEL)
|
||||||
|
.set(metaChannel);
|
||||||
|
|
||||||
|
logger.trace("New LOCAL connection.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STEP 2: Channel is now active. Start the registration process (Client starts the process)
|
* STEP 2: Channel is now active. Start the registration process (Client starts the process)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,7 +34,6 @@ import dorkbox.network.pipeline.tcp.KryoDecoderTcp;
|
||||||
import dorkbox.network.pipeline.tcp.KryoDecoderTcpCompression;
|
import dorkbox.network.pipeline.tcp.KryoDecoderTcpCompression;
|
||||||
import dorkbox.network.pipeline.tcp.KryoDecoderTcpCrypto;
|
import dorkbox.network.pipeline.tcp.KryoDecoderTcpCrypto;
|
||||||
import dorkbox.network.pipeline.tcp.KryoDecoderTcpNone;
|
import dorkbox.network.pipeline.tcp.KryoDecoderTcpNone;
|
||||||
import dorkbox.network.serialization.NetworkSerializationManager;
|
|
||||||
import dorkbox.util.crypto.CryptoECC;
|
import dorkbox.util.crypto.CryptoECC;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
|
@ -51,7 +50,7 @@ import io.netty.util.concurrent.FutureListener;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
|
||||||
public abstract
|
public abstract
|
||||||
class RegistrationRemoteHandler extends RegistrationHandler {
|
class RegistrationRemoteHandler<T extends RegistrationWrapper> extends RegistrationHandler<T> {
|
||||||
static final AttributeKey<LinkedList> MESSAGES = AttributeKey.valueOf(RegistrationRemoteHandler.class, "messages");
|
static final AttributeKey<LinkedList> MESSAGES = AttributeKey.valueOf(RegistrationRemoteHandler.class, "messages");
|
||||||
|
|
||||||
static final String DELETE_IP = "eleteIP"; // purposefully missing the "D", since that is a system parameter, which starts with "-D"
|
static final String DELETE_IP = "eleteIP"; // purposefully missing the "D", since that is a system parameter, which starts with "-D"
|
||||||
|
@ -86,12 +85,8 @@ class RegistrationRemoteHandler extends RegistrationHandler {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected final NetworkSerializationManager serializationManager;
|
RegistrationRemoteHandler(final String name, final T registrationWrapper, final EventLoopGroup workerEventLoop) {
|
||||||
|
|
||||||
RegistrationRemoteHandler(final String name, final RegistrationWrapper registrationWrapper, final EventLoopGroup workerEventLoop) {
|
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
|
|
||||||
this.serializationManager = registrationWrapper.getSerialization();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,7 +107,7 @@ class RegistrationRemoteHandler extends RegistrationHandler {
|
||||||
///////////////////////
|
///////////////////////
|
||||||
// DECODE (or upstream)
|
// DECODE (or upstream)
|
||||||
///////////////////////
|
///////////////////////
|
||||||
pipeline.addFirst(TCP_DECODE, new KryoDecoderTcp(this.serializationManager)); // cannot be shared because of possible fragmentation.
|
pipeline.addFirst(TCP_DECODE, new KryoDecoderTcp(registrationWrapper.getSerialization())); // cannot be shared because of possible fragmentation.
|
||||||
}
|
}
|
||||||
else if (isUdpChannel) {
|
else if (isUdpChannel) {
|
||||||
// can be shared because there cannot be fragmentation for our UDP packets. If there is, we throw an error and continue...
|
// can be shared because there cannot be fragmentation for our UDP packets. If there is, we throw an error and continue...
|
||||||
|
@ -225,15 +220,15 @@ class RegistrationRemoteHandler extends RegistrationHandler {
|
||||||
// cannot be shared because of possible fragmentation.
|
// cannot be shared because of possible fragmentation.
|
||||||
switch (upgradeType) {
|
switch (upgradeType) {
|
||||||
case (UpgradeType.NONE) :
|
case (UpgradeType.NONE) :
|
||||||
pipeline.replace(TCP_DECODE, TCP_DECODE_NONE, new KryoDecoderTcpNone(this.serializationManager));
|
pipeline.replace(TCP_DECODE, TCP_DECODE_NONE, new KryoDecoderTcpNone(registrationWrapper.getSerialization()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (UpgradeType.COMPRESS) :
|
case (UpgradeType.COMPRESS) :
|
||||||
pipeline.replace(TCP_DECODE, TCP_DECODE_COMPRESS, new KryoDecoderTcpCompression(this.serializationManager));
|
pipeline.replace(TCP_DECODE, TCP_DECODE_COMPRESS, new KryoDecoderTcpCompression(registrationWrapper.getSerialization()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (UpgradeType.ENCRYPT) :
|
case (UpgradeType.ENCRYPT) :
|
||||||
pipeline.replace(TCP_DECODE, TCP_DECODE_CRYPTO, new KryoDecoderTcpCrypto(this.serializationManager));
|
pipeline.replace(TCP_DECODE, TCP_DECODE_CRYPTO, new KryoDecoderTcpCrypto(registrationWrapper.getSerialization()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unable to upgrade TCP connection pipeline for type: " + upgradeType);
|
throw new IllegalArgumentException("Unable to upgrade TCP connection pipeline for type: " + upgradeType);
|
||||||
|
|
|
@ -33,7 +33,7 @@ import com.esotericsoftware.kryo.io.Input;
|
||||||
import com.esotericsoftware.kryo.io.Output;
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperClient;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import dorkbox.util.crypto.CryptoECC;
|
import dorkbox.util.crypto.CryptoECC;
|
||||||
|
@ -44,9 +44,9 @@ import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
|
||||||
public
|
public
|
||||||
class RegistrationRemoteHandlerClient extends RegistrationRemoteHandler {
|
class RegistrationRemoteHandlerClient extends RegistrationRemoteHandler<RegistrationWrapperClient> {
|
||||||
|
|
||||||
RegistrationRemoteHandlerClient(final String name, final RegistrationWrapper registrationWrapper, final EventLoopGroup workerEventLoop) {
|
RegistrationRemoteHandlerClient(final String name, final RegistrationWrapperClient registrationWrapper, final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
|
|
||||||
// check to see if we need to delete an IP address as commanded from the user prompt
|
// check to see if we need to delete an IP address as commanded from the user prompt
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package dorkbox.network.connection.registration.remote;
|
package dorkbox.network.connection.registration.remote;
|
||||||
|
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperClient;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -26,7 +26,7 @@ public
|
||||||
class RegistrationRemoteHandlerClientTCP extends RegistrationRemoteHandlerClient {
|
class RegistrationRemoteHandlerClientTCP extends RegistrationRemoteHandlerClient {
|
||||||
public
|
public
|
||||||
RegistrationRemoteHandlerClientTCP(final String name,
|
RegistrationRemoteHandlerClientTCP(final String name,
|
||||||
final RegistrationWrapper registrationWrapper,
|
final RegistrationWrapperClient registrationWrapper,
|
||||||
final EventLoopGroup workerEventLoop) {
|
final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ class RegistrationRemoteHandlerClientTCP extends RegistrationRemoteHandlerClient
|
||||||
|
|
||||||
// TCP channel registration is ALWAYS first, so this is the correct way to do this.
|
// TCP channel registration is ALWAYS first, so this is the correct way to do this.
|
||||||
if (metaChannel == null) {
|
if (metaChannel == null) {
|
||||||
metaChannel = registrationWrapper.createSessionClient(sessionId);
|
metaChannel = registrationWrapper.createSession(sessionId);
|
||||||
metaChannel.tcpChannel = channel;
|
metaChannel.tcpChannel = channel;
|
||||||
|
|
||||||
logger.debug("New TCP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
logger.debug("New TCP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
||||||
|
|
|
@ -18,7 +18,7 @@ package dorkbox.network.connection.registration.remote;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperClient;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -30,7 +30,7 @@ public
|
||||||
class RegistrationRemoteHandlerClientUDP extends RegistrationRemoteHandlerClient {
|
class RegistrationRemoteHandlerClientUDP extends RegistrationRemoteHandlerClient {
|
||||||
public
|
public
|
||||||
RegistrationRemoteHandlerClientUDP(final String name,
|
RegistrationRemoteHandlerClientUDP(final String name,
|
||||||
final RegistrationWrapper registrationWrapper,
|
final RegistrationWrapperClient registrationWrapper,
|
||||||
final EventLoopGroup workerEventLoop) {
|
final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ class RegistrationRemoteHandlerClientUDP extends RegistrationRemoteHandlerClient
|
||||||
metaChannel = registrationWrapper.getSession(sessionId);
|
metaChannel = registrationWrapper.getSession(sessionId);
|
||||||
|
|
||||||
if (metaChannel == null) {
|
if (metaChannel == null) {
|
||||||
metaChannel = registrationWrapper.createSessionClient(sessionId);
|
metaChannel = registrationWrapper.createSession(sessionId);
|
||||||
|
|
||||||
logger.debug("New UDP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
logger.debug("New UDP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,9 @@ import com.esotericsoftware.kryo.KryoException;
|
||||||
import com.esotericsoftware.kryo.io.Input;
|
import com.esotericsoftware.kryo.io.Input;
|
||||||
import com.esotericsoftware.kryo.io.Output;
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.EndPoint;
|
||||||
import dorkbox.network.connection.RegistrationWrapper.STATE;
|
import dorkbox.network.connection.RegistrationWrapper.STATE;
|
||||||
|
import dorkbox.network.connection.RegistrationWrapperServer;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import dorkbox.util.crypto.CryptoECC;
|
import dorkbox.util.crypto.CryptoECC;
|
||||||
|
@ -47,7 +48,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
|
||||||
public
|
public
|
||||||
class RegistrationRemoteHandlerServer extends RegistrationRemoteHandler {
|
class RegistrationRemoteHandlerServer extends RegistrationRemoteHandler<RegistrationWrapperServer> {
|
||||||
private static final long ECDH_TIMEOUT = TimeUnit.MINUTES.toNanos(10L); // 10 minutes in nanoseconds
|
private static final long ECDH_TIMEOUT = TimeUnit.MINUTES.toNanos(10L); // 10 minutes in nanoseconds
|
||||||
|
|
||||||
private static final ECParameterSpec eccSpec = ECNamedCurveTable.getParameterSpec(CryptoECC.curve25519);
|
private static final ECParameterSpec eccSpec = ECNamedCurveTable.getParameterSpec(CryptoECC.curve25519);
|
||||||
|
@ -56,10 +57,31 @@ class RegistrationRemoteHandlerServer extends RegistrationRemoteHandler {
|
||||||
private volatile long ecdhTimeout = System.nanoTime();
|
private volatile long ecdhTimeout = System.nanoTime();
|
||||||
|
|
||||||
|
|
||||||
RegistrationRemoteHandlerServer(final String name, final RegistrationWrapper registrationWrapper, final EventLoopGroup workerEventLoop) {
|
RegistrationRemoteHandlerServer(final String name, final RegistrationWrapperServer registrationWrapper, final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 1: Channel is first created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void initChannel(final Channel channel) {
|
||||||
|
// check to see if this connection is permitted.
|
||||||
|
final InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
|
||||||
|
if (!registrationWrapper.acceptRemoteConnection(remoteAddress)) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
EndPoint.getHostDetails(stringBuilder, remoteAddress);
|
||||||
|
|
||||||
|
logger.error("Remote connection [{}] is not permitted! Aborting connection process.", stringBuilder.toString());
|
||||||
|
shutdown(channel, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.initChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the direction that traffic is going to this handler (" <== " or " ==> ")
|
* @return the direction that traffic is going to this handler (" <== " or " ==> ")
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
package dorkbox.network.connection.registration.remote;
|
package dorkbox.network.connection.registration.remote;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperServer;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -28,11 +28,13 @@ class RegistrationRemoteHandlerServerTCP extends RegistrationRemoteHandlerServer
|
||||||
|
|
||||||
public
|
public
|
||||||
RegistrationRemoteHandlerServerTCP(final String name,
|
RegistrationRemoteHandlerServerTCP(final String name,
|
||||||
final RegistrationWrapper registrationWrapper,
|
final RegistrationWrapperServer registrationWrapper,
|
||||||
final EventLoopGroup workerEventLoop) {
|
final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STEP 3-XXXXX: We pass registration messages around until we the registration handshake is complete!
|
* STEP 3-XXXXX: We pass registration messages around until we the registration handshake is complete!
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +51,7 @@ class RegistrationRemoteHandlerServerTCP extends RegistrationRemoteHandlerServer
|
||||||
MetaChannel metaChannel;
|
MetaChannel metaChannel;
|
||||||
int sessionId = registration.sessionID;
|
int sessionId = registration.sessionID;
|
||||||
if (sessionId == 0) {
|
if (sessionId == 0) {
|
||||||
metaChannel = registrationWrapper.createSessionServer();
|
metaChannel = registrationWrapper.createSession();
|
||||||
metaChannel.tcpChannel = channel;
|
metaChannel.tcpChannel = channel;
|
||||||
// TODO: use this: channel.voidPromise();
|
// TODO: use this: channel.voidPromise();
|
||||||
logger.debug("New TCP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
logger.debug("New TCP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
||||||
|
@ -70,8 +72,7 @@ class RegistrationRemoteHandlerServerTCP extends RegistrationRemoteHandlerServer
|
||||||
logger.error("Error registering TCP with remote client!");
|
logger.error("Error registering TCP with remote client!");
|
||||||
|
|
||||||
// this is what happens when the registration happens too quickly...
|
// this is what happens when the registration happens too quickly...
|
||||||
Object connection = context.pipeline()
|
Object connection = context.pipeline().last();
|
||||||
.last();
|
|
||||||
if (connection instanceof ConnectionImpl) {
|
if (connection instanceof ConnectionImpl) {
|
||||||
((ConnectionImpl) connection).channelRead(context, message);
|
((ConnectionImpl) connection).channelRead(context, message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
package dorkbox.network.connection.registration.remote;
|
package dorkbox.network.connection.registration.remote;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapperServer;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
@ -30,11 +30,14 @@ public
|
||||||
class RegistrationRemoteHandlerServerUDP extends RegistrationRemoteHandlerServer {
|
class RegistrationRemoteHandlerServerUDP extends RegistrationRemoteHandlerServer {
|
||||||
public
|
public
|
||||||
RegistrationRemoteHandlerServerUDP(final String name,
|
RegistrationRemoteHandlerServerUDP(final String name,
|
||||||
final RegistrationWrapper registrationWrapper,
|
final RegistrationWrapperServer registrationWrapper,
|
||||||
final EventLoopGroup workerEventLoop) {
|
final EventLoopGroup workerEventLoop) {
|
||||||
super(name, registrationWrapper, workerEventLoop);
|
super(name, registrationWrapper, workerEventLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 3-XXXXX: We pass registration messages around until we the registration handshake is complete!
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void channelRead(final ChannelHandlerContext context, Object message) throws Exception {
|
void channelRead(final ChannelHandlerContext context, Object message) throws Exception {
|
||||||
|
@ -47,7 +50,7 @@ class RegistrationRemoteHandlerServerUDP extends RegistrationRemoteHandlerServer
|
||||||
int sessionId = 0;
|
int sessionId = 0;
|
||||||
sessionId = registration.sessionID;
|
sessionId = registration.sessionID;
|
||||||
if (sessionId == 0) {
|
if (sessionId == 0) {
|
||||||
metaChannel = registrationWrapper.createSessionServer();
|
metaChannel = registrationWrapper.createSession();
|
||||||
metaChannel.udpChannel = channel;
|
metaChannel.udpChannel = channel;
|
||||||
logger.debug("New UDP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
logger.debug("New UDP connection. Saving meta-channel id: {}", metaChannel.sessionId);
|
||||||
}
|
}
|
||||||
|
@ -66,12 +69,15 @@ class RegistrationRemoteHandlerServerUDP extends RegistrationRemoteHandlerServer
|
||||||
|
|
||||||
readServer(context, channel, registration, "UDP server", metaChannel);
|
readServer(context, channel, registration, "UDP server", metaChannel);
|
||||||
}
|
}
|
||||||
else {
|
else if (message instanceof io.netty.channel.socket.DatagramPacket) {
|
||||||
logger.error("Error registering UDP with remote client!");
|
logger.error("Error registering UDP with remote client!");
|
||||||
|
shutdown(channel, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.error("Error registering UDP with remote client! Attempting to queue message: " + message.getClass());
|
||||||
|
|
||||||
// this is what happens when the registration happens too quickly...
|
// this is what happens when the registration happens too quickly...
|
||||||
Object connection = context.pipeline()
|
Object connection = context.pipeline().last();
|
||||||
.last();
|
|
||||||
if (connection instanceof ConnectionImpl) {
|
if (connection instanceof ConnectionImpl) {
|
||||||
((ConnectionImpl) connection).channelRead(context, message);
|
((ConnectionImpl) connection).channelRead(context, message);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user