Raw-sockets et calcul de checksum tcp

Fermé
anonyme - 17 mars 2003 à 21:13
 mat - 17 mars 2003 à 22:49
Bonjour,
je souhaite réaliser un programme (sous gnu/linux) permettant d'envoyer un paquet TCP SYN vers le port d'un hôte distant, mais le calcul de checksum TCP me pose problème (ethereal me signale qu'il est inval ide, et par conséquent, l'hôte distant ne répond jamais au paquet SYN que je lui envoie).
Voilà le code source:
-------------------------------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netdb.h>

#define IPHDR sizeof(struct iphdr)
#define TCPHDR sizeof(struct tcphdr)
#define PSEUDOHDR sizeof(struct pseudohdr)


struct pseudohdr {
unsigned long saddr;
unsigned long daddr;
char useless;
unsigned char protocol;
unsigned short length;
};


unsigned long resolve(char *name){
struct hostent * hip;
hip = gethostbyname(name);
if (!hip)
{
perror("unknown host");
return(-1);
}
return *(unsigned long *)hip -> h_addr;
}

unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;

while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}

int send_syn(unsigned long source,unsigned long dest,int dport)
{
int fd;
char *packet,*buffer;
struct iphdr *ip;
struct tcphdr *tcp;
struct pseudohdr *pseudo;
struct sockaddr_in addy;

packet = (char *) malloc(IPHDR + TCPHDR);
buffer = (char *) malloc(IPHDR + TCPHDR);

ip = (struct iphdr *) packet;
tcp = (struct tcphdr *) (packet + IPHDR);
pseudo = (struct pseudohdr *) malloc(PSEUDOHDR);


ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = IPHDR + TCPHDR;
ip->id = htons(getuid());
ip->ttl = 255;
ip->protocol = IPPROTO_TCP;
ip->saddr = source;
ip->daddr = dest;

pseudo->saddr = source;
pseudo->daddr = dest;
pseudo->useless = 0;
pseudo->protocol = IPPROTO_TCP;
pseudo->length = htons(TCPHDR);

tcp->source = htons(5000);
tcp->dest = htons(dport);
tcp->seq = htonl(random());
tcp->ack_seq = htonl(0);
tcp->doff = 5;
tcp->fin = 0;
tcp->syn = 1;
tcp->rst = 0;
tcp->psh = 0;
tcp->ack = 0;
tcp->urg = 0;
tcp->window = htons(512);
tcp->urg_ptr = htons(0);

tcp->check = in_cksum((unsigned short *)pseudo,TCPHDR+PSEUDOHDR);
ip->check = in_cksum((unsigned short *)ip, IPHDR);

if((fd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0){
perror("SOCK_RAW");
return(-1);
}

addy.sin_family = AF_INET;
addy.sin_port = tcp->dest;
addy.sin_addr.s_addr = ip->daddr;

printf("SYN packet sent\n");

if(sendto(fd,packet,ip->tot_len,0,(struct sockaddr *)&addy, sizeof(struct sockaddr)) < 0)
{
perror("sendto()");
return(-1);
}

close(fd);
return 0;
}

int main(int argc,char *argv[])
{
int port,n;
unsigned long src,dst;
if(argc < 4)
{
printf("usage: %s source destination port\n",argv[0]);
return 0;
}
else { src=resolve(argv[1]);
dst=resolve(argv[2]);
port=atoi(argv[3]); }
send_syn(src,dst,port);
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
Puisse une âme charitable résoudre mon problème.
Merci.
A voir également:

1 réponse

salut,

ça c'est vraiment bien ce que tu fais. Je t'aurais aidé avec plaisir mais j'ai décroché des sockets raw. Je suppose que tu connais l'UNIX SOCKET FAQ, (http://www.developerweb.net/sock-faq/), vas-y refaire un tour, je me rappelle qu'elle est excellente.

a+
mat
0