#define _BSD_SOURCE
/* BSD compatibility */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>


#define CISCO_AUTH 1999
#define RESPOND_TIME 10


struct pseudo {
    
u_long saddr;
    
u_long daddr;
    
u_char zero;
    
u_char protocol;
    
u_short length;
};

/* diz piece is ripped off.. who carez */
unsigned short
in_cksum 
(unsigned short *ptrint nbytes)
{

  
register long sum;        /* assumes long == 32 bits */
  
u_short oddbyte;
  
register u_short answer;    /* assumes u_short == 16 bits */

  /*
   * Our algorithm is simple, using a 32-bit accumulator (sum),
   * we add sequential 16-bit words to it, and at the end, fold back
   * all the carry bits from the top 16 bits into the lower 16 bits.
   */

  
sum 0;
  while (
nbytes 1)
    {
      
sum += *ptr++;
      
nbytes -= 2;
    }

  
/* mop up an odd byte, if necessary */
  
if (nbytes == 1)
    {
      
oddbyte 0;        /* make sure top half is zero */
      
*((u_char *) & oddbyte) = *(u_char *) ptr;    /* one byte only */
      
sum += oddbyte;
    }

  
/*
   * Add back carry outs from top 16 bits to low 16 bits.
   */

  
sum = (sum >> 16) + (sum 0xffff);    /* add high-16 to low-16 */
  
sum += (sum >> 16);        /* add carry */
  
answer = ~sum;        /* ones-complement, then truncate to 16 bits */
  
return (answer);
}

/* sendpack : ripped from another piece of mine. packet_body isn't used here.
 * (so length is not supposed to).
 */

int sendpackint su_long srcaddru_short srcportu_long dstaddru_short dstport,u_short th_flagsu_char *packet_body,u_long length) {

    
u_char packet[sizeof(struct ip) + sizeof(struct pseudo) + sizeof(struct tcphdr)];
    
struct sockaddr_in foo;
    
struct in_addr srcinaddr,dstinaddr;
    
struct ip *ip = (struct ip *) packet;
    
struct pseudo *pseudo = (struct pseudo *) (packet sizeof(struct ip));
    
struct tcphdr *tcp = (struct tcphdr *) (packet sizeof(struct ip
                + 
sizeof(struct pseudo));
    
bzero(packetsizeof(packet));
    
bzero(&foo,sizeof(foo));

    
/* only BSD, linux has plain u_long declared */
    
srcinaddr.s_addr srcaddr;
    
dstinaddr.s_addr dstaddr;

/* building packets */
            
pseudo->saddr srcaddr;
            
pseudo->daddr dstaddr;
            
pseudo->zero 0;
            
pseudo->protocol=IPPROTO_TCP;
            
pseudo->length htons(sizeof (struct tcphdr));
            
ip->ip_v 4;
            
ip->ip_hl 5;
            
ip->ip_id 1234;
            
ip->ip_src srcinaddr;
            
ip->ip_dst dstinaddr;
            
ip->ip_p IPPROTO_TCP;
            
ip->ip_ttl 40;
            
ip->ip_off 0;
            
ip->ip_len sizeof(struct ip) + sizeof(struct tcphdr)
                            + 
length;
            
tcp->th_sport htons(srcport);
            
tcp->th_dport htons(dstport);
            
tcp->th_seq htonl(rand());
            
tcp->th_ack htonl(rand());
            
tcp->th_off=5;
            
tcp->th_flags th_flags;
            
tcp->th_urp 0;
            
tcp->th_sum in_cksum((u_short *) pseudo,
                    
sizeof(struct pseudo) +
                     
sizeof(struct tcphdr));
            
bcopy(tcp,pseudo,sizeof(struct tcphdr));
            
foo.sin_family=AF_INET;
            
foo.sin_addr.s_addr=dstaddr;
            
sendto(s,packet,sizeof(struct ip) + 
                    
sizeof(struct tcphdr) + length0,
                    (
struct sockaddr *) &foo,sizeof(foo));

    return 
0;
}

void usage(char *name) {
    
fprintf(stderr,"Usage: %s local_IP remote_IP\n",name);
    exit(
1);
}

u_long resolve_name(char *hostname) {
    
struct hostent *host;
    
u_long addr;
    if ((
addr inet_addr(hostname)) != -1) return addr;
    if ((
host gethostbyname(hostname)) == NULL) {
        
fprintf(stderr,"Can not resolve name: %s\n",hostname);
        exit(
1);
    }
    
bcopy(host->h_addr,&addr,host->h_length);
    return 
addr;
}

int rawfd;

void sig_alarm(int sig) {
    
fprintf(stderr,"No responce received. Packets might be blocked\n");
    
close(rawfd);
    exit(
1);
}

int main(argc,argv)
    
int argc;
    
char **argv;
{
    
int rd,rsize;
    
int one=1;
    
int i;
    
u_char buf[1024];
    
struct sockaddr_in raddr;
    
struct in_addr srcip,dstip;
    
struct ip *ip;
    
struct tcphdr *tcp;
    
u_short srcport,dstport;

    if (
argc!=3usage(argv[0]);
    
    
    
srcip.s_addr    =    resolve_name(argv[1]);
    
srcport        =    rand();
    
dstip.s_addr    =    resolve_name(argv[2]);
    
dstport        =    CISCO_AUTH;

    if ((
rawfd=socket(PF_INET,SOCK_RAW,IPPROTO_TCP))<0) {
        
perror("RawSocket:");
        exit(
1);
    }
    if (
setsockopt(rawfd,IPPROTO_IP,IP_HDRINCL,&one,sizeof(one))<0) {
        
perror("SetSockOpt:");
        
close(rawfd);
        exit(
1);
    }

fprintf(stderr,"Indent [%s]: ",inet_ntoa(dstip));
sendpack(rawfd,srcip.s_addr,srcport,dstip.s_addr,dstport,TH_SYN,NULL,0);

    
signal(SIGALRM,sig_alarm);
    
alarm(RESPOND_TIME);
        
for(;;) {
        if ((
rd=recvfrom(rawfd,buf,1024,0,
                (
struct sockaddr *)&raddr,&rsize))<0) break;

        
ip=(struct ip *)buf;
        
tcp=(struct tcphdr *)&buf[ip->ip_hl<<2];
        if(
ip->ip_src.s_addr == dstip.s_addr || 
                
tcp->th_sport == dstport) {
        if ((
ip->ip_hl<<2)+(tcp->th_off<<2)==rd
                    
fprintf(stderr,"non-cisco device");
        else
            for(
i=(ip->ip_hl<<2)+(tcp->th_off<<2);i<rd;i++) 
                
fprintf(stderr,"%c",buf[i]);
        
fprintf(stderr,"\n");
        break;
        }
    }
    
close(rawfd);
    return 
0;
}