Skip to content

Commit

Permalink
Merge pull request #30 from Zmax0/dev/2.5.1
Browse files Browse the repository at this point in the history
  • Loading branch information
Zmax0 committed Jul 19, 2024
2 parents b3864f8 + 5a148ca commit 0860092
Show file tree
Hide file tree
Showing 30 changed files with 418 additions and 146 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>urban-spork</groupId>
<artifactId>urban-spork</artifactId>
<version>2.5.0</version>
<version>2.5.1</version>
<packaging>pom</packaging>
<modules>
<module>urban-spork-common</module>
Expand All @@ -14,7 +14,7 @@
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<urban-spork.version>2.5.0</urban-spork.version>
<urban-spork.version>2.5.1</urban-spork.version>
<maven-surefire-plugin.versioin>3.2.5</maven-surefire-plugin.versioin>
<maven-jar-plugin.version>3.4.1</maven-jar-plugin.version>
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
Expand Down
2 changes: 1 addition & 1 deletion urban-spork-client-gui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>urban-spork</groupId>
<artifactId>urban-spork</artifactId>
<version>2.5.0</version>
<version>2.5.1</version>
</parent>
<groupId>urban-spork-client-gui</groupId>
<artifactId>urban-spork-client-gui</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion urban-spork-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>urban-spork</groupId>
<artifactId>urban-spork</artifactId>
<version>2.5.0</version>
<version>2.5.1</version>
</parent>
<artifactId>urban-spork-client</artifactId>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpMethod;

import java.net.InetSocketAddress;
import java.util.function.Consumer;

@ChannelHandler.Sharable
Expand All @@ -20,10 +22,16 @@ private ClientHttpUnificationHandler() {}
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
HttpProxyUtil.Option option = HttpProxyUtil.parseOption(msg);
if (HttpMethod.GET == option.method()) {
new HttpRelayHandler(msg.retain()).connect(ctx.channel(), option.address());
InetSocketAddress dstAddress = option.address();
InetSocketAddress localAddress = (InetSocketAddress) ctx.channel().localAddress();
if (localAddress.getHostString().equals(dstAddress.getHostString()) && localAddress.getPort() == dstAddress.getPort()) {
ctx.writeAndFlush(Unpooled.wrappedBuffer("HTTP/1.1 400 Bad Request\r\n\r\n".getBytes())).addListener(ChannelFutureListener.CLOSE);
return;
}
if (HttpMethod.CONNECT == option.method()) {
new HttpsRelayHandler().connect(ctx.channel(), dstAddress);
} else {
new HttpsRelayHandler().connect(ctx.channel(), option.address());
new HttpRelayHandler(msg.retain()).connect(ctx.channel(), dstAddress);
}
}

Expand All @@ -33,11 +41,6 @@ public ChannelHandler inboundHandler() {
return INSTANCE;
}

@Override
public InboundWriter inboundWriter() {
return new InboundWriter(channel -> {}, channel -> {});
}

@Override
public Consumer<Channel> outboundWriter() {
return channel -> channel.writeAndFlush(msg);
Expand All @@ -60,10 +63,5 @@ public InboundWriter inboundWriter() {
channel -> channel.writeAndFlush(Unpooled.wrappedBuffer(FAILED))
);
}

@Override
public Consumer<Channel> outboundWriter() {
return channel -> {};
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.urbanspork.client;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
Expand All @@ -9,7 +8,6 @@
import io.netty.handler.codec.socksx.v5.Socks5CommandStatus;

import java.net.InetSocketAddress;
import java.util.function.Consumer;

class ClientSocksConnectHandler extends SimpleChannelInboundHandler<Socks5CommandRequest> {
@Override
Expand All @@ -27,11 +25,6 @@ public InboundWriter inboundWriter() {
c -> c.writeAndFlush(new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, request.dstAddrType()))
);
}

