Авторские статьи Программирование Raw сокетов на языке Си

Discussion in 'Статьи' started by t0x1n, 9 May 2006.

  1. t0x1n

    t0x1n New Member

    Joined:
    8 May 2006
    Messages:
    3
    Likes Received:
    2
    Reputations:
    -1
    t0x1n
    http://www.security.e-gloryon.com
    [email protected]

    Сокеты бывают трех типов:
    SOCK_DGRAM датаграмные сокеты - сокеты которые отсылаются в сеть без запроса на соединение (к ним относятся UDP сокеты)
    SOCK_STREAM потоковые сокеты - сокеты требующие соединение (TCP сокеты)
    SOCK_RAW сырые сокеты - то что хотим, т.е. пишем сокеты с нуля.
    В этой статье нас будут интересовать RAW (сырые) сокеты.

    В качестве примера я напишу программу которая посылает обычный UDP пакет.
    Если вы пользуетесь операционной системой Linux то код программы нужно компилировать с параметром
    -D_BSD_SOURCE т.к. мы будет использовать бсдешные сокеты. Также компилировать и запускать
    код программы необходимо с правами root (суперпользователя). Для этого достаточно ввести команду
    su root.

    Начнем...

    Для начала функции нужные нам для работы:

    Открытие RAW сокета:
    int sock;
    sock=socket(PF_INET, SOCKET_RAW, протокол);
    Закрытие сокета:
    close (sock);
    Указание порта отправителя и получателя:
    htons(порт);
    Указание IP адреса отправителя и получателя:
    inet_addr ("IP адрес");

    Теперь покажу как устроен заголовок UDP на Си т.к. мы будем писать прогрумму посылающую UDP пакет.
    UDP:
    uh_sport Порт отправителя
    uh_dport Порт получателя
    uh_ulen Длина заголовка
    uh_sum Контрольная сумма

    Сообщения об ошибках:
    Чтобы в случае ошибки программа нам выдала сообщение о ней
    необходимо написать такую конструкцию:
    Code:
    int sock;
    socket(PF_INET, SOCK_RAW, IPPROTO_UDP); //Создаем сокет
    if ((sock)<0) //Если sock<0 тогда
    {
    perror ("socket"); //выдать сообщение об ошибке
    } else { //Если нет то
    printf ("socket ok"); //Выдать сообщение socket ok
    }
    
    А вот код программы посылающий UDP пакет:
    #include 
    #include 
    #include 
    
    main()
    {
        int sock;
        sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP); //Открываем сокет
        if ((sock)<0){
        perror ("socket");
        } else {
        printf ("socket ok\n");
        }
        char buf[9999];
    
        /* Структуры*/
        struct sockaddr_in sin;
        struct udphdr *udph=(struct udphdr*)buf;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = inet_addr("127.0.0.1"); //IP адрес получателя
        /***********/    
    
        /*UDP заголовок */
        udph->uh_sport=htons(21); //Порт отправителя
        udph->uh_dport=htons(22); //Порт получателя
        udph->uh_ulen=0; //Длина заголовка
        udph->uh_sum=0; //Контрольная сумма
        /***************/
        
        /*Посылаем пакет*/
        if((sendto(sock, &udph, sizeof(udph), 0, (struct sockaddr*)&sin, sizeof(sin)))<0){
        perror ("sendto");
        } else {
        printf ("sendto ok\n");
        }
        close (sock); //Закрываем сокет
    }
    
    Теперь компилируем и запускаем код с правами рута. Чтобы вполне убедиться, что программ работает
    можете запустить tcpdump и посмотреть отослался пакет или нет.
    
    [t0x1n@t0x1n~]$ su root
    [root@t0x1n~]$ gcc -D_BSD_SOURCE udp.c -udp
    [root@t0x1n~]$ ./udp
    socket ok
    sendto ok
    [root@t0x1n~]$
    Ну вот думаю и все! Желаю удач в сетевом кодинге
     
    #1 t0x1n, 9 May 2006
    Last edited by a moderator: 10 Jun 2006
    2 people like this.
  2. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    А файрвол пропускает провайдерский?
     
  3. Xex

    Xex Banned

    Joined:
    10 Jul 2005
    Messages:
    108
    Likes Received:
    41
    Reputations:
    7
    И чем она отличается от статей типа:"Кодим по сетевому для чайников"?
    Это больше похоже на инструкцию про программингу примитивнейшей сетевой проги.
     
  4. t0x1n

    t0x1n New Member

    Joined:
    8 May 2006
    Messages:
    3
    Likes Received:
    2
    Reputations:
    -1
    Да, это что то вроде инструкции по программированию сырых сокетов для самых маленьких.
     
  5. t0x1n

    t0x1n New Member

    Joined:
    8 May 2006
    Messages:
    3
    Likes Received:
    2
    Reputations:
    -1
    Должен пропускать
     
  6. lexa

    lexa Elder - Старейшина

    Joined:
    14 Jan 2005
    Messages:
    75
    Likes Received:
    11
    Reputations:
    -2
    а вот мне это интерестно ! спасибо t0x1n
     
  7. faust45

    faust45 Member

    Joined:
    2 Mar 2006
    Messages:
    42
    Likes Received:
    7
    Reputations:
    -5
    Ну мне честно говоря премер с ROW Socket совсем не понятен
    где ты заголовок IP формируеш ? Вот я нашёл в инете крутой пример лови

    Code:
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in_systm.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    #include <netinet/ip_icmp.h>
    #include <netdb.h>
    
    unsigned short ip_cksum(unsigned char * buff, int len)
    {
            unsigned long sum = 0;
            if (len > 3)
            {
                    __asm__("clc\n"
                    "1:\t"
                    "lodsl\n\t"
                    "adcl %%eax, %%ebx\n\t"
                    "loop 1b\n\t"
                    "adcl $0, %%ebx\n\t"
                    "movl %%ebx, %%eax\n\t"
                    "shrl $16, %%eax\n\t"
                    "addw %%ax, %%bx\n\t"
                    "adcw $0, %%bx"
                    : "=b" (sum) , "=S" (buff)
                    : "0" (sum), "c" (len >> 2) ,"1" (buff)
                    : "ax", "cx", "si", "bx" );
            }
            if (len & 2)
            {
                    __asm__("lodsw\n\t"
                    "addw %%ax, %%bx\n\t"
                    "adcw $0, %%bx"
                    : "=b" (sum), "=S" (buff)
                    : "0" (sum), "1" (buff)
                    : "bx", "ax", "si");
            }
            if (len & 1)
            {
                    __asm__("lodsb\n\t"
                    "movb $0, %%ah\n\t"
                    "addw %%ax, %%bx\n\t"
                    "adcw $0, %%bx"
                    : "=b" (sum), "=S" (buff)
                    : "0" (sum), "1" (buff)
                    : "bx", "ax", "si");
            }
            sum =~sum;
            return(sum & 0xffff);
    }
    
    unsigned short tcp_check(struct tcphdr *th, int len,
              unsigned long saddr, unsigned long daddr)
    {
            unsigned long sum;
            __asm__("
                addl %%ecx, %%ebx
                adcl %%edx, %%ebx
                adcl $0, %%ebx
                "
            : "=b"(sum)
            : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
            : "bx", "cx", "dx" );
            __asm__("
                movl %%ecx, %%edx
                cld
                cmpl $32, %%ecx
                jb 2f
                shrl $5, %%ecx
                clc
    1:          lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                lodsl
                adcl %%eax, %%ebx
                loop 1b
                adcl $0, %%ebx
                movl %%edx, %%ecx
    2:          andl $28, %%ecx
                je 4f
                shrl $2, %%ecx
                clc
    3:          lodsl
                adcl %%eax, %%ebx
                loop 3b
                adcl $0, %%ebx
    4:          movl $0, %%eax
                testw $2, %%dx
                je 5f
                lodsw
                addl %%eax, %%ebx
                adcl $0, %%ebx
                movw $0, %%ax
    5:          test $1, %%edx
                je 6f
                lodsb
                addl %%eax, %%ebx
                adcl $0, %%ebx
    6:          movl %%ebx, %%eax
                shrl $16, %%eax
                addw %%ax, %%bx
                adcw $0, %%bx
                "
            : "=b"(sum)
            : "0"(sum), "c"(len), "S"(th)
            : "ax", "bx", "cx", "dx", "si" );
    
            /* We only want the bottom 16 bits, but we never cleared the top 16. */
    
            return((~sum) & 0xffff);
    }
    
    void resolve_address(struct sockaddr *addr, char *hostname, u_short port) {
    struct sockaddr_in *address;
    struct hostent *host;
    
    address = (struct sockaddr_in *)addr;
    (void) bzero((char *)address, sizeof(struct sockaddr_in));
    address->sin_family = AF_INET;
    address->sin_port = htons(port);
    address->sin_addr.s_addr = inet_addr(hostname);
    if ((int)address->sin_addr.s_addr == -1) {
      host = gethostbyname(hostname);
      if (host) {
       bcopy( host->h_addr, (char *)&address->sin_addr, host->h_length);
      }
      else {
       puts("Couldn't resolve address!!!");
       exit(-1);
      }
     }
    }
    
    char *create_ip(u_long source, u_long dest, u_char protocol, u_char ttl, 
            u_short id, char *data, int data_len)
    {
     char *ip_datagram;
     struct iphdr *ip_header; 
     ip_datagram = malloc(sizeof(struct iphdr) + data_len);
     ip_header = ip_datagram;
     ip_header->version   = 4;
     ip_header->tos       = 0;
     ip_header->frag_off  = 0;
     ip_header->check     = 0;
     ip_header->saddr     = source;
     ip_header->daddr     = dest;
     ip_header->protocol  = protocol;
     ip_header->ttl       = ttl;
     ip_header->id        = htons(id);
     ip_header->ihl       = 5;
     ip_header->tot_len   = htons(sizeof(struct iphdr) + data_len); 
     ip_header->check = htons(ip_cksum(ip_datagram,sizeof(struct iphdr)));
     bcopy(data,ip_datagram+sizeof(struct iphdr),data_len);
     return ip_datagram;
    }
    
    char *create_tcp(u_long source, u_long dest, u_short sport, u_short dport, 
            u_long seqnum, u_long acknum, u_char flags, char *data, int datalen) 
    {
     char *wewt;
     struct tcphdr *tcp_header;
     wewt = malloc(sizeof(struct tcphdr) + datalen);
     tcp_header = wewt;
     tcp_header->th_sport = sport;
     tcp_header->th_dport = dport;
     tcp_header->th_seq   = seqnum;
     tcp_header->th_ack   = acknum;
     tcp_header->th_flags = flags;
     tcp_header->th_sum   = 0;
     tcp_header->th_sum = htons(tcp_check(tcp_header, sizeof(struct tcphdr), 
        source, dest));
     bcopy(data,wewt+sizeof(struct tcphdr),datalen);
     return wewt;
    }
    
    void sendpack(char *fromhost, int fromport, char *tohost, int toport) {
     char *packet;
     char *tcppacket;
     char *sendme;
     static struct sockaddr_in local, remote;
     static int sock = 0;
     if (!sock) {
       resolve_address((struct sockaddr *)&local, fromhost, fromport);
       resolve_address((struct sockaddr *)&remote, tohost, toport);
       sock = socket(AF_INET, SOCK_RAW, 255);
       if (sock == -1) { perror("Getting raw socket"); exit(-1); }
      }
       tcppacket = create_tcp(&local.sin_addr, &remote.sin_addr, 
            local.sin_port, remote.sin_port, 795930600, 0, TH_SYN,
            NULL, 0);
       packet = create_ip(&local.sin_addr, &remote.sin_addr,
            6, 24, 4, NULL, 0);
       sendme = (struct iphdr *)packet;
       bcopy(tcppacket, sendme+sizeof(struct iphdr), sizeof(tcppacket));
       printf("the ip header is %d bytes long.\n", sizeof(struct iphdr));
       printf("the tcp header is %d bytes long.\n", sizeof(struct tcphdr));
       printf("the ip packet is %d bytes long.\n", sizeof(packet));
       printf("the tcp packet is %d bytes long.\n", sizeof(tcppacket));
       printf("the final packet is %d bytes long.\n", sizeof(sendme));
      {
       int result;
    
       result = sendto(sock, packet, sizeof(packet), 0,
            (struct sockaddr *)&remote, sizeof(remote));
       if (result != sizeof(packet)) { perror("sending packet"); }
      }
    }
    
    main(int argc, char **argv) {
    if (argc!=5) {
     printf("usage: %s <from host> <from port> <to host> <to port>\n", argv[0]);
     exit(-1);
    }
     printf("forging packet from %s.%d to %s.%d\n", argv[1], atoi(argv[2]), 
            argv[3], atoi(argv[4]));
     sendpack(argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
    }
     
     
    #7 faust45, 10 Jun 2006
    Last edited by a moderator: 10 Jun 2006