public void start() { Configuration config = Configuration.INSTANCE; InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE); bossGroup = new NioEventLoopGroup(1); workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline() .addLast("logging", new LoggingHandler(LogLevel.DEBUG)) .addLast(new SocksInitRequestDecoder()) .addLast(new SocksMessageEncoder()) .addLast(new Socks5Handler()) .addLast(Status.TRAFFIC_HANDLER); } }); log.info("\tStartup {}-{}-client [{}{}]", Constants.APP_NAME, Constants.APP_VERSION, config.getMode(), config.getMode().equals("socks5") ? "" : ":" + config.getProtocol()); new Thread(() -> new UdpServer().start()).start(); ChannelFuture future = bootstrap.bind(config.getLocalHost(), config.getLocalPort()).sync(); future.addListener(future1 -> log.info("\tTCP listening at {}:{}...", config.getLocalHost(), config.getLocalPort())); future.channel().closeFuture().sync(); } catch (Exception e) { log.error("\tSocket bind failure ({})", e.getMessage()); } finally { log.info("\tShutting down"); bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }
@Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline p = socketChannel.pipeline(); //Socks request decode it will remove itself p.addLast(new SocksInitRequestDecoder()); //socks encode p.addLast(new SocksMessageEncoder()); //process SocksRequest p.addLast(new SocksRequestHandler()); // connect to Shadow Socks p.addLast(new ConnectRelayHandler(instance.getAddress(), instance.getPort(), () -> new ShadowSocksClientInitializer(shadowSocksContext))); }
@Override public void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline channelPipeline = socketChannel.pipeline(); channelPipeline.addLast(SocksInitRequestDecoder.getName(), new SocksInitRequestDecoder()); channelPipeline.addLast(SocksMessageEncoder.getName(), socksMessageEncoder); channelPipeline.addLast(SocksServerHandler.getName(), socksServerHandler); }
@Test public void shouldSwitchToSOCKS() throws IOException, InterruptedException { // given - embedded channel short localPort = 1234; EmbeddedChannel embeddedChannel = new EmbeddedChannel(new MockServerUnificationInitializer(mock(LifeCycle.class), new HttpStateHandler(mock(Scheduler.class)), null)); // embeddedChannel.attr(HTTP_CONNECT_SOCKET).set(new InetSocketAddress(localPort)); // and - no SOCKS handlers assertThat(embeddedChannel.pipeline().get(SocksProxyHandler.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksMessageEncoder.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksInitRequestDecoder.class), is(nullValue())); // when - SOCKS INIT message embeddedChannel.writeInbound(Unpooled.wrappedBuffer(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x02, // 1 authentication method (byte) 0x00, // NO_AUTH (byte) 0x02, // AUTH_PASSWORD })); // then - INIT response assertThat(ByteBufUtil.hexDump((ByteBuf) embeddedChannel.readOutbound()), is(Hex.encodeHexString(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x00, // NO_AUTH }))); // and then - should add SOCKS handlers first assertThat(String.valueOf(embeddedChannel.pipeline().names()), embeddedChannel.pipeline().names(), contains( "SocksCmdRequestDecoder#0", "SocksMessageEncoder#0", "SocksProxyHandler#0", "MockServerUnificationInitializer#0", "DefaultChannelPipeline$TailContext#0" )); }
public SocksServerInitializer(Config config, GlobalTrafficShapingHandler trafficHandler) { this.trafficHandler = trafficHandler; socksMessageEncoder = new SocksMessageEncoder(); socksServerHandler = new SocksServerHandler(config); }
@Test public void shouldHandleErrorsDuringSOCKSConnection() { // given - embedded channel short localPort = 1234; EmbeddedChannel embeddedChannel = new EmbeddedChannel(new MockServerUnificationInitializer(mock(LifeCycle.class), new HttpStateHandler(mock(Scheduler.class)), null)); // embeddedChannel.attr(HTTP_CONNECT_SOCKET).set(new InetSocketAddress(localPort)); // and - no SOCKS handlers assertThat(embeddedChannel.pipeline().get(SocksProxyHandler.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksMessageEncoder.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksInitRequestDecoder.class), is(nullValue())); // when - SOCKS INIT message embeddedChannel.writeInbound(Unpooled.wrappedBuffer(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x02, // 1 authentication method (byte) 0x00, // NO_AUTH (byte) 0x02, // AUTH_PASSWORD })); // then - INIT response assertThat(ByteBufUtil.hexDump((ByteBuf) embeddedChannel.readOutbound()), is(Hex.encodeHexString(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x00, // NO_AUTH }))); // and then - should add SOCKS handlers first if (new MockServerLogger().isEnabled(TRACE)) { assertThat(String.valueOf(embeddedChannel.pipeline().names()), embeddedChannel.pipeline().names(), contains( "LoggingHandler#0", "SocksCmdRequestDecoder#0", "SocksMessageEncoder#0", "SocksProxyHandler#0", "MockServerUnificationInitializer#0", "DefaultChannelPipeline$TailContext#0" )); } else { assertThat(String.valueOf(embeddedChannel.pipeline().names()), embeddedChannel.pipeline().names(), contains( "SocksCmdRequestDecoder#0", "SocksMessageEncoder#0", "SocksProxyHandler#0", "MockServerUnificationInitializer#0", "DefaultChannelPipeline$TailContext#0" )); } // and when - SOCKS CONNECT command embeddedChannel.writeInbound(Unpooled.wrappedBuffer(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x01, // command type CONNECT (byte) 0x00, // reserved (must be 0x00) (byte) 0x01, // address type IPv4 (byte) 0x7f, (byte) 0x00, (byte) 0x00, (byte) 0x01, // ip address (byte) (localPort & 0xFF00), (byte) localPort // port })); // then - CONNECT response assertThat(ByteBufUtil.hexDump((ByteBuf) embeddedChannel.readOutbound()), is(Hex.encodeHexString(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x01, // general failure (caused by connection failure) (byte) 0x00, // reserved (must be 0x00) (byte) 0x01, // address type IPv4 (byte) 0x7f, (byte) 0x00, (byte) 0x00, (byte) 0x01, // ip address (byte) (localPort & 0xFF00), (byte) localPort // port }))); // then - channel is closed after error assertThat(embeddedChannel.isOpen(), is(false)); }
@Test public void shouldSwitchToSOCKS() throws IOException, InterruptedException { // given - embedded channel short localPort = 1234; EmbeddedChannel embeddedChannel = new EmbeddedChannel(new MockServerUnificationInitializer(mock(LifeCycle.class), new HttpStateHandler(mock(Scheduler.class)), null)); // embeddedChannel.attr(HTTP_CONNECT_SOCKET).set(new InetSocketAddress(localPort)); // and - no SOCKS handlers assertThat(embeddedChannel.pipeline().get(SocksProxyHandler.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksMessageEncoder.class), is(nullValue())); assertThat(embeddedChannel.pipeline().get(SocksInitRequestDecoder.class), is(nullValue())); // when - SOCKS INIT message embeddedChannel.writeInbound(Unpooled.wrappedBuffer(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x02, // 1 authentication method (byte) 0x00, // NO_AUTH (byte) 0x02, // AUTH_PASSWORD })); // then - INIT response assertThat(ByteBufUtil.hexDump((ByteBuf) embeddedChannel.readOutbound()), is(Hex.encodeHexString(new byte[]{ (byte) 0x05, // SOCKS5 (byte) 0x00, // NO_AUTH }))); // and then - should add SOCKS handlers first if (new MockServerLogger().isEnabled(TRACE)) { assertThat(String.valueOf(embeddedChannel.pipeline().names()), embeddedChannel.pipeline().names(), contains( "LoggingHandler#0", "SocksCmdRequestDecoder#0", "SocksMessageEncoder#0", "SocksProxyHandler#0", "MockServerUnificationInitializer#0", "DefaultChannelPipeline$TailContext#0" )); } else { assertThat(String.valueOf(embeddedChannel.pipeline().names()), embeddedChannel.pipeline().names(), contains( "SocksCmdRequestDecoder#0", "SocksMessageEncoder#0", "SocksProxyHandler#0", "MockServerUnificationInitializer#0", "DefaultChannelPipeline$TailContext#0" )); } }