/*
 * Tentun - covert tunneling project
 *
 * Copyright (C) 2003 David Gordon
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 * This file contains the basic tunnel encapsulation code. The class
 * tcp_by_generic_tcp provides a tunnel that will route TCP data through
 * a TCP tunnel that implements some protocol. That protocol can be
 * implemented by deriving the class. It's the same thing for the
 * tcp_by_generic_udp class.
 */

#ifndef __ENCAP_H__
#define __ENCAP_H__

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <dnet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <unistd.h>
#include "util.h"
#include "tool.h"
#include "debugpkt.h"
#include "round_buf.h"


#define CONN_SOCK_DEBUG         0
#define	TRANS_BUF_SIZE		100*1024


struct tunnel {
    // The tunnel struct is a generic tunnel struct.

  public:
    virtual int establish_l2r_tunnel(int src_port,
				     sockaddr_in * dest_addr_ptr,
				     int dest_port, bool loop) = 0;

    virtual int establish_r2l_tunnel(int src_port,
				     sockaddr_in * dest_addr_ptr,
				     int dest_port, bool loop) = 0;
};

struct tcp_local {
    // The TCP local struct contains methods to communicate to the
    // socket that link the tunnel to the outside world.

  public:

    const static int local_end = 1;
    const static int remote_end = 2;

    // Size of the data buffer used for data transfers.
    const static int round_buf_size = 500 * 1024;
    const static int trans_buf_size = 100 * 1024;

    int data_sock;
    int listen_sock;
    bool data_sock_open;	// True if data sock open.
    bool listen_sock_open;
    int end_type;
    round_buf l2t_buf;
    round_buf t2l_buf;

     tcp_local::tcp_local();
     tcp_local::~tcp_local();
    void tcp_local::init();
    void tcp_local::clean_up();
    int tcp_local::establish_l_end(int src_port);
    int tcp_local::wait_for_conn();
    void tcp_local::close_l_end();
    int tcp_local::establish_r_end(sockaddr_in * dest_addr_ptr,
				   int dest_port);
    void tcp_local::close_r_end();
    int tcp_local::local_to_tunnel_avail();
    int tcp_local::tunnel_to_local_avail();
    bool tcp_local::has_unflushed_data();
    void tcp_local::tunnel_to_local(void *buf, int size);
    void tcp_local::local_to_tunnel(void *buf, int size);
    void tcp_local::register_sock(fd_set * read_set_ptr,
				  fd_set * write_set_ptr, int *max);
    int tcp_local::do_local_comm(bool * closed, bool * worked);
    int tcp_local::read_data_from_sock();
    int tcp_local::write_data_to_sock();
};

struct data_stream_encoder {
    // Specialize your struct from this struct to implement a data stream
    // encoder. The encode function takes two parameters. The first is the
    // buffer from which you must read data, and the second is the buffer
    // where you write the encoded data. You must be prepared to handle 
    // buffer underflow/overflow problems. The has_unflushed_data function
    // must return true if you currently have data waiting to be flushed
    // to the second buffer (because it's full).

  public:

    virtual ~ data_stream_encoder() {
    }
    // Encode() must return 1 on error, 0 otherwise.
	virtual int encode(round_buf * in_rb_ptr, round_buf * out_rb_ptr) =
	0;
    virtual bool has_unflushed_data() = 0;
};

struct data_stream_decoder {
    // Specialize your struct from this struct to implement a data stream
    // decoder. The decode function takes two parameters. The first is the
    // buffer from which you must read data, and the second is the buffer
    // where you write the decoded data. You must be prepared to handle 
    // buffer underflow/overflow problems. The has_unflushed_data function
    // must return true if you currently have data waiting to be flushed
    // to the second buffer (because it's full). If you read data from the
    // first buffer and you can't decode it because it is not a complete
    // message (more data must be read first), then this DOES NOT count as
    // unflushed data.

  public:

    virtual ~ data_stream_decoder() {
    }
    // Decode() must return 1 on error, 0 otherwise.
	virtual int decode(round_buf * in_rb_ptr, round_buf * out_rb_ptr) =
	0;
    virtual bool has_unflushed_data() = 0;
};

struct tcp_tunnel {
    // A TCP tunnel will forward any incoming TCP traffic.
  public:

    const static int local_end = 1;
    const static int remote_end = 2;

    // Size of the data buffer used for data transfers.
    const static int round_buf_size = 500 * 1024;
    const static int trans_buf_size = 100 * 1024;

    int data_sock;
    int listen_sock;
    bool data_sock_open;	// True if data sock open.
    bool listen_sock_open;
    int end_type;
    round_buf l2t_buf;
    round_buf t2l_buf;

     tcp_tunnel::tcp_tunnel();
     tcp_tunnel::~tcp_tunnel();
    void tcp_tunnel::init();
    void tcp_tunnel::clean_up();
    int tcp_tunnel::establish_l_end(int src_port);
    int tcp_tunnel::wait_for_conn();
    void tcp_tunnel::close_l_end();
    int tcp_tunnel::establish_r_end(sockaddr_in * dest_addr_ptr,
				    int dest_port);
    void tcp_tunnel::close_r_end();
    int tcp_tunnel::local_to_tunnel_avail();
    int tcp_tunnel::tunnel_to_local_avail();
    bool tcp_tunnel::has_unflushed_data();
    void tcp_tunnel::tunnel_to_local(void *buf, int size);
    void tcp_tunnel::local_to_tunnel(void *buf, int size);
    void tcp_tunnel::register_sock(fd_set * read_set_ptr,
				   fd_set * write_set_ptr, int *max);
    int tcp_tunnel::do_tunnel_comm(bool * closed, bool * worked);
    int tcp_tunnel::read_data_from_sock();
    int tcp_tunnel::write_data_to_sock();
};

