
(Sorry Goatboy, I thought it was more convenient to post it as a follow-up... I guess not).
Well, to cut the long story short, I have a seminar in Computer security comming up. I'm writing a raw socket to establish the three-way handshake. I found an example of the code and decided to adjust it for my needs. After some tweaks (IP spoofing) I was able to send the SYN packet to my server. My problem is that I can't, however, seem to get a SYN/ACK response from it.
A bit about the environment:
The socket program runs on a Ubuntu 10.04 in a virtual machine (in Virtualbox) and the server is Apache on WinXP, also in a virtual machine. They are networked internally and I hosted a small website on the server which I am able to access from a browser (three-way handshake succesful).
I have compared the packets info in Wireshark. My SYN packet is not much different from the one Firefox uses. The main difference is that mine doesn't have SACK permitted option enabled. Should this matter?
The code:
You'll notice weird comments mostly in Croatian, it's my native language so don't get frightened or anything

Wasn't exactly sure about all the includes needed, so there are probably a few extras unnecessary.
- Code: Select all
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<sys/socket.h>
#include<linux/if_packet.h>
#include<linux/if_ether.h>
#include<errno.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<net/if.h>
#include<net/ethernet.h>
#include<unistd.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<features.h>
#define __FAVOR_BSD
#include<netinet/tcp.h>
#define P 80 /* Port koji cemo preplaviti */
unsigned short chksum (unsigned short *buff, int nwords) /* Funkcija za generiranje cheksume */
{
unsigned long sum;
for (sum=0; nwords > 0; nwords--)
sum += *buff++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
}
int randint (int max) /* Generira pseudonasumican broj izmedju 0 i max */
{
return (max*rand()/(RAND_MAX+1.0));
}
void spoof (char* adresa)
{
int prvi, drugi, treci, cetvrti;
char a[5], b[5], c[5], d[5];
//srandom (time(0));
prvi = rand() % 255 + 1;
if (prvi==127 || prvi ==255 || prvi == 10 || prvi ==192) prvi =126; //localhost i broadcast...
drugi = rand() % 255 + 1;
treci = rand() % 255 + 1;
cetvrti = rand() % 254 + 1; /* Generirali smo nasumicne vrijednosti do 255 */
/******** Sada ih pretvaramo u stringove koje cemo poslije konkatenirati *********/
sprintf(a, "%i", prvi);
sprintf(b, "%i", drugi);
sprintf(c, "%i", treci);
sprintf(d, "%i", cetvrti);
/********* Konkatenacija **********/
strcpy (adresa, a);
strcat (adresa, ".");
strcpy (adresa, b);
strcat (adresa, ".");
strcat (adresa, c);
strcat (adresa, ".");
strcat (adresa, d);
}
int main (void)
{
int rawsock;
rawsock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); // stvori novi raw socket
char paket [4096]; // ovo je spremnik koji ce postat paket, dakle u njega spremam IP i TCP header te neke dodatne podatke
// potrebno je jos napraviti pointere koji ce pokazivati na pocetak pojedinih zaglavlja (u nastavku)
struct ip *iph = (struct ip*) paket;
struct tcphdr *tcph = (struct tcphdr *)(paket + sizeof (struct ip));
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons (P); // prevest port sa little na big endian
sin.sin_addr.s_addr = inet_addr ("192.168.56.11"); // postavit odredisnu adresu adresu na lokalno racunalo (localhost)
memset (paket, 0, 4096); // postavit buffer u nule
/*************** Postavljanje vrijednosti IP headera ***************/
iph->ip_hl = 5; /* velieina zaglavlja u bajtovima je jednaka ip_hl * 4 */
iph->ip_v = 4; /* verzija protokola koji koristimo za prijenos, ovdje IPv4 */
iph->ip_tos = 0; /* Type of Service - odnosi se na prioritet paketa, 0 je defaultna vrijednost */
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* Ukupna duljina PDU-a zaglavljem, bez podataka */
iph->ip_id = htonl(1950); /* Nije bitno, samo ako je PDU fragmentiran */
iph->ip_off = 0; /* Offset, bitno samo kod fragmentiranih PDU-ova */
iph->ip_ttl = 255; /* Broj skokova koje može "preživjeti" */
iph->ip_p = 6; /* Oznaeava protokol prijenosne razine, 6 za TCP */
iph->ip_sum = 0; /* Poeetna checksum, stvarna ae se raeunati poslije */
/*************** Postavljanje vrijednosti TCP headera ***************/
tcph->th_sport = htons(10425); /* Proizvoljni izvorisni port */
tcph->th_dport = htons (P); /* Odredisni port, gore je u DEFINE */
tcph->th_seq = random(); /* Poeetni broj sekvence, kod SYN paketa je nasumiean */
tcph->th_ack = 0; /* Kod prvog paketa ACK je 0 */
//tcph->th_x2 = 0; /* Zastarjelo ?!?*/ /* BZVZ */
tcph->th_off = 5; /* Prvi i jedini TCP header, zato je offset nula */
tcph->th_flags = TH_SYN; /* Postavili smo zastavice tako da klijent dâ do znanja da želi uspostavti novu konekciju s odr. portom */
tcph->th_win = htons(5840); /* TCP prozor; stavimo MAX broj bajtova koje možemo poslati prije dobivanja ACK da bi mogli opet slati */
tcph->th_sum = 0; /* Kada je cheksum nula, OS prilikom prijenosa unese tocnu vrijednost */
tcph->th_urp = 0; /* Urgent zastavica, nebitno */
iph->ip_sum = chksum ((unsigned short *) paket, iph->ip_len >> 1);
/********************* Poziv IP_HDRINCL ************************/
/******** Kako bi kernel znao da je header vec ukljucen ********/
{
int one = 1;
const int *val = &one;
if (setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
}
int two = 2;
const int *lala = &two;
if (setsockopt (rawsock, IPPROTO_TCP, TCPOPT_SACK_PERMITTED, lala, sizeof (two)))
printf ("Nece!\n");
srand (time(0));
float paketBr=0;
int i=1;
while (i!=0)
{
/******* Spoof ***********/
char spoofAddr[16];
spoof(spoofAddr);
// printf("Adresa: %s", spoofAddr);
iph->ip_src.s_addr = inet_addr (spoofAddr); /* Adresa posiljatelja; OVO CE SE SPOOFAT */
iph->ip_dst.s_addr = sin.sin_addr.s_addr; /* Vec je gori postavljena vrijednost */
if (sendto ( rawsock, /* nas socket */
paket,
iph->ip_len, /* ukupna duzina paketa */
0, /* zastavice za routanje */
(struct sockaddr *) &sin,
sizeof (sin)) < 0) /* a normal send() */
{
printf ("error\n");
break;
}
else
{
paketBr++;
printf ("OK! Sent from: %s ----- Package number %f \n", spoofAddr, paketBr);
}
i--;
}
return 0;
}
And the original code:
http://mixter.void.ru/rawip.html
Please help!
Thanks