Les Forums

Les Forums

Les forums sont fermés. Ils restent présent pour consultation et archivage.
Vous pouvez désormais poser vos questions directement dans les commentaires en bas de chaque page du site.
Alors n'hésitez pas à participer

sendto:Permission Denied (socket raw)

Bonjour,
J'ai fait un programme utilisant un socket raw (je gère moi même les headers IP et TCP), tout se passe bien sauf au moment de l'execution. En effet, je suis loggué en root, mais j'ai tout de même un message d'erreur "Permission Denied" (perror) lors de l'utilisation de sendto(). J'ai utilisé setsockopt pour mettre l'option HDRINCL sur mon socket indiquant à mon OS de ne pas s'occuper des headers.

Le programme fonctionne chez d'autres personnes, le problème vien apparament de ma machine. Je suis sous GNU/Linux, Debian Sarge.

Je me demandais donc si d'autres avaient déjà rencontré ce genre de problèmes.

Voilà le code :
[code:1:9cbdbfba38]
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define DATAGRAM_SIZE 4096
#define PORT_DST 80
#define PORT_SRC 1234
#define IP_SRC "127.0.0.1"
#define IP_DST "213.246.63.35"


unsigned short csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}

int main(void)
{
char datagram[DATAGRAM_SIZE];
struct iphdr *iph = (struct iphdr *) datagram;
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof(struct iphdr);
struct sockaddr_in sain;
int sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
int on;

sain.sin_family = AF_INET;
sain.sin_port = htons(PORT_DST);
sain.sin_addr.s_addr = inet_addr(IP_DST);
memset(&(sain.sin_zero),0,8);

memset(datagram,0,DATAGRAM_SIZE);
iph->version = 4;
iph->ihl = 5;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
iph->id = htonl(8147);
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = 6;
iph->check = 0;
iph->saddr = inet_addr(IP_SRC);
iph->daddr = sain.sin_addr.s_addr;
tcph->source = htons(PORT_SRC);
tcph->dest = htons(PORT_DST);
tcph->seq = 0;
tcph->ack_seq = 0;
tcph->res1 = 0;
tcph->doff = 5;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->ece = 0;
tcph->cwr = 0;
tcph->window = htonl(65535);
tcph->check = 0;
tcph->urg_ptr = 0;

iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);

if (setsockopt(sockfd, SOL_IP, IP_HDRINCL,(char *)&on, sizeof (on)) == SOCKET_ERROR)
{
puts("Warning: Cannot set HDRINCL!\n");
}
if (sendto(sockfd, datagram, iph->tot_len, 0, (struct sockaddr *) &sain, sizeof (sain)) < 0)
{
perror("sendto");
}
else
{
puts("ok\n");
}
return 0;
}
[/code:1:9cbdbfba38]
(pour ceux qui, comme moi, ne trouvent pas le code trop lisible sur le forum, vous pouvez également le consulter à [url=http://postit.xiato.com/?show=17]cette adresse[/url]).
Voilà, si ça peut servire à quelqu'un, ça fonctionne avec une petite modification au niveau des flags concernant les fragments:
[code:1:aee76405de]iph->frag_off = 0;[/code:1:aee76405de]
devient
[code:1:aee76405de]iph->frag_off = 0x04;[/code:1:aee76405de]
En fait comme la structure d'ip.h regroupe les flags de fragments et le fragment d'offset dans une seule partie, je n'y avait pas prêté attention.
Apparemment je ne peux pas envoyer de paquets si la demande de "non-fragmentation" des paquets n'est pas faite au niveau de l'entête.