Raw Sockets

Started by mrx, 19 de October , 2008, 08:53:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

mrx

A programação utilizando sockets do tipo TCP ou UDP implica que apenas informações de dados (ou do protocolo de aplicação) são fornecidas pela aplicação.

Os cabeçalhos dos protocolos IP, TCP ou UDP são criados automaticamente utilizando as informações padrões (e.g. TTL), informações geradas pela S.O. (e.g. checksum) e informações fornecidas pela aplicação (endereços IP e porta). A programação em RAW SOCKETS, por outro lado, permite que os cabeçalhos sejam construídos pela aplicação.

1) Criação do Socket
Um RAW SOCKET é criado da seguinte forma:
#include <sys/socket.h>
#include <netinet/in.h>

raw_socket = socket(PF_INET, SOCK_RAW, int protocol);


O parâmetro protocol refere-se ao protocolo transportado pelo pacote IP (RFC 1700)
Esse parâmetro é utilizado como filtro para selecionar quais pacotes são recebidos pelo socket.
Por exemplo:
·        TCP: protocol = 0x06
·        UDP: protocol = 0x11
·        ICMP: protocol = 0x1

OBSERVAÇÕES:
· IPPROTO_RAW permite enviar pacotes com qualquer tipo de protocolo pelo mesmo socket. Todavia, essa opção não permite receber todos os pacotes.

· A opção de socket IP_HDRINCL indica que o cabeçalho IP será criado pela aplicação usuária. Essa opção é habilitada pelo parâmetro IPPROTO_RAW.

2) Estruturas de Cabeçalhos Importantes
// Cabeçalho IP: Tamanho total 20 bytes

struct ipheader {
unsigned char ip_hl:4, ip_v:4;
unsigned char ip_tos;
unsigned short int ip_len;
unsigned short int ip_id;
unsigned short int ip_off;
unsigned char ip_ttl;
unsigned char ip_p;
unsigned short int ip_sum;
unsigned int ip_src;
unsigned int ip_dst;
}; 
// Cabeçalho ICMP: Tamanho total 8 bytes
struct icmpheader {
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short int icmp_cksum;
/* Campos dependentes do tipo de msg ICMP */
unsigned short int icmp_id;
unsigned short int icmp_seq;
};
// Cabeçalho UDP: Tamanho total 8 bytes
struct udpheader {
unsigned short int uh_sport;
unsigned short int uh_dport;
unsigned short int uh_len;
unsigned short int uh_check;
};
// Cabeçalho TCP: Tamanho total 20 bytes
struct tcpheader {
unsigned short int th_sport;
unsigned short int th_dport;
unsigned int th_seq;
unsigned int th_ack;
unsigned char th_x2:4, th_off:4;
unsigned char th_flags;
unsigned short int th_win;
unsigned short int th_sum;
unsigned short int th_urp;

};


Exemplo de RawSocket
// Edgard Jamhour
// 2006
// Programa PING

#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>

void ping(struct sockaddr_in *);
unsigned short checksum(void *, int);
void eco();

struct ipheader {
unsigned char ip_hl:4, ip_v:4;
unsigned char ip_tos;
unsigned short int ip_len;
unsigned short int ip_id;
unsigned short int ip_off;
unsigned char ip_ttl;
unsigned char ip_p;
unsigned short int ip_sum;
unsigned int ip_src;
unsigned int ip_dst;
};

struct icmpheader {
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short int icmp_cksum;
unsigned short int icmp_id;
unsigned short int icmp_seq;
};

struct packet
{
struct icmpheader hdr;
char msg[10];
};

/*--------------------------------------------------------------------*/
/*  Funcao Main       -*/
/*--------------------------------------------------------------------*/

int main(int count, char *strings[])
{
struct sockaddr_in sa;

if ( count != 2 )
{
printf("digite: %s <addr>\n", strings[0]);
exit(1);
}

memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = 0;
sa.sin_addr.s_addr = inet_addr(strings[1]);

if ( fork() == 0 )
ping(&sa); // processo filho
else
eco(); // processo pai
}

/*--------------------------------------------------------------------*/
/*- ping - Envia a mensagem ICMP                                   ---*/
/*--------------------------------------------------------------------*/

void ping(struct sockaddr_in *addr)
{
int i, sd;
struct packet pckt;
struct sockaddr_in r_addr;

sd = socket(PF_INET, SOCK_RAW, 1);
if ( sd < 0 )
{
printf("Erro na criacao do socket\n");
return;
}

else
printf("Raw socket criado com sucesso\n");

for (i=0;i<10;++i)
{
int len=sizeof(r_addr);

memset(&pckt,0,sizeof(pckt));

pckt.hdr.icmp_type = 8; //ECHO REQUEST
pckt.hdr.icmp_code = 0;
pckt.hdr.icmp_seq = i;
pckt.hdr.icmp_id = 1;
memcpy(pckt.msg,"1234567890",9);
pckt.hdr.icmp_cksum = checksum(&pckt, sizeof(pckt));


if (sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 )
{
printf("Erro no send\n");
exit(1);
}

sleep(1); //aguarda um segundo
}
close(sd);
}

/*--------------------------------------------------------------------*/
/*- Calcula o complemento de 1 do cabeçalho do pacote                -*/
/*--------------------------------------------------------------------*/

unsigned short checksum(void *b, int len)
{
unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;

for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if (len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}

/*--------------------------------------------------------------------*/
/*- Eco -*/
/*--------------------------------------------------------------------*/

void eco(void)
{
int sd;
struct sockaddr_in addr;
unsigned char buf[1024];
struct packet *pkt;
struct ipheader *iph;
char ips[20];

iph = (struct ipheader *) (buf);
pkt = (struct packet *) (buf + 20);

sd = socket(PF_INET, SOCK_RAW, 1);
if ( sd < 0 )
{
printf("Erro na criacao do socket\n");
exit(0);
}
else
printf("Aguardando Eco\n");

for (;;)
{
int bytes;
unsigned int len=sizeof(addr);
memset(buf, 0, sizeof(buf));

bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len);
if ( bytes > 0 )
{
printf("Recebi mensagem ICMP %s\n",pkt->msg);
printf("ID: %d SEQ: %d\n",pkt->hdr.icmp_id, pkt->hdr.icmp_seq);
}
else
printf("Erro na recepcao\n");
}
close(sd);
}


Creditos: jamhour


Voltando a ativa. ;P