#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define CKSUM_CARRY(x) \
   (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))

typedef struct tcp_pseudo_header{
  unsigned int   src_addr;
  unsigned int   dst_addr;
  unsigned char  zero;
  unsigned char  proto;
  unsigned short tcp_len;
  char 		 tcp[1500];
}tcp_pseudo_hd_t;

int in_cksum(u_short *addr, int len){
  int sum;
  int nleft;
  u_short ans;
  u_short *w;
  
  sum = 0;
  ans = 0;
  nleft = len;
  w = addr;

  while (nleft > 1){
    sum += *w++;
    nleft -= 2;
  }
  if (nleft == 1){
    *(u_char *)(&ans) = *(u_char *)w;
    sum += ans;
  }
  return (sum);
}

u_int16_t do_tcp_checksum(pack, zero, proto, len, ip_addr)
  u_char        *pack;
  unsigned char zero;
  unsigned char proto;
  unsigned short len;
  char *ip_addr;
{
  tcp_pseudo_hd_t pseudo_hdr;
  unsigned int sum = 0;
  struct tcphdr *tcp = (struct tcphdr*)(pack);

  memset(&pseudo_hdr,0,sizeof(pseudo_hdr));
  memcpy(&pseudo_hdr.src_addr,ip_addr,4);
  memcpy(&pseudo_hdr.dst_addr,ip_addr+4,4);
  pseudo_hdr.zero       = zero;
  pseudo_hdr.proto      = proto;
  pseudo_hdr.tcp_len    = htons(len);
  memcpy(pseudo_hdr.tcp,tcp,len);
  sum = in_cksum((u_short *)&pseudo_hdr,12+len);
  return CKSUM_CARRY(sum);
}

void send_it(char *pack,int psize){
  struct sockaddr_in sin;
  char  on = 1;
  int   sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
  int   status = 0;
  char	*dst = pack+16;
  
  printf("Socket number: %d\n",sockd);
  memset(&sin,0,sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = 0;
  memcpy(&sin.sin_addr.s_addr,dst,4);
  printf("to %#x\n",sin.sin_addr);
  
  setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
  status = sendto(sockd,pack,psize,0x0,(struct sockaddr *)&sin,sizeof(sin));
  printf("Sent %d bytes\n",status);
}


int main(int argc, char **argv){
  unsigned char pack[1500];
  FILE *fd = fopen(argv[1],"r");
  int j,i=0;
  char str1[3], str2[3];
  unsigned char *tcp;  
  u_int32_t	sum;
  
  str1[2] = 0;
  str2[2] = 0;
  memset(pack,0,1500);
  while(fscanf(fd,"%c%c%c%c ",&str1[0],&str1[1],&str2[0],&str2[1]) != EOF){
    pack[i++] = (char)strtoul(str1,NULL,16);
    pack[i++] = (char)strtoul(str2,NULL,16);
  }
  tcp = pack+20;
 
  for(j=0;j<65;j+=2){
    if(!(j%16)) printf("\n");
    printf("%.2x%.2x ",pack[j],pack[j+1]);
  }
  printf("\n");
  printf("((*(tcp+12))): %u\n",((*(tcp+12))));
  //sum = do_tcp_checksum(tcp,0,IPPROTO_TCP,((*(tcp+12))>>2)&0x3f,pack+12);
  sum = do_tcp_checksum(tcp,0,IPPROTO_TCP,45,pack+12);
  printf("SUM: %#x\n",sum);
  memcpy(tcp+16,&sum,2);

  //sum = do_ip_checksum(pack);
  
  for(j=0;j<65;j+=2){
    if(!(j%16)) printf("\n");
    printf("%.2x%.2x ",pack[j],pack[j+1]);
  }
  printf("\n");
  send_it(pack ,65);
  
  return 0;
}

