#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/poll.h>
#include<linux/if_ether.h>
#include<linux/if_packet.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/select.h>
#include<sys/time.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
#include<netinet/udp.h>
#include<netinet/ip_icmp.h>
#include<netdb.h>

#define MARK_CLT 0
#define MARK_SRV 255 

#define MAX_PACKET 65535
#define IP_FO 2

#define ERROR(msg) { perror(msg); exit -1; }
#define FD_EVENT(i) i.revents & POLLIN==POLLIN || i.revents & POLLPRI==POLLPRI

struct struct_conf {
	unsigned char       type;
	int                 protocol;
	int                 id;
	int                 delay;
	int                 packetsize;
	int                 ethhdrlen;
	int                 sport;
	int                 dport;
	unsigned char       mark;
};

/* Define common functions */
int               frag_open_tunnel_send();
int               frag_open_tunnel_recv();
void              frag_send_tunnel(int, unsigned char *, int, struct sockaddr_in, struct sockaddr_in, struct struct_conf);
int               frag_recv_tunnel(int, unsigned char *, struct sockaddr_in *, struct sockaddr_in *, struct struct_conf);

int               tcp_open_tunnel_send();
int               tcp_open_tunnel_recv();
void              tcp_send_tunnel(int, unsigned char *, int, struct sockaddr_in, struct sockaddr_in, struct struct_conf);
int               tcp_recv_tunnel(int, unsigned char *, struct sockaddr_in *, struct sockaddr_in *, struct struct_conf);

int               udp_open_tunnel_send();
int               udp_open_tunnel_recv();
void              udp_send_tunnel(int, unsigned char *, int, struct sockaddr_in, struct sockaddr_in, struct struct_conf);
int               udp_recv_tunnel(int, unsigned char *, struct sockaddr_in *, struct sockaddr_in *, struct struct_conf);

int               icmp_open_tunnel_send();
int               icmp_open_tunnel_recv();
void              icmp_send_tunnel(int, unsigned char *, int, struct sockaddr_in, struct sockaddr_in, struct struct_conf);
int               icmp_recv_tunnel(int, unsigned char *, struct sockaddr_in *, struct sockaddr_in *, struct struct_conf);

int               ip_open_tunnel_send();
int               ip_open_tunnel_recv();
void              ip_send_tunnel(int, unsigned char *, int, struct sockaddr_in, struct sockaddr_in, struct struct_conf);
int               ip_recv_tunnel(int, unsigned char *, struct sockaddr_in *, struct sockaddr_in *, struct struct_conf);

void              source_addr(struct sockaddr_in, struct sockaddr_in *);
unsigned short    cksum(unsigned short *,int);
char              *token(char *, const int);
