c сырые сокеты и 64-битная проблема - PullRequest
0 голосов
/ 21 января 2010

Я все еще пытаюсь заставить мой пример кода работать на 64-битной машине. Моя предыдущая проблема была решена из-за отсутствия / устаревших заголовков / библиотек.

Я скомпилировал этот код следующим образом: gcc -Wall -g -o server server.c и gcc -Wall -g -o client client.c Я запускаю их на 2 Linux-машинах (оба 32-битных), и это работает нормально. Когда я перекомпилирую этот код на 64-битных машинах, кажется, что никакие пакеты не проходят от клиента к серверу. При установке tcpdump на клиенте кажется, что он отправляет искаженные заголовки, которые постоянно отклоняются. Кто-нибудь может просветить меня?

#include "client.h"
#include "util.h"

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <asm/types.h>

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

#define BUF_SIZE ETH_FRAME_TOTALLEN
#define NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA 100000 /*how often to measure travelling time with one certain amount of data*/

int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_sent_packets = 0;

int main(int argc, char* argv[]) 
{
    buffer = (void*)malloc(BUF_SIZE);   /*Buffer for ethernet frame*/
    unsigned char* etherhead = buffer;  /*Pointer to ethenet header*/
    unsigned char* data = buffer + 14;  /*Userdata in ethernet frame*/
    struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to ethernet header*/

    unsigned char src_mac[6];       /*our MAC address */
    unsigned char dest_mac[6] = {0x00, 0x1E, 0x4F, 0xB1, 0xCB, 0x43};   /*MAC address, hardcoded...... :-(*/ 

    struct ifreq ifr;
    struct sockaddr_ll socket_address;
    int ifindex = 0;            /*Ethernet Interface index*/
    int i,j,k;
    int length;             /*length of received packet*/
    int sent;               /*length of sent packet*/

    /*stuff for time measuring: */
    struct timeval begin;
    struct timeval end;
    struct timeval result;
    unsigned long long allovertime;

    printf("Client started, entering initialiation phase...\n");

    /*open socket*/
    s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (s == -1) {
        perror("socket():");
            exit(1);
    }
    printf("Successfully opened socket: %i\n", s);

    /*retrieve ethernet interface index*/
    strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
    if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
    ifindex = ifr.ifr_ifindex;
    printf("Successfully got interface index: %i\n", ifindex);

    /*retrieve corresponding MAC*/
    if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
        for (i = 0; i < 6; i++) {
        src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
    }
    printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", 
            src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);

    /*prepare sockaddr_ll*/
    socket_address.sll_family   = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_IP);
    socket_address.sll_ifindex  = ifindex;
    socket_address.sll_hatype   = ARPHRD_ETHER;
    socket_address.sll_pkttype  = PACKET_OTHERHOST;
    socket_address.sll_halen    = ETH_ALEN;
    socket_address.sll_addr[0]  = dest_mac[0];
    socket_address.sll_addr[1]  = dest_mac[1];
        socket_address.sll_addr[2]  = dest_mac[2];
        socket_address.sll_addr[3]  = dest_mac[3];
        socket_address.sll_addr[4]  = dest_mac[4];
        socket_address.sll_addr[5]  = dest_mac[5];
    socket_address.sll_addr[6]  = 0x00; 
    socket_address.sll_addr[7]  = 0x00;


    /*establish signal handler*/
    signal(SIGINT, sigint);
    printf("Successfully established signal handler for SIGINT\n");

    /*init random number generator*/
    srand(time(NULL));

    printf("We are in production state, sending packets to: %02X:%02X:%02X:%02X:%02X:%02X\n",
            dest_mac[0],dest_mac[1],dest_mac[2],dest_mac[3],dest_mac[4],dest_mac[5]);

    for (i = 50; i <= 1500; i += 50) {

        allovertime = 0;

        for (k = 0; k < NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA; k++) {
            /*prepare buffer*/
            memcpy((void*)buffer, (void*)dest_mac, ETH_MAC_LEN);
            memcpy((void*)(buffer+ETH_MAC_LEN), (void*)src_mac, ETH_MAC_LEN);
            eh->h_proto = ETH_P_NULL;
            /*fill it with random data....*/
            for (j = 0; j < i; j++) {
                data[j] = (unsigned char)((int) (256.0*rand()/(RAND_MAX+1.0)));
            }

            /*clear the timers:*/
            timerclear(&begin);
            timerclear(&end);

            /*get time before sending.....*/
             gettimeofday(&begin,NULL);


            /*send packet*/
            sent = sendto(s, buffer, i+ETH_HEADER_LEN, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
            if (sent == -1) {
                perror("sendto():");
                exit(1);
            }

            /*Wait for incoming packet...*/
            length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
            if (length == -1) {
                perror("recvfrom():");
                exit(1);
            }

            /*get time after sending.....*/
            gettimeofday(&end,NULL);
            /*...and calculate difference.........*/
            timersub(&end,&begin,&result); 

                allovertime += ((result.tv_sec * 1000000 ) + result.tv_usec );

            total_sent_packets++;
        }

        printf("Sending %i bytes takes %lld microseconds in average\n",i ,allovertime/NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA);
    }
    return (0);
}