@Override
public Consumer<Channel> outboundWriter() {
return c -> {};
}
}.connect(ctx.channel(), InetSocketAddress.createUnresolved(request.dstAddr(), request.dstPort()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ public interface ClientTcpRelayHandler {

ChannelHandler inboundHandler();

InboundWriter inboundWriter();
default InboundWriter inboundWriter() {
return new InboundWriter(channel -> {}, channel -> {});
}

Consumer<Channel> outboundWriter();
default Consumer<Channel> outboundWriter() {
return channel -> {};
}

default void connect(Channel inbound, InetSocketAddress dstAddress) {
ServerConfig config = inbound.attr(AttributeKeys.SERVER_CONFIG).get();
Expand Down Expand Up @@ -100,7 +104,7 @@ protected void initChannel(Channel outbound) throws Exception {
private void enableWebSocket(Channel inbound, Channel outbound, ServerConfig config) throws URISyntaxException {
outbound.pipeline().addLast(
new HttpClientCodec(),
new HttpObjectAggregator(0xffff),
new HttpObjectAggregator(0xfffff),
buildWebSocketHandler(config),
new WebSocketCodec(inbound, config, inboundWriter(), outboundWriter())
);
Expand Down Expand Up @@ -190,6 +194,7 @@ static WebSocketClientProtocolHandler buildWebSocketHandler(ServerConfig config)
}
builder.generateOriginHeader(false).customHeaders(headers);
});
builder.maxFramePayloadLength(0xfffff);
return new WebSocketClientProtocolHandler(builder.build());
}
}
2 changes: 1 addition & 1 deletion urban-spork-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>urban-spork</groupId>
<artifactId>urban-spork</artifactId>
<version>2.5.0</version>
<version>2.5.1</version>
</parent>
<artifactId>urban-spork-common</artifactId>
<dependencies>
Expand Down
14 changes: 11 additions & 3 deletions urban-spork-common/src/com/urbanspork/common/codec/CipherKind.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,31 @@

import com.fasterxml.jackson.annotation.JsonValue;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public enum CipherKind {

aes_128_gcm(16),
aes_256_gcm(32),
chacha20_poly1305(32),
aead2022_blake3_aes_128_gcm("2022-blake3-aes-128-gcm", 16),
aead2022_blake3_aes_256_gcm("2022-blake3-aes-256-gcm", 32),
;

private static final Map<String, CipherKind> MAP;
private final String value;
private final int keySize;
private final boolean aead2022;
private final boolean eih;

static {
MAP = new HashMap<>();
for (CipherKind cipherKind : CipherKind.values()) {
MAP.put(cipherKind.toString(), cipherKind);
}
}

CipherKind(int keySize) {
this.value = name().replace('_', '-'); // aes_128_gcm -> aes-128-gcm
this.keySize = keySize;
Expand All @@ -40,7 +48,7 @@ public String toString() {
}

public static Optional<CipherKind> from(String method) {
return Arrays.stream(CipherKind.values()).filter(kind -> kind.toString().equals(method)).findAny();
return Optional.ofNullable(MAP.get(method));
}

public int keySize() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,15 @@ private void initAEAD2022PayloadDecoder(Session session, ByteBuf in, List<Object
}
if (session.context().checkNonceReplay(salt)) {
String msg = String.format("detected repeated nonce salt %s", ByteString.valueOf(salt));
throw new DecoderException(msg);
throw new RepeatedNonceException(msg);
}
session.identity().setRequestSalt(salt);
ByteBuf sealedHeaderBuf = Unpooled.buffer();
int sealedHeaderLength = eihLength + 1 + 8 + requestSaltLength + 2 + tagSize;
if (in.readableBytes() < sealedHeaderLength) {
String msg = String.format("header too short, expecting %d bytes, but found %d bytes", sealedHeaderLength, in.readableBytes());
throw new TooShortHeaderException(msg);
}
in.getBytes(in.readerIndex(), sealedHeaderBuf, sealedHeaderLength);
PayloadDecoder newPayloadDecoder;
if (requireEih) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.urbanspork.common.codec.shadowsocks.tcp;

import io.netty.handler.codec.DecoderException;

class RepeatedNonceException extends DecoderException {
RepeatedNonceException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.DecoderException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -44,15 +43,28 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) t

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (Mode.Server == session.mode() && cause instanceof DecoderException) {
SocketChannel channel = (SocketChannel) ctx.channel();
String transLog = ExceptionHandler.transLog(channel);
logger.error("[tcp][{}] {}", transLog, cause.getMessage());
ctx.deregister();
channel.config().setSoLinger(0);
channel.shutdownOutput().addListener(future -> channel.unsafe().beginRead());
} else {
ctx.fireExceptionCaught(cause);
switch (cause) {
case TooShortHeaderException ignore -> {
logError(ctx, cause);
ctx.deregister();
SocketChannel channel = (SocketChannel) ctx.channel();
if (channel.isActive()) {
channel.config().setSoLinger(0);
channel.shutdownOutput();
}
}
case RepeatedNonceException ignore -> {
logError(ctx, cause);
SocketChannel channel = (SocketChannel) ctx.channel();
channel.config().setSoLinger(0);
channel.close(); // send RST
}
default -> ctx.fireExceptionCaught(cause);
}
}

private void logError(ChannelHandlerContext ctx, Throwable cause) {
String transLog = ExceptionHandler.transLog(ctx.channel());
logger.error("[tcp][{}] {}", transLog, cause.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.urbanspork.common.codec.shadowsocks.tcp;

import io.netty.handler.codec.DecoderException;

class TooShortHeaderException extends DecoderException {
TooShortHeaderException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public RelayingPacket<ByteBuf> decode(Context context, ByteBuf in) throws Invali
}
}

// Client -> Server
// Client -> Server(*)
private RelayingPacket<ByteBuf> decodeClientPocketAead2022(Context context, ByteBuf in) throws InvalidCipherTextException {
int nonceLength = AEAD2022.UDP.getNonceLength(cipherKind);
int tagSize = cipherMethod.tagSize();
Expand Down Expand Up @@ -144,7 +144,7 @@ private RelayingPacket<ByteBuf> decodeClientPocketAead2022(Context context, Byte
return new RelayingPacket<>(address, packet);
}

// Server -> Client
// Server -> Client(*)
private RelayingPacket<ByteBuf> decodeServerPocketAead2022(Context context, ByteBuf in) throws InvalidCipherTextException {
int nonceLength = AEAD2022.UDP.getNonceLength(cipherKind);
int tagSize = cipherMethod.tagSize();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.urbanspork.common.protocol.vmess.header;

import java.util.Arrays;

public enum AddressType {

IPV4((byte) 1), DOMAIN((byte) 2), IPV6((byte) 3);

private static final AddressType[] VALUES = values();
private final byte value;

AddressType(byte value) {
Expand All @@ -17,7 +16,10 @@ public byte getValue() {
}

public static AddressType valueOf(byte value) {
return Arrays.stream(values()).filter(type -> type.value == value)
.findFirst().orElseThrow(() -> new IllegalArgumentException("Unknown address type: " + value));
if (1 <= value && value <= 3) {
return VALUES[value - 1];
} else {
throw new IllegalArgumentException("Unknown address type: " + value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import java.util.Arrays;

public enum RequestOption {

Empty((byte) 0),
// RequestOptionChunkStream indicates request payload is chunked. Each chunk consists of length, authentication and payload.
ChunkStream((byte) 1),

// RequestOptionConnectionReuse indicates client side expects to reuse the connection.
ConnectionReuse((byte) 2),

Expand All @@ -17,6 +16,8 @@ public enum RequestOption {
AuthenticatedLength((byte) 16),
;

private static final RequestOption[] VALUES = values();

private final byte value;

RequestOption(byte value) {
Expand All @@ -36,18 +37,21 @@ public static byte toMask(RequestOption[] arr) {
}

public static RequestOption[] fromMask(byte mask) {
RequestOption[] options = values();
RequestOption[] res = new RequestOption[options.length];
int i = 0;
for (RequestOption option : options) {
if ((option.value & mask) != 0) {
res[i++] = option;
RequestOption[] res = Arrays.copyOf(VALUES, VALUES.length);
for (int i = 0; i < VALUES.length; i++) {
if ((VALUES[i].value & mask) == 0) {
res[i] = Empty;
}
}
return Arrays.copyOf(res, i);
return res;
}

public static boolean has(RequestOption[] options, RequestOption target) {
return Arrays.stream(options).anyMatch(option -> option == target);
for (RequestOption option : options) {
if (option == target) {
return true;
}
}
return false;
}
}
Loading

0 comments on commit 0860092

Please sign in to comment.