├── .idea ├── .name └── encodings.xml ├── VERSIONS ├── assets ├── TextLogo.png ├── TextLogo.psd ├── Dragonite-100.png ├── Dragonite-512.png └── Dragonite-64.png ├── dragonite-proxy ├── samples │ ├── sample-server-simple.json │ ├── sample-client-simple.json │ ├── sample-client-full.json │ └── sample-server-full.json ├── src │ └── main │ │ └── java │ │ └── com │ │ └── vecsight │ │ └── dragonite │ │ └── proxy │ │ ├── acl │ │ ├── ACLItemMethod.java │ │ ├── ACLItemType.java │ │ ├── item │ │ │ ├── ACLItem.java │ │ │ ├── DomainACLItem.java │ │ │ ├── DomainSuffixACLItem.java │ │ │ ├── IPv4ACLItem.java │ │ │ ├── IPv6ACLItem.java │ │ │ ├── IPv4CIDRACLItem.java │ │ │ └── IPv6CIDRACLItem.java │ │ └── ParsedACL.java │ │ ├── exception │ │ ├── ACLException.java │ │ ├── SOCKS5Exception.java │ │ ├── JSONConfigException.java │ │ ├── InvalidAddressException.java │ │ ├── ServerRejectedException.java │ │ └── IncorrectHeaderException.java │ │ ├── network │ │ ├── StreamPipe.java │ │ ├── MuxPipe.java │ │ ├── socks5 │ │ │ ├── SOCKS5Header.java │ │ │ └── SOCKS5SocketHelper.java │ │ └── server │ │ │ └── ProxyServer.java │ │ ├── header │ │ ├── AddressType.java │ │ ├── mux │ │ │ ├── ConnectionStatus.java │ │ │ ├── MuxConnectionResponseHeader.java │ │ │ └── MuxConnectionRequestHeader.java │ │ ├── ServerResponseHeader.java │ │ ├── udp │ │ │ ├── ProxyUDPRelayHeader.java │ │ │ └── SOCKS5UDPRelayHeader.java │ │ └── ClientInfoHeader.java │ │ ├── misc │ │ └── ProxyGlobalConstants.java │ │ └── config │ │ ├── ProxyServerConfig.java │ │ └── ProxyClientConfig.java └── build.gradle ├── benchmarks ├── TCPvsDragonite.png └── TCPvsDragonite.xlsx ├── dragonite-forwarder ├── diagram.png ├── src │ └── main │ │ └── java │ │ └── com │ │ └── vecsight │ │ └── dragonite │ │ └── forwarder │ │ ├── exception │ │ ├── IncorrectHeaderException.java │ │ └── ServerRejectedException.java │ │ ├── misc │ │ └── ForwarderGlobalConstants.java │ │ ├── network │ │ ├── Pipe.java │ │ └── server │ │ │ ├── ForwarderServer.java │ │ │ └── ForwarderMuxHandler.java │ │ ├── header │ │ ├── ServerResponseHeader.java │ │ └── ClientInfoHeader.java │ │ └── config │ │ ├── ForwarderClientConfig.java │ │ └── ForwarderServerConfig.java └── build.gradle ├── docs ├── Dragonite Protocol v2 (zh-CHS).docx └── Dragonite Protocol v2 (zh-CHS).pdf ├── WORKFLOW.md ├── docker-entrypoint.sh ├── Dockerfile ├── Dockerfile.alpine ├── docker-build.sh ├── dragonite-mux ├── src │ └── main │ │ └── java │ │ └── com │ │ └── vecsight │ │ └── dragonite │ │ └── mux │ │ ├── conn │ │ └── PacketSender.java │ │ ├── exception │ │ ├── IncorrectFrameException.java │ │ ├── MuxException.java │ │ ├── SenderClosedException.java │ │ ├── MultiplexerClosedException.java │ │ ├── ConnectionNotAliveException.java │ │ └── ConnectionAlreadyExistsException.java │ │ ├── frame │ │ ├── Frame.java │ │ ├── FrameType.java │ │ ├── FrameBuffer.java │ │ ├── FrameParser.java │ │ └── types │ │ │ ├── PauseConnectionFrame.java │ │ │ ├── CloseConnectionFrame.java │ │ │ ├── CreateConnectionFrame.java │ │ │ ├── ContinueConnectionFrame.java │ │ │ └── DataFrame.java │ │ └── misc │ │ └── MuxGlobalConstants.java └── build.gradle ├── settings.gradle ├── dragonite-sdk ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── vecsight │ │ │ └── dragonite │ │ │ └── sdk │ │ │ ├── msg │ │ │ ├── ReliableMessage.java │ │ │ ├── Message.java │ │ │ ├── MessageType.java │ │ │ ├── MessageParser.java │ │ │ └── types │ │ │ │ ├── HeartbeatMessage.java │ │ │ │ ├── CloseMessage.java │ │ │ │ ├── DataMessage.java │ │ │ │ └── ACKMessage.java │ │ │ ├── socket │ │ │ ├── PacketSender.java │ │ │ ├── ConnectionState.java │ │ │ ├── MessageStat.java │ │ │ ├── ResendItem.java │ │ │ ├── DragoniteSocket.java │ │ │ ├── BucketPacketSender.java │ │ │ ├── DragoniteSocketStatistics.java │ │ │ └── RTTEstimator.java │ │ │ ├── exception │ │ │ ├── EncryptionException.java │ │ │ ├── IncorrectSizeException.java │ │ │ ├── IncorrectMessageException.java │ │ │ ├── DragoniteException.java │ │ │ ├── SenderClosedException.java │ │ │ └── ConnectionNotAliveException.java │ │ │ ├── web │ │ │ ├── StatisticsProvider.java │ │ │ └── DevConsoleWebServer.java │ │ │ ├── misc │ │ │ ├── NumUtils.java │ │ │ ├── PerfStopWatch.java │ │ │ └── DragoniteGlobalConstants.java │ │ │ ├── cryptor │ │ │ ├── PacketCryptor.java │ │ │ ├── SimpleXORCryptor.java │ │ │ └── AESCryptor.java │ │ │ └── config │ │ │ └── DragoniteSocketParameters.java │ └── test │ │ └── java │ │ ├── DragoniteSocketTest.java │ │ └── MessageTest.java └── build.gradle ├── dragonite-utils ├── src │ └── main │ │ └── java │ │ └── com │ │ └── vecsight │ │ └── dragonite │ │ └── utils │ │ ├── misc │ │ ├── UtilsGlobalConstants.java │ │ └── UpdateChecker.java │ │ ├── type │ │ └── UnitConverter.java │ │ ├── flow │ │ └── Preconditions.java │ │ ├── network │ │ └── FileUtils.java │ │ ├── system │ │ └── SystemInfo.java │ │ └── binary │ │ ├── BinaryReader.java │ │ └── BinaryWriter.java └── build.gradle ├── dragonite-echo ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── vecsight │ └── dragonite │ └── echo │ └── EchoMain.java ├── README.md ├── .travis.yml └── CHANGELOG.md /.idea/.name: -------------------------------------------------------------------------------- 1 | dragonite -------------------------------------------------------------------------------- /VERSIONS: -------------------------------------------------------------------------------- 1 | forwarder-0.4.0 2 | proxy-0.4.0 -------------------------------------------------------------------------------- /assets/TextLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/assets/TextLogo.png -------------------------------------------------------------------------------- /assets/TextLogo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/assets/TextLogo.psd -------------------------------------------------------------------------------- /dragonite-proxy/samples/sample-server-simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": true, 3 | "password": "LoveSatania" 4 | } -------------------------------------------------------------------------------- /assets/Dragonite-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/assets/Dragonite-100.png -------------------------------------------------------------------------------- /assets/Dragonite-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/assets/Dragonite-512.png -------------------------------------------------------------------------------- /assets/Dragonite-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/assets/Dragonite-64.png -------------------------------------------------------------------------------- /benchmarks/TCPvsDragonite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/benchmarks/TCPvsDragonite.png -------------------------------------------------------------------------------- /benchmarks/TCPvsDragonite.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/benchmarks/TCPvsDragonite.xlsx -------------------------------------------------------------------------------- /dragonite-forwarder/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/dragonite-forwarder/diagram.png -------------------------------------------------------------------------------- /docs/Dragonite Protocol v2 (zh-CHS).docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/docs/Dragonite Protocol v2 (zh-CHS).docx -------------------------------------------------------------------------------- /docs/Dragonite Protocol v2 (zh-CHS).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonite-network/dragonite-java/HEAD/docs/Dragonite Protocol v2 (zh-CHS).pdf -------------------------------------------------------------------------------- /dragonite-proxy/samples/sample-client-simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "addr": "example.com", 3 | "password": "LoveSatania", 4 | "up": 5, 5 | "down": 5 6 | } -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /WORKFLOW.md: -------------------------------------------------------------------------------- 1 | # To release a new version: 2 | - Update the code 3 | - Change "version" in build.gradle 4 | - Update the CHANGELOG.md 5 | - Change "Current status" in Wiki 6 | - Update VERSIONS 7 | - Commit 8 | - distReleaseZip -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | target="`find . -name \"dragonite-$1\"`" 4 | 5 | if [ "$target" = "" ]; then 6 | echo "no such tool 'dragonite-$1'" >&2 7 | exit 1 8 | fi 9 | 10 | shift 1 11 | 12 | $target "$@" 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:slim 2 | 3 | EXPOSE 5233/udp 5234/udp 1080/tcp 4 | 5 | WORKDIR /code 6 | 7 | ADD docker-entrypoint.sh ./ 8 | ADD dragonite-*/build/distributions/*.tar ./ 9 | 10 | ENTRYPOINT [ "/bin/bash", "docker-entrypoint.sh" ] 11 | -------------------------------------------------------------------------------- /Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM openjdk:alpine 2 | 3 | EXPOSE 5233/udp 5234/udp 1080/tcp 4 | 5 | WORKDIR /code 6 | 7 | ADD docker-entrypoint.sh ./ 8 | ADD dragonite-*/build/distributions/*.tar ./ 9 | 10 | ENTRYPOINT [ "/bin/sh", "docker-entrypoint.sh" ] 11 | -------------------------------------------------------------------------------- /docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REPO='dragonitenetwork/dragonite-java' 4 | 5 | docker login -u $DOCKER_USER -p $DOCKER_PASS 6 | docker build . -f Dockerfile -t $REPO 7 | docker build . -f Dockerfile.alpine -t $REPO:alpine 8 | docker tag $REPO $REPO:$TRAVIS_TAG 9 | docker tag $REPO:alpine $REPO:$TRAVIS_TAG-alpine 10 | docker push $REPO 11 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/conn/PacketSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.conn; 9 | 10 | public interface PacketSender { 11 | 12 | void sendPacket(byte[] bytes); 13 | 14 | } -------------------------------------------------------------------------------- /dragonite-proxy/samples/sample-client-full.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": false, 3 | "addr": "example.com", 4 | "port": 9225, 5 | "socks5port": 1080, 6 | "password": "blahblah", 7 | "up": 5, 8 | "down": 5, 9 | "acl": "chn.txt", 10 | "mtu": 1300, 11 | "multiplier": 4, 12 | "dscp": 0, 13 | "webpanel": true, 14 | "paneladdr": "127.0.0.1", 15 | "panelport": 8088 16 | } -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/ACLItemMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl; 9 | 10 | public enum ACLItemMethod { 11 | DIRECT, 12 | PROXY, 13 | REJECT 14 | } 15 | -------------------------------------------------------------------------------- /dragonite-proxy/samples/sample-server-full.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": true, 3 | "addr": "example.com", 4 | "port": 9225, 5 | "password": "blahblah", 6 | "limit": 100, 7 | "welcome": "Sample server config", 8 | "loopback": false, 9 | "mtu": 1300, 10 | "multiplier": 4, 11 | "dscp": 0, 12 | "webpanel": true, 13 | "paneladdr": "127.0.0.1", 14 | "panelport": 8088 15 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | rootProject.name = 'dragonite' 10 | 11 | include 'dragonite-sdk' 12 | include 'dragonite-mux' 13 | include 'dragonite-forwarder' 14 | include 'dragonite-echo' 15 | include 'dragonite-utils' 16 | include 'dragonite-proxy' 17 | 18 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/ACLItemType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl; 9 | 10 | public enum ACLItemType { 11 | DOMAIN, 12 | DOMAIN_SUFFIX, 13 | IPv4, 14 | IPv4_CIDR, 15 | IPv6, 16 | IPv6_CIDR 17 | } 18 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/ReliableMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg; 9 | 10 | public interface ReliableMessage extends Message { 11 | 12 | int getSequence(); 13 | 14 | void setSequence(int sequence); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/ACLException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class ACLException extends Exception { 11 | 12 | public ACLException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/SOCKS5Exception.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class SOCKS5Exception extends Exception { 11 | 12 | public SOCKS5Exception(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg; 9 | 10 | public interface Message { 11 | 12 | byte getVersion(); 13 | 14 | MessageType getType(); 15 | 16 | byte[] toBytes(); 17 | 18 | int getFixedLength(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/PacketSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import java.io.IOException; 11 | 12 | public interface PacketSender { 13 | 14 | void sendPacket(byte[] bytes) throws InterruptedException, IOException; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/EncryptionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class EncryptionException extends Exception { 11 | 12 | public EncryptionException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/JSONConfigException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class JSONConfigException extends Exception { 11 | 12 | public JSONConfigException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/IncorrectFrameException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class IncorrectFrameException extends MuxException { 11 | 12 | public IncorrectFrameException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/InvalidAddressException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class InvalidAddressException extends Exception { 11 | 12 | public InvalidAddressException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/ServerRejectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class ServerRejectedException extends Exception { 11 | 12 | public ServerRejectedException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/IncorrectSizeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class IncorrectSizeException extends DragoniteException { 11 | 12 | public IncorrectSizeException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/IncorrectHeaderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.exception; 9 | 10 | public class IncorrectHeaderException extends Exception { 11 | 12 | public IncorrectHeaderException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/IncorrectMessageException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class IncorrectMessageException extends DragoniteException { 11 | 12 | public IncorrectMessageException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/exception/IncorrectHeaderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.exception; 9 | 10 | public class IncorrectHeaderException extends Exception { 11 | 12 | public IncorrectHeaderException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/exception/ServerRejectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.exception; 9 | 10 | public class ServerRejectedException extends Exception { 11 | 12 | public ServerRejectedException(final String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/Frame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame; 9 | 10 | public interface Frame { 11 | 12 | byte getVersion(); 13 | 14 | FrameType getType(); 15 | 16 | byte[] toBytes(); 17 | 18 | int getFixedLength(); 19 | 20 | int getExpectedLength(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/misc/UtilsGlobalConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.misc; 9 | 10 | import com.vecsight.dragonite.UtilsBuildConfig; 11 | 12 | public final class UtilsGlobalConstants { 13 | 14 | public static final String LIBRARY_VERSION = UtilsBuildConfig.VERSION; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/web/StatisticsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.web; 9 | 10 | import com.vecsight.dragonite.sdk.socket.DragoniteSocketStatistics; 11 | 12 | import java.util.List; 13 | 14 | public interface StatisticsProvider { 15 | 16 | List getLatest(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/MuxException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class MuxException extends Exception { 11 | 12 | public MuxException() { 13 | super(); 14 | } 15 | 16 | public MuxException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-echo/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | group 'com.vecsight.dragonite' 10 | version '0.1.0' 11 | 12 | apply plugin: 'java' 13 | apply plugin: 'application' 14 | 15 | sourceCompatibility = 1.8 16 | 17 | mainClassName = 'com.vecsight.dragonite.echo.EchoMain' 18 | 19 | repositories { 20 | jcenter() 21 | } 22 | 23 | dependencies { 24 | compile project(':dragonite-sdk') 25 | } 26 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/DragoniteException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class DragoniteException extends Exception { 11 | 12 | public DragoniteException() { 13 | super(); 14 | } 15 | 16 | public DragoniteException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-utils/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | plugins { 10 | id 'de.fuerstenau.buildconfig' version '1.1.8' 11 | } 12 | 13 | group 'com.vecsight.dragonite' 14 | version '0.1.0' 15 | 16 | apply plugin: 'java-library' 17 | apply plugin: 'java-library-distribution' 18 | apply plugin: 'idea' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | buildConfig { 23 | clsName = 'UtilsBuildConfig' 24 | } -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/SenderClosedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class SenderClosedException extends MuxException { 11 | 12 | public SenderClosedException() { 13 | super("Sender closed"); 14 | } 15 | 16 | public SenderClosedException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/SenderClosedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class SenderClosedException extends DragoniteException { 11 | 12 | public SenderClosedException() { 13 | super("Sender closed"); 14 | } 15 | 16 | public SenderClosedException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/MultiplexerClosedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class MultiplexerClosedException extends MuxException { 11 | 12 | public MultiplexerClosedException() { 13 | super("Multiplexer closed"); 14 | } 15 | 16 | public MultiplexerClosedException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionNotAliveException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class ConnectionNotAliveException extends MuxException { 11 | 12 | public ConnectionNotAliveException() { 13 | super("Connection is not alive"); 14 | } 15 | 16 | public ConnectionNotAliveException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/ConnectionNotAliveException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.exception; 9 | 10 | public class ConnectionNotAliveException extends DragoniteException { 11 | 12 | public ConnectionNotAliveException() { 13 | super("Connection is not alive"); 14 | } 15 | 16 | public ConnectionNotAliveException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.exception; 9 | 10 | public class ConnectionAlreadyExistsException extends MuxException { 11 | 12 | public ConnectionAlreadyExistsException() { 13 | super("Connection already exists"); 14 | } 15 | 16 | public ConnectionAlreadyExistsException(final String msg) { 17 | super(msg); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/misc/MuxGlobalConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.misc; 9 | 10 | 11 | import com.vecsight.dragonite.MuxBuildConfig; 12 | 13 | public final class MuxGlobalConstants { 14 | 15 | public static final String LIBRARY_VERSION = MuxBuildConfig.VERSION; 16 | 17 | public static final byte PROTOCOL_VERSION = 2; 18 | 19 | public static final int CONNECTION_MAX_DATA_BUFFER_SIZE = 1048576; //1M 20 | 21 | } 22 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/type/UnitConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.type; 9 | 10 | public final class UnitConverter { 11 | 12 | public static long mbpsToSpeed(final int mbps) { 13 | return mbps * 125000L; 14 | } 15 | 16 | public static int speedToMbps(final long speed) { 17 | return (int) (speed / 125000); 18 | } 19 | 20 | public static int DSCPtoTrafficClass(final int dscp) { 21 | return dscp << 2; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /dragonite-mux/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | plugins { 10 | id 'de.fuerstenau.buildconfig' version '1.1.8' 11 | } 12 | 13 | group 'com.vecsight.dragonite' 14 | version '0.3.0' 15 | 16 | apply plugin: 'java-library' 17 | apply plugin: 'java-library-distribution' 18 | apply plugin: 'idea' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | repositories { 23 | jcenter() 24 | } 25 | 26 | dependencies { 27 | compile project(':dragonite-utils') 28 | compile 'com.github:bucket4j:1.3.0' 29 | } 30 | 31 | buildConfig { 32 | clsName = 'MuxBuildConfig' 33 | } -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/ACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | 13 | public interface ACLItem { 14 | 15 | ACLItemType getType(); 16 | 17 | ACLItemMethod getMethod(); 18 | 19 | boolean match(final byte[] address); 20 | 21 | //DO NOT resolve and match with hostname's IPs!!! Just return false if it's an IP address item 22 | boolean match(final String domain); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /dragonite-sdk/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | plugins { 10 | id 'de.fuerstenau.buildconfig' version '1.1.8' 11 | } 12 | 13 | group 'com.vecsight.dragonite' 14 | version '0.3.4' 15 | 16 | apply plugin: 'java-library' 17 | apply plugin: 'java-library-distribution' 18 | apply plugin: 'idea' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | repositories { 23 | jcenter() 24 | } 25 | 26 | dependencies { 27 | compile project(':dragonite-utils') 28 | compile 'com.github:bucket4j:1.3.0' 29 | testCompile 'junit:junit:4.12' 30 | } 31 | 32 | buildConfig { 33 | clsName = 'DragoniteBuildConfig' 34 | } -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/flow/Preconditions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.flow; 9 | 10 | public final class Preconditions { 11 | 12 | public static void checkArgument(final boolean ok, final String message) { 13 | if (!ok) throw new IllegalArgumentException(message); 14 | } 15 | 16 | public static boolean inPortRange(final int port) { 17 | return port > 0 && port <= 65535; 18 | } 19 | 20 | public static boolean inTrafficClassRange(final int trafficClass) { 21 | return trafficClass >= 0 && trafficClass <= 255; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/misc/NumUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.misc; 9 | 10 | public final class NumUtils { 11 | 12 | public static long min(final long l1, final long l2) { 13 | return l1 < l2 ? l1 : l2; 14 | } 15 | 16 | public static long max(final long l1, final long l2) { 17 | return l1 > l2 ? l1 : l2; 18 | } 19 | 20 | public static int min(final int i1, final int i2) { 21 | return i1 < i2 ? i1 : i2; 22 | } 23 | 24 | public static int max(final int i1, final int i2) { 25 | return i1 > i2 ? i1 : i2; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/StreamPipe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.network; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.OutputStream; 13 | 14 | public class StreamPipe { 15 | 16 | private final short bufferSize; 17 | 18 | public StreamPipe(final short bufferSize) { 19 | this.bufferSize = bufferSize; 20 | } 21 | 22 | public void pipe(final InputStream inputStream, final OutputStream outputStream) throws IOException { 23 | int len; 24 | final byte[] buf = new byte[bufferSize]; 25 | while ((len = inputStream.read(buf)) > 0) { 26 | outputStream.write(buf, 0, len); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/network/FileUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.network; 9 | 10 | import java.io.FileReader; 11 | import java.io.IOException; 12 | import java.io.InputStreamReader; 13 | import java.io.Reader; 14 | import java.net.URL; 15 | 16 | public final class FileUtils { 17 | 18 | public static Reader pathToReader(final String path) throws IOException { 19 | final String loweredPath = path.toLowerCase(); 20 | final Reader reader; 21 | if (loweredPath.startsWith("http://") || loweredPath.startsWith("https://")) { 22 | reader = new InputStreamReader(new URL(path).openStream()); 23 | } else { 24 | reader = new FileReader(path); 25 | } 26 | return reader; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /dragonite-forwarder/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | plugins { 10 | id 'de.fuerstenau.buildconfig' version '1.1.8' 11 | } 12 | 13 | group 'com.vecsight.dragonite' 14 | version '0.4.0' 15 | 16 | apply plugin: 'java' 17 | apply plugin: 'application' 18 | apply plugin: 'idea' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | mainClassName = 'com.vecsight.dragonite.forwarder.CLIMain' 23 | 24 | repositories { 25 | mavenCentral() 26 | jcenter() 27 | } 28 | 29 | dependencies { 30 | compile project(':dragonite-sdk') 31 | compile project(':dragonite-mux') 32 | compile project(':dragonite-utils') 33 | compile group: 'org.tinylog', name: 'tinylog', version: '1.2' 34 | compile group: 'commons-cli', name: 'commons-cli', version: '1.4' 35 | } 36 | 37 | buildConfig { 38 | clsName = 'ForwarderBuildConfig' 39 | } -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/AddressType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header; 9 | 10 | public enum AddressType { 11 | IPv4((byte) 0), 12 | IPv6((byte) 1), 13 | DOMAIN((byte) 2); 14 | 15 | private final byte value; 16 | 17 | AddressType(final byte value) { 18 | this.value = value; 19 | } 20 | 21 | public byte getValue() { 22 | return value; 23 | } 24 | 25 | private static final AddressType[] types = AddressType.values(); 26 | 27 | public static AddressType fromByte(final byte type) { 28 | try { 29 | return types[type]; 30 | } catch (final ArrayIndexOutOfBoundsException e) { 31 | throw new IllegalArgumentException("Type byte " + type + " not found"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/MessageType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg; 9 | 10 | public enum MessageType { 11 | DATA((byte) 0), 12 | CLOSE((byte) 1), 13 | ACK((byte) 2), 14 | HEARTBEAT((byte) 3); 15 | 16 | private final byte value; 17 | 18 | MessageType(final byte value) { 19 | this.value = value; 20 | } 21 | 22 | public byte getValue() { 23 | return value; 24 | } 25 | 26 | private static final MessageType[] types = MessageType.values(); 27 | 28 | public static MessageType fromByte(final byte type) { 29 | try { 30 | return types[type]; 31 | } catch (final ArrayIndexOutOfBoundsException e) { 32 | throw new IllegalArgumentException("Type byte " + type + " not found"); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/mux/ConnectionStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header.mux; 9 | 10 | public enum ConnectionStatus { 11 | OK((byte) 0), 12 | ERROR((byte) 1), 13 | REJECTED((byte) 2); 14 | 15 | private final byte value; 16 | 17 | ConnectionStatus(final byte value) { 18 | this.value = value; 19 | } 20 | 21 | public byte getValue() { 22 | return value; 23 | } 24 | 25 | private static final ConnectionStatus[] types = ConnectionStatus.values(); 26 | 27 | public static ConnectionStatus fromByte(final byte type) { 28 | try { 29 | return types[type]; 30 | } catch (final ArrayIndexOutOfBoundsException e) { 31 | throw new IllegalArgumentException("Type byte " + type + " not found"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame; 9 | 10 | public enum FrameType { 11 | CREATE((byte) 0), 12 | DATA((byte) 1), 13 | CLOSE((byte) 2), 14 | PAUSE((byte) 3), 15 | CONTINUE((byte) 4); 16 | 17 | private final byte value; 18 | 19 | FrameType(final byte value) { 20 | this.value = value; 21 | } 22 | 23 | public byte getValue() { 24 | return value; 25 | } 26 | 27 | private static final FrameType[] types = FrameType.values(); 28 | 29 | public static FrameType fromByte(final byte type) { 30 | try { 31 | return types[type]; 32 | } catch (final ArrayIndexOutOfBoundsException e) { 33 | throw new IllegalArgumentException("Type byte " + type + " not found"); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameBuffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame; 9 | 10 | import java.util.Arrays; 11 | 12 | public class FrameBuffer { 13 | 14 | private final byte[] bytesBuffer; 15 | 16 | private int position = 0; 17 | 18 | public FrameBuffer(final int maxSize) { 19 | bytesBuffer = new byte[maxSize]; 20 | } 21 | 22 | public void add(final byte[] bytes) { 23 | System.arraycopy(bytes, 0, bytesBuffer, position, bytes.length); 24 | position += bytes.length; 25 | } 26 | 27 | public byte[] get() { 28 | return Arrays.copyOf(bytesBuffer, position); 29 | } 30 | 31 | public void reset() { 32 | position = 0; 33 | } 34 | 35 | public int getSize() { 36 | return position; 37 | } 38 | 39 | public int getMaxSize() { 40 | return bytesBuffer.length; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /dragonite-proxy/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | 9 | plugins { 10 | id 'de.fuerstenau.buildconfig' version '1.1.8' 11 | } 12 | 13 | group 'com.vecsight.dragonite' 14 | version '0.4.0' 15 | 16 | apply plugin: 'java' 17 | apply plugin: 'application' 18 | apply plugin: 'idea' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | mainClassName = 'com.vecsight.dragonite.proxy.CLIMain' 23 | 24 | repositories { 25 | mavenCentral() 26 | jcenter() 27 | } 28 | 29 | applicationDistribution.from("samples") { 30 | into "samples" 31 | } 32 | 33 | dependencies { 34 | compile project(':dragonite-sdk') 35 | compile project(':dragonite-mux') 36 | compile project(':dragonite-utils') 37 | compile group: 'org.tinylog', name: 'tinylog', version: '1.2' 38 | compile group: 'commons-cli', name: 'commons-cli', version: '1.4' 39 | compile 'com.eclipsesource.minimal-json:minimal-json:0.9.4' 40 | } 41 | 42 | buildConfig { 43 | clsName = 'ProxyBuildConfig' 44 | } -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/misc/PerfStopWatch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.misc; 9 | 10 | public class PerfStopWatch { 11 | 12 | private final boolean warn; 13 | 14 | private final long warnDelta; 15 | 16 | private volatile long lastTick; 17 | 18 | public PerfStopWatch(final boolean warn, final long warnDelta) { 19 | this.warn = warn; 20 | this.warnDelta = warnDelta; 21 | start(); 22 | } 23 | 24 | private void start() { 25 | lastTick = System.currentTimeMillis(); 26 | } 27 | 28 | public long tick(final String msg) { 29 | final long time = System.currentTimeMillis() - lastTick; 30 | if (warn && time >= warnDelta) { 31 | System.out.println("[PerfStopWatch] " + msg + " " + time + "ms"); 32 | } 33 | start(); 34 | return time; 35 | } 36 | 37 | public long tick() { 38 | return tick("DEFAULT"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/system/SystemInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.system; 9 | 10 | import java.net.InetAddress; 11 | import java.net.UnknownHostException; 12 | 13 | public final class SystemInfo { 14 | 15 | public static String getUsername() { 16 | final String name = System.getProperty("user.name"); 17 | return name != null ? name : "Unknown"; 18 | } 19 | 20 | public static String getHostname() { 21 | try { 22 | return InetAddress.getLocalHost().getHostName(); 23 | } catch (final UnknownHostException e) { 24 | return "Unknown"; 25 | } 26 | } 27 | 28 | public static String getOS() { 29 | final String os = System.getProperty("os.name"); 30 | return os != null ? os : "Unknown"; 31 | } 32 | 33 | public static int getProcessorsCount() { 34 | return Runtime.getRuntime().availableProcessors(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/DomainACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | 13 | public class DomainACLItem implements ACLItem { 14 | 15 | private final String domain; 16 | 17 | private final ACLItemMethod method; 18 | 19 | public DomainACLItem(final String domain, final ACLItemMethod method) { 20 | this.domain = domain; 21 | this.method = method; 22 | } 23 | 24 | @Override 25 | public ACLItemType getType() { 26 | return ACLItemType.DOMAIN; 27 | } 28 | 29 | @Override 30 | public ACLItemMethod getMethod() { 31 | return method; 32 | } 33 | 34 | @Override 35 | public boolean match(final String domain) { 36 | return this.domain.equalsIgnoreCase(domain); 37 | } 38 | 39 | @Override 40 | public boolean match(final byte[] address) { 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/misc/DragoniteGlobalConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.misc; 9 | 10 | import com.vecsight.dragonite.DragoniteBuildConfig; 11 | 12 | public final class DragoniteGlobalConstants { 13 | 14 | public static final String LIBRARY_VERSION = DragoniteBuildConfig.VERSION; 15 | 16 | public static final byte PROTOCOL_VERSION = 2; 17 | 18 | public static final int MIN_SEND_WINDOW_SIZE = 20; 19 | 20 | public static final int ACK_INTERVAL_MS = 10; 21 | 22 | public static final int MAX_FAST_RESEND_COUNT = 3; 23 | 24 | public static final int MAX_SLOW_RESEND_MULT = 4; 25 | 26 | public static final int INIT_RTT_MS = 200, RTT_MAX_VARIATION_MS = 200, RTT_UPDATE_INTERVAL_MS = 100, RTT_RESEND_CORRECTION_INTERVAL_MS = 2000; 27 | 28 | public static final int DEV_RTT_MULT = 4; 29 | 30 | public static final float RTT_RESENDED_REFRESH_MAX_MULT = 1.5f; 31 | 32 | public static final int MIN_CLOSE_WAIT_MS = 100, CLOSE_WAIT_RTT_MULT = 4; 33 | 34 | public static final int WEB_PANEL_PORT = 8000; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/ConnectionState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 11 | 12 | public class ConnectionState { 13 | 14 | private volatile long estimatedRTT = DragoniteGlobalConstants.INIT_RTT_MS; 15 | 16 | private volatile long devRTT = 0; 17 | 18 | private volatile int sendSequence = 0; 19 | 20 | protected final Object sendWindowLock = new Object(); 21 | 22 | public long getEstimatedRTT() { 23 | return estimatedRTT; 24 | } 25 | 26 | protected void setEstimatedRTT(final long estimatedRTT) { 27 | this.estimatedRTT = estimatedRTT; 28 | } 29 | 30 | public long getDevRTT() { 31 | return devRTT; 32 | } 33 | 34 | public void setDevRTT(final long devRTT) { 35 | this.devRTT = devRTT; 36 | } 37 | 38 | public int getSendSequence() { 39 | return sendSequence; 40 | } 41 | 42 | public void setSendSequence(final int sendSequence) { 43 | this.sendSequence = sendSequence; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/cryptor/PacketCryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.cryptor; 9 | 10 | public interface PacketCryptor { 11 | 12 | /** 13 | * Encrypt the message and return the ciphertext. 14 | * This function may be called by multiple threads at the same time. 15 | * 16 | * @param rawData Content to be encrypted 17 | * @return Encrypted content 18 | */ 19 | byte[] encrypt(final byte[] rawData); 20 | 21 | /** 22 | * Decrypt the ciphertext and return the message. 23 | * This function may be called by multiple threads at the same time. 24 | * 25 | * @param encryptedData Content to be decrypted 26 | * @return Decrypted content 27 | */ 28 | byte[] decrypt(final byte[] encryptedData); 29 | 30 | /** 31 | * Many encryption methods need to add additional bytes to the original message. 32 | * Please specify the maximum length of additional bytes that the encryption might cause. 33 | * 34 | * @return Length of additional bytes 35 | */ 36 | int getMaxAdditionalBytesLength(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/misc/ForwarderGlobalConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.misc; 9 | 10 | import com.vecsight.dragonite.ForwarderBuildConfig; 11 | 12 | import java.nio.charset.Charset; 13 | import java.nio.charset.StandardCharsets; 14 | 15 | public final class ForwarderGlobalConstants { 16 | 17 | public static final String APP_VERSION = ForwarderBuildConfig.VERSION; 18 | 19 | public static final byte PROTOCOL_VERSION = 3; 20 | 21 | public static final int DEFAULT_SERVER_PORT = 5233; 22 | 23 | public static final long INIT_SEND_SPEED = 100 * 1024; //100kb/s 24 | 25 | public static final Charset STRING_CHARSET = StandardCharsets.UTF_8; 26 | 27 | public static final short PIPE_BUFFER_SIZE = 10240; 28 | 29 | public static final short MAX_FRAME_SIZE = 20480; 30 | 31 | public static final int PASSWORD_MIN_LENGTH = 4; 32 | 33 | public static final String UPDATE_API_URL = "https://github.com/dragonite-network/dragonite-java/raw/master/VERSIONS"; 34 | 35 | public static final String UPDATE_API_PRODUCT_NAME = "forwarder"; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/MessageStat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | public class MessageStat { 11 | 12 | private boolean exist = false; 13 | 14 | private long RTT; 15 | 16 | private boolean resended; 17 | 18 | public MessageStat(final boolean exist, final long RTT, final boolean resended) { 19 | this.exist = exist; 20 | this.RTT = RTT; 21 | this.resended = resended; 22 | } 23 | 24 | public MessageStat() { 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "MessageStat{" + "exist=" + exist + 30 | ", RTT=" + RTT + 31 | ", resended=" + resended + 32 | '}'; 33 | } 34 | 35 | public boolean isExist() { 36 | return exist; 37 | } 38 | 39 | public void setExist(final boolean exist) { 40 | this.exist = exist; 41 | } 42 | 43 | public long getRTT() { 44 | return RTT; 45 | } 46 | 47 | public void setRTT(final long RTT) { 48 | this.RTT = RTT; 49 | } 50 | 51 | public boolean isResended() { 52 | return resended; 53 | } 54 | 55 | public void setResended(final boolean resended) { 56 | this.resended = resended; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/misc/ProxyGlobalConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.misc; 9 | 10 | import com.vecsight.dragonite.ProxyBuildConfig; 11 | 12 | import java.nio.charset.Charset; 13 | import java.nio.charset.StandardCharsets; 14 | 15 | public final class ProxyGlobalConstants { 16 | 17 | public static final String APP_VERSION = ProxyBuildConfig.VERSION; 18 | 19 | public static final byte PROTOCOL_VERSION = 2; 20 | 21 | public static final int DEFAULT_SERVER_PORT = 5234; 22 | 23 | public static final long INIT_SEND_SPEED = 100 * 1024; //100kb/s 24 | 25 | public static final Charset STRING_CHARSET = StandardCharsets.UTF_8; 26 | 27 | public static final Charset HEADER_ADDRESS_CHARSET = StandardCharsets.US_ASCII; 28 | 29 | public static final short PIPE_BUFFER_SIZE = 10240; 30 | 31 | public static final short MAX_FRAME_SIZE = 20480; 32 | 33 | public static final int PASSWORD_MIN_LENGTH = 4; 34 | 35 | public static final int SOCKS5_PORT = 1080; 36 | 37 | public static final int TCP_CONNECT_TIMEOUT_MS = 4000; 38 | 39 | public static final String UPDATE_API_URL = "https://github.com/dragonite-network/dragonite-java/raw/master/VERSIONS"; 40 | 41 | public static final String UPDATE_API_PRODUCT_NAME = "proxy"; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![dragonite-java](assets/TextLogo.png) 2 | 3 | INTERNET UNLEASHED. 4 | 5 | ![powered by dragonite](https://img.shields.io/badge/powered%20by-dragonite-yellow.svg) 6 | 7 | [![https://t.me/DragoniteProject](https://img.shields.io/badge/Telegram%20Group%20CN-https%3A%2F%2Ft.me%2FDragoniteProject-blue.svg)](https://t.me/DragoniteProject) 8 | 9 | **This project is no longer being maintained and has been superseded by https://github.com/tobyxdd/hysteria** 10 | 11 | **本项目已经停止维护,请使用续作 https://github.com/tobyxdd/hysteria** 12 | 13 | Dragonite is a reliable application level data transport protocol based on UDP. Highly optimized for lossy & unstable networks. Use cases include 14 | 15 | - Transfer data between countries over lossy network connections 16 | - Your application needs a persistent connection to your servers, without interference from NAT gateways 17 | - Firewall blocking TCP 18 | 19 | *Dragonite Network Project* contains a series of Dragonite-based network applications. 20 | 21 | **[See the Wiki page](https://github.com/dragonite-network/dragonite-java/wiki)** 22 | 23 | Dragonite 是一个基于 UDP 的可靠传输协议,能针对高丢包与不稳定的网络极大提高传输速度。本项目有一系列基于 Dragonite 协议的应用,例如 **TCP 双边加速流量转发工具**与**加密 SOCKS5 代理**。 24 | 25 | **中文用户请加入 [Telegram 群组](https://t.me/DragoniteProject)** 26 | 27 | [**中文 Wiki 页面**](https://github.com/dragonite-network/dragonite-java/wiki/%E4%B8%BB%E9%A1%B5) 28 | 29 | ![TCP vs Dragonite](https://github.com/dragonite-network/dragonite-java/raw/master/benchmarks/TCPvsDragonite.png) 30 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/ResendItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | public class ResendItem { 11 | 12 | private final int sequence; 13 | 14 | private final long startTime; 15 | 16 | private volatile int sendCount = 0; 17 | 18 | private volatile long nextSendTime; 19 | 20 | private volatile boolean resended = false; 21 | 22 | public ResendItem(final int sequence, final long startTime, final long nextSendTime) { 23 | this.sequence = sequence; 24 | this.startTime = startTime; 25 | this.nextSendTime = nextSendTime; 26 | } 27 | 28 | public int getSequence() { 29 | return sequence; 30 | } 31 | 32 | public long getStartTime() { 33 | return startTime; 34 | } 35 | 36 | public int getSendCount() { 37 | return sendCount; 38 | } 39 | 40 | public void addSendCount() { 41 | sendCount++; 42 | } 43 | 44 | public long getNextSendTime() { 45 | return nextSendTime; 46 | } 47 | 48 | public void setNextSendTime(final long nextSendTime) { 49 | this.nextSendTime = nextSendTime; 50 | } 51 | 52 | public boolean isResended() { 53 | return resended; 54 | } 55 | 56 | public void setResended() { 57 | this.resended = true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/MuxPipe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.network; 9 | 10 | import com.vecsight.dragonite.mux.conn.MultiplexedConnection; 11 | import com.vecsight.dragonite.mux.exception.ConnectionNotAliveException; 12 | import com.vecsight.dragonite.mux.exception.SenderClosedException; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | import java.util.Arrays; 18 | 19 | public class MuxPipe { 20 | 21 | private final short bufferSize; 22 | 23 | public MuxPipe(final short bufferSize) { 24 | this.bufferSize = bufferSize; 25 | } 26 | 27 | public void pipe(final InputStream inputStream, final MultiplexedConnection connection) throws IOException, SenderClosedException, InterruptedException { 28 | int len; 29 | final byte[] buf = new byte[bufferSize]; 30 | while ((len = inputStream.read(buf)) > 0) { 31 | connection.send(Arrays.copyOf(buf, len)); 32 | } 33 | } 34 | 35 | public void pipe(final MultiplexedConnection connection, final OutputStream outputStream) throws ConnectionNotAliveException, InterruptedException, IOException { 36 | byte[] buf; 37 | while ((buf = connection.read()) != null) { 38 | outputStream.write(buf); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/network/Pipe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.network; 9 | 10 | import com.vecsight.dragonite.mux.conn.MultiplexedConnection; 11 | import com.vecsight.dragonite.mux.exception.ConnectionNotAliveException; 12 | import com.vecsight.dragonite.mux.exception.SenderClosedException; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | import java.util.Arrays; 18 | 19 | public class Pipe { 20 | 21 | private final short bufferSize; 22 | 23 | public Pipe(final short bufferSize) { 24 | this.bufferSize = bufferSize; 25 | } 26 | 27 | public void pipe(final InputStream inputStream, final MultiplexedConnection connection) throws IOException, SenderClosedException, InterruptedException { 28 | int len; 29 | final byte[] buf = new byte[bufferSize]; 30 | while ((len = inputStream.read(buf)) > 0) { 31 | connection.send(Arrays.copyOf(buf, len)); 32 | } 33 | } 34 | 35 | public void pipe(final MultiplexedConnection connection, final OutputStream outputStream) throws ConnectionNotAliveException, InterruptedException, IOException { 36 | byte[] buf; 37 | while ((buf = connection.read()) != null) { 38 | outputStream.write(buf); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/MessageParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg; 9 | 10 | import com.vecsight.dragonite.sdk.exception.IncorrectMessageException; 11 | import com.vecsight.dragonite.sdk.msg.types.ACKMessage; 12 | import com.vecsight.dragonite.sdk.msg.types.CloseMessage; 13 | import com.vecsight.dragonite.sdk.msg.types.DataMessage; 14 | import com.vecsight.dragonite.sdk.msg.types.HeartbeatMessage; 15 | 16 | public final class MessageParser { 17 | 18 | public static Message parseMessage(final byte[] msgBytes) throws IncorrectMessageException { 19 | if (msgBytes.length >= 2) { 20 | try { 21 | switch (MessageType.fromByte(msgBytes[1])) { 22 | case DATA: 23 | return new DataMessage(msgBytes); 24 | case CLOSE: 25 | return new CloseMessage(msgBytes); 26 | case ACK: 27 | return new ACKMessage(msgBytes); 28 | case HEARTBEAT: 29 | return new HeartbeatMessage(msgBytes); 30 | default: 31 | throw new IncorrectMessageException("Unknown Message Type"); 32 | } 33 | } catch (final IllegalArgumentException e) { 34 | throw new IncorrectMessageException("Unknown Message Type"); 35 | } 36 | } else { 37 | throw new IncorrectMessageException("Packet is too short"); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/misc/UpdateChecker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | package com.vecsight.dragonite.utils.misc; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | import java.net.URL; 13 | import java.net.URLConnection; 14 | 15 | public class UpdateChecker { 16 | 17 | private final static int TIMEOUT = 4000; 18 | 19 | private final String URLString; 20 | 21 | public UpdateChecker(final String URL) { 22 | this.URLString = URL; 23 | } 24 | 25 | public String getURL() { 26 | return URLString; 27 | } 28 | 29 | public String getVersionString(final String productName) { 30 | try { 31 | final URL url = new URL(URLString); 32 | final URLConnection conn = url.openConnection(); 33 | conn.setConnectTimeout(TIMEOUT); 34 | conn.setReadTimeout(TIMEOUT); 35 | try (final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { 36 | String line; 37 | while ((line = reader.readLine()) != null) { 38 | if (line.contains("-")) { 39 | final String[] kv = line.split("-"); 40 | if (kv[0].equalsIgnoreCase(productName)) 41 | return kv[1]; 42 | } 43 | } 44 | } 45 | return null; 46 | } catch (final IOException e) { 47 | return null; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/DomainSuffixACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | 13 | public class DomainSuffixACLItem implements ACLItem { 14 | 15 | private final String domain; 16 | 17 | private final ACLItemMethod method; 18 | 19 | public DomainSuffixACLItem(final String domain, final ACLItemMethod method) { 20 | this.domain = domain; 21 | this.method = method; 22 | } 23 | 24 | @Override 25 | public ACLItemType getType() { 26 | return ACLItemType.DOMAIN_SUFFIX; 27 | } 28 | 29 | @Override 30 | public ACLItemMethod getMethod() { 31 | return method; 32 | } 33 | 34 | @Override 35 | public boolean match(final String domain) { 36 | return this.domain.equalsIgnoreCase(domain) || endsWithIgnoreCase(domain, "." + this.domain); 37 | } 38 | 39 | @Override 40 | public boolean match(final byte[] address) { 41 | return false; 42 | } 43 | 44 | private static boolean endsWithIgnoreCase(final String str, final String suffix) { 45 | if (str == null || suffix == null) { 46 | return str == null && suffix == null; 47 | } 48 | if (suffix.length() > str.length()) { 49 | return false; 50 | } 51 | final int strOffset = str.length() - suffix.length(); 52 | return str.regionMatches(true, strOffset, suffix, 0, suffix.length()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/DragoniteSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import com.vecsight.dragonite.sdk.exception.ConnectionNotAliveException; 11 | import com.vecsight.dragonite.sdk.exception.IncorrectSizeException; 12 | import com.vecsight.dragonite.sdk.exception.SenderClosedException; 13 | 14 | import java.io.IOException; 15 | import java.net.SocketAddress; 16 | 17 | public abstract class DragoniteSocket { 18 | 19 | public abstract byte[] read() throws InterruptedException, ConnectionNotAliveException; 20 | 21 | public abstract void send(byte[] bytes) throws InterruptedException, IncorrectSizeException, IOException, SenderClosedException; 22 | 23 | public abstract boolean isAlive(); 24 | 25 | protected abstract void updateLastReceiveTime(); 26 | 27 | public abstract long getLastReceiveTime(); 28 | 29 | protected abstract void updateLastSendTime(); 30 | 31 | public abstract long getLastSendTime(); 32 | 33 | public abstract SocketAddress getRemoteSocketAddress(); 34 | 35 | public abstract void setSendSpeed(long sendSpeed); 36 | 37 | public abstract long getSendSpeed(); 38 | 39 | public abstract DragoniteSocketStatistics getStatistics(); 40 | 41 | public abstract String getDescription(); 42 | 43 | public abstract void setDescription(String description); 44 | 45 | protected abstract void closeSender(); 46 | 47 | public abstract void closeGracefully() throws InterruptedException, IOException, SenderClosedException; 48 | 49 | public abstract void destroy(); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/BucketPacketSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import com.github.bucket4j.Bandwidth; 11 | import com.github.bucket4j.Bucket; 12 | import com.github.bucket4j.Bucket4j; 13 | 14 | import java.io.IOException; 15 | import java.time.Duration; 16 | import java.util.concurrent.atomic.AtomicLong; 17 | 18 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 19 | 20 | public class BucketPacketSender implements PacketSender { 21 | 22 | private final PacketSender packetSender; 23 | 24 | private volatile Bucket bucket; 25 | 26 | private volatile long speed; 27 | 28 | private final AtomicLong sendRawLength = new AtomicLong(0); 29 | 30 | public BucketPacketSender(final PacketSender packetSender, final long speed) { 31 | this.packetSender = packetSender; 32 | setSpeed(speed); 33 | } 34 | 35 | public void setSpeed(final long speed) { 36 | checkArgument(speed > 0, "Speed must be greater than zero"); 37 | bucket = Bucket4j.builder().addLimit(Bandwidth.simple(speed, Duration.ofSeconds(1))).build(); 38 | this.speed = speed; 39 | } 40 | 41 | public long getSpeed() { 42 | return speed; 43 | } 44 | 45 | public void sendPacket(final byte[] bytes) throws InterruptedException, IOException { 46 | bucket.consume(bytes.length); 47 | packetSender.sendPacket(bytes); 48 | sendRawLength.addAndGet(bytes.length); 49 | } 50 | 51 | public long getSendRawLength() { 52 | return sendRawLength.get(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/IPv4ACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | import com.vecsight.dragonite.proxy.exception.InvalidAddressException; 13 | 14 | import java.net.InetAddress; 15 | import java.net.UnknownHostException; 16 | import java.util.Arrays; 17 | 18 | public class IPv4ACLItem implements ACLItem { 19 | 20 | private final byte[] bytes; 21 | 22 | private final ACLItemMethod method; 23 | 24 | public IPv4ACLItem(final String string, final ACLItemMethod method) throws InvalidAddressException { 25 | this.method = method; 26 | try { 27 | bytes = InetAddress.getByName(string).getAddress(); 28 | if (bytes.length != 4) throw new InvalidAddressException(string + " is not a valid IPv4 address"); 29 | } catch (final UnknownHostException e) { 30 | throw new InvalidAddressException(string + " is not a valid IPv4 address"); 31 | } 32 | } 33 | 34 | public IPv4ACLItem(final byte[] bytes, final ACLItemMethod method) { 35 | this.method = method; 36 | this.bytes = bytes; 37 | } 38 | 39 | @Override 40 | public ACLItemType getType() { 41 | return ACLItemType.IPv4; 42 | } 43 | 44 | @Override 45 | public ACLItemMethod getMethod() { 46 | return method; 47 | } 48 | 49 | @Override 50 | public boolean match(final String domain) { 51 | return false; 52 | } 53 | 54 | @Override 55 | public boolean match(final byte[] address) { 56 | return Arrays.equals(address, bytes); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/IPv6ACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | import com.vecsight.dragonite.proxy.exception.InvalidAddressException; 13 | 14 | import java.net.InetAddress; 15 | import java.net.UnknownHostException; 16 | import java.util.Arrays; 17 | 18 | public class IPv6ACLItem implements ACLItem { 19 | 20 | private final byte[] bytes; 21 | 22 | private final ACLItemMethod method; 23 | 24 | public IPv6ACLItem(final String string, final ACLItemMethod method) throws InvalidAddressException { 25 | this.method = method; 26 | try { 27 | bytes = InetAddress.getByName(string).getAddress(); 28 | if (bytes.length != 16) throw new InvalidAddressException(string + " is not a valid IPv6 address"); 29 | } catch (final UnknownHostException e) { 30 | throw new InvalidAddressException(string + " is not a valid IPv6 address"); 31 | } 32 | } 33 | 34 | public IPv6ACLItem(final byte[] bytes, final ACLItemMethod method) { 35 | this.method = method; 36 | this.bytes = bytes; 37 | } 38 | 39 | @Override 40 | public ACLItemType getType() { 41 | return ACLItemType.IPv6; 42 | } 43 | 44 | @Override 45 | public ACLItemMethod getMethod() { 46 | return method; 47 | } 48 | 49 | @Override 50 | public boolean match(final String domain) { 51 | return false; 52 | } 53 | 54 | @Override 55 | public boolean match(final byte[] address) { 56 | return Arrays.equals(address, bytes); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/binary/BinaryReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.binary; 9 | 10 | import java.nio.ByteBuffer; 11 | 12 | public class BinaryReader { 13 | 14 | private final ByteBuffer byteBuffer; 15 | 16 | public BinaryReader(final byte[] bytes) { 17 | byteBuffer = ByteBuffer.wrap(bytes); 18 | } 19 | 20 | public byte getSignedByte() { 21 | return byteBuffer.get(); 22 | } 23 | 24 | public short getUnsignedByte() { 25 | return (short) (byteBuffer.get() & (short) 0xff); 26 | } 27 | 28 | public short getSignedShort() { 29 | return byteBuffer.getShort(); 30 | } 31 | 32 | public int getUnsignedShort() { 33 | return byteBuffer.getShort() & 0xffff; 34 | } 35 | 36 | public int getSignedInt() { 37 | return byteBuffer.getInt(); 38 | } 39 | 40 | public long getUnsignedInt() { 41 | return (long) byteBuffer.getInt() & 0xffffffffL; 42 | } 43 | 44 | public void getBytes(final byte[] bytes) { 45 | byteBuffer.get(bytes); 46 | } 47 | 48 | public byte[] getBytesGroupWithByteLength() { 49 | final short len = getUnsignedByte(); 50 | final byte[] bytes = new byte[len]; 51 | byteBuffer.get(bytes); 52 | return bytes; 53 | } 54 | 55 | public byte[] getBytesGroupWithShortLength() { 56 | final int len = getUnsignedShort(); 57 | final byte[] bytes = new byte[len]; 58 | byteBuffer.get(bytes); 59 | return bytes; 60 | } 61 | 62 | public boolean getBoolean() { 63 | return byteBuffer.get() != 0; 64 | } 65 | 66 | public int remaining() { 67 | return byteBuffer.remaining(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/socks5/SOCKS5Header.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.network.socks5; 9 | 10 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 11 | 12 | import java.util.Arrays; 13 | 14 | public class SOCKS5Header { 15 | 16 | private boolean isDomain; 17 | 18 | private byte[] addr; 19 | 20 | private int port; 21 | 22 | private boolean udp; 23 | 24 | public SOCKS5Header(final boolean isDomain, final byte[] addr, final int port, final boolean udp) { 25 | this.isDomain = isDomain; 26 | this.addr = addr; 27 | this.port = port; 28 | this.udp = udp; 29 | } 30 | 31 | public boolean isDomain() { 32 | return isDomain; 33 | } 34 | 35 | public void setDomain(final boolean domain) { 36 | isDomain = domain; 37 | } 38 | 39 | public byte[] getAddr() { 40 | return addr; 41 | } 42 | 43 | public void setAddr(final byte[] addr) { 44 | this.addr = addr; 45 | } 46 | 47 | public int getPort() { 48 | return port; 49 | } 50 | 51 | public void setPort(final int port) { 52 | this.port = port; 53 | } 54 | 55 | public boolean isUdp() { 56 | return udp; 57 | } 58 | 59 | public void setUdp(final boolean udp) { 60 | this.udp = udp; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "SOCKS5Header{" + 66 | "isDomain=" + isDomain + 67 | ", addr=" + (isDomain ? new String(addr, ProxyGlobalConstants.HEADER_ADDRESS_CHARSET) : Arrays.toString(addr)) + 68 | ", port=" + port + 69 | ", udp=" + udp + 70 | '}'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /dragonite-sdk/src/test/java/DragoniteSocketTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 9 | import com.vecsight.dragonite.sdk.exception.DragoniteException; 10 | import com.vecsight.dragonite.sdk.socket.DragoniteClientSocket; 11 | import com.vecsight.dragonite.sdk.socket.DragoniteServer; 12 | import com.vecsight.dragonite.sdk.socket.DragoniteSocket; 13 | import org.junit.Test; 14 | 15 | import java.io.IOException; 16 | import java.net.InetSocketAddress; 17 | import java.net.SocketException; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | public class DragoniteSocketTest { 22 | 23 | private final DragoniteServer dragoniteServer = new DragoniteServer(9876, 100 * 1024, new DragoniteSocketParameters()); 24 | 25 | public DragoniteSocketTest() throws SocketException { 26 | } 27 | 28 | @Test 29 | public void basicAcceptReadSend() throws IOException, InterruptedException, DragoniteException { 30 | final String text = "By design, JUnit does not specify the execution order of test method invocations. " + 31 | "Until now, the methods were simply invoked in the order returned by the reflection API. " + 32 | "However, using the JVM order is unwise since the Java platform does not specify any particular order, " + 33 | "and in fact JDK 7 returns a more or less random order."; 34 | final DragoniteClientSocket clientSocket = new DragoniteClientSocket(new InetSocketAddress("localhost", 9876), 100 * 1024, new DragoniteSocketParameters()); 35 | final DragoniteSocket socket = dragoniteServer.accept(); 36 | clientSocket.send(text.getBytes()); 37 | final byte[] sr = socket.read(); 38 | assertEquals(text, new String(sr)); 39 | socket.send(text.getBytes()); 40 | final byte[] cr = clientSocket.read(); 41 | assertEquals(text, new String(cr)); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /dragonite-utils/src/main/java/com/vecsight/dragonite/utils/binary/BinaryWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.utils.binary; 9 | 10 | import java.nio.ByteBuffer; 11 | 12 | public class BinaryWriter { 13 | 14 | private final ByteBuffer byteBuffer; 15 | 16 | public BinaryWriter(final int capacity) { 17 | byteBuffer = ByteBuffer.allocate(capacity); 18 | } 19 | 20 | public BinaryWriter putSignedByte(final byte sb) { 21 | byteBuffer.put(sb); 22 | return this; 23 | } 24 | 25 | public BinaryWriter putUnsignedByte(final short ub) { 26 | byteBuffer.put((byte) (ub & 0xff)); 27 | return this; 28 | } 29 | 30 | public BinaryWriter putSignedShort(final short ss) { 31 | byteBuffer.putShort(ss); 32 | return this; 33 | } 34 | 35 | public BinaryWriter putUnsignedShort(final int us) { 36 | byteBuffer.putShort((short) (us & 0xffff)); 37 | return this; 38 | } 39 | 40 | public BinaryWriter putSignedInt(final int si) { 41 | byteBuffer.putInt(si); 42 | return this; 43 | } 44 | 45 | public BinaryWriter putUnsignedInt(final long ui) { 46 | byteBuffer.putInt((int) (ui & 0xffffffffL)); 47 | return this; 48 | } 49 | 50 | public BinaryWriter putBytes(final byte[] bytes) { 51 | byteBuffer.put(bytes); 52 | return this; 53 | } 54 | 55 | public BinaryWriter putBytesGroupWithByteLength(final byte[] bytes) { 56 | putUnsignedByte((short) bytes.length); 57 | putBytes(bytes); 58 | return this; 59 | } 60 | 61 | public BinaryWriter putBytesGroupWithShortLength(final byte[] bytes) { 62 | putUnsignedShort(bytes.length); 63 | putBytes(bytes); 64 | return this; 65 | } 66 | 67 | public BinaryWriter putBoolean(final boolean b) { 68 | byteBuffer.put((byte) (b ? 1 : 0)); 69 | return this; 70 | } 71 | 72 | public byte[] toBytes() { 73 | return byteBuffer.array(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /dragonite-sdk/src/test/java/MessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | import com.vecsight.dragonite.sdk.exception.DragoniteException; 9 | import com.vecsight.dragonite.sdk.msg.types.ACKMessage; 10 | import com.vecsight.dragonite.sdk.msg.types.CloseMessage; 11 | import com.vecsight.dragonite.sdk.msg.types.DataMessage; 12 | import com.vecsight.dragonite.sdk.msg.types.HeartbeatMessage; 13 | import org.junit.Test; 14 | 15 | import static org.junit.Assert.assertArrayEquals; 16 | import static org.junit.Assert.assertEquals; 17 | 18 | public final class MessageTest { 19 | 20 | @Test 21 | public void dataMessageSerialization() throws DragoniteException { 22 | final String text = "Hello...?!"; 23 | final DataMessage message = new DataMessage(666, text.getBytes()); 24 | final DataMessage newMessage = new DataMessage(message.toBytes()); 25 | assertEquals(666, newMessage.getSequence()); 26 | assertEquals(text, new String(newMessage.getData())); 27 | } 28 | 29 | @Test 30 | public void ackMessageSerialization() throws DragoniteException { 31 | final int[] ints = new int[]{3, 4, 5, 6, 7}; 32 | final ACKMessage message = new ACKMessage(ints, 5); 33 | final ACKMessage newMessage = new ACKMessage(message.toBytes()); 34 | assertEquals(newMessage.getConsumedSeq(), 5); 35 | assertArrayEquals(newMessage.getSequenceList(), ints); 36 | } 37 | 38 | @Test 39 | public void closeMessageSerialization() throws DragoniteException { 40 | final CloseMessage message = new CloseMessage(101, (short) 2); 41 | final CloseMessage newMessage = new CloseMessage(message.toBytes()); 42 | assertEquals(newMessage.getSequence(), 101); 43 | assertEquals(newMessage.getStatus(), 2); 44 | } 45 | 46 | @Test 47 | public void heartbeatMessageSerialization() throws DragoniteException { 48 | final HeartbeatMessage message = new HeartbeatMessage(233); 49 | final HeartbeatMessage newMessage = new HeartbeatMessage(message.toBytes()); 50 | assertEquals(newMessage.getSequence(), 233); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /dragonite-echo/src/main/java/com/vecsight/dragonite/echo/EchoMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.echo; 9 | 10 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 11 | import com.vecsight.dragonite.sdk.exception.SenderClosedException; 12 | import com.vecsight.dragonite.sdk.socket.DragoniteServer; 13 | import com.vecsight.dragonite.sdk.socket.DragoniteSocket; 14 | 15 | import java.io.IOException; 16 | import java.net.InetSocketAddress; 17 | import java.net.SocketException; 18 | 19 | public final class EchoMain { 20 | 21 | public static void main(final String[] args) throws SocketException, InterruptedException { 22 | final DragoniteSocketParameters parameters = new DragoniteSocketParameters(); 23 | parameters.setEnableWebPanel(true); 24 | parameters.setWebPanelBindAddress(new InetSocketAddress(8001)); 25 | final DragoniteServer dragoniteServer = new DragoniteServer(9225, 102400, parameters); 26 | DragoniteSocket tmpDragoniteSocket; 27 | while ((tmpDragoniteSocket = dragoniteServer.accept()) != null) { 28 | final DragoniteSocket dragoniteSocket = tmpDragoniteSocket; 29 | print("New connection from " + dragoniteSocket.getRemoteSocketAddress().toString()); 30 | new Thread(() -> { 31 | try { 32 | while (dragoniteSocket.isAlive()) { 33 | final byte[] bytes = dragoniteSocket.read(); 34 | print(new String(bytes)); 35 | dragoniteSocket.send(bytes); 36 | } 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } finally { 40 | try { 41 | dragoniteSocket.closeGracefully(); 42 | } catch (InterruptedException | IOException | SenderClosedException ignored) { 43 | } 44 | print(dragoniteSocket.getRemoteSocketAddress().toString() + " connection closed"); 45 | } 46 | }).start(); 47 | } 48 | } 49 | 50 | private static void print(final String msg) { 51 | System.out.println(msg); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/cryptor/SimpleXORCryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.cryptor; 9 | 10 | import java.nio.BufferUnderflowException; 11 | import java.nio.ByteBuffer; 12 | import java.util.Random; 13 | 14 | public class SimpleXORCryptor implements PacketCryptor { 15 | 16 | private static final int BASE_RANDOM_BYTES_LENGTH = 20; 17 | 18 | private static final int VAR_RANDOM_BYTES_LENGTH = 50; 19 | 20 | private final Random random = new Random(); 21 | 22 | private final byte[] psk; 23 | 24 | public SimpleXORCryptor(final byte[] psk) { 25 | this.psk = psk; 26 | } 27 | 28 | @Override 29 | public byte[] encrypt(final byte[] rawData) { 30 | final byte lengthByte = (byte) random.nextInt(); 31 | final int realLength = BASE_RANDOM_BYTES_LENGTH + Math.abs(lengthByte) % VAR_RANDOM_BYTES_LENGTH; 32 | final byte[] key = new byte[realLength]; 33 | random.nextBytes(key); 34 | final ByteBuffer buffer = ByteBuffer.allocate(1 + key.length + rawData.length); 35 | buffer.put(lengthByte); 36 | buffer.put(key); 37 | buffer.put(xor(rawData, xor(key, psk))); 38 | return buffer.array(); 39 | } 40 | 41 | @Override 42 | public byte[] decrypt(final byte[] encryptedData) { 43 | final ByteBuffer buffer = ByteBuffer.wrap(encryptedData); 44 | try { 45 | final byte lengthByte = buffer.get(); 46 | final int realLength = BASE_RANDOM_BYTES_LENGTH + Math.abs(lengthByte) % VAR_RANDOM_BYTES_LENGTH; 47 | final byte[] key = new byte[realLength]; 48 | buffer.get(key); 49 | final byte[] content = new byte[buffer.remaining()]; 50 | buffer.get(content); 51 | return xor(content, xor(key, psk)); 52 | } catch (final BufferUnderflowException e) { 53 | return null; 54 | } 55 | } 56 | 57 | @Override 58 | public int getMaxAdditionalBytesLength() { 59 | return BASE_RANDOM_BYTES_LENGTH + VAR_RANDOM_BYTES_LENGTH; 60 | } 61 | 62 | private static byte[] xor(final byte[] input, final byte[] key) { 63 | final byte[] result = new byte[input.length]; 64 | for (int i = 0; i < input.length; i++) { 65 | result[i] = (byte) (input[i] ^ key[i % key.length]); 66 | } 67 | return result; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/DragoniteSocketStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import java.net.SocketAddress; 11 | 12 | public class DragoniteSocketStatistics { 13 | 14 | private final SocketAddress remoteAddress; 15 | 16 | private final String description; 17 | 18 | private final long sendLength, sendRawLength, readLength, receiveRawLength, estimatedRTT, devRTT; 19 | 20 | private final long sendCount, resendCount, receiveCount, dupCount; 21 | 22 | public DragoniteSocketStatistics(final SocketAddress remoteAddress, final String description, final long sendLength, final long sendRawLength, final long readLength, final long receiveRawLength, final long estimatedRTT, final long devRTT, final long sendCount, final long resendCount, final long receiveCount, final long dupCount) { 23 | this.remoteAddress = remoteAddress; 24 | this.description = description; 25 | this.sendLength = sendLength; 26 | this.sendRawLength = sendRawLength; 27 | this.readLength = readLength; 28 | this.receiveRawLength = receiveRawLength; 29 | this.estimatedRTT = estimatedRTT; 30 | this.devRTT = devRTT; 31 | this.sendCount = sendCount; 32 | this.resendCount = resendCount; 33 | this.receiveCount = receiveCount; 34 | this.dupCount = dupCount; 35 | } 36 | 37 | public long getSendLength() { 38 | return sendLength; 39 | } 40 | 41 | public long getSendRawLength() { 42 | return sendRawLength; 43 | } 44 | 45 | public long getReadLength() { 46 | return readLength; 47 | } 48 | 49 | public long getReceiveRawLength() { 50 | return receiveRawLength; 51 | } 52 | 53 | public long getEstimatedRTT() { 54 | return estimatedRTT; 55 | } 56 | 57 | public long getDevRTT() { 58 | return devRTT; 59 | } 60 | 61 | public long getSendCount() { 62 | return sendCount; 63 | } 64 | 65 | public long getResendCount() { 66 | return resendCount; 67 | } 68 | 69 | public long getReceiveCount() { 70 | return receiveCount; 71 | } 72 | 73 | public long getDupCount() { 74 | return dupCount; 75 | } 76 | 77 | public SocketAddress getRemoteAddress() { 78 | return remoteAddress; 79 | } 80 | 81 | public String getDescription() { 82 | return description; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | language: java 7 | 8 | install: 9 | - gradle clean 10 | - gradle assemble 11 | 12 | script: 13 | - gradle check 14 | - gradle distZip 15 | - gradle distTar 16 | 17 | deploy: 18 | - provider: releases 19 | api_key: 20 | secure: sfRsmy+ERytUMTj5IX8lIltu5C+hK1XjyEE4pNqLAtMpZhKUJDDoaJuiqLe1dTKs+hwFuViGHFgGUw5RGA+J57GTZCkkSvhe2e8ECMwBkmgXMX5PgFTtBpIkaqjppqy/qoyFkMIsyzzuxS76UnA7oG4cz4y0xgo4Wsuh75txGBHgpn718VwFUoTAR8cLfhsILbgyOau7YeDdTB13K+Pe2d+kOu02IeOCIUDpBMCVmAtj7FjWQmHWqoddZWxFOKxI4gDi2/DUx+3H9AHT+bzoe3fwE0oEiX/54fVK7HWMt8HjSdM43SYBokw3vn9Wn5A+ywMHOP2JCkKFIe6GIj8Fk2t/3MAeivh2WdBx4Hf/U6GiDzG2xPthO8js0/2chFjG7q1uRetnJtlx64kaMHnd45ZoPeESXIs1zRNVL/k9S4yc/Lfdj++Q/o7Q+5gJx39M1b8Gk1QCb6ZreflsH7fuCXtEIE8JLeEmEmyKnkuOq8ynWs+bMH7Go/qhD53ic9s+0sJxE21XOBkc4r4NQMljfcJSQQLgAtC8NyitfGSOcZiXvY3vxmINEkWpEufh1cKHe6ii9LV9vF/E8206Q/xfT2C4CfxsHgNApZzWQMf+Bm2cZplx5ooZNuO6Eg5m4Br5x2Quty/4U7dz/F6jAChsY8Mac6Bizx3XaqwBuqdabnA= 21 | file_glob: true 22 | file: 23 | - dragonite-*/build/distributions/*.tar 24 | - dragonite-*/build/distributions/*.zip 25 | skip_cleanup: true 26 | on: 27 | branch: master 28 | tags: true 29 | - provider: script 30 | script: "sh docker-build.sh" 31 | skip_cleanup: true 32 | on: 33 | branch: master 34 | tags: true 35 | 36 | env: 37 | global: 38 | - secure: TZHUNeZcWY1EksRm/dHPqH46cWrgQN3um6pfGF1pvIfBwgmmwfKh8jyvV/GA6hlMqHLZB8qsWIHXimOoR8S4W3cTSmWIhZ0hun4LUrkgkzPoI1VWl11cbksF0kpa+PCOfe/ftZKu8lFJP6Q4Ng/0YMQtl2HM6EmrX+jpnn+I6xt0u8kcanQ/1zA1MAwVWYb8Yz3BKrC5LM1Hd0zIJTMnz+RXZNRlewk/xwaajOqjghqDKa6rRXImN82wINuX6KoF8HzuJZvwQOa7s/S3uYkO8xszvmYyVib0U9LIEoKuAPVnhAZgAw3XZ8bMTfCiA2wBg1I5dKk9cBydVWucWMGWvp26CdX8+GwWWF9xwIfqb1wNOCouxr40RVG2unX2gDUGE8d+VIWkhO9rBq52uaN3eThtPy9vU15u/DlGCWjuFmPJ2QJqxp3EYVEnCbpRGwln5RDtvayjBTujqd6rjBj6H/AmdDUuFWAA9/0B5qk17uwQGXd2lZyGZ5sFHhGCjKtYuwD4mmSosebkC0Qqicw00aJ19ArWGxx0lSt1HImZ0R8UjB8gY40895WgKnC62eJ5Us0/bgk4lDW6zsMpCbw+bk7mIFZWxff2x/9xaHfTrRWdHn8JQXNhRsiLZSWh6Uy7x9MagaZ1N/DGzoQ59hcnUotO9F03h4nvILuY0uvysnI= 39 | - secure: b1AJhJYOsXvCvqeCzRQBwbAnZm0BvjUuKN+qNjn3XnvwoMjA3L0KGeIDn3zIV/j4o0jvRIY8c58uyXsF8msNHxZDJWCeJ7LCwcCzfMM0kALJETvuvSSXXItgyRttRPsdKkY6LoNvE/noOXy6EDJwG/X9QKNmEVg64U7KcJ2Bjlui80yB43i4u/uxgpK8a5XqgN8tzDPUafvMoBBf92VGV8TNs/1ZQnfk4/snwY24uReMTK02q/+3UeSNcBcS5e270OU4DdjXcJc802pxCV74ZiROI9082RI3w/WFAZ12QCPrOv21+RUwrCb5ge2JNvR6qm+CqiUQrXzvaVvV+GICWTdizwvHeFsapdCgi2HNpgDVxy1bU4v+qW1a/jya20+SSQ3pLiRLIzlHndDql/ZzDHBA71MLu6fL92Oa+ctqJ4iEvldJydODTmJZKmAmsIHNreX2+DG8kFezIf36iqYW2AsstpgFQbTm/iQf7tTn/cVRYswcoJ665xmJMpBERVh8mbaRMyRWNjaHdCRS+w/BdbzkHFRDk5fy8P3UgBF2EKD1Fw/YMtsrUOUMZ06WWrmVBjTJ8zGom9mgj1fILzI/jZrreYyYWm69aiJek+D6OkJShqrPoWFIOkcx9hsv67Vp1+6pmMwC9xf6uWPqOdx3Gj+ippYblUMqngQ/KYlvrzk= 40 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame; 9 | 10 | 11 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 12 | import com.vecsight.dragonite.mux.frame.types.*; 13 | 14 | public class FrameParser { 15 | 16 | private final FrameBuffer frameBuffer; 17 | 18 | private boolean needMore = false; 19 | 20 | private int expectedLength = 0; 21 | 22 | public FrameParser(final int maxFrameSize) { 23 | frameBuffer = new FrameBuffer(maxFrameSize); 24 | } 25 | 26 | public Frame feed(final byte[] rawBytes) { 27 | 28 | frameBuffer.add(rawBytes); 29 | 30 | if (!needMore || frameBuffer.getSize() >= expectedLength) { 31 | 32 | try { 33 | final Frame frame = parseFrameRaw(frameBuffer.get()); 34 | 35 | if (frame.getExpectedLength() == 0) { 36 | frameBuffer.reset(); 37 | needMore = false; 38 | return frame; 39 | 40 | } else { 41 | expectedLength = frame.getExpectedLength(); 42 | needMore = true; 43 | } 44 | } catch (final IncorrectFrameException e) { 45 | frameBuffer.reset(); 46 | needMore = false; 47 | } 48 | return null; 49 | 50 | } else { 51 | return null; 52 | } 53 | 54 | } 55 | 56 | private static Frame parseFrameRaw(final byte[] rawBytes) throws IncorrectFrameException { 57 | if (rawBytes.length >= 2) { 58 | try { 59 | switch (FrameType.fromByte(rawBytes[1])) { 60 | case CREATE: 61 | return new CreateConnectionFrame(rawBytes); 62 | case CLOSE: 63 | return new CloseConnectionFrame(rawBytes); 64 | case DATA: 65 | return new DataFrame(rawBytes); 66 | case PAUSE: 67 | return new PauseConnectionFrame(rawBytes); 68 | case CONTINUE: 69 | return new ContinueConnectionFrame(rawBytes); 70 | default: 71 | throw new IncorrectFrameException("Unknown Frame Type"); 72 | } 73 | } catch (final IllegalArgumentException e) { 74 | throw new IncorrectFrameException("Unknown Frame Type"); 75 | } 76 | } else { 77 | throw new IncorrectFrameException("Packet is too short"); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/network/server/ForwarderServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.network.server; 9 | 10 | import com.vecsight.dragonite.forwarder.config.ForwarderServerConfig; 11 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 12 | import com.vecsight.dragonite.sdk.socket.DragoniteServer; 13 | import com.vecsight.dragonite.sdk.socket.DragoniteSocket; 14 | import org.pmw.tinylog.Logger; 15 | 16 | import java.net.InetSocketAddress; 17 | import java.net.SocketException; 18 | 19 | public class ForwarderServer { 20 | 21 | private final InetSocketAddress bindAddress; 22 | 23 | private final InetSocketAddress forwardingAddress; 24 | 25 | private final int limitMbps; 26 | 27 | private final String welcomeMessage; 28 | 29 | private final DragoniteServer dragoniteServer; 30 | 31 | private volatile boolean doAccept = true; 32 | 33 | private final Thread acceptThread; 34 | 35 | public ForwarderServer(final ForwarderServerConfig config) throws SocketException { 36 | this.bindAddress = config.getBindAddress(); 37 | this.forwardingAddress = config.getForwardingAddress(); 38 | this.limitMbps = config.getMbpsLimit(); 39 | this.welcomeMessage = config.getWelcomeMessage(); 40 | 41 | this.dragoniteServer = new DragoniteServer(bindAddress.getAddress(), bindAddress.getPort(), 42 | ForwarderGlobalConstants.INIT_SEND_SPEED, config.getDragoniteSocketParameters()); 43 | 44 | acceptThread = new Thread(() -> { 45 | try { 46 | DragoniteSocket socket; 47 | while (doAccept && (socket = dragoniteServer.accept()) != null) { 48 | Logger.debug("New client from {}", socket.getRemoteSocketAddress().toString()); 49 | handleClient(socket); 50 | } 51 | } catch (final InterruptedException e) { 52 | Logger.error(e, "Unable to accept Dragonite connections"); 53 | } 54 | }, "FS-Accept"); 55 | acceptThread.start(); 56 | } 57 | 58 | private void handleClient(final DragoniteSocket socket) { 59 | final ForwarderClientHandler clientHandler = new ForwarderClientHandler(forwardingAddress, socket, limitMbps, welcomeMessage); 60 | final Thread handlerThread = new Thread(clientHandler::run, "FS-Handler"); 61 | handlerThread.start(); 62 | } 63 | 64 | public boolean isDoAccept() { 65 | return doAccept; 66 | } 67 | 68 | public void stopAccept() { 69 | acceptThread.interrupt(); 70 | doAccept = false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/ParsedACL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl; 9 | 10 | import com.vecsight.dragonite.proxy.acl.item.ACLItem; 11 | 12 | import java.net.InetAddress; 13 | import java.net.UnknownHostException; 14 | import java.nio.ByteBuffer; 15 | import java.util.List; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | public class ParsedACL { 19 | 20 | private final String title; 21 | 22 | private final String author; 23 | 24 | private final ACLItemMethod defaultMethod; 25 | 26 | private final List items; 27 | 28 | private final ConcurrentHashMap domainCacheMap = new ConcurrentHashMap<>(); 29 | 30 | private final ConcurrentHashMap ipCacheMap = new ConcurrentHashMap<>(); 31 | 32 | public ParsedACL(final String title, final String author, final ACLItemMethod defaultMethod, final List items) { 33 | this.title = title; 34 | this.author = author; 35 | this.defaultMethod = defaultMethod; 36 | this.items = items; 37 | } 38 | 39 | public String getTitle() { 40 | return title; 41 | } 42 | 43 | public String getAuthor() { 44 | return author; 45 | } 46 | 47 | public List getItems() { 48 | return items; 49 | } 50 | 51 | public ACLItemMethod getDefaultMethod() { 52 | return defaultMethod; 53 | } 54 | 55 | public ACLItemMethod checkDomain(final String address) { 56 | final ACLItemMethod cachedMethod = domainCacheMap.get(address); 57 | if (cachedMethod != null) return cachedMethod; 58 | 59 | byte[] ip; 60 | try { 61 | ip = InetAddress.getByName(address).getAddress(); 62 | } catch (final UnknownHostException e) { 63 | ip = null; 64 | } 65 | 66 | for (final ACLItem item : items) { 67 | if (item.match(address) || (ip != null && item.match(ip))) { 68 | domainCacheMap.put(address, item.getMethod()); 69 | return item.getMethod(); 70 | } 71 | } 72 | return defaultMethod; 73 | } 74 | 75 | public ACLItemMethod checkIP(final byte[] ip) { 76 | final ACLItemMethod cachedMethod = ipCacheMap.get(ByteBuffer.wrap(ip)); 77 | if (cachedMethod != null) return cachedMethod; 78 | 79 | for (final ACLItem item : items) { 80 | if (item.match(ip)) { 81 | ipCacheMap.put(ByteBuffer.wrap(ip), item.getMethod()); 82 | return item.getMethod(); 83 | } 84 | } 85 | 86 | return defaultMethod; 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/ServerResponseHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * VERSION 1 SB 19 | * status 1 SB 20 | * msgLen 2 US 21 | * msg [length] 22 | */ 23 | 24 | public class ServerResponseHeader { 25 | 26 | private static final byte VERSION = ProxyGlobalConstants.PROTOCOL_VERSION; 27 | 28 | public static final int FIXED_LENGTH = 4; 29 | 30 | private byte status; 31 | 32 | private String msg; 33 | 34 | public ServerResponseHeader(final byte status, final String msg) { 35 | this.status = status; 36 | this.msg = msg; 37 | } 38 | 39 | public ServerResponseHeader(final byte[] header) throws IncorrectHeaderException { 40 | final BinaryReader reader = new BinaryReader(header); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | 46 | if (remoteVersion != VERSION) { 47 | throw new IncorrectHeaderException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 48 | } 49 | 50 | status = reader.getSignedByte(); 51 | 52 | msg = new String(reader.getBytesGroupWithShortLength(), ProxyGlobalConstants.STRING_CHARSET); 53 | 54 | } catch (final BufferUnderflowException e) { 55 | throw new IncorrectHeaderException("Incorrect header length"); 56 | } 57 | } 58 | 59 | public byte getStatus() { 60 | return status; 61 | } 62 | 63 | public void setStatus(final byte status) { 64 | this.status = status; 65 | } 66 | 67 | public String getMsg() { 68 | return msg; 69 | } 70 | 71 | public void setMsg(final String msg) { 72 | this.msg = msg; 73 | } 74 | 75 | public static byte getVersion() { 76 | return VERSION; 77 | } 78 | 79 | public static int getFixedLength() { 80 | return FIXED_LENGTH; 81 | } 82 | 83 | public byte[] toBytes() { 84 | final byte[] msgBytes = msg.getBytes(ProxyGlobalConstants.STRING_CHARSET); 85 | 86 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + msgBytes.length); 87 | 88 | writer.putSignedByte(VERSION) 89 | .putSignedByte(status) 90 | .putBytesGroupWithShortLength(msgBytes); 91 | 92 | return writer.toBytes(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/header/ServerResponseHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.header; 9 | 10 | import com.vecsight.dragonite.forwarder.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * VERSION 1 SB 19 | * status 1 SB 20 | * msgLen 2 US 21 | * msg [length] 22 | */ 23 | 24 | public class ServerResponseHeader { 25 | 26 | private static final byte VERSION = ForwarderGlobalConstants.PROTOCOL_VERSION; 27 | 28 | public static final int FIXED_LENGTH = 4; 29 | 30 | private byte status; 31 | 32 | private String msg; 33 | 34 | public ServerResponseHeader(final byte status, final String msg) { 35 | this.status = status; 36 | this.msg = msg; 37 | } 38 | 39 | public ServerResponseHeader(final byte[] header) throws IncorrectHeaderException { 40 | final BinaryReader reader = new BinaryReader(header); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | 46 | if (remoteVersion != VERSION) { 47 | throw new IncorrectHeaderException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 48 | } 49 | 50 | status = reader.getSignedByte(); 51 | 52 | msg = new String(reader.getBytesGroupWithShortLength(), ForwarderGlobalConstants.STRING_CHARSET); 53 | 54 | } catch (final BufferUnderflowException e) { 55 | throw new IncorrectHeaderException("Incorrect header length"); 56 | } 57 | } 58 | 59 | public byte getStatus() { 60 | return status; 61 | } 62 | 63 | public void setStatus(final byte status) { 64 | this.status = status; 65 | } 66 | 67 | public String getMsg() { 68 | return msg; 69 | } 70 | 71 | public void setMsg(final String msg) { 72 | this.msg = msg; 73 | } 74 | 75 | public static byte getVersion() { 76 | return VERSION; 77 | } 78 | 79 | public static int getFixedLength() { 80 | return FIXED_LENGTH; 81 | } 82 | 83 | public byte[] toBytes() { 84 | final byte[] msgBytes = msg.getBytes(ForwarderGlobalConstants.STRING_CHARSET); 85 | 86 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + msgBytes.length); 87 | 88 | writer.putSignedByte(VERSION) 89 | .putSignedByte(status) 90 | .putBytesGroupWithShortLength(msgBytes); 91 | 92 | return writer.toBytes(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/types/HeartbeatMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg.types; 9 | 10 | import com.vecsight.dragonite.sdk.exception.IncorrectMessageException; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | import com.vecsight.dragonite.sdk.msg.MessageType; 13 | import com.vecsight.dragonite.sdk.msg.ReliableMessage; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | public class HeartbeatMessage implements ReliableMessage { 20 | 21 | private static final byte VERSION = DragoniteGlobalConstants.PROTOCOL_VERSION; 22 | 23 | private static final MessageType TYPE = MessageType.HEARTBEAT; 24 | 25 | public static final int FIXED_LENGTH = 6; 26 | 27 | private int sequence; 28 | 29 | public HeartbeatMessage(final int sequence) { 30 | this.sequence = sequence; 31 | } 32 | 33 | public HeartbeatMessage(final byte[] msg) throws IncorrectMessageException { 34 | final BinaryReader reader = new BinaryReader(msg); 35 | 36 | try { 37 | 38 | final byte remoteVersion = reader.getSignedByte(); 39 | final byte remoteType = reader.getSignedByte(); 40 | 41 | if (remoteVersion != VERSION) { 42 | throw new IncorrectMessageException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 43 | } 44 | if (remoteType != TYPE.getValue()) { 45 | throw new IncorrectMessageException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 46 | } 47 | 48 | sequence = reader.getSignedInt(); 49 | 50 | } catch (final BufferUnderflowException e) { 51 | throw new IncorrectMessageException("Incorrect message length"); 52 | } 53 | } 54 | 55 | @Override 56 | public byte getVersion() { 57 | return VERSION; 58 | } 59 | 60 | @Override 61 | public MessageType getType() { 62 | return TYPE; 63 | } 64 | 65 | @Override 66 | public byte[] toBytes() { 67 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 68 | 69 | writer.putSignedByte(VERSION) 70 | .putSignedByte(TYPE.getValue()) 71 | .putSignedInt(sequence); 72 | 73 | return writer.toBytes(); 74 | } 75 | 76 | @Override 77 | public int getFixedLength() { 78 | return FIXED_LENGTH; 79 | } 80 | 81 | @Override 82 | public int getSequence() { 83 | return sequence; 84 | } 85 | 86 | @Override 87 | public void setSequence(final int sequence) { 88 | this.sequence = sequence; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/server/ProxyServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.network.server; 9 | 10 | import com.vecsight.dragonite.proxy.config.ProxyServerConfig; 11 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 12 | import com.vecsight.dragonite.sdk.cryptor.PacketCryptor; 13 | import com.vecsight.dragonite.sdk.socket.DragoniteServer; 14 | import com.vecsight.dragonite.sdk.socket.DragoniteSocket; 15 | import org.pmw.tinylog.Logger; 16 | 17 | import java.net.InetSocketAddress; 18 | import java.net.SocketException; 19 | 20 | public class ProxyServer { 21 | 22 | private final InetSocketAddress bindAddress; 23 | 24 | private final int limitMbps; 25 | 26 | private final String welcomeMessage; 27 | 28 | private final boolean allowLoopback; 29 | 30 | private final PacketCryptor packetCryptor; 31 | 32 | private final DragoniteServer dragoniteServer; 33 | 34 | private volatile boolean doAccept = true; 35 | 36 | private final Thread acceptThread; 37 | 38 | public ProxyServer(final ProxyServerConfig config) throws SocketException { 39 | this.bindAddress = config.getBindAddress(); 40 | this.limitMbps = config.getMbpsLimit(); 41 | this.welcomeMessage = config.getWelcomeMessage(); 42 | this.allowLoopback = config.isAllowLoopback(); 43 | this.packetCryptor = config.getDragoniteSocketParameters().getPacketCryptor(); 44 | 45 | this.dragoniteServer = new DragoniteServer(bindAddress.getAddress(), bindAddress.getPort(), 46 | ProxyGlobalConstants.INIT_SEND_SPEED, config.getDragoniteSocketParameters()); 47 | 48 | acceptThread = new Thread(() -> { 49 | try { 50 | DragoniteSocket socket; 51 | while (doAccept && (socket = dragoniteServer.accept()) != null) { 52 | Logger.debug("New client from {}", socket.getRemoteSocketAddress().toString()); 53 | handleClient(socket); 54 | } 55 | } catch (final InterruptedException e) { 56 | Logger.error(e, "Unable to accept Dragonite connections"); 57 | } 58 | }, "PS-Accept"); 59 | acceptThread.start(); 60 | } 61 | 62 | private void handleClient(final DragoniteSocket socket) { 63 | final ProxyClientHandler clientHandler = new ProxyClientHandler(socket, limitMbps, welcomeMessage, 64 | allowLoopback, packetCryptor); 65 | final Thread handlerThread = new Thread(clientHandler::run, "PS-Handler"); 66 | handlerThread.start(); 67 | } 68 | 69 | public boolean isDoAccept() { 70 | return doAccept; 71 | } 72 | 73 | public void stopAccept() { 74 | acceptThread.interrupt(); 75 | doAccept = false; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/mux/MuxConnectionResponseHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header.mux; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * status 1 SB 19 | * udp port 2 US 20 | * msgLen 1 UB 21 | * msg [length] 22 | */ 23 | 24 | public class MuxConnectionResponseHeader { 25 | 26 | private ConnectionStatus status; 27 | 28 | private int udpPort; 29 | 30 | private String msg; 31 | 32 | public MuxConnectionResponseHeader(final ConnectionStatus status, final int udpPort, final String msg) { 33 | this.status = status; 34 | this.udpPort = udpPort; 35 | this.msg = msg; 36 | } 37 | 38 | public MuxConnectionResponseHeader(final byte[] header) throws IncorrectHeaderException { 39 | final BinaryReader reader = new BinaryReader(header); 40 | 41 | try { 42 | 43 | final byte rawStatus = reader.getSignedByte(); 44 | 45 | try { 46 | status = ConnectionStatus.fromByte(rawStatus); 47 | } catch (final IllegalArgumentException e) { 48 | throw new IncorrectHeaderException("Invalid status type " + rawStatus); 49 | } 50 | 51 | udpPort = reader.getUnsignedShort(); 52 | 53 | msg = new String(reader.getBytesGroupWithByteLength(), ProxyGlobalConstants.STRING_CHARSET); 54 | 55 | } catch (final BufferUnderflowException e) { 56 | throw new IncorrectHeaderException("Incorrect frame length"); 57 | } 58 | 59 | } 60 | 61 | public ConnectionStatus getStatus() { 62 | return status; 63 | } 64 | 65 | public void setStatus(final ConnectionStatus status) { 66 | this.status = status; 67 | } 68 | 69 | public int getUdpPort() { 70 | return udpPort; 71 | } 72 | 73 | public void setUdpPort(final int udpPort) { 74 | this.udpPort = udpPort; 75 | } 76 | 77 | public String getMsg() { 78 | return msg; 79 | } 80 | 81 | public void setMsg(final String msg) { 82 | this.msg = msg; 83 | } 84 | 85 | public byte[] toBytes() { 86 | final byte[] msgBytes = msg.getBytes(ProxyGlobalConstants.STRING_CHARSET); 87 | 88 | final BinaryWriter writer = new BinaryWriter(4 + msgBytes.length); 89 | 90 | writer.putSignedByte(status.getValue()) 91 | .putUnsignedShort(udpPort) 92 | .putBytesGroupWithByteLength(msgBytes); 93 | 94 | return writer.toBytes(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/IPv4CIDRACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | import com.vecsight.dragonite.proxy.exception.InvalidAddressException; 13 | 14 | import java.net.InetAddress; 15 | import java.net.UnknownHostException; 16 | 17 | public class IPv4CIDRACLItem implements ACLItem { 18 | 19 | private final int lowest; 20 | 21 | private final int highest; 22 | 23 | private final ACLItemMethod method; 24 | 25 | public IPv4CIDRACLItem(final String string, final ACLItemMethod method) throws InvalidAddressException { 26 | this.method = method; 27 | 28 | if (!string.contains("/")) { 29 | throw new InvalidAddressException(string + " is not a valid IPv4 CIDR address"); 30 | } 31 | 32 | final String[] stringSplit = string.split("/"); 33 | if (stringSplit.length != 2) { 34 | throw new InvalidAddressException(string + " is not a valid IPv4 CIDR address"); 35 | } 36 | 37 | final byte[] bytes; 38 | try { 39 | bytes = InetAddress.getByName(stringSplit[0]).getAddress(); 40 | if (bytes.length != 4) throw new InvalidAddressException(string + " is not a valid IPv4 address"); 41 | } catch (final UnknownHostException e) { 42 | throw new InvalidAddressException(stringSplit[0] + " is not a valid IPv4 address"); 43 | } 44 | 45 | final int mask; 46 | try { 47 | final int shift = Integer.parseInt(stringSplit[1]); 48 | 49 | if (shift < 1 || shift > 32) 50 | throw new InvalidAddressException(string + " is not a valid IPv4 CIDR address"); 51 | 52 | mask = (-1) << (32 - shift); 53 | } catch (final NumberFormatException e) { 54 | throw new InvalidAddressException(string + " is not a valid IPv4 CIDR address"); 55 | } 56 | 57 | final int addr = ipv4ToInt(bytes); 58 | 59 | lowest = addr & mask; 60 | 61 | highest = lowest + (~mask); 62 | 63 | } 64 | 65 | private int ipv4ToInt(final byte[] bytes) { 66 | return ((bytes[0] << 24) & 0xFF000000) 67 | | ((bytes[1] << 16) & 0xFF0000) 68 | | ((bytes[2] << 8) & 0xFF00) 69 | | (bytes[3] & 0xFF); 70 | } 71 | 72 | @Override 73 | public ACLItemType getType() { 74 | return ACLItemType.IPv4_CIDR; 75 | } 76 | 77 | @Override 78 | public ACLItemMethod getMethod() { 79 | return method; 80 | } 81 | 82 | @Override 83 | public boolean match(final String domain) { 84 | return false; 85 | } 86 | 87 | @Override 88 | public boolean match(final byte[] address) { 89 | if (address.length != 4) return false; 90 | final int addr = ipv4ToInt(address); 91 | return addr >= lowest && addr <= highest; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/types/PauseConnectionFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame.types; 9 | 10 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 11 | import com.vecsight.dragonite.mux.frame.Frame; 12 | import com.vecsight.dragonite.mux.frame.FrameType; 13 | import com.vecsight.dragonite.mux.misc.MuxGlobalConstants; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | /* 20 | * VERSION 1 SB 21 | * TYPE 1 SB 22 | * connID 2 SS 23 | */ 24 | 25 | public class PauseConnectionFrame implements Frame { 26 | 27 | private static final byte VERSION = MuxGlobalConstants.PROTOCOL_VERSION; 28 | 29 | private static final FrameType TYPE = FrameType.PAUSE; 30 | 31 | public static final int FIXED_LENGTH = 4; 32 | 33 | private short connectionID; 34 | 35 | public PauseConnectionFrame(final short connectionID) { 36 | this.connectionID = connectionID; 37 | } 38 | 39 | public PauseConnectionFrame(final byte[] frame) throws IncorrectFrameException { 40 | final BinaryReader reader = new BinaryReader(frame); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | final byte remoteType = reader.getSignedByte(); 46 | 47 | if (remoteVersion != VERSION) { 48 | throw new IncorrectFrameException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 49 | } 50 | if (remoteType != TYPE.getValue()) { 51 | throw new IncorrectFrameException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 52 | } 53 | 54 | connectionID = reader.getSignedShort(); 55 | 56 | } catch (final BufferUnderflowException e) { 57 | throw new IncorrectFrameException("Incorrect frame length"); 58 | } 59 | } 60 | 61 | public short getConnectionID() { 62 | return connectionID; 63 | } 64 | 65 | public void setConnectionID(final short connectionID) { 66 | this.connectionID = connectionID; 67 | } 68 | 69 | @Override 70 | public byte getVersion() { 71 | return VERSION; 72 | } 73 | 74 | @Override 75 | public FrameType getType() { 76 | return TYPE; 77 | } 78 | 79 | @Override 80 | public byte[] toBytes() { 81 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 82 | 83 | writer.putSignedByte(VERSION) 84 | .putSignedByte(TYPE.getValue()) 85 | .putSignedShort(connectionID); 86 | 87 | return writer.toBytes(); 88 | } 89 | 90 | @Override 91 | public int getFixedLength() { 92 | return FIXED_LENGTH; 93 | } 94 | 95 | @Override 96 | public int getExpectedLength() { 97 | return 0; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/types/CloseConnectionFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame.types; 9 | 10 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 11 | import com.vecsight.dragonite.mux.frame.Frame; 12 | import com.vecsight.dragonite.mux.frame.FrameType; 13 | import com.vecsight.dragonite.mux.misc.MuxGlobalConstants; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | /* 20 | * VERSION 1 SB 21 | * TYPE 1 SB 22 | * connID 2 SS 23 | */ 24 | 25 | public class CloseConnectionFrame implements Frame { 26 | 27 | private static final byte VERSION = MuxGlobalConstants.PROTOCOL_VERSION; 28 | 29 | private static final FrameType TYPE = FrameType.CLOSE; 30 | 31 | public static final int FIXED_LENGTH = 4; 32 | 33 | private short connectionID; 34 | 35 | public CloseConnectionFrame(final short connectionID) { 36 | this.connectionID = connectionID; 37 | } 38 | 39 | public CloseConnectionFrame(final byte[] frame) throws IncorrectFrameException { 40 | final BinaryReader reader = new BinaryReader(frame); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | final byte remoteType = reader.getSignedByte(); 46 | 47 | if (remoteVersion != VERSION) { 48 | throw new IncorrectFrameException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 49 | } 50 | if (remoteType != TYPE.getValue()) { 51 | throw new IncorrectFrameException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 52 | } 53 | 54 | connectionID = reader.getSignedShort(); 55 | 56 | } catch (final BufferUnderflowException e) { 57 | throw new IncorrectFrameException("Incorrect frame length"); 58 | } 59 | 60 | } 61 | 62 | public short getConnectionID() { 63 | return connectionID; 64 | } 65 | 66 | public void setConnectionID(final short connectionID) { 67 | this.connectionID = connectionID; 68 | } 69 | 70 | @Override 71 | public byte getVersion() { 72 | return VERSION; 73 | } 74 | 75 | @Override 76 | public FrameType getType() { 77 | return TYPE; 78 | } 79 | 80 | @Override 81 | public byte[] toBytes() { 82 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 83 | 84 | writer.putSignedByte(VERSION) 85 | .putSignedByte(TYPE.getValue()) 86 | .putSignedShort(connectionID); 87 | 88 | return writer.toBytes(); 89 | } 90 | 91 | @Override 92 | public int getFixedLength() { 93 | return FIXED_LENGTH; 94 | } 95 | 96 | @Override 97 | public int getExpectedLength() { 98 | return 0; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/types/CreateConnectionFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame.types; 9 | 10 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 11 | import com.vecsight.dragonite.mux.frame.Frame; 12 | import com.vecsight.dragonite.mux.frame.FrameType; 13 | import com.vecsight.dragonite.mux.misc.MuxGlobalConstants; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | /* 20 | * VERSION 1 SB 21 | * TYPE 1 SB 22 | * connID 2 SS 23 | */ 24 | 25 | public class CreateConnectionFrame implements Frame { 26 | 27 | private static final byte VERSION = MuxGlobalConstants.PROTOCOL_VERSION; 28 | 29 | private static final FrameType TYPE = FrameType.CREATE; 30 | 31 | public static final int FIXED_LENGTH = 4; 32 | 33 | private short connectionID; 34 | 35 | public CreateConnectionFrame(final short connectionID) { 36 | this.connectionID = connectionID; 37 | } 38 | 39 | public CreateConnectionFrame(final byte[] frame) throws IncorrectFrameException { 40 | final BinaryReader reader = new BinaryReader(frame); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | final byte remoteType = reader.getSignedByte(); 46 | 47 | if (remoteVersion != VERSION) { 48 | throw new IncorrectFrameException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 49 | } 50 | if (remoteType != TYPE.getValue()) { 51 | throw new IncorrectFrameException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 52 | } 53 | 54 | connectionID = reader.getSignedShort(); 55 | 56 | } catch (final BufferUnderflowException e) { 57 | throw new IncorrectFrameException("Incorrect frame length"); 58 | } 59 | } 60 | 61 | public short getConnectionID() { 62 | return connectionID; 63 | } 64 | 65 | public void setConnectionID(final short connectionID) { 66 | this.connectionID = connectionID; 67 | } 68 | 69 | @Override 70 | public byte getVersion() { 71 | return VERSION; 72 | } 73 | 74 | @Override 75 | public FrameType getType() { 76 | return TYPE; 77 | } 78 | 79 | @Override 80 | public byte[] toBytes() { 81 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 82 | 83 | writer.putSignedByte(VERSION) 84 | .putSignedByte(TYPE.getValue()) 85 | .putSignedShort(connectionID); 86 | 87 | return writer.toBytes(); 88 | } 89 | 90 | @Override 91 | public int getFixedLength() { 92 | return FIXED_LENGTH; 93 | } 94 | 95 | @Override 96 | public int getExpectedLength() { 97 | return 0; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/types/ContinueConnectionFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame.types; 9 | 10 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 11 | import com.vecsight.dragonite.mux.frame.Frame; 12 | import com.vecsight.dragonite.mux.frame.FrameType; 13 | import com.vecsight.dragonite.mux.misc.MuxGlobalConstants; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | /* 20 | * VERSION 1 SB 21 | * TYPE 1 SB 22 | * connID 2 SS 23 | */ 24 | 25 | public class ContinueConnectionFrame implements Frame { 26 | 27 | private static final byte VERSION = MuxGlobalConstants.PROTOCOL_VERSION; 28 | 29 | private static final FrameType TYPE = FrameType.CONTINUE; 30 | 31 | public static final int FIXED_LENGTH = 4; 32 | 33 | private short connectionID; 34 | 35 | public ContinueConnectionFrame(final short connectionID) { 36 | this.connectionID = connectionID; 37 | } 38 | 39 | public ContinueConnectionFrame(final byte[] frame) throws IncorrectFrameException { 40 | final BinaryReader reader = new BinaryReader(frame); 41 | 42 | try { 43 | 44 | final byte remoteVersion = reader.getSignedByte(); 45 | final byte remoteType = reader.getSignedByte(); 46 | 47 | if (remoteVersion != VERSION) { 48 | throw new IncorrectFrameException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 49 | } 50 | if (remoteType != TYPE.getValue()) { 51 | throw new IncorrectFrameException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 52 | } 53 | 54 | connectionID = reader.getSignedShort(); 55 | 56 | } catch (final BufferUnderflowException e) { 57 | throw new IncorrectFrameException("Incorrect frame length"); 58 | } 59 | 60 | } 61 | 62 | public short getConnectionID() { 63 | return connectionID; 64 | } 65 | 66 | public void setConnectionID(final short connectionID) { 67 | this.connectionID = connectionID; 68 | } 69 | 70 | @Override 71 | public byte getVersion() { 72 | return VERSION; 73 | } 74 | 75 | @Override 76 | public FrameType getType() { 77 | return TYPE; 78 | } 79 | 80 | @Override 81 | public byte[] toBytes() { 82 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 83 | 84 | writer.putSignedByte(VERSION) 85 | .putSignedByte(TYPE.getValue()) 86 | .putSignedShort(connectionID); 87 | 88 | return writer.toBytes(); 89 | } 90 | 91 | @Override 92 | public int getFixedLength() { 93 | return FIXED_LENGTH; 94 | } 95 | 96 | @Override 97 | public int getExpectedLength() { 98 | return 0; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/acl/item/IPv6CIDRACLItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.acl.item; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ACLItemMethod; 11 | import com.vecsight.dragonite.proxy.acl.ACLItemType; 12 | import com.vecsight.dragonite.proxy.exception.InvalidAddressException; 13 | 14 | import java.math.BigInteger; 15 | import java.net.InetAddress; 16 | import java.net.UnknownHostException; 17 | 18 | public class IPv6CIDRACLItem implements ACLItem { 19 | 20 | private final BigInteger lowest; 21 | 22 | private final BigInteger highest; 23 | 24 | private final ACLItemMethod method; 25 | 26 | private static final byte[] MASK_BASE = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; 27 | 28 | public IPv6CIDRACLItem(final String string, final ACLItemMethod method) throws InvalidAddressException { 29 | this.method = method; 30 | 31 | if (!string.contains("/")) { 32 | throw new InvalidAddressException(string + " is not a valid IPv6 CIDR address"); 33 | } 34 | 35 | final String[] stringSplit = string.split("/"); 36 | if (stringSplit.length != 2) { 37 | throw new InvalidAddressException(string + " is not a valid IPv6 CIDR address"); 38 | } 39 | 40 | final byte[] ipBytes; 41 | try { 42 | ipBytes = InetAddress.getByName(stringSplit[0]).getAddress(); 43 | if (ipBytes.length != 16) throw new InvalidAddressException(string + " is not a valid IPv6 address"); 44 | } catch (final UnknownHostException e) { 45 | throw new InvalidAddressException(stringSplit[0] + " is not a valid IPv6 address"); 46 | } 47 | 48 | final int cidrShift; 49 | try { 50 | cidrShift = Integer.parseInt(stringSplit[1]); 51 | if (cidrShift < 1 || cidrShift > 128) 52 | throw new InvalidAddressException(string + " is not a valid IPv6 CIDR address"); 53 | } catch (final NumberFormatException e) { 54 | throw new InvalidAddressException(string + " is not a valid IPv4 CIDR address"); 55 | } 56 | 57 | final BigInteger mask = (new BigInteger(1, MASK_BASE)).not().shiftRight(cidrShift); 58 | 59 | final BigInteger ipVal = new BigInteger(1, ipBytes); 60 | 61 | lowest = ipVal.and(mask); 62 | 63 | highest = lowest.add(mask.not()); 64 | } 65 | 66 | @Override 67 | public ACLItemType getType() { 68 | return ACLItemType.IPv4_CIDR; 69 | } 70 | 71 | @Override 72 | public ACLItemMethod getMethod() { 73 | return method; 74 | } 75 | 76 | @Override 77 | public boolean match(final String domain) { 78 | return false; 79 | } 80 | 81 | @Override 82 | public boolean match(final byte[] address) { 83 | if (address.length != 16) return false; 84 | final BigInteger target = new BigInteger(1, address); 85 | final int st = lowest.compareTo(target); 86 | final int te = target.compareTo(highest); 87 | return (st <= 0) && (te <= 0); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## dragonite-sdk 4 | 5 | ### 0.1.0 6 | The initial release. 7 | 8 | ### 0.1.1 9 | Fix a thread deadlock problem 10 | 11 | ### 0.1.2 12 | Add slow retransmission mode for packets that lost too many times 13 | 14 | ### 0.2.0 15 | Add HTTP(JSON) statistics interface 16 | 17 | Fix redundant retransmissions caused by delayed ACKs 18 | 19 | ### 0.2.1 20 | Enable Cross-Origin Resource Sharing (CORS) for HTTP(JSON) statistics interface 21 | 22 | ### 0.2.2 23 | Minor bandwidth usage optimizations 24 | 25 | ### 0.3.1 26 | Protocol Version 2: Major robustness improvement 27 | 28 | Obfuscator interface for customized packet obfuscation 29 | 30 | ### 0.3.2 31 | Add CRXObfuscator 32 | 33 | ### 0.3.3 34 | Obfuscators are now Cryptors, shipped with a new AESCryptor 35 | 36 | ### 0.3.4 37 | Add DSCP option 38 | 39 | ## dragonite-mux 40 | 41 | ### 0.1.0 42 | The initial release. 43 | 44 | ### 0.2.0 45 | New flow control mechanism (Buffer size limitations, Pause & Continue frames) 46 | 47 | ### 0.3.0 48 | Protocol Version 2: Major robustness improvement 49 | 50 | ## dragonite-forwarder 51 | 52 | ### 0.1.0 53 | The initial release. 54 | 55 | ### 0.1.1 56 | Add a new speed limit option for server (-l) 57 | 58 | ### 0.1.2 59 | Auto reconnect for broken underlying dragonite socket connections 60 | 61 | Set default logging level to INFO, use --debug to enable debug mode 62 | 63 | ### 0.1.3 64 | Add an option for enabling HTTP(JSON) statistics interface of underlying dragonite socket connections 65 | 66 | ### 0.1.4 67 | GUI Web Panel for HTTP(JSON) statistics interface 68 | 69 | --web-panel & --web-panel-public options 70 | 71 | ### 0.1.5 72 | Minor bandwidth usage optimizations from SDK v0.2.2 73 | 74 | Adjustable send window size multiplier (option --window-size-multiplier) 75 | 76 | ### 0.2.0 77 | Protocol Version 2: Added Server Response Message allowing custom server welcome message (option -w) 78 | 79 | ### 0.3.0 80 | Protocol Version 3: Major robustness improvement 81 | 82 | ### 0.3.1 83 | Update checking system 84 | 85 | ### 0.3.2 86 | Add an option (-r) for forwarding connections to remote servers 87 | 88 | ### 0.3.3 89 | Add the same encryption system as dragonite-proxy, use option (-k) to set passwords 90 | 91 | ### 0.4.0 92 | Add an option (--dscp) for customizing DSCP field of UDP packets 93 | 94 | Add an option (--skip-update) for skipping update-checking 95 | 96 | ## dragonite-proxy 97 | 98 | ### 0.1.0 99 | The initial release. 100 | 101 | ### 0.1.1 102 | Add a new obfuscation option (--obfs) 103 | 104 | ### 0.1.2 105 | Adapt to new CRXObfuscator 106 | 107 | ### 0.2.0 108 | Protocol Version 2: Full SOCKS5 UDP relay support 109 | 110 | ### 0.2.1 111 | Block loopback address by default, add --allow-loopback option 112 | 113 | ### 0.2.2 114 | JSON configuration support 115 | 116 | ### 0.3.0 117 | Adapt to the new protocol layer encryption, remove obsolete encryption system. 118 | 119 | Fix a buffer length bug in UDP relay 120 | 121 | ### 0.3.1 122 | Update checking system 123 | 124 | ### 0.4.0 125 | Add an option (--dscp) for customizing DSCP field of UDP packets 126 | 127 | Add an option (--skip-update) for skipping update-checking 128 | 129 | Fix unclear ACL exception messages 130 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/types/CloseMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg.types; 9 | 10 | import com.vecsight.dragonite.sdk.exception.IncorrectMessageException; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | import com.vecsight.dragonite.sdk.msg.MessageType; 13 | import com.vecsight.dragonite.sdk.msg.ReliableMessage; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | public class CloseMessage implements ReliableMessage { 20 | 21 | private static final byte VERSION = DragoniteGlobalConstants.PROTOCOL_VERSION; 22 | 23 | private static final MessageType TYPE = MessageType.CLOSE; 24 | 25 | public static final int FIXED_LENGTH = 8; 26 | 27 | private int sequence; 28 | 29 | private short status; 30 | 31 | public CloseMessage(final int sequence, final short status) { 32 | this.sequence = sequence; 33 | this.status = status; 34 | } 35 | 36 | public CloseMessage(final byte[] msg) throws IncorrectMessageException { 37 | final BinaryReader reader = new BinaryReader(msg); 38 | 39 | try { 40 | 41 | final byte remoteVersion = reader.getSignedByte(); 42 | final byte remoteType = reader.getSignedByte(); 43 | 44 | if (remoteVersion != VERSION) { 45 | throw new IncorrectMessageException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 46 | } 47 | if (remoteType != TYPE.getValue()) { 48 | throw new IncorrectMessageException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 49 | } 50 | 51 | sequence = reader.getSignedInt(); 52 | 53 | status = reader.getSignedShort(); 54 | 55 | } catch (final BufferUnderflowException e) { 56 | throw new IncorrectMessageException("Incorrect message length"); 57 | } 58 | } 59 | 60 | @Override 61 | public byte getVersion() { 62 | return VERSION; 63 | } 64 | 65 | @Override 66 | public MessageType getType() { 67 | return TYPE; 68 | } 69 | 70 | @Override 71 | public byte[] toBytes() { 72 | final BinaryWriter writer = new BinaryWriter(getFixedLength()); 73 | 74 | writer.putSignedByte(VERSION) 75 | .putSignedByte(TYPE.getValue()) 76 | .putSignedInt(sequence) 77 | .putSignedShort(status); 78 | 79 | return writer.toBytes(); 80 | } 81 | 82 | @Override 83 | public int getFixedLength() { 84 | return FIXED_LENGTH; 85 | } 86 | 87 | @Override 88 | public int getSequence() { 89 | return sequence; 90 | } 91 | 92 | @Override 93 | public void setSequence(final int sequence) { 94 | this.sequence = sequence; 95 | } 96 | 97 | public short getStatus() { 98 | return status; 99 | } 100 | 101 | public void setStatus(final short status) { 102 | this.status = status; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/types/DataMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg.types; 9 | 10 | import com.vecsight.dragonite.sdk.exception.IncorrectMessageException; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | import com.vecsight.dragonite.sdk.msg.MessageType; 13 | import com.vecsight.dragonite.sdk.msg.ReliableMessage; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | public class DataMessage implements ReliableMessage { 20 | 21 | private static final byte VERSION = DragoniteGlobalConstants.PROTOCOL_VERSION; 22 | 23 | private static final MessageType TYPE = MessageType.DATA; 24 | 25 | public static final int FIXED_LENGTH = 8; 26 | 27 | private int sequence; 28 | 29 | private byte[] data; 30 | 31 | public DataMessage(final int sequence, final byte[] data) { 32 | this.sequence = sequence; 33 | this.data = data; 34 | } 35 | 36 | public DataMessage(final byte[] msg) throws IncorrectMessageException { 37 | final BinaryReader reader = new BinaryReader(msg); 38 | 39 | try { 40 | 41 | final byte remoteVersion = reader.getSignedByte(); 42 | final byte remoteType = reader.getSignedByte(); 43 | 44 | if (remoteVersion != VERSION) { 45 | throw new IncorrectMessageException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 46 | } 47 | if (remoteType != TYPE.getValue()) { 48 | throw new IncorrectMessageException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 49 | } 50 | 51 | sequence = reader.getSignedInt(); 52 | 53 | data = reader.getBytesGroupWithShortLength(); 54 | 55 | } catch (final BufferUnderflowException e) { 56 | throw new IncorrectMessageException("Incorrect message length"); 57 | } 58 | } 59 | 60 | @Override 61 | public byte getVersion() { 62 | return VERSION; 63 | } 64 | 65 | @Override 66 | public MessageType getType() { 67 | return TYPE; 68 | } 69 | 70 | @Override 71 | public int getSequence() { 72 | return sequence; 73 | } 74 | 75 | @Override 76 | public void setSequence(final int sequence) { 77 | this.sequence = sequence; 78 | } 79 | 80 | public byte[] getData() { 81 | return data; 82 | } 83 | 84 | public void setData(final byte[] data) { 85 | this.data = data; 86 | } 87 | 88 | @Override 89 | public byte[] toBytes() { 90 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + data.length); 91 | 92 | writer.putSignedByte(VERSION) 93 | .putSignedByte(TYPE.getValue()) 94 | .putSignedInt(sequence) 95 | .putBytesGroupWithShortLength(data); 96 | 97 | return writer.toBytes(); 98 | } 99 | 100 | @Override 101 | public int getFixedLength() { 102 | return FIXED_LENGTH; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/RTTEstimator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.socket; 9 | 10 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 11 | import com.vecsight.dragonite.sdk.misc.NumUtils; 12 | 13 | public class RTTEstimator { 14 | 15 | private final static float estimatedRTTUpdateFactor = 0.125f, devRTTUpdateFactor = 0.25f; 16 | 17 | private final ConnectionState state; 18 | 19 | private long estimatedRTT = DragoniteGlobalConstants.INIT_RTT_MS, devRTT; 20 | 21 | private long lastUpdate = 0; 22 | 23 | private int continuousResendCount = 0; 24 | 25 | public RTTEstimator(final ConnectionState state) { 26 | this.state = state; 27 | } 28 | 29 | public void pushStat(final MessageStat stat) { 30 | //System.out.println(stat); 31 | if (stat.isExist()) { 32 | final long currentTime = System.currentTimeMillis(); 33 | /*if (currentTime - lastRefresh >= DragoniteGlobalConstants.rttRefreshIntervalMS) { 34 | lastRefresh = System.currentTimeMillis(); 35 | if (stat.isResended()) { 36 | long maxCRTT = (long) (estimatedRTT * DragoniteGlobalConstants.RTT_RESENDED_REFRESH_MAX_MULT); 37 | setRTT(NumUtils.min(stat.getRTT(), maxCRTT), 0); 38 | } 39 | }*/ 40 | if (currentTime - lastUpdate >= DragoniteGlobalConstants.RTT_UPDATE_INTERVAL_MS) { 41 | lastUpdate = currentTime; 42 | 43 | //System.out.println(stat.toString()); 44 | 45 | if (!stat.isResended()) { 46 | continuousResendCount = 0; 47 | clampSetRTT((long) ((1 - estimatedRTTUpdateFactor) * estimatedRTT + estimatedRTTUpdateFactor * stat.getRTT()), 48 | (long) ((1 - devRTTUpdateFactor) * devRTT + devRTTUpdateFactor * Math.abs(stat.getRTT() - estimatedRTT))); 49 | } else { 50 | continuousResendCount++; 51 | if (continuousResendCount > (DragoniteGlobalConstants.RTT_RESEND_CORRECTION_INTERVAL_MS / DragoniteGlobalConstants.RTT_UPDATE_INTERVAL_MS)) { 52 | final long maxCRTT = (long) (estimatedRTT * DragoniteGlobalConstants.RTT_RESENDED_REFRESH_MAX_MULT); 53 | final long tmpRTT = NumUtils.min(stat.getRTT(), maxCRTT); 54 | clampSetRTT((long) ((1 - estimatedRTTUpdateFactor) * estimatedRTT + estimatedRTTUpdateFactor * tmpRTT), 55 | (long) ((1 - devRTTUpdateFactor) * devRTT + devRTTUpdateFactor * Math.abs(tmpRTT - estimatedRTT))); 56 | continuousResendCount = 0; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | private void clampSetRTT(final long estimatedRTT, final long devRTT) { 64 | long tempDevRTT = devRTT * DragoniteGlobalConstants.DEV_RTT_MULT; 65 | if (tempDevRTT > estimatedRTT && tempDevRTT > DragoniteGlobalConstants.RTT_MAX_VARIATION_MS) { 66 | tempDevRTT = estimatedRTT; 67 | } 68 | tempDevRTT /= DragoniteGlobalConstants.DEV_RTT_MULT; 69 | setRTT(estimatedRTT, tempDevRTT); 70 | } 71 | 72 | private void setRTT(final long estimatedRTT, final long devRTT) { 73 | this.estimatedRTT = estimatedRTT; 74 | this.devRTT = devRTT; 75 | state.setEstimatedRTT(estimatedRTT); 76 | state.setDevRTT(devRTT); 77 | //System.out.println("Update estimated RTT " + estimatedRTT + " devRTT " + devRTT); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/types/ACKMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.msg.types; 9 | 10 | import com.vecsight.dragonite.sdk.exception.IncorrectMessageException; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | import com.vecsight.dragonite.sdk.msg.Message; 13 | import com.vecsight.dragonite.sdk.msg.MessageType; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | public class ACKMessage implements Message { 20 | 21 | private static final byte VERSION = DragoniteGlobalConstants.PROTOCOL_VERSION; 22 | 23 | private static final MessageType TYPE = MessageType.ACK; 24 | 25 | public static final int FIXED_LENGTH = 8; 26 | 27 | private int[] sequenceList; 28 | 29 | private int consumedSeq; 30 | 31 | public ACKMessage(final int[] sequenceList, final int consumedSeq) { 32 | this.sequenceList = sequenceList; 33 | this.consumedSeq = consumedSeq; 34 | } 35 | 36 | public ACKMessage(final byte[] msg) throws IncorrectMessageException { 37 | final BinaryReader reader = new BinaryReader(msg); 38 | 39 | try { 40 | 41 | final byte remoteVersion = reader.getSignedByte(); 42 | final byte remoteType = reader.getSignedByte(); 43 | 44 | if (remoteVersion != VERSION) { 45 | throw new IncorrectMessageException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 46 | } 47 | if (remoteType != TYPE.getValue()) { 48 | throw new IncorrectMessageException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 49 | } 50 | 51 | consumedSeq = reader.getSignedInt(); 52 | 53 | final int seqCount = reader.getUnsignedShort(); 54 | 55 | sequenceList = new int[seqCount]; 56 | for (int i = 0; i < seqCount; i++) { 57 | sequenceList[i] = reader.getSignedInt(); 58 | } 59 | 60 | } catch (final BufferUnderflowException e) { 61 | throw new IncorrectMessageException("Incorrect message length"); 62 | } 63 | } 64 | 65 | @Override 66 | public byte getVersion() { 67 | return VERSION; 68 | } 69 | 70 | @Override 71 | public MessageType getType() { 72 | return TYPE; 73 | } 74 | 75 | @Override 76 | public byte[] toBytes() { 77 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + sequenceList.length * Integer.BYTES); 78 | 79 | writer.putSignedByte(VERSION) 80 | .putSignedByte(TYPE.getValue()) 81 | .putSignedInt(consumedSeq) 82 | .putUnsignedShort(sequenceList.length); 83 | 84 | for (final int seq : sequenceList) { 85 | writer.putSignedInt(seq); 86 | } 87 | 88 | return writer.toBytes(); 89 | } 90 | 91 | @Override 92 | public int getFixedLength() { 93 | return FIXED_LENGTH; 94 | } 95 | 96 | public int[] getSequenceList() { 97 | return sequenceList; 98 | } 99 | 100 | public void setSequenceList(final int[] sequenceList) { 101 | this.sequenceList = sequenceList; 102 | } 103 | 104 | public int getConsumedSeq() { 105 | return consumedSeq; 106 | } 107 | 108 | public void setConsumedSeq(final int consumedSeq) { 109 | this.consumedSeq = consumedSeq; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/network/server/ForwarderMuxHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.network.server; 9 | 10 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 11 | import com.vecsight.dragonite.forwarder.network.Pipe; 12 | import com.vecsight.dragonite.mux.conn.MultiplexedConnection; 13 | import com.vecsight.dragonite.mux.conn.Multiplexer; 14 | import com.vecsight.dragonite.mux.exception.MultiplexerClosedException; 15 | import org.pmw.tinylog.Logger; 16 | 17 | import java.io.IOException; 18 | import java.net.InetSocketAddress; 19 | import java.net.Socket; 20 | import java.net.SocketAddress; 21 | 22 | public class ForwarderMuxHandler { 23 | 24 | private final Multiplexer multiplexer; 25 | 26 | private final String clientName; 27 | 28 | private final SocketAddress clientAddress; 29 | 30 | private final InetSocketAddress forwardingAddress; 31 | 32 | public ForwarderMuxHandler(final Multiplexer multiplexer, final String clientName, final SocketAddress clientAddress, final InetSocketAddress forwardingAddress) { 33 | this.multiplexer = multiplexer; 34 | this.clientName = clientName; 35 | this.clientAddress = clientAddress; 36 | this.forwardingAddress = forwardingAddress; 37 | } 38 | 39 | public void run() throws MultiplexerClosedException, InterruptedException { 40 | MultiplexedConnection multiplexedConnection; 41 | 42 | while ((multiplexedConnection = multiplexer.acceptConnection()) != null) { 43 | final MultiplexedConnection finalMuxConn = multiplexedConnection; 44 | 45 | Logger.debug("New connection by client \"{}\" ({})", 46 | clientName, clientAddress.toString()); 47 | try { 48 | final Socket tcpSocket = new Socket(forwardingAddress.getAddress(), forwardingAddress.getPort()); 49 | 50 | final Thread pipeFromRemoteThread = new Thread(() -> { 51 | final Pipe pipeFromRemotePipe = new Pipe(ForwarderGlobalConstants.PIPE_BUFFER_SIZE); 52 | try { 53 | pipeFromRemotePipe.pipe(finalMuxConn, tcpSocket.getOutputStream()); 54 | } catch (final Exception e) { 55 | Logger.debug(e, "Pipe closed"); 56 | } finally { 57 | try { 58 | tcpSocket.close(); 59 | } catch (final IOException ignored) { 60 | } 61 | finalMuxConn.close(); 62 | } 63 | }, "FS-R2L"); 64 | pipeFromRemoteThread.start(); 65 | 66 | final Thread pipeFromLocalThread = new Thread(() -> { 67 | final Pipe pipeFromLocalPipe = new Pipe(ForwarderGlobalConstants.PIPE_BUFFER_SIZE); 68 | try { 69 | pipeFromLocalPipe.pipe(tcpSocket.getInputStream(), finalMuxConn); 70 | } catch (final Exception e) { 71 | Logger.debug(e, "Pipe closed"); 72 | } finally { 73 | try { 74 | tcpSocket.close(); 75 | } catch (final IOException ignored) { 76 | } 77 | finalMuxConn.close(); 78 | } 79 | }, "FS-L2R"); 80 | pipeFromLocalThread.start(); 81 | 82 | } catch (final IOException e) { 83 | Logger.error(e, "Unable to establish local connection"); 84 | finalMuxConn.close(); 85 | } 86 | 87 | } 88 | 89 | } 90 | } -------------------------------------------------------------------------------- /dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/types/DataFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.mux.frame.types; 9 | 10 | import com.vecsight.dragonite.mux.exception.IncorrectFrameException; 11 | import com.vecsight.dragonite.mux.frame.Frame; 12 | import com.vecsight.dragonite.mux.frame.FrameType; 13 | import com.vecsight.dragonite.mux.misc.MuxGlobalConstants; 14 | import com.vecsight.dragonite.utils.binary.BinaryReader; 15 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 16 | 17 | import java.nio.BufferUnderflowException; 18 | 19 | /* 20 | * VERSION 1 SB 21 | * TYPE 1 SB 22 | * connID 2 SS 23 | * length 2 US 24 | * data [length] 25 | */ 26 | 27 | public class DataFrame implements Frame { 28 | 29 | private static final byte VERSION = MuxGlobalConstants.PROTOCOL_VERSION; 30 | 31 | private static final FrameType TYPE = FrameType.DATA; 32 | 33 | public static final int FIXED_LENGTH = 6; 34 | 35 | private short connectionID; 36 | 37 | private byte[] data; 38 | 39 | private int expectedLength = 0; 40 | 41 | public DataFrame(final short connectionID, final byte[] data) { 42 | this.connectionID = connectionID; 43 | this.data = data; 44 | } 45 | 46 | public DataFrame(final byte[] frame) throws IncorrectFrameException { 47 | final BinaryReader reader = new BinaryReader(frame); 48 | 49 | try { 50 | 51 | final byte remoteVersion = reader.getSignedByte(); 52 | final byte remoteType = reader.getSignedByte(); 53 | 54 | if (remoteVersion != VERSION) { 55 | throw new IncorrectFrameException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 56 | } 57 | if (remoteType != TYPE.getValue()) { 58 | throw new IncorrectFrameException("Incorrect type (" + remoteType + ", should be " + TYPE + ")"); 59 | } 60 | 61 | connectionID = reader.getSignedShort(); 62 | 63 | final int length = reader.getUnsignedShort(); 64 | 65 | if (reader.remaining() < length) { 66 | expectedLength = length; 67 | } else { 68 | data = new byte[length]; 69 | reader.getBytes(data); 70 | } 71 | 72 | } catch (final BufferUnderflowException e) { 73 | throw new IncorrectFrameException("Incorrect frame length"); 74 | } 75 | } 76 | 77 | public short getConnectionID() { 78 | return connectionID; 79 | } 80 | 81 | public void setConnectionID(final short connectionID) { 82 | this.connectionID = connectionID; 83 | } 84 | 85 | public byte[] getData() { 86 | return data; 87 | } 88 | 89 | public void setData(final byte[] data) { 90 | this.data = data; 91 | } 92 | 93 | @Override 94 | public byte getVersion() { 95 | return VERSION; 96 | } 97 | 98 | @Override 99 | public FrameType getType() { 100 | return TYPE; 101 | } 102 | 103 | @Override 104 | public byte[] toBytes() { 105 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + data.length); 106 | 107 | writer.putSignedByte(VERSION) 108 | .putSignedByte(TYPE.getValue()) 109 | .putSignedShort(connectionID) 110 | .putBytesGroupWithShortLength(data); 111 | 112 | return writer.toBytes(); 113 | } 114 | 115 | @Override 116 | public int getFixedLength() { 117 | return FIXED_LENGTH; 118 | } 119 | 120 | @Override 121 | public int getExpectedLength() { 122 | return expectedLength; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/mux/MuxConnectionRequestHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header.mux; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.header.AddressType; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * addrType 1 SB 19 | * addr [4B/16B/1+length] 20 | * port 2 US 21 | * UDP mode 1 BOOL 22 | */ 23 | 24 | public class MuxConnectionRequestHeader { 25 | 26 | private AddressType type; 27 | 28 | private byte[] addr; 29 | 30 | private int port; 31 | 32 | private boolean udpMode; 33 | 34 | public MuxConnectionRequestHeader(final AddressType type, final byte[] addr, final int port, final boolean udpMode) { 35 | this.type = type; 36 | this.addr = addr; 37 | this.port = port; 38 | this.udpMode = udpMode; 39 | } 40 | 41 | public MuxConnectionRequestHeader(final byte[] header) throws IncorrectHeaderException { 42 | final BinaryReader reader = new BinaryReader(header); 43 | 44 | try { 45 | 46 | final byte rawType = reader.getSignedByte(); 47 | 48 | try { 49 | type = AddressType.fromByte(rawType); 50 | } catch (final IllegalArgumentException e) { 51 | throw new IncorrectHeaderException("Invalid address type " + rawType); 52 | } 53 | 54 | switch (type) { 55 | case IPv4: 56 | addr = new byte[4]; 57 | reader.getBytes(addr); 58 | break; 59 | case IPv6: 60 | addr = new byte[16]; 61 | reader.getBytes(addr); 62 | break; 63 | case DOMAIN: 64 | addr = reader.getBytesGroupWithByteLength(); 65 | break; 66 | default: 67 | throw new IncorrectHeaderException("Invalid address type " + rawType); 68 | } 69 | 70 | port = reader.getUnsignedShort(); 71 | 72 | udpMode = reader.getBoolean(); 73 | 74 | } catch (final BufferUnderflowException e) { 75 | throw new IncorrectHeaderException("Incorrect frame length"); 76 | } 77 | } 78 | 79 | public AddressType getType() { 80 | return type; 81 | } 82 | 83 | public void setType(final AddressType type) { 84 | this.type = type; 85 | } 86 | 87 | public byte[] getAddr() { 88 | return addr; 89 | } 90 | 91 | public void setAddr(final byte[] addr) { 92 | this.addr = addr; 93 | } 94 | 95 | public int getPort() { 96 | return port; 97 | } 98 | 99 | public void setPort(final int port) { 100 | this.port = port; 101 | } 102 | 103 | public boolean isUdpMode() { 104 | return udpMode; 105 | } 106 | 107 | public void setUdpMode(final boolean udpMode) { 108 | this.udpMode = udpMode; 109 | } 110 | 111 | public byte[] toBytes() { 112 | final int addrTotalLength = (type == AddressType.IPv4 ? 4 : (type == AddressType.IPv6 ? 16 : 1 + addr.length)); 113 | 114 | final BinaryWriter writer = new BinaryWriter(4 + addrTotalLength); 115 | 116 | writer.putSignedByte(type.getValue()); 117 | if (type == AddressType.DOMAIN) { 118 | writer.putBytesGroupWithByteLength(addr); 119 | } else { 120 | writer.putBytes(addr); 121 | } 122 | writer.putUnsignedShort(port); 123 | writer.putBoolean(udpMode); 124 | 125 | return writer.toBytes(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/udp/ProxyUDPRelayHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header.udp; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.header.AddressType; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * addrType 1 SB 19 | * addr [4B/16B/1+length] 20 | * port 2 US 21 | * payload [REMAINING] 22 | */ 23 | 24 | public class ProxyUDPRelayHeader { 25 | 26 | private AddressType type; 27 | 28 | private byte[] addr; 29 | 30 | private int port; 31 | 32 | private byte[] payload; 33 | 34 | public ProxyUDPRelayHeader(final AddressType type, final byte[] addr, final int port, final byte[] payload) { 35 | this.type = type; 36 | this.addr = addr; 37 | this.port = port; 38 | this.payload = payload; 39 | } 40 | 41 | public ProxyUDPRelayHeader(final byte[] header) throws IncorrectHeaderException { 42 | final BinaryReader reader = new BinaryReader(header); 43 | 44 | try { 45 | 46 | final byte rawType = reader.getSignedByte(); 47 | 48 | try { 49 | type = AddressType.fromByte(rawType); 50 | } catch (final IllegalArgumentException e) { 51 | throw new IncorrectHeaderException("Invalid address type " + rawType); 52 | } 53 | 54 | switch (type) { 55 | case IPv4: 56 | addr = new byte[4]; 57 | reader.getBytes(addr); 58 | break; 59 | case IPv6: 60 | addr = new byte[16]; 61 | reader.getBytes(addr); 62 | break; 63 | case DOMAIN: 64 | addr = reader.getBytesGroupWithByteLength(); 65 | break; 66 | default: 67 | throw new IncorrectHeaderException("Invalid address type " + rawType); 68 | } 69 | 70 | port = reader.getUnsignedShort(); 71 | 72 | payload = new byte[reader.remaining()]; 73 | reader.getBytes(payload); 74 | 75 | } catch (final BufferUnderflowException e) { 76 | throw new IncorrectHeaderException("Incorrect packet length"); 77 | } 78 | } 79 | 80 | public AddressType getType() { 81 | return type; 82 | } 83 | 84 | public void setType(final AddressType type) { 85 | this.type = type; 86 | } 87 | 88 | public byte[] getAddr() { 89 | return addr; 90 | } 91 | 92 | public void setAddr(final byte[] addr) { 93 | this.addr = addr; 94 | } 95 | 96 | public int getPort() { 97 | return port; 98 | } 99 | 100 | public void setPort(final int port) { 101 | this.port = port; 102 | } 103 | 104 | public byte[] getPayload() { 105 | return payload; 106 | } 107 | 108 | public void setPayload(final byte[] payload) { 109 | this.payload = payload; 110 | } 111 | 112 | public byte[] toBytes() { 113 | final int addrTotalLength = (type == AddressType.IPv4 ? 4 : (type == AddressType.IPv6 ? 16 : 1 + addr.length)); 114 | 115 | final BinaryWriter writer = new BinaryWriter(3 + addrTotalLength + payload.length); 116 | 117 | writer.putSignedByte(type.getValue()); 118 | if (type == AddressType.DOMAIN) { 119 | writer.putBytesGroupWithByteLength(addr); 120 | } else { 121 | writer.putBytes(addr); 122 | } 123 | writer.putUnsignedShort(port); 124 | writer.putBytes(payload); 125 | 126 | return writer.toBytes(); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/web/DevConsoleWebServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.web; 9 | 10 | import com.sun.net.httpserver.HttpServer; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | import com.vecsight.dragonite.sdk.socket.DragoniteSocketStatistics; 13 | 14 | import java.io.IOException; 15 | import java.net.InetSocketAddress; 16 | import java.nio.charset.Charset; 17 | import java.nio.charset.StandardCharsets; 18 | import java.util.List; 19 | 20 | /* 21 | 22 | sample: 23 | { 24 | "title": "Dragonite Developer Web Interface", 25 | "version": "0.2.0", 26 | "connections": [ 27 | { 28 | "remote": "123.123.123.123:54321", 29 | "description": "someEvilConnection", 30 | "rtt": 90, 31 | "devrtt": 5, 32 | "send": 10240, 33 | "sendraw": 12680, 34 | "sendpkt": 400, 35 | "resend": 60, 36 | "recv": 204800, 37 | "recvraw": 219400, 38 | "recvcount": 3800, 39 | "dup": 280 40 | } 41 | ] 42 | } 43 | 44 | */ 45 | 46 | public class DevConsoleWebServer { 47 | 48 | private static final String WEB_TITLE = "Dragonite Developer Web Interface"; 49 | 50 | private static final Charset CHARSET = StandardCharsets.UTF_8; 51 | 52 | private static final int SHUTDOWN_SEC = 2; 53 | 54 | private final HttpServer httpServer; 55 | 56 | private final StatisticsProvider statisticsProvider; 57 | 58 | public DevConsoleWebServer(final InetSocketAddress bindAddress, final StatisticsProvider provider) throws IOException { 59 | this.statisticsProvider = provider; 60 | 61 | httpServer = HttpServer.create(bindAddress, 0); 62 | httpServer.createContext("/statistics", httpExchange -> { 63 | final byte[] jsonBytes = getJSON(statisticsProvider.getLatest()).getBytes(CHARSET); 64 | httpExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*"); 65 | httpExchange.sendResponseHeaders(200, jsonBytes.length); 66 | httpExchange.getResponseBody().write(jsonBytes); 67 | httpExchange.close(); 68 | }); 69 | 70 | httpServer.start(); 71 | } 72 | 73 | private String getJSON(final List statisticsList) { 74 | return "{\"title\":\"" + WEB_TITLE + 75 | "\",\"version\":\"" + DragoniteGlobalConstants.LIBRARY_VERSION + 76 | "\",\"connections\":" + getConnectionsJSONArray(statisticsList) + "}"; 77 | } 78 | 79 | private String getConnectionsJSONArray(final List statisticsList) { 80 | StringBuilder json = new StringBuilder("["); 81 | int i = 0; 82 | for (final DragoniteSocketStatistics statistics : statisticsList) { 83 | final String cinfo = "{\"remote\":\"" + statistics.getRemoteAddress().toString() + 84 | "\",\"description\":\"" + statistics.getDescription() + 85 | "\",\"rtt\":" + statistics.getEstimatedRTT() + 86 | ",\"devrtt\":" + statistics.getDevRTT() + 87 | ",\"send\":" + statistics.getSendLength() + 88 | ",\"sendraw\":" + statistics.getSendRawLength() + 89 | ",\"sendpkt\":" + statistics.getSendCount() + 90 | ",\"resend\":" + statistics.getResendCount() + 91 | ",\"recv\":" + statistics.getReadLength() + 92 | ",\"recvraw\":" + statistics.getReceiveRawLength() + 93 | ",\"recvcount\":" + statistics.getReceiveCount() + 94 | ",\"dup\":" + statistics.getDupCount() + "}"; 95 | json.append(cinfo); 96 | if (++i != statisticsList.size()) { 97 | json.append(","); 98 | } 99 | } 100 | json.append("]"); 101 | return json.toString(); 102 | } 103 | 104 | public void stop() { 105 | httpServer.stop(SHUTDOWN_SEC); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/config/ProxyServerConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.config; 9 | 10 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 11 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 12 | import com.vecsight.dragonite.sdk.cryptor.AESCryptor; 13 | import com.vecsight.dragonite.sdk.exception.EncryptionException; 14 | import com.vecsight.dragonite.utils.system.SystemInfo; 15 | 16 | import java.net.InetSocketAddress; 17 | 18 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 19 | 20 | public class ProxyServerConfig { 21 | 22 | private InetSocketAddress bindAddress; 23 | 24 | private String password; 25 | 26 | private int mbpsLimit = 0; 27 | 28 | private String welcomeMessage = "Welcome to " + SystemInfo.getHostname(); 29 | 30 | private boolean allowLoopback = false; 31 | 32 | private final DragoniteSocketParameters dragoniteSocketParameters = new DragoniteSocketParameters(); 33 | 34 | public ProxyServerConfig(final InetSocketAddress bindAddress, final String password) throws EncryptionException { 35 | setBindAddress(bindAddress); 36 | setPassword(password); 37 | } 38 | 39 | public InetSocketAddress getBindAddress() { 40 | return bindAddress; 41 | } 42 | 43 | public void setBindAddress(final InetSocketAddress bindAddress) { 44 | checkArgument(bindAddress != null, "Invalid bind address"); 45 | this.bindAddress = bindAddress; 46 | } 47 | 48 | public String getPassword() { 49 | return password; 50 | } 51 | 52 | public void setPassword(final String password) throws EncryptionException { 53 | checkArgument(password != null && password.length() >= ProxyGlobalConstants.PASSWORD_MIN_LENGTH, "Invalid password"); 54 | dragoniteSocketParameters.setPacketCryptor(new AESCryptor(password)); 55 | this.password = password; 56 | } 57 | 58 | public int getMbpsLimit() { 59 | return mbpsLimit; 60 | } 61 | 62 | public void setMbpsLimit(final int mbpsLimit) { 63 | checkArgument(mbpsLimit > 0 && mbpsLimit <= 65535, "Invalid Mbps"); 64 | this.mbpsLimit = mbpsLimit; 65 | } 66 | 67 | public String getWelcomeMessage() { 68 | return welcomeMessage; 69 | } 70 | 71 | public void setWelcomeMessage(final String welcomeMessage) { 72 | checkArgument(welcomeMessage != null, "Null welcome message"); 73 | this.welcomeMessage = welcomeMessage; 74 | } 75 | 76 | public boolean isAllowLoopback() { 77 | return allowLoopback; 78 | } 79 | 80 | public void setAllowLoopback(final boolean allowLoopback) { 81 | this.allowLoopback = allowLoopback; 82 | } 83 | 84 | public int getMTU() { 85 | return dragoniteSocketParameters.getPacketSize(); 86 | } 87 | 88 | public void setMTU(final int mtu) { 89 | dragoniteSocketParameters.setPacketSize(mtu); 90 | } 91 | 92 | public int getWindowMultiplier() { 93 | return dragoniteSocketParameters.getWindowMultiplier(); 94 | } 95 | 96 | public void setWindowMultiplier(final int mult) { 97 | dragoniteSocketParameters.setWindowMultiplier(mult); 98 | } 99 | 100 | public int getTrafficClass() { 101 | return dragoniteSocketParameters.getTrafficClass(); 102 | } 103 | 104 | public void setTrafficClass(final int tc) { 105 | dragoniteSocketParameters.setTrafficClass(tc); 106 | } 107 | 108 | public boolean getWebPanelEnabled() { 109 | return dragoniteSocketParameters.isEnableWebPanel(); 110 | } 111 | 112 | public void setWebPanelEnabled(final boolean enabled) { 113 | dragoniteSocketParameters.setEnableWebPanel(enabled); 114 | } 115 | 116 | public InetSocketAddress getWebPanelBind() { 117 | return dragoniteSocketParameters.getWebPanelBindAddress(); 118 | } 119 | 120 | public void setWebPanelBind(final InetSocketAddress address) { 121 | dragoniteSocketParameters.setWebPanelBindAddress(address); 122 | } 123 | 124 | public DragoniteSocketParameters getDragoniteSocketParameters() { 125 | return dragoniteSocketParameters; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/config/ForwarderClientConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.config; 9 | 10 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 11 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 12 | import com.vecsight.dragonite.sdk.cryptor.AESCryptor; 13 | import com.vecsight.dragonite.sdk.exception.EncryptionException; 14 | 15 | import java.net.InetSocketAddress; 16 | 17 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 18 | import static com.vecsight.dragonite.utils.flow.Preconditions.inPortRange; 19 | 20 | public class ForwarderClientConfig { 21 | 22 | private InetSocketAddress remoteAddress; 23 | 24 | private int localPort; 25 | 26 | private String password; 27 | 28 | private int downMbps, upMbps; 29 | 30 | private final DragoniteSocketParameters dragoniteSocketParameters = new DragoniteSocketParameters(); 31 | 32 | public ForwarderClientConfig(final InetSocketAddress remoteAddress, final int localPort, final int downMbps, final int upMbps) { 33 | setRemoteAddress(remoteAddress); 34 | setLocalPort(localPort); 35 | setDownMbps(downMbps); 36 | setUpMbps(upMbps); 37 | } 38 | 39 | public InetSocketAddress getRemoteAddress() { 40 | return remoteAddress; 41 | } 42 | 43 | public void setRemoteAddress(final InetSocketAddress remoteAddress) { 44 | checkArgument(remoteAddress != null, "Invalid remote address"); 45 | this.remoteAddress = remoteAddress; 46 | } 47 | 48 | public int getLocalPort() { 49 | return localPort; 50 | } 51 | 52 | public void setLocalPort(final int localPort) { 53 | checkArgument(inPortRange(localPort), "Invalid port"); 54 | this.localPort = localPort; 55 | } 56 | 57 | public int getDownMbps() { 58 | return downMbps; 59 | } 60 | 61 | public void setDownMbps(final int downMbps) { 62 | checkArgument(downMbps > 0 && downMbps <= 65535, "Invalid Mbps"); 63 | this.downMbps = downMbps; 64 | } 65 | 66 | public int getUpMbps() { 67 | return upMbps; 68 | } 69 | 70 | public void setUpMbps(final int upMbps) { 71 | checkArgument(upMbps > 0 && upMbps <= 65535, "Invalid Mbps"); 72 | this.upMbps = upMbps; 73 | } 74 | 75 | public String getPassword() { 76 | return password; 77 | } 78 | 79 | public void setPassword(final String password) throws EncryptionException { 80 | checkArgument(password != null && password.length() >= ForwarderGlobalConstants.PASSWORD_MIN_LENGTH, "Invalid password"); 81 | dragoniteSocketParameters.setPacketCryptor(new AESCryptor(password)); 82 | this.password = password; 83 | } 84 | 85 | public int getMTU() { 86 | return dragoniteSocketParameters.getPacketSize(); 87 | } 88 | 89 | public void setMTU(final int mtu) { 90 | dragoniteSocketParameters.setPacketSize(mtu); 91 | } 92 | 93 | public int getWindowMultiplier() { 94 | return dragoniteSocketParameters.getWindowMultiplier(); 95 | } 96 | 97 | public void setWindowMultiplier(final int mult) { 98 | dragoniteSocketParameters.setWindowMultiplier(mult); 99 | } 100 | 101 | public int getTrafficClass() { 102 | return dragoniteSocketParameters.getTrafficClass(); 103 | } 104 | 105 | public void setTrafficClass(final int tc) { 106 | dragoniteSocketParameters.setTrafficClass(tc); 107 | } 108 | 109 | public boolean getWebPanelEnabled() { 110 | return dragoniteSocketParameters.isEnableWebPanel(); 111 | } 112 | 113 | public void setWebPanelEnabled(final boolean enabled) { 114 | dragoniteSocketParameters.setEnableWebPanel(enabled); 115 | } 116 | 117 | public InetSocketAddress getWebPanelBind() { 118 | return dragoniteSocketParameters.getWebPanelBindAddress(); 119 | } 120 | 121 | public void setWebPanelBind(final InetSocketAddress address) { 122 | dragoniteSocketParameters.setWebPanelBindAddress(address); 123 | } 124 | 125 | public DragoniteSocketParameters getDragoniteSocketParameters() { 126 | return dragoniteSocketParameters; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/ClientInfoHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * VERSION 1 SB 19 | * downMbps 2 US 20 | * upMbps 2 US 21 | * nameLen 1 UB 22 | * nameStr [length] 23 | * verLen 1 UB 24 | * verStr [length] 25 | * osLen 1 UB 26 | * osStr [length] 27 | */ 28 | 29 | public class ClientInfoHeader { 30 | 31 | private static final byte VERSION = ProxyGlobalConstants.PROTOCOL_VERSION; 32 | 33 | public static final int FIXED_LENGTH = 8; 34 | 35 | private int downMbps, upMbps; 36 | 37 | private String name, appVer, osName; 38 | 39 | public ClientInfoHeader(final int downMbps, final int upMbps, final String name, final String appVer, final String osName) { 40 | this.downMbps = downMbps; 41 | this.upMbps = upMbps; 42 | this.name = name; 43 | this.appVer = appVer; 44 | this.osName = osName; 45 | } 46 | 47 | public ClientInfoHeader(final byte[] header) throws IncorrectHeaderException { 48 | final BinaryReader reader = new BinaryReader(header); 49 | 50 | try { 51 | 52 | final byte remoteVersion = reader.getSignedByte(); 53 | 54 | if (remoteVersion != VERSION) { 55 | throw new IncorrectHeaderException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 56 | } 57 | 58 | downMbps = reader.getUnsignedShort(); 59 | upMbps = reader.getUnsignedShort(); 60 | 61 | name = new String(reader.getBytesGroupWithByteLength(), ProxyGlobalConstants.STRING_CHARSET); 62 | 63 | appVer = new String(reader.getBytesGroupWithByteLength(), ProxyGlobalConstants.STRING_CHARSET); 64 | 65 | osName = new String(reader.getBytesGroupWithByteLength(), ProxyGlobalConstants.STRING_CHARSET); 66 | 67 | } catch (final BufferUnderflowException e) { 68 | throw new IncorrectHeaderException("Incorrect header length"); 69 | } 70 | } 71 | 72 | public int getDownMbps() { 73 | return downMbps; 74 | } 75 | 76 | public void setDownMbps(final int downMbps) { 77 | this.downMbps = downMbps; 78 | } 79 | 80 | public int getUpMbps() { 81 | return upMbps; 82 | } 83 | 84 | public void setUpMbps(final int upMbps) { 85 | this.upMbps = upMbps; 86 | } 87 | 88 | public String getName() { 89 | return name; 90 | } 91 | 92 | public void setName(final String name) { 93 | this.name = name; 94 | } 95 | 96 | public String getAppVer() { 97 | return appVer; 98 | } 99 | 100 | public void setAppVer(final String appVer) { 101 | this.appVer = appVer; 102 | } 103 | 104 | public String getOsName() { 105 | return osName; 106 | } 107 | 108 | public void setOsName(final String osName) { 109 | this.osName = osName; 110 | } 111 | 112 | public static byte getVersion() { 113 | return VERSION; 114 | } 115 | 116 | public static int getFixedLength() { 117 | return FIXED_LENGTH; 118 | } 119 | 120 | public byte[] toBytes() { 121 | final byte[] nameBytes = name.getBytes(ProxyGlobalConstants.STRING_CHARSET); 122 | final byte[] appVerBytes = appVer.getBytes(ProxyGlobalConstants.STRING_CHARSET); 123 | final byte[] osNameBytes = osName.getBytes(ProxyGlobalConstants.STRING_CHARSET); 124 | 125 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + nameBytes.length + appVerBytes.length + osNameBytes.length); 126 | 127 | writer.putSignedByte(VERSION) 128 | .putUnsignedShort(downMbps) 129 | .putUnsignedShort(upMbps) 130 | .putBytesGroupWithByteLength(nameBytes) 131 | .putBytesGroupWithByteLength(appVerBytes) 132 | .putBytesGroupWithByteLength(osNameBytes); 133 | 134 | return writer.toBytes(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/config/ForwarderServerConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.config; 9 | 10 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 11 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 12 | import com.vecsight.dragonite.sdk.cryptor.AESCryptor; 13 | import com.vecsight.dragonite.sdk.exception.EncryptionException; 14 | import com.vecsight.dragonite.utils.system.SystemInfo; 15 | 16 | import java.net.InetSocketAddress; 17 | 18 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 19 | 20 | public class ForwarderServerConfig { 21 | 22 | private InetSocketAddress bindAddress; 23 | 24 | private InetSocketAddress forwardingAddress; 25 | 26 | private String password; 27 | 28 | private int mbpsLimit = 0; 29 | 30 | private String welcomeMessage = "Welcome to " + SystemInfo.getHostname(); 31 | 32 | private final DragoniteSocketParameters dragoniteSocketParameters = new DragoniteSocketParameters(); 33 | 34 | public ForwarderServerConfig(final InetSocketAddress bindAddress, final InetSocketAddress forwardingAddress) { 35 | setBindAddress(bindAddress); 36 | setForwardingAddress(forwardingAddress); 37 | } 38 | 39 | public InetSocketAddress getBindAddress() { 40 | return bindAddress; 41 | } 42 | 43 | public void setBindAddress(final InetSocketAddress bindAddress) { 44 | checkArgument(bindAddress != null, "Invalid bind address"); 45 | this.bindAddress = bindAddress; 46 | } 47 | 48 | public InetSocketAddress getForwardingAddress() { 49 | return forwardingAddress; 50 | } 51 | 52 | public void setForwardingAddress(final InetSocketAddress forwardingAddress) { 53 | this.forwardingAddress = forwardingAddress; 54 | } 55 | 56 | public int getMbpsLimit() { 57 | return mbpsLimit; 58 | } 59 | 60 | public void setMbpsLimit(final int mbpsLimit) { 61 | checkArgument(mbpsLimit > 0 && mbpsLimit <= 65535, "Invalid Mbps"); 62 | this.mbpsLimit = mbpsLimit; 63 | } 64 | 65 | public String getWelcomeMessage() { 66 | return welcomeMessage; 67 | } 68 | 69 | public void setWelcomeMessage(final String welcomeMessage) { 70 | checkArgument(welcomeMessage != null, "Null welcome message"); 71 | this.welcomeMessage = welcomeMessage; 72 | } 73 | 74 | public String getPassword() { 75 | return password; 76 | } 77 | 78 | public void setPassword(final String password) throws EncryptionException { 79 | checkArgument(password != null && password.length() >= ForwarderGlobalConstants.PASSWORD_MIN_LENGTH, "Invalid password"); 80 | dragoniteSocketParameters.setPacketCryptor(new AESCryptor(password)); 81 | this.password = password; 82 | } 83 | 84 | public int getMTU() { 85 | return dragoniteSocketParameters.getPacketSize(); 86 | } 87 | 88 | public void setMTU(final int mtu) { 89 | dragoniteSocketParameters.setPacketSize(mtu); 90 | } 91 | 92 | public int getWindowMultiplier() { 93 | return dragoniteSocketParameters.getWindowMultiplier(); 94 | } 95 | 96 | public void setWindowMultiplier(final int mult) { 97 | dragoniteSocketParameters.setWindowMultiplier(mult); 98 | } 99 | 100 | public int getTrafficClass() { 101 | return dragoniteSocketParameters.getTrafficClass(); 102 | } 103 | 104 | public void setTrafficClass(final int tc) { 105 | dragoniteSocketParameters.setTrafficClass(tc); 106 | } 107 | 108 | public boolean getWebPanelEnabled() { 109 | return dragoniteSocketParameters.isEnableWebPanel(); 110 | } 111 | 112 | public void setWebPanelEnabled(final boolean enabled) { 113 | dragoniteSocketParameters.setEnableWebPanel(enabled); 114 | } 115 | 116 | public InetSocketAddress getWebPanelBind() { 117 | return dragoniteSocketParameters.getWebPanelBindAddress(); 118 | } 119 | 120 | public void setWebPanelBind(final InetSocketAddress address) { 121 | dragoniteSocketParameters.setWebPanelBindAddress(address); 122 | } 123 | 124 | public DragoniteSocketParameters getDragoniteSocketParameters() { 125 | return dragoniteSocketParameters; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/header/ClientInfoHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.forwarder.header; 9 | 10 | import com.vecsight.dragonite.forwarder.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.forwarder.misc.ForwarderGlobalConstants; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | * VERSION 1 SB 19 | * downMbps 2 US 20 | * upMbps 2 US 21 | * nameLen 1 UB 22 | * nameStr [length] 23 | * verLen 1 UB 24 | * verStr [length] 25 | * osLen 1 UB 26 | * osStr [length] 27 | */ 28 | 29 | public class ClientInfoHeader { 30 | 31 | private static final byte VERSION = ForwarderGlobalConstants.PROTOCOL_VERSION; 32 | 33 | public static final int FIXED_LENGTH = 8; 34 | 35 | private int downMbps, upMbps; 36 | 37 | private String name, appVer, osName; 38 | 39 | public ClientInfoHeader(final int downMbps, final int upMbps, final String name, final String appVer, final String osName) { 40 | this.downMbps = downMbps; 41 | this.upMbps = upMbps; 42 | this.name = name; 43 | this.appVer = appVer; 44 | this.osName = osName; 45 | } 46 | 47 | public ClientInfoHeader(final byte[] header) throws IncorrectHeaderException { 48 | final BinaryReader reader = new BinaryReader(header); 49 | 50 | try { 51 | 52 | final byte remoteVersion = reader.getSignedByte(); 53 | 54 | if (remoteVersion != VERSION) { 55 | throw new IncorrectHeaderException("Incorrect version (" + remoteVersion + ", should be " + VERSION + ")"); 56 | } 57 | 58 | downMbps = reader.getUnsignedShort(); 59 | upMbps = reader.getUnsignedShort(); 60 | 61 | name = new String(reader.getBytesGroupWithByteLength(), ForwarderGlobalConstants.STRING_CHARSET); 62 | 63 | appVer = new String(reader.getBytesGroupWithByteLength(), ForwarderGlobalConstants.STRING_CHARSET); 64 | 65 | osName = new String(reader.getBytesGroupWithByteLength(), ForwarderGlobalConstants.STRING_CHARSET); 66 | 67 | } catch (final BufferUnderflowException e) { 68 | throw new IncorrectHeaderException("Incorrect header length"); 69 | } 70 | } 71 | 72 | public int getDownMbps() { 73 | return downMbps; 74 | } 75 | 76 | public void setDownMbps(final int downMbps) { 77 | this.downMbps = downMbps; 78 | } 79 | 80 | public int getUpMbps() { 81 | return upMbps; 82 | } 83 | 84 | public void setUpMbps(final int upMbps) { 85 | this.upMbps = upMbps; 86 | } 87 | 88 | public String getName() { 89 | return name; 90 | } 91 | 92 | public void setName(final String name) { 93 | this.name = name; 94 | } 95 | 96 | public String getAppVer() { 97 | return appVer; 98 | } 99 | 100 | public void setAppVer(final String appVer) { 101 | this.appVer = appVer; 102 | } 103 | 104 | public String getOsName() { 105 | return osName; 106 | } 107 | 108 | public void setOsName(final String osName) { 109 | this.osName = osName; 110 | } 111 | 112 | public static byte getVersion() { 113 | return VERSION; 114 | } 115 | 116 | public static int getFixedLength() { 117 | return FIXED_LENGTH; 118 | } 119 | 120 | public byte[] toBytes() { 121 | final byte[] nameBytes = name.getBytes(ForwarderGlobalConstants.STRING_CHARSET); 122 | final byte[] appVerBytes = appVer.getBytes(ForwarderGlobalConstants.STRING_CHARSET); 123 | final byte[] osNameBytes = osName.getBytes(ForwarderGlobalConstants.STRING_CHARSET); 124 | 125 | final BinaryWriter writer = new BinaryWriter(getFixedLength() + nameBytes.length + appVerBytes.length + osNameBytes.length); 126 | 127 | writer.putSignedByte(VERSION) 128 | .putUnsignedShort(downMbps) 129 | .putUnsignedShort(upMbps) 130 | .putBytesGroupWithByteLength(nameBytes) 131 | .putBytesGroupWithByteLength(appVerBytes) 132 | .putBytesGroupWithByteLength(osNameBytes); 133 | 134 | return writer.toBytes(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/config/ProxyClientConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.config; 9 | 10 | import com.vecsight.dragonite.proxy.acl.ParsedACL; 11 | import com.vecsight.dragonite.proxy.misc.ProxyGlobalConstants; 12 | import com.vecsight.dragonite.sdk.config.DragoniteSocketParameters; 13 | import com.vecsight.dragonite.sdk.cryptor.AESCryptor; 14 | import com.vecsight.dragonite.sdk.exception.EncryptionException; 15 | 16 | import java.net.InetSocketAddress; 17 | 18 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 19 | import static com.vecsight.dragonite.utils.flow.Preconditions.inPortRange; 20 | 21 | public class ProxyClientConfig { 22 | 23 | private InetSocketAddress remoteAddress; 24 | 25 | private int socks5port; 26 | 27 | private String password; 28 | 29 | private int downMbps, upMbps; 30 | 31 | private ParsedACL acl; 32 | 33 | private final DragoniteSocketParameters dragoniteSocketParameters = new DragoniteSocketParameters(); 34 | 35 | public ProxyClientConfig(final InetSocketAddress remoteAddress, final int socks5port, final String password, final int downMbps, final int upMbps) throws EncryptionException { 36 | setRemoteAddress(remoteAddress); 37 | setSocks5port(socks5port); 38 | setPassword(password); 39 | setDownMbps(downMbps); 40 | setUpMbps(upMbps); 41 | } 42 | 43 | public InetSocketAddress getRemoteAddress() { 44 | return remoteAddress; 45 | } 46 | 47 | public void setRemoteAddress(final InetSocketAddress remoteAddress) { 48 | checkArgument(remoteAddress != null, "Invalid remote address"); 49 | this.remoteAddress = remoteAddress; 50 | } 51 | 52 | public int getSocks5port() { 53 | return socks5port; 54 | } 55 | 56 | public void setSocks5port(final int socks5port) { 57 | checkArgument(inPortRange(socks5port), "Invalid port"); 58 | this.socks5port = socks5port; 59 | } 60 | 61 | public String getPassword() { 62 | return password; 63 | } 64 | 65 | public void setPassword(final String password) throws EncryptionException { 66 | checkArgument(password != null && password.length() >= ProxyGlobalConstants.PASSWORD_MIN_LENGTH, "Invalid password"); 67 | dragoniteSocketParameters.setPacketCryptor(new AESCryptor(password)); 68 | this.password = password; 69 | } 70 | 71 | public int getDownMbps() { 72 | return downMbps; 73 | } 74 | 75 | public void setDownMbps(final int downMbps) { 76 | checkArgument(downMbps > 0 && downMbps <= 65535, "Invalid Mbps"); 77 | this.downMbps = downMbps; 78 | } 79 | 80 | public int getUpMbps() { 81 | return upMbps; 82 | } 83 | 84 | public void setUpMbps(final int upMbps) { 85 | checkArgument(upMbps > 0 && upMbps <= 65535, "Invalid Mbps"); 86 | this.upMbps = upMbps; 87 | } 88 | 89 | public ParsedACL getAcl() { 90 | return acl; 91 | } 92 | 93 | public void setAcl(final ParsedACL acl) { 94 | this.acl = acl; 95 | } 96 | 97 | public int getMTU() { 98 | return dragoniteSocketParameters.getPacketSize(); 99 | } 100 | 101 | public void setMTU(final int mtu) { 102 | dragoniteSocketParameters.setPacketSize(mtu); 103 | } 104 | 105 | public int getWindowMultiplier() { 106 | return dragoniteSocketParameters.getWindowMultiplier(); 107 | } 108 | 109 | public void setWindowMultiplier(final int mult) { 110 | dragoniteSocketParameters.setWindowMultiplier(mult); 111 | } 112 | 113 | public int getTrafficClass() { 114 | return dragoniteSocketParameters.getTrafficClass(); 115 | } 116 | 117 | public void setTrafficClass(final int tc) { 118 | dragoniteSocketParameters.setTrafficClass(tc); 119 | } 120 | 121 | public boolean getWebPanelEnabled() { 122 | return dragoniteSocketParameters.isEnableWebPanel(); 123 | } 124 | 125 | public void setWebPanelEnabled(final boolean enabled) { 126 | dragoniteSocketParameters.setEnableWebPanel(enabled); 127 | } 128 | 129 | public InetSocketAddress getWebPanelBind() { 130 | return dragoniteSocketParameters.getWebPanelBindAddress(); 131 | } 132 | 133 | public void setWebPanelBind(final InetSocketAddress address) { 134 | dragoniteSocketParameters.setWebPanelBindAddress(address); 135 | } 136 | 137 | public DragoniteSocketParameters getDragoniteSocketParameters() { 138 | return dragoniteSocketParameters; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/config/DragoniteSocketParameters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.config; 9 | 10 | import com.vecsight.dragonite.sdk.cryptor.PacketCryptor; 11 | import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants; 12 | 13 | import java.net.InetAddress; 14 | import java.net.InetSocketAddress; 15 | 16 | import static com.vecsight.dragonite.utils.flow.Preconditions.checkArgument; 17 | import static com.vecsight.dragonite.utils.flow.Preconditions.inTrafficClassRange; 18 | 19 | public class DragoniteSocketParameters { 20 | 21 | private int packetSize = 1300; 22 | 23 | private boolean autoSplit = true; 24 | 25 | private int maxPacketBufferSize = 0; 26 | 27 | private int windowMultiplier = 4; 28 | 29 | private int resendMinDelayMS = 50; 30 | 31 | private int heartbeatIntervalSec = 5; 32 | 33 | private int receiveTimeoutSec = 10; 34 | 35 | private boolean enableWebPanel = false; 36 | 37 | private InetSocketAddress webPanelBindAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), DragoniteGlobalConstants.WEB_PANEL_PORT); 38 | 39 | private PacketCryptor packetCryptor = null; 40 | 41 | private int trafficClass = 0; 42 | 43 | public int getPacketSize() { 44 | return packetSize; 45 | } 46 | 47 | public void setPacketSize(final int packetSize) { 48 | checkArgument(packetSize >= 500, "Packet size is too small"); 49 | this.packetSize = packetSize; 50 | } 51 | 52 | public boolean isAutoSplit() { 53 | return autoSplit; 54 | } 55 | 56 | public void setAutoSplit(final boolean autoSplit) { 57 | this.autoSplit = autoSplit; 58 | } 59 | 60 | public int getMaxPacketBufferSize() { 61 | return maxPacketBufferSize; 62 | } 63 | 64 | public void setMaxPacketBufferSize(final int maxPacketBufferSize) { 65 | checkArgument(maxPacketBufferSize >= 1, "Receive window must be greater than zero"); 66 | this.maxPacketBufferSize = maxPacketBufferSize; 67 | } 68 | 69 | public int getWindowMultiplier() { 70 | return windowMultiplier; 71 | } 72 | 73 | public void setWindowMultiplier(final int windowMultiplier) { 74 | checkArgument(windowMultiplier >= 1 && windowMultiplier <= 10, "Multiplier must be greater than zero (and no more than 10)"); 75 | this.windowMultiplier = windowMultiplier; 76 | } 77 | 78 | public int getResendMinDelayMS() { 79 | return resendMinDelayMS; 80 | } 81 | 82 | public void setResendMinDelayMS(final int resendMinDelayMS) { 83 | checkArgument(resendMinDelayMS >= 1, "Resend delay must be greater than zero"); 84 | this.resendMinDelayMS = resendMinDelayMS; 85 | } 86 | 87 | public int getHeartbeatIntervalSec() { 88 | return heartbeatIntervalSec; 89 | } 90 | 91 | public void setHeartbeatIntervalSec(final int heartbeatIntervalSec) { 92 | checkArgument(heartbeatIntervalSec >= 1, "Heartbeat interval must be greater than zero"); 93 | this.heartbeatIntervalSec = heartbeatIntervalSec; 94 | } 95 | 96 | public int getReceiveTimeoutSec() { 97 | return receiveTimeoutSec; 98 | } 99 | 100 | public void setReceiveTimeoutSec(final int receiveTimeoutSec) { 101 | checkArgument(receiveTimeoutSec >= 1, "Receive timeout must be greater than zero"); 102 | this.receiveTimeoutSec = receiveTimeoutSec; 103 | } 104 | 105 | public boolean isEnableWebPanel() { 106 | return enableWebPanel; 107 | } 108 | 109 | public void setEnableWebPanel(final boolean enableWebPanel) { 110 | this.enableWebPanel = enableWebPanel; 111 | } 112 | 113 | public InetSocketAddress getWebPanelBindAddress() { 114 | return webPanelBindAddress; 115 | } 116 | 117 | public void setWebPanelBindAddress(final InetSocketAddress webPanelBindAddress) { 118 | checkArgument(webPanelBindAddress != null, "Bind address cannot be null"); 119 | this.webPanelBindAddress = webPanelBindAddress; 120 | } 121 | 122 | public PacketCryptor getPacketCryptor() { 123 | return packetCryptor; 124 | } 125 | 126 | public void setPacketCryptor(final PacketCryptor packetCryptor) { 127 | this.packetCryptor = packetCryptor; 128 | } 129 | 130 | public int getTrafficClass() { 131 | return trafficClass; 132 | } 133 | 134 | public void setTrafficClass(final int trafficClass) { 135 | checkArgument(inTrafficClassRange(trafficClass), "TC must be in the range 0 <= tc <= 255"); 136 | this.trafficClass = trafficClass; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/socks5/SOCKS5SocketHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.network.socks5; 9 | 10 | import com.vecsight.dragonite.proxy.exception.SOCKS5Exception; 11 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 12 | 13 | import java.io.DataInputStream; 14 | import java.io.IOException; 15 | import java.io.OutputStream; 16 | import java.net.Socket; 17 | 18 | public final class SOCKS5SocketHelper { 19 | 20 | private static final byte SOCKS5_VERSION = 0x05; 21 | 22 | private static final byte[] SOCKS5_SUCCEED = {SOCKS5_VERSION, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 23 | 24 | private static final byte[] SOCKS5_NOT_ALLOWED = {SOCKS5_VERSION, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 25 | 26 | private static final byte[] SOCKS5_FAILED_REFUSED = {SOCKS5_VERSION, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 27 | 28 | private static final byte[] SOCKS5_NOT_SUPPORTED = {SOCKS5_VERSION, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 29 | 30 | public static SOCKS5Header getHeader(final Socket socket) throws IOException, SOCKS5Exception { 31 | final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); 32 | final OutputStream outputStream = socket.getOutputStream(); 33 | /* 34 | Auth frame: 35 | VER NMETHODS METHODS 36 | 1 1 1-255 37 | */ 38 | if (inputStream.readByte() != SOCKS5_VERSION) { 39 | throw new SOCKS5Exception("Invalid protocol version"); 40 | } 41 | boolean supportNoAuth = false; 42 | final int methodCount = inputStream.readUnsignedByte(); 43 | for (int i = 0; i < methodCount; i++) { 44 | if (inputStream.readByte() == 0x00) { 45 | supportNoAuth = true; 46 | } 47 | } 48 | if (!supportNoAuth) { 49 | final byte[] failResponse = {SOCKS5_VERSION, (byte) 0xFF}; 50 | outputStream.write(failResponse); 51 | throw new SOCKS5Exception("The client does not support no authentication mode"); 52 | } 53 | //Use no auth 54 | final byte[] noAuthResponse = {SOCKS5_VERSION, 0x00}; 55 | outputStream.write(noAuthResponse); 56 | /* 57 | Request frame: 58 | VER CMD RSV ATYP DST.ADDR DST.PORT 59 | 1 1 0x00 1 ... 2 60 | */ 61 | if (inputStream.readByte() != SOCKS5_VERSION) { 62 | throw new SOCKS5Exception("Invalid protocol version"); 63 | } 64 | final byte cmd = inputStream.readByte(); 65 | final byte rsv = inputStream.readByte(); //reserved, we just ignore it 66 | final byte atyp = inputStream.readByte(); 67 | final byte[] addr; 68 | final int port; 69 | if (atyp == 0x01) { 70 | //IPv4 71 | addr = new byte[4]; 72 | inputStream.readFully(addr); 73 | } else if (atyp == 0x03) { 74 | //Domain 75 | addr = new byte[inputStream.readUnsignedByte()]; 76 | inputStream.readFully(addr); 77 | } else if (atyp == 0x04) { 78 | //IPv6 79 | addr = new byte[16]; 80 | inputStream.readFully(addr); 81 | } else { 82 | throw new SOCKS5Exception("Unknown address type"); 83 | } 84 | port = inputStream.readUnsignedShort(); 85 | if (cmd == 0x01 || cmd == 0x03) { 86 | //CONNECT & UDP ASSOCIATE 87 | if (atyp == 0x03) 88 | return new SOCKS5Header(true, addr, port, cmd == 0x03); 89 | else 90 | return new SOCKS5Header(false, addr, port, cmd == 0x03); 91 | //No response frame yet 92 | } else { 93 | //Not supported, yet 94 | outputStream.write(SOCKS5_NOT_SUPPORTED); 95 | throw new SOCKS5Exception("Command " + cmd + " is not supported."); 96 | } 97 | } 98 | 99 | public static void sendSucceed(final Socket socket) throws IOException { 100 | socket.getOutputStream().write(SOCKS5_SUCCEED); 101 | } 102 | 103 | public static void sendSucceedUDP(final Socket socket, final int port) throws IOException { 104 | final byte[] localAddress = socket.getLocalAddress().getAddress(); 105 | 106 | final BinaryWriter writer = new BinaryWriter(6 + localAddress.length); 107 | writer.putSignedByte(SOCKS5_VERSION) 108 | .putSignedByte((byte) 0) 109 | .putSignedByte((byte) 0) 110 | .putSignedByte((byte) (localAddress.length == 4 ? 1 : 4)) 111 | .putBytes(localAddress) 112 | .putUnsignedShort(port); 113 | 114 | socket.getOutputStream().write(writer.toBytes()); 115 | } 116 | 117 | public static void sendFailed(final Socket socket) throws IOException { 118 | socket.getOutputStream().write(SOCKS5_FAILED_REFUSED); 119 | } 120 | 121 | public static void sendRejected(final Socket socket) throws IOException { 122 | socket.getOutputStream().write(SOCKS5_NOT_ALLOWED); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/header/udp/SOCKS5UDPRelayHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.proxy.header.udp; 9 | 10 | import com.vecsight.dragonite.proxy.exception.IncorrectHeaderException; 11 | import com.vecsight.dragonite.proxy.header.AddressType; 12 | import com.vecsight.dragonite.utils.binary.BinaryReader; 13 | import com.vecsight.dragonite.utils.binary.BinaryWriter; 14 | 15 | import java.nio.BufferUnderflowException; 16 | 17 | /* 18 | https://www.ietf.org/rfc/rfc1928.txt 19 | 20 | +----+------+------+----------+----------+----------+ 21 | |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | 22 | +----+------+------+----------+----------+----------+ 23 | | 2 | 1 | 1 | Variable | 2 | Variable | 24 | +----+------+------+----------+----------+----------+ 25 | 26 | The fields in the UDP request header are: 27 | 28 | o RSV Reserved X'0000' 29 | o FRAG Current fragment number 30 | o ATYP address type of following addresses: 31 | o IP V4 address: X'01' 32 | o DOMAINNAME: X'03' 33 | o IP V6 address: X'04' 34 | o DST.ADDR desired destination address 35 | o DST.PORT desired destination port 36 | o DATA user data 37 | */ 38 | 39 | public class SOCKS5UDPRelayHeader { 40 | 41 | private AddressType type; 42 | 43 | private byte[] addr; 44 | 45 | private int port; 46 | 47 | private byte[] payload; 48 | 49 | public SOCKS5UDPRelayHeader(final AddressType type, final byte[] addr, final int port, final byte[] payload) { 50 | this.type = type; 51 | this.addr = addr; 52 | this.port = port; 53 | this.payload = payload; 54 | } 55 | 56 | public SOCKS5UDPRelayHeader(final byte[] header) throws IncorrectHeaderException { 57 | final BinaryReader reader = new BinaryReader(header); 58 | 59 | try { 60 | 61 | final short rsv = reader.getSignedShort(); 62 | 63 | final byte frag = reader.getSignedByte(); 64 | 65 | if (frag != 0) { 66 | throw new IncorrectHeaderException("UDP fragmentation is not supported"); 67 | } 68 | 69 | final byte rawType = reader.getSignedByte(); 70 | 71 | if (rawType == 1) { 72 | type = AddressType.IPv4; 73 | } else if (rawType == 3) { 74 | type = AddressType.DOMAIN; 75 | } else if (rawType == 4) { 76 | type = AddressType.IPv6; 77 | } else { 78 | throw new IncorrectHeaderException("Unknown address type"); 79 | } 80 | 81 | switch (type) { 82 | case IPv4: 83 | addr = new byte[4]; 84 | reader.getBytes(addr); 85 | break; 86 | case IPv6: 87 | addr = new byte[16]; 88 | reader.getBytes(addr); 89 | break; 90 | case DOMAIN: 91 | addr = reader.getBytesGroupWithByteLength(); 92 | break; 93 | default: 94 | throw new IncorrectHeaderException("Invalid address type " + rawType); 95 | } 96 | 97 | port = reader.getUnsignedShort(); 98 | 99 | payload = new byte[reader.remaining()]; 100 | reader.getBytes(payload); 101 | 102 | } catch (final BufferUnderflowException e) { 103 | throw new IncorrectHeaderException("Incorrect packet length"); 104 | } 105 | } 106 | 107 | public AddressType getType() { 108 | return type; 109 | } 110 | 111 | public void setType(final AddressType type) { 112 | this.type = type; 113 | } 114 | 115 | public byte[] getAddr() { 116 | return addr; 117 | } 118 | 119 | public void setAddr(final byte[] addr) { 120 | this.addr = addr; 121 | } 122 | 123 | public int getPort() { 124 | return port; 125 | } 126 | 127 | public void setPort(final int port) { 128 | this.port = port; 129 | } 130 | 131 | public byte[] getPayload() { 132 | return payload; 133 | } 134 | 135 | public void setPayload(final byte[] payload) { 136 | this.payload = payload; 137 | } 138 | 139 | public byte[] toBytes() { 140 | final int addrTotalLength = (type == AddressType.IPv4 ? 4 : (type == AddressType.IPv6 ? 16 : 1 + addr.length)); 141 | 142 | final BinaryWriter writer = new BinaryWriter(6 + addrTotalLength + payload.length); 143 | 144 | writer.putSignedShort((short) 0); //RSV 145 | writer.putSignedByte((byte) 0); //FRAG 146 | 147 | if (type == AddressType.DOMAIN) { 148 | writer.putSignedByte((byte) 3); 149 | writer.putBytesGroupWithByteLength(addr); 150 | } else { 151 | if (type == AddressType.IPv4) { 152 | writer.putSignedByte((byte) 1); 153 | } else { 154 | writer.putSignedByte((byte) 4); 155 | } 156 | writer.putBytes(addr); 157 | } 158 | writer.putUnsignedShort(port); 159 | writer.putBytes(payload); 160 | 161 | return writer.toBytes(); 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/cryptor/AESCryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The Dragonite Project 3 | * ------------------------- 4 | * See the LICENSE file in the root directory for license information. 5 | */ 6 | 7 | 8 | package com.vecsight.dragonite.sdk.cryptor; 9 | 10 | import com.vecsight.dragonite.sdk.exception.EncryptionException; 11 | 12 | import javax.crypto.*; 13 | import javax.crypto.spec.IvParameterSpec; 14 | import javax.crypto.spec.PBEKeySpec; 15 | import javax.crypto.spec.SecretKeySpec; 16 | import java.nio.BufferUnderflowException; 17 | import java.nio.ByteBuffer; 18 | import java.nio.charset.StandardCharsets; 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.security.InvalidKeyException; 21 | import java.security.NoSuchAlgorithmException; 22 | import java.security.SecureRandom; 23 | import java.security.spec.InvalidKeySpecException; 24 | import java.security.spec.KeySpec; 25 | 26 | public class AESCryptor implements PacketCryptor { 27 | 28 | private static final int IV_LENGTH = 16; 29 | 30 | private static final int PADDING_LENGTH = 16; 31 | 32 | private static final String ENCRYPTION_ALGORITHM = "AES"; 33 | 34 | private static final String ENCRYPTION_ALGORITHM_WITH_MODE = "AES/CBC/PKCS5Padding"; 35 | 36 | private static final String PASSWORD_HASH_ALGORITHM = "PBKDF2WithHmacSHA1"; 37 | 38 | private static final byte[] PASSWORD_HASH_SALT = "*1w@UTcZLS@6fS713x80".getBytes(StandardCharsets.UTF_8); 39 | 40 | private static final int PASSWORD_HASH_ITERATION_COUNT = 12450; 41 | 42 | private static final int PASSWORD_HASH_LENGTH_BITS = 128; 43 | 44 | private final SecretKeySpec keySpec; 45 | 46 | private final Cipher decryptionCipher; 47 | 48 | private final Cipher encryptionCipher; 49 | 50 | private final SecureRandom random = new SecureRandom(); 51 | 52 | public AESCryptor(final String password) throws EncryptionException { 53 | this(getKey(password)); 54 | } 55 | 56 | public AESCryptor(final byte[] encryptionKey) throws EncryptionException { 57 | this.keySpec = new SecretKeySpec(encryptionKey, ENCRYPTION_ALGORITHM); 58 | try { 59 | decryptionCipher = Cipher.getInstance(ENCRYPTION_ALGORITHM_WITH_MODE); 60 | encryptionCipher = Cipher.getInstance(ENCRYPTION_ALGORITHM_WITH_MODE); 61 | } catch (final NoSuchAlgorithmException | NoSuchPaddingException e) { 62 | throw new EncryptionException(e.getMessage()); 63 | } 64 | } 65 | 66 | private byte[] decryptImpl(final byte[] bytes) { 67 | final ByteBuffer buffer = ByteBuffer.wrap(bytes); 68 | try { 69 | 70 | final byte[] iv = new byte[IV_LENGTH]; 71 | buffer.get(iv); 72 | 73 | final byte[] content = new byte[buffer.remaining()]; 74 | buffer.get(content); 75 | 76 | final IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 77 | 78 | synchronized (decryptionCipher) { 79 | decryptionCipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec); 80 | return decryptionCipher.doFinal(content); 81 | } 82 | 83 | } catch (final BufferUnderflowException | InvalidAlgorithmParameterException | InvalidKeyException | 84 | IllegalBlockSizeException | BadPaddingException e) { 85 | return null; 86 | } 87 | } 88 | 89 | private byte[] encryptImpl(final byte[] bytes) { 90 | try { 91 | 92 | final byte[] iv = new byte[IV_LENGTH]; 93 | random.nextBytes(iv); 94 | 95 | final IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 96 | 97 | final byte[] result; 98 | 99 | synchronized (encryptionCipher) { 100 | encryptionCipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec); 101 | result = encryptionCipher.doFinal(bytes); 102 | } 103 | 104 | final ByteBuffer buffer = ByteBuffer.allocate(iv.length + result.length); 105 | 106 | buffer.put(iv); 107 | buffer.put(result); 108 | 109 | return buffer.array(); 110 | 111 | } catch (final BufferUnderflowException | InvalidAlgorithmParameterException | InvalidKeyException | 112 | IllegalBlockSizeException | BadPaddingException e) { 113 | return null; 114 | } 115 | } 116 | 117 | @Override 118 | public byte[] encrypt(final byte[] rawData) { 119 | return encryptImpl(rawData); 120 | } 121 | 122 | @Override 123 | public byte[] decrypt(final byte[] encryptedData) { 124 | return decryptImpl(encryptedData); 125 | } 126 | 127 | @Override 128 | public int getMaxAdditionalBytesLength() { 129 | return IV_LENGTH + PADDING_LENGTH; 130 | } 131 | 132 | private static SecretKeyFactory getFactory() throws NoSuchAlgorithmException { 133 | return SecretKeyFactory.getInstance(PASSWORD_HASH_ALGORITHM); 134 | } 135 | 136 | private static byte[] getKey(final String password) throws EncryptionException { 137 | final KeySpec keySpec = new PBEKeySpec(password.toCharArray(), PASSWORD_HASH_SALT, 138 | PASSWORD_HASH_ITERATION_COUNT, PASSWORD_HASH_LENGTH_BITS); 139 | try { 140 | return getFactory().generateSecret(keySpec).getEncoded(); 141 | } catch (final NoSuchAlgorithmException | InvalidKeySpecException e) { 142 | throw new EncryptionException(e.getMessage()); 143 | } 144 | } 145 | } 146 | --------------------------------------------------------------------------------