#include "common.h"

int icmp_open_tunnel_send() {
int on = 1, s;

  if((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
		ERROR("socket");

return s;
}

int icmp_open_tunnel_recv() {
int s;

	if((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP))) < 0)
		ERROR("socket input");

return s;
}

void icmp_send_tunnel(int fd, unsigned char *buffer, int length, struct sockaddr_in saddr, struct sockaddr_in daddr, struct struct_conf conf) {
struct icmphdr    *icmphdr;
unsigned char     packet[MAX_PACKET];
 
/* Clean packet */
  memset(packet, 0, MAX_PACKET);

/* Define pointers */
	icmphdr =                     (struct icmphdr *)packet;
  
/* ICMP packet */
	icmphdr->type =               conf.sport;
	icmphdr->code =               0;
	icmphdr->un.echo.id =         htons(conf.id);
	icmphdr->un.echo.sequence =   htons(10000);

   *((unsigned char *)icmphdr+sizeof(struct icmphdr)) = conf.mark;
   memcpy((unsigned char *)icmphdr+sizeof(struct icmphdr)+1, buffer, length++);

	length += sizeof(struct iphdr);
	icmphdr->checksum=            cksum((u_short *)packet, length);

   if(sendto(fd, packet, length, 0x0, (struct sockaddr *)&daddr, sizeof(struct sockaddr)) != length)
     ERROR("sendto");
}

int icmp_recv_tunnel(int fd, unsigned char *buffer, struct sockaddr_in *saddr, struct sockaddr_in *daddr, struct struct_conf conf) {
unsigned char packet[MAX_PACKET];
struct sockaddr     from;
struct iphdr        *iphdr;
struct icmphdr      *icmphdr;
int                 fromlen, length;

	fromlen = sizeof(from);
	if(recvfrom(fd, packet, MAX_PACKET, 0x0, (struct sockaddr *)&from, &fromlen) <= 0) 
		ERROR("recvfrom");

   iphdr = (struct iphdr *)(packet+conf.ethhdrlen);
	icmphdr = (struct icmphdr *)(packet+conf.ethhdrlen+sizeof(struct iphdr));

   
	if(iphdr->protocol == IPPROTO_ICMP && htons(icmphdr->un.echo.id) == conf.id &&
       htons(icmphdr->un.echo.sequence) == 10000 && icmphdr->type == conf.dport &&
       *(packet+conf.ethhdrlen+sizeof(struct iphdr)+sizeof(struct icmphdr)) != conf.mark) {
			length = htons(iphdr->tot_len)-sizeof(struct iphdr)-sizeof(struct icmphdr)-1;
			memcpy(buffer, packet+conf.ethhdrlen+sizeof(struct iphdr)+sizeof(struct icmphdr)+1, length); 
         saddr->sin_addr.s_addr = iphdr->saddr;
         daddr->sin_addr.s_addr = iphdr->daddr;

	return(length);
	}

return(0);
}
