Esempio n. 1
0
 public String start() throws Exception {
   authSocket = AprLibrary.createLocalSocketAddress();
   pool = Pool.create(AprLibrary.getInstance().getRootPool());
   handle = Local.create(authSocket, pool);
   int result = Local.bind(handle, 0);
   if (result != Status.APR_SUCCESS) {
     throwException(result);
   }
   AprLibrary.secureLocalSocket(authSocket, handle);
   result = Local.listen(handle, 0);
   if (result != Status.APR_SUCCESS) {
     throwException(result);
   }
   thread =
       new Thread() {
         public void run() {
           try {
             while (true) {
               long clientSock = Local.accept(handle);
               Socket.timeoutSet(clientSock, 10000000);
               new SshAgentSession(clientSock, agent);
             }
           } catch (Exception e) {
             e.printStackTrace();
           }
         }
       };
   thread.start();
   return authSocket;
 }
  @Override
  protected OpenFuture doInit(Buffer buffer) {
    OpenFuture f = new DefaultOpenFuture(this);
    try {
      out =
          new ChannelOutputStream(
              this, getRemoteWindow(), log, SshConstants.SSH_MSG_CHANNEL_DATA, true);
      authSocket = PropertyResolverUtils.getString(this, SshAgent.SSH_AUTHSOCKET_ENV_NAME);
      pool = Pool.create(AprLibrary.getInstance().getRootPool());
      handle = Local.create(authSocket, pool);
      int result = Local.connect(handle, 0);
      if (result != Status.APR_SUCCESS) {
        throwException(result);
      }

      ExecutorService service = getExecutorService();
      forwardService =
          (service == null)
              ? ThreadUtils.newSingleThreadExecutor("ChannelAgentForwarding[" + authSocket + "]")
              : service;
      shutdownForwarder = service != forwardService || isShutdownOnExit();

      final int copyBufSize =
          PropertyResolverUtils.getIntProperty(
              this, FORWARDER_BUFFER_SIZE, DEFAULT_FORWARDER_BUF_SIZE);
      ValidateUtils.checkTrue(
          copyBufSize >= MIN_FORWARDER_BUF_SIZE, "Copy buf size below min.: %d", copyBufSize);
      ValidateUtils.checkTrue(
          copyBufSize <= MAX_FORWARDER_BUF_SIZE, "Copy buf size above max.: %d", copyBufSize);

      forwarder =
          forwardService.submit(
              () -> {
                try {
                  byte[] buf = new byte[copyBufSize];
                  while (true) {
                    int len = Socket.recv(handle, buf, 0, buf.length);
                    if (len > 0) {
                      out.write(buf, 0, len);
                      out.flush();
                    }
                  }
                } catch (IOException e) {
                  close(true);
                }
              });

      signalChannelOpenSuccess();
      f.setOpened();
    } catch (Throwable t) {
      Throwable e = GenericUtils.peelException(t);
      signalChannelOpenFailure(e);
      f.setException(e);
    }

    return f;
  }
  void destroyPull() {
    if (shutdowned) return;

    // Causes segfault in AprSocketSource.poll() method, so this function must be called from it
    try {
      Socket.close(socket);
      // or
      // Socket.shutdown(socket, Socket.APR_SHUTDOWN_READWRITE);
      Pool.destroy(pool);
    } catch (Exception e) {
      s_logger.info("[ignored]" + "failure during network cleanup: " + e.getLocalizedMessage());
    }
  }
public class AprSocketWrapperImpl extends PipelineImpl implements SocketWrapper {
  private static final Logger s_logger = Logger.getLogger(AprSocketWrapperImpl.class);

  static {
    try {
      Library.initialize(null);
      SSL.initialize(null);
    } catch (Exception e) {
      throw new RuntimeException("Cannot load Tomcat Native Library (Apache Portable Runtime).", e);
    }
  }

  private final SSLState sslState;

  final long pool = Pool.create(0);
  long inetAddress;
  long socket;
  private AprSocketSource source;
  private AprSocketSink sink;

  boolean shutdown = false;

  private final boolean shutdowned = false;

  public AprSocketWrapperImpl(String id, SSLState sslState) {
    super(id);
    this.sslState = sslState;
  }

  @Override
  protected HashMap<String, Element> initElementMap(String id) {
    HashMap<String, Element> map = new HashMap<String, Element>();

    source = new AprSocketSource(id + "." + OUT, this);
    sink = new AprSocketSink(id + "." + IN, this);

    // Pass requests to read data to socket input stream
    map.put(OUT, source);

    // All incoming data, which is sent to this socket wrapper, will be sent
    // to socket remote
    map.put(IN, sink);

    return map;
  }

  /**
   * Connect this socket wrapper to remote server and start main loop on AprSocketSource stdout
   * link, to watch for incoming data, and AprSocketSink stdin link, to pull for outgoing data.
   */
  @Override
  public void connect(InetSocketAddress address) throws IOException {
    try {
      inetAddress =
          Address.info(address.getHostName(), Socket.APR_UNSPEC, address.getPort(), 0, pool);
      socket =
          Socket.create(
              Address.getInfo(inetAddress).family, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, pool);
    } catch (Exception e) {
      throw new IOException(
          "[" + this + "] ERROR: Cannot create socket for \"" + address + "\".", e);
    }

    int ret = Socket.connect(socket, inetAddress);
    if (ret != 0)
      throw new IOException(
          "["
              + this
              + "] ERROR: Cannot connect to remote host \""
              + address
              + "\": "
              + Error.strerror(ret));

    source.setSocket(socket);
    sink.setSocket(socket);

    // Start polling for data to send to remote sever
    runMainLoop(IN, STDIN, true, true);

    // Push incoming data from server to handlers
    runMainLoop(OUT, STDOUT, false, false);
  }

  @Override
  public void handleEvent(Event event, Direction direction) {
    switch (event) {
      case SOCKET_UPGRADE_TO_SSL:
        upgradeToSsl();
        break;
      default:
        super.handleEvent(event, direction);
        break;
    }
  }

  @Override
  public void validate() {

    if (getPads(Direction.IN).size() == 0)
      throw new RuntimeException("[ " + this + "] BUG: Input of socket is not connected.");

    if (getPads(Direction.OUT).size() == 0)
      throw new RuntimeException("[ " + this + "] BUG: Output of socket is not connected.");
  }

  @Override
  public void upgradeToSsl() {

    try {
      long sslContext;
      try {
        sslContext = SSLContext.make(pool, SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_MODE_CLIENT);
      } catch (Exception e) {
        throw new RuntimeException("Cannot create SSL context using Tomcat native library.", e);
      }

      SSLContext.setOptions(
          sslContext,
          SSL.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
              | SSL.SSL_OP_TLS_BLOCK_PADDING_BUG
              | SSL.SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
              | SSL.SSL_OP_MSIE_SSLV2_RSA_PADDING);
      // FIXME: verify certificate by default
      SSLContext.setVerify(sslContext, SSL.SSL_CVERIFY_NONE, 0);
      int ret;
      try {
        ret = SSLSocket.attach(sslContext, socket);
      } catch (Exception e) {
        throw new RuntimeException(
            "[" + this + "] ERROR: Cannot attach SSL context to socket: ", e);
      }
      if (ret != 0)
        throw new RuntimeException(
            "["
                + this
                + "] ERROR: Cannot attach SSL context to socket("
                + ret
                + "): "
                + SSL.getLastError());

      try {
        ret = SSLSocket.handshake(socket);
      } catch (Exception e) {
        throw new RuntimeException(
            "[" + this + "] ERROR: Cannot make SSL handshake with server: ", e);
      }
      if (ret != 0
          && ret
              != 20014) // 20014: bad certificate signature FIXME: show prompt for self signed
                        // certificate
      throw new RuntimeException(
            "["
                + this
                + "] ERROR: Cannot make SSL handshake with server("
                + ret
                + "): "
                + SSL.getLastError());

      try {
        byte[] key = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT);
        // *DEBUG*/System.out.println("DEBUG: Server cert:\n"+new ByteBuffer(key).dump());
        sslState.serverCertificateSubjectPublicKeyInfo =
            new X509CertImpl(key).getPublicKey().getEncoded();
      } catch (Exception e) {
        throw new RuntimeException("[" + this + "] ERROR: Cannot get server public key: ", e);
      }

    } catch (RuntimeException e) {
      shutdown();
      throw e;
    }
  }

  @Override
  public void shutdown() {
    if (shutdown) return;

    shutdown = true;

    try {
      handleEvent(Event.STREAM_CLOSE, Direction.IN);
    } catch (Exception e) {
      s_logger.info(
          "[ignored]" + "handling stream close event failed on input: " + e.getLocalizedMessage());
    }
    try {
      handleEvent(Event.STREAM_CLOSE, Direction.OUT);
    } catch (Exception e) {
      s_logger.info(
          "[ignored]" + "handling event close event failed on output: " + e.getLocalizedMessage());
    }
  }

  void destroyPull() {
    if (shutdowned) return;

    // Causes segfault in AprSocketSource.poll() method, so this function must be called from it
    try {
      Socket.close(socket);
      // or
      // Socket.shutdown(socket, Socket.APR_SHUTDOWN_READWRITE);
      Pool.destroy(pool);
    } catch (Exception e) {
      s_logger.info("[ignored]" + "failure during network cleanup: " + e.getLocalizedMessage());
    }
  }

  @Override
  public String toString() {
    return "AprSocketWrapper(" + id + ")";
  }

  /** Example. */
  public static void main(String args[]) {

    try {
      System.setProperty("streamer.Link.debug", "true");
      System.setProperty("streamer.Element.debug", "true");
      System.setProperty("rdpclient.MockServer.debug", "true");

      Pipeline pipeline = new PipelineImpl("echo client");

      AprSocketWrapperImpl socketWrapper = new AprSocketWrapperImpl("socket", null);

      pipeline.add(socketWrapper);
      pipeline.add(new BaseElement("echo"));
      pipeline.add(new Queue("queue")); // To decouple input and output

      pipeline.link("socket", "echo", "queue", "socket");

      final byte[] mockData = new byte[] {0x01, 0x02, 0x03};
      MockServer server =
          new MockServer(
              new Packet[] {
                new Packet("Server hello") {
                  {
                    type = SERVER;
                    data = mockData;
                  }
                },
                new Packet("Client hello") {
                  {
                    type = CLIENT;
                    data = mockData;
                  }
                },
                new Packet("Server hello") {
                  {
                    type = SERVER;
                    data = mockData;
                  }
                },
                new Packet("Client hello") {
                  {
                    type = CLIENT;
                    data = mockData;
                  }
                }
              });
      server.start();
      InetSocketAddress address = server.getAddress();

      socketWrapper.connect(address);

    } catch (Exception e) {
      e.printStackTrace(System.err);
    }
  }
}