struct udp_tunnel {
    // A UDP tunnel will forward any incoming UDP traffic.
  public:

    const static int local_end = 1;
    const static int remote_end = 2;

    // Size of the data buffer used for data transfers.
    // Must be greater than the max UDP data size (more than 65536 bytes to
    // be sure).
    const static int round_buf_size = 500 * 1024;
    const static int trans_buf_size = 100 * 1024;

    int data_sock;
    bool data_sock_open;	// True if data sock open.
    int end_type;
    round_buf l2t_buf;
    round_buf t2l_buf;
    sockaddr tunnel_addr;
    socklen_t tunnel_addr_len;

     udp_tunnel::udp_tunnel();
     udp_tunnel::~udp_tunnel();
    void udp_tunnel::init();
    void udp_tunnel::clean_up();
    int udp_tunnel::establish_l_end(int src_port);
    int udp_tunnel::wait_for_conn();
    void udp_tunnel::close_l_end();
    int udp_tunnel::establish_r_end(sockaddr_in * dest_addr_ptr,
				    int dest_port);
    void udp_tunnel::close_r_end();
    bool udp_tunnel::has_unflushed_data();
    void udp_tunnel::tunnel_to_local(void *buf, int size);
    void udp_tunnel::local_to_tunnel(void *buf, int size);
    void udp_tunnel::register_sock(fd_set * read_set_ptr,
				   fd_set * write_set_ptr, int *max);
    int udp_tunnel::do_tunnel_comm(bool * closed, bool * worked);
    int udp_tunnel::read_data_from_sock();
    int udp_tunnel::write_data_to_sock();
};

struct tcp_by_generic_tcp:public tunnel {
    // This struct implements a TCP tunnel over a generic TCP protocol.
    // It must be specialized by another struct which will implement the
    // protocol (e.g. HTTP) that hides the channel. The methods to override
    // are get_l2r_coder and get_r2l_coder. Each method provide a TCP 
    // stream encoder/decoder. There are two methods to model the
    // client-server relationship found in most protocols, such as HTTP.
    // The encoder/decoder pair returned by get_l2r_coder must behave as if
    // they were on the client side. It's the opposite for the get_r2l_coder
    // method.
  public:

    tcp_local local_conn;
    tcp_tunnel tunnel_conn;
    bool local_sock_closed, tunnel_sock_closed;

    const static int local_end = 1;
    const static int remote_end = 2;

    // Virtual methods to implements.
    virtual int get_l2r_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) = 0;
    virtual int get_r2l_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) = 0;

     tcp_by_generic_tcp::tcp_by_generic_tcp();
    virtual tcp_by_generic_tcp::~tcp_by_generic_tcp();
    int tcp_by_generic_tcp::establish_l2r_tunnel(int src_port,
						 sockaddr_in *
						 dest_addr_ptr,
						 int dest_port, bool loop);
    int tcp_by_generic_tcp::establish_r2l_tunnel(int src_port,
						 sockaddr_in *
						 dest_addr_ptr,
						 int dest_port, bool loop);
    int tcp_by_generic_tcp::l2r_comm();
    int tcp_by_generic_tcp::r2l_comm();
    int tcp_by_generic_tcp::do_comm(data_stream_encoder * encoder,
				    data_stream_decoder * decoder);
    int tcp_by_generic_tcp::do_sock_comm();
};

struct tcp_by_generic_udp:public tunnel {
    // This struct implements a TCP tunnel over a generic UDP protocol.
    // It must be specialized by another struct which will implement the
    // protocol (e.g. DNS) that hides the channel. The methods to override
    // are get_l2r_coder and get_r2l_coder. Each method provide a data 
    // stream encoder/decoder. There are two methods to model the
    // client-server relationship found in most protocols, such as DNS.
    // The encoder/decoder pair returned by get_l2r_coder must behave as if
    // they were on the client side. It's the opposite for the get_r2l_coder
    // method.
  public:

    tcp_local local_conn;
    udp_tunnel tunnel_conn;
    bool local_sock_closed, tunnel_sock_closed;

    const static int local_end = 1;
    const static int remote_end = 2;

    // Virtual methods to implements.
    virtual int get_l2r_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) = 0;
    virtual int get_r2l_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) = 0;

     tcp_by_generic_udp::tcp_by_generic_udp();
    virtual tcp_by_generic_udp::~tcp_by_generic_udp();
    int tcp_by_generic_udp::establish_l2r_tunnel(int src_port,
						 sockaddr_in *
						 dest_addr_ptr,
						 int dest_port, bool loop);
    int tcp_by_generic_udp::establish_r2l_tunnel(int src_port,
						 sockaddr_in *
						 dest_addr_ptr,
						 int dest_port, bool loop);
    int tcp_by_generic_udp::l2r_comm();
    int tcp_by_generic_udp::r2l_comm();
    int tcp_by_generic_udp::do_comm(data_stream_encoder * encoder,
				    data_stream_decoder * decoder);
    int tcp_by_generic_udp::do_sock_comm();
};


#endif
