BSD Sockets em linguagem C

Venho neste artigo explicar como funciona sockets em ANSi C, explicar portabilidade e exemplos reais e diferentes de artigos semelhantes. Enfim, aqui você aprenderá a usar sockets na prática.

[ Hits: 109.343 ]

Por: C00L3R_ em 06/07/2010 | Blog: http://bugsec.com.br


Funções listen(), bind(), accept() e exemplo de servidor HTTP



Só que ao invés de fazer POG com memset, vamos usar uma função para setar dados para zero *bzero (). Uma função que escreve zeros para uma string. No nosso caso, serve para zerar o resto da struct.

void bzero (void *s, int n);

Pega os primeiros "n" bytes da string apontada em s e muda-os para zero.

listen() - esta função faz com que um socket aguarde por conexões.

Fica na escuta:

listen (socket, numero maximo de conexoes);

Ex.:

int sock2; sock2 = socket (AF_INET, SOCK_STREAM, 0);
listen (sock2, 4); // apenas 4 clients podem se conectar nesse socket.

write() - tambem é usada para enviar mensagens para um socket.

int write (socket, *buffer, tamanho utilizado do buffer);
write (sock, msg, strlen (msg));

Você pode substituir a função send() por write() dependendo do caso...

bind() - bind serve para unir um nome ao socket que você abriu. Para que fique bem claro, observe abaixo, IP do servidor: 201.34.36.133, IP do cliente: 201.45.44.144.

Para que o cliente localizado em 201.45.44.144 se comunique com um programa (servidor) localizado em 201.34.36.133 é necessário que os dois se comuniquem por um canal em comum, uma porta. Conexões telnet são feitas normalmente pela porta 23, ftp pela 21, http pela 80 etc. A diferenciação entre os tipos de serviço está pela porta que este abre. Então se eu for mandar uma mensagem para o servidor, esta tem que ir por uma porta aberta no sistema, específica para aquele programa servidor.

A função bind() faz o papel de abrir a porta no sistema.

A sintaxe da bind() é:

int bind (socket, estrutura de conexao (local), tamanho da estrutura);

accept() - estabelece conexões em um socket. Ela cria um novo socket com as mesmas propriedades do socket anterior do seu programa e aloca um novo "int socket" para a nova conexão.

int sock2,
    newSock,   // Este sera o novo socket
    tamanho;
sock2 = socket (AF_INET, SOCK_STREAM, 0);
...
tamanho = sizeof (struct sockaddr);
listen (sock2, 3);
newSock = accept (sock2, (struct sockaddr_in *)&remote, &tamanho);

A sintaxe seria:

novo socket = accept (socket, estrutura de conexao, tamanho);

Paramos de conversa e vamos ao programa comentado:

#include "stdio.h"
#include "errno.h"
#include "sys/socket.h"
#include "resolv.h"
#include "arpa/inet.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
//nossa porta
#define PORT    666

int main (int argc, char *argv[]){
   int serversock;
   struct sockaddr_in self;

   /* cria o socket */
   serversock = socket (AF_INET, SOCK_STREAM, 0) ;
   if ( serversock < 0 ){
      perror("Erro no socket");
      exit(1);
   }

   /* monta o endereço */
   bzero (&self, sizeof(self));
   self.sin_family = AF_INET;
   self.sin_port   = htons(PORT);
   self.sin_addr.s_addr = INADDR_ANY; /* uso o endereço do host */

   /* associa o endereço ao socket */
   if ( bind (serversock, (struct sockaddr*)&self, sizeof(self)) ) {
      perror("Erro no bind");
      exit(1);
   }

   /* coloca o socket em escuta */
   if ( listen (serversock, 20) ) {
      perror("Erro no listen");
      exit(1);
   }

   for(;;) {
      int clientsock;  
      struct sockaddr_in client_addr;
      int addrlen = sizeof (client_addr);
      char * resposta ;

      /* aguarda e aceita uma conexão externa */
      clientsock = accept (serversock, (struct sockaddr*)&client_addr, &addrlen);

      printf ("Client %s:%d connected\n",
              inet_ntoa (client_addr.sin_addr),
              ntohs (client_addr.sin_port));

      /* envia uma resposta HTTP padrão */
      <code>resposta = "HTTP/1.1 200 Ok\n\ncodigo em html\n" ;

      write (clientsock, resposta, strlen (resposta));

      /* fecha o socket da conexão recebida */
      close (clientsock);
   }

   /* encerra o socket servidor */
   close (serversock);

   return 0;
}

Vamos lá, compile:

gcc -o code code.c; ./code

Feito isso, abra navegador na url http://localhost:666

BINGO!

