All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sandpolis.server.vanilla.net.handler.ProxyHandler Maven / Gradle / Ivy

There is a newer version: 6.1.0
Show newest version
/******************************************************************************
 *                                                                            *
 *                    Copyright 2017 Subterranean Security                    *
 *                                                                            *
 *  Licensed under the Apache License, Version 2.0 (the "License");           *
 *  you may not use this file except in compliance with the License.          *
 *  You may obtain a copy of the License at                                   *
 *                                                                            *
 *      http://www.apache.org/licenses/LICENSE-2.0                            *
 *                                                                            *
 *  Unless required by applicable law or agreed to in writing, software       *
 *  distributed under the License is distributed on an "AS IS" BASIS,         *
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 *  See the License for the specific language governing permissions and       *
 *  limitations under the License.                                            *
 *                                                                            *
 *****************************************************************************/
package com.sandpolis.server.vanilla.net.handler;

import com.sandpolis.core.net.Sock;
import com.sandpolis.core.net.exception.InvalidMessageException;
import com.sandpolis.core.net.init.ChannelConstant;
import com.sandpolis.core.net.store.connection.ConnectionStore;
import com.sandpolis.core.proto.net.MCNetwork.EV_EndpointClosed;
import com.sandpolis.core.proto.net.MSG.Message;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.util.ReferenceCountUtil;

/**
 * This handler reads the first two fields of an incoming {@link Message} to
 * determine its destination. If the destination is another instance, the
 * {@link ByteBuf} will be efficiently forwarded. Otherwise the {@link ByteBuf}
 * will be decoded and executed for this instance.
*
* * This handler MUST be placed after a {@link ProtobufVarint32FrameDecoder}! * Otherwise a malicious instance could send messages to unauthorized instances * by sending two messages in rapid succession. Since this handler only verifies * the first few bytes and then routes the entire buffer accordingly, sending * one small valid message followed by an invalid message would lead to the * invalid message being delivered to the receiver. * * @author cilki * @since 5.0.0 */ @Sharable public class ProxyHandler extends SimpleChannelInboundHandler { /** * The server's CVID which is used in determining when to route messages. */ private final int cvid; public ProxyHandler(int cvid) { this.cvid = cvid; } @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { msg.markReaderIndex(); // Read field: "to" if (msg.isReadable() && msg.readByte() == 0x08) { int to = readCvid(msg); // Perform redirection if necessary if (to != cvid) { // Read field: "from" if (msg.isReadable() && msg.readByte() == 0x10) { int from = readCvid(msg); // Verify the from field to prevent spoofing if (ctx.channel().attr(ChannelConstant.CVID).get() != from) { throw new InvalidMessageException("Message 'from' does not match channel's CVID"); } } else { throw new InvalidMessageException("Message specifies 'to' but not 'from'"); } // route Sock con = ConnectionStore.get(to); if (con != null) { msg.resetReaderIndex(); // Skip to the middle of the pipeline ((ProtobufVarint32LengthFieldPrepender) con.channel().pipeline().get("protobuf.frame_encoder")) .acceptOutboundMessage(msg); } else { ctx.channel().writeAndFlush(Message.newBuilder() .setEvEndpointClosed(EV_EndpointClosed.newBuilder().setCvid(to)).build()); } return; } } msg.resetReaderIndex(); ReferenceCountUtil.retain(msg); ctx.fireChannelRead(msg); } /** * Read a CVID varint from the given {@link ByteBuf}. * * @param buffer The buffer to read (read pointer will be modified) * @return The decoded CVID */ private static int readCvid(ByteBuf buffer) { byte tmp = buffer.readByte(); if (tmp >= 0) { return tmp; } else { int result = tmp & 127; if ((tmp = buffer.readByte()) >= 0) { result |= tmp << 7; } else { result |= (tmp & 127) << 7; if ((tmp = buffer.readByte()) >= 0) { result |= tmp << 14; } else { result |= (tmp & 127) << 14; if ((tmp = buffer.readByte()) >= 0) { result |= tmp << 21; } else { result |= (tmp & 127) << 21; result |= (tmp = buffer.readByte()) << 28; if (tmp < 0) { // The CVID is negative (negative varints are always 10 bytes) throw new CorruptedFrameException("Invalid CVID"); } } } } if (result < 0) throw new CorruptedFrameException("Invalid CVID"); return result; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy