/*******************************************/
/* DESCRIPTION */

// This file contains the code to hide a TCP stream inside a 
// fake DNS query / answer session.


/*******************************************/
/* INCLUDES */

#ifndef __TCP_BY_DNS_TUNNEL_H__
#define __TCP_BY_DNS_TUNNEL_H__

#include "encap.h"


/*******************************************/
/* DEFINES AND ENUM */

#define DNS_MAX_READ		63	// Maximum number of bytes that
						// go in a single query.
#define DNS_Q_BEGIN_SIZE	12	// Header (Query).
#define DNS_Q_END_SIZE		4	// End (Query).
#define DNS_A_BEGIN_SIZE	12	// Same for Answer.
#define DNS_A_END_SIZE		20


/*******************************************/
/* PROTOTYPES */

void dns_flush_msg(char *buf, int *buf_index, int buf_size,
		   round_buf * out_rb_ptr);

class dns_l_encoder:public data_stream_encoder {
  public:

    bool msg_to_flush;
    char *msg;
    int msg_size;
    int msg_index;

     dns_l_encoder() {
	msg_to_flush = 0;
    } virtual ~ dns_l_encoder() {
	if (msg_to_flush)
	    delete[]msg;
    }

    int dns_l_encoder::encode(round_buf * in_rb_ptr,
			      round_buf * out_rb_ptr);
    int dns_l_encoder::build_message(round_buf * in_rb_ptr,
				     round_buf * out_rb_ptr);
    int dns_l_encoder::flush_msg(round_buf * out_rb_ptr);
    bool dns_l_encoder::has_unflushed_data();
};


class dns_l_decoder:public data_stream_decoder {
  public:

    bool msg_to_flush;
    char *buf;
    int buf_size;
    int buf_used_size;
    int msg_index;

     dns_l_decoder() {
	msg_to_flush = 0;
	buf_size = 10;
	buf_used_size = 0;
	msg_index = 0;
	buf = (char *) my_malloc(buf_size);
    } virtual ~ dns_l_decoder() {
	free(buf);
    }

    int dns_l_decoder::decode(round_buf * in_rb_ptr,
			      round_buf * out_rb_ptr);
    int dns_l_decoder::build_message(round_buf * in_rb_ptr,
				     round_buf * out_rb_ptr);
    int dns_l_decoder::flush_msg(round_buf * out_rb_ptr);
    bool dns_l_decoder::has_unflushed_data();
};


class dns_r_encoder:public data_stream_encoder {
  public:

    bool msg_to_flush;
    char *msg;
    int msg_size;
    int msg_index;

     dns_r_encoder() {
	msg_to_flush = 0;
    } virtual ~ dns_r_encoder() {
	if (msg_to_flush)
	    delete[]msg;
    }

    int dns_r_encoder::encode(round_buf * in_rb_ptr,
			      round_buf * out_rb_ptr);
    int dns_r_encoder::build_message(round_buf * in_rb_ptr,
				     round_buf * out_rb_ptr);
    int dns_r_encoder::flush_msg(round_buf * out_rb_ptr);
    bool dns_r_encoder::has_unflushed_data();
};


class dns_r_decoder:public data_stream_decoder {
  public:

    bool msg_to_flush;
    char *buf;
    int buf_size;
    int buf_used_size;
    int msg_index;

     dns_r_decoder() {
	msg_to_flush = 0;
	buf_size = 10;
	buf_used_size = 0;
	buf = (char *) my_malloc(buf_size);
    } virtual ~ dns_r_decoder() {
	free(buf);
    }

    int dns_r_decoder::decode(round_buf * in_rb_ptr,
			      round_buf * out_rb_ptr);
    int dns_r_decoder::build_message(round_buf * in_rb_ptr,
				     round_buf * out_rb_ptr);
    int dns_r_decoder::flush_msg(round_buf * out_rb_ptr);
    bool dns_r_decoder::has_unflushed_data();
};


class tcp_by_dns_tunnel:public tcp_by_generic_udp {
  public:

    virtual int get_l2r_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) {
	*encoder = new dns_l_encoder;
	*decoder = new dns_l_decoder;

	return 0;
    } virtual int get_r2l_coder(data_stream_encoder ** encoder,
				data_stream_decoder ** decoder) {
	*encoder = new dns_r_encoder;
	*decoder = new dns_r_decoder;

	return 0;
    }
};


#endif