void sigint(int signum) {
    /*Clean up.......*/

    struct ifreq ifr;

        if (s == -1)
            return;

    strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
    ioctl(s, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags &= ~IFF_PROMISC;
    ioctl(s, SIOCSIFFLAGS, &ifr);
    close(s);

    free(buffer);

    printf("Client terminating....\n");

    printf("Totally sent: %ld packets\n", total_sent_packets);
    exit(0);
}

------------------ server.c ---------------------

#include "server.h"
#include "util.h"

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <asm/types.h>

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

#define BUF_SIZE ETH_FRAME_TOTALLEN

int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_packets = 0;
long answered_packets = 0;

int main(int argc, char* argv[]) 
{
    buffer = (void*)malloc(BUF_SIZE);   /*Buffer for Ethernet Frame*/
    unsigned char* etherhead = buffer;  /*Pointer to Ethenet Header*/
    struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to ethernet header*/

    unsigned char src_mac[6];       /*our MAC address*/

    struct ifreq ifr;
    struct sockaddr_ll socket_address;
    int ifindex = 0;            /*Ethernet Interface index*/
    int i;
    int length;             /*length of received packet*/
    int sent;

    printf("Server started, entering initialiation phase...\n");

    /*open socket*/
    s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (s == -1) {
        perror("socket():");
            exit(1);
    }
    printf("Successfully opened socket: %i\n", s);

    /*retrieve ethernet interface index*/
    strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
    if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
    ifindex = ifr.ifr_ifindex;
    printf("Successfully got interface index: %i\n", ifindex);

    /*retrieve corresponding MAC*/
    if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
        for (i = 0; i < 6; i++) {
        src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
    }
    printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", 
            src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);

    /*prepare sockaddr_ll*/
    socket_address.sll_family   = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_IP);
    socket_address.sll_ifindex  = ifindex;
    socket_address.sll_hatype   = ARPHRD_ETHER;
    socket_address.sll_pkttype  = PACKET_OTHERHOST;
    socket_address.sll_halen    = ETH_ALEN;
    socket_address.sll_addr[6]  = 0x00; 
    socket_address.sll_addr[7]  = 0x00;


    /*establish signal handler (keyboard)*/
    signal(SIGINT, sigint);
    printf("Successfully established signal handler for SIGINT\n");

    printf("We are in production state, waiting for incoming packets....\n");

    while (1) {
        /*Wait for incoming packet...*/ 
        length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
        if (length == -1) {
            perror("recvfrom():");
            exit(1);
        }
        /*See if we should answer (Ethertype == 0x0 && destination address == our MAC)*/
        if (eh->h_proto == ETH_P_NULL && memcmp( (const void*)eh->h_dest, (const void*)src_mac, ETH_MAC_LEN) == 1 ) 
        {
            /*exchange addresses in buffer*/
            memcpy( (void*)etherhead, (const void*)(etherhead+ETH_MAC_LEN), ETH_MAC_LEN);
            memcpy( (void*)(etherhead+ETH_MAC_LEN), (const void*)src_mac, ETH_MAC_LEN);

            /*prepare sockaddr_ll*/
            socket_address.sll_addr[0]  = eh->h_dest[0];
            socket_address.sll_addr[1]  = eh->h_dest[1];
            socket_address.sll_addr[2]  = eh->h_dest[2];
            socket_address.sll_addr[3]  = eh->h_dest[3];
            socket_address.sll_addr[4]  = eh->h_dest[4];
            socket_address.sll_addr[5]  = eh->h_dest[5];

            /*send answer*/
            sent = sendto(s, buffer, length-4, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
            if (sent == -1) {
                perror("sendto():");
                exit(1);
            }

            answered_packets++;
        }

        total_packets++;
    }
}

void sigint(int signum) {
    /*Clean up.......*/

    struct ifreq ifr;

        if (s == -1)
            return;

    strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
    ioctl(s, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags &= ~IFF_PROMISC;
    ioctl(s, SIOCSIFFLAGS, &ifr);
    close(s);

    free(buffer);

    printf("Server terminating....\n");

    printf("Totally received: %ld packets\n", total_packets);
    printf("Answered %ld packets\n", answered_packets);
    exit(0);
}

1 Ответ

0 голосов
/ 24 января 2010

Извините за весь код, но я не знал, как сделать его короче, так как не знал, где была ошибка Во всяком случае, я нашел проблему, поэтому извиняюсь за «стену кода», ребята!

Оказывается, проблема заключалась в том, как настроены наши коммутаторы. После того, как я получил 2 машины в одной подсети, код работал прекрасно!

...