Veja que o servidor é simples se agente usar netcat para conectar, por exemplo, o servidor responde do mesmo jeito, não usa uma regex ou parser para identificar apenas navegadores.

nc localhost 666
HTTP/1.1 200 Ok

Sua página HTML vai estar aqui.

Se não me engano o servidor Apache usa "pcre.h" para fazer estas regex de verificação... Bom, nosso servidor funcionou, voltando para o HTTP e estudando suas documentações podemos até fazer um post ou um get enviando dados, porém não é nosso objetivo aqui lidar com bots e spiders de web.

Se quiser aí vai o link para te ajudar nos spiders e entender HTTP, boa sorte:
Se conseguir mandar POST para um link usando "client" com socket, mande e-mail do seu programa em C para eu ver. ;)

Pulo do gato para o pessoal que não gosta de criar a roda, quer criar seus bots e spiders de forma portável, com estas bibliotecas você pode usar POST, GET e fazer AUTH, extrair links, tarefas no FTP, fazer downloads...

Vamos continuar estudando sockets a fundo e deixar as bibliotecas que usam sockets para depois.

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Explanação ao TCP/IP
   3. O que é socket
   4. Funções read(), send() e exemplo cliente HTTP
   5. Funções listen(), bind(), accept() e exemplo de servidor HTTP
   6. Na prática fazendo um FUZZER TCP
   7. Servidor e cliente com fork
   8. Servidor de comandos e scanner de portas
   9. Simple socket library
   10. Explanação ao UDP e exemplo de servidor e cliente
   11. Exemplo UDP Flood
   12. Portabilidade
   13. Conclusão
Outros artigos deste autor

Usando o NetBSD como desktop

Módulos de Web no Perl

Usando o PF - Packet Filter

Usando OpenBSD como desktop

Banco de dados orientados a documentos

Leitura recomendada

Controlando UPLOAD com o CBQ

O Modelo de Referência OSI

Monitorando o consumo de banda com Bwbar

Tutorial - Aplicação em C para transferência de arquivo usando socket TCP e Thread

Manipulando arquivos em C (parte 2)

  
Comentários
[1] Comentário enviado por VonNaturAustreVe em 06/07/2010 - 03:24h

Excelente cara vou ler tudo :)

[2] Comentário enviado por removido em 06/07/2010 - 05:29h

Hey C00L3R,
Parabéns, é um ótimo artigo. Minhas dúvidas surgiram após meus testes.
Um abraço.

[3] Comentário enviado por andrezc em 06/07/2010 - 08:12h

Cara, realmente esse é um dos melhores artigos que eu já li por aqui. Parabéns.

[4] Comentário enviado por werneral em 06/07/2010 - 11:18h

Muito bom! Obrigado!

[5] Comentário enviado por uberalles em 06/07/2010 - 11:43h

verdadeira aula, velho. parabéns!
muito bom "resumão" do Unix Network programming. Nunca consegui fazer nada decente em sockets e esta tua aula deverá me ajudar muito.

[6] Comentário enviado por stremer em 07/07/2010 - 15:28h

para quem interessar, ha algum tempo atras escrevi um script mostrando como criar um robo http e enviei ao VOL.

http://www.vivaolinux.com.br/script/Robo-HTTP-usando-socket-e-codigo-multiplataforma

Interessante para quem esta aprendendo sockets...

OTIMO ARTIGO

[7] Comentário enviado por andrezc em 07/07/2010 - 15:43h

Opa stremer, eu cheguei a ver este seu script, realmente fabuloso.

Um abraço.

[8] Comentário enviado por fernandopinheiro em 07/07/2010 - 20:23h

Parabens, muito bom!!

[9] Comentário enviado por brunosolar em 08/07/2010 - 09:48h

Parabens realmente muito bom. So queria fazer um comentario sobra a parte do UDP flood. Sim hoje em dia qualquer firewal simples pode recusar este tipo de pacote.

No entanto dependendo da quantidade de pacotes UDP enviados (leia-se DDOS) você poderá ser "derrubado" pois o firewall irá gastar muito processador para descatar todos os pacotes. A melhor solução (AINDA) para ataques DOS / DDOS é diretamente no ISP onde eles irão setar no roteador o IP do atacante para /dev/null (exemplo). claro que voce corre o risco de perder algum cliente que faça parte da rede redirecionada.

No mais excelente trabalho.

[10] Comentário enviado por shazaum em 24/09/2010 - 11:44h

opa, no fuzzer faltou uma lib...

#include <netinet/in.h>

[11] Comentário enviado por thomasawrd em 18/07/2014 - 12:41h

parabéns cara excelente artigo,me ajudou muito.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts