RX_RING正在捕获TX_RING数据包

时间:2018-11-27 06:35:29

标签: linux sockets network-programming raw-sockets

在参考以下两个链接之后,

https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt

https://sites.google.com/site/packetmmap/

我写了一个带有两个线程的代码,以使用RX / TX环读写数据包。 两者正在并行运行。 令我惊讶的是,我看到TX线程正在写入的数据包在接收线程中显示为RX数据包。

代码如下:

//gcc packet_mmap_read_write.c -lpthread

#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <net/if.h>
#include <net/if.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <poll.h>

char const * const card_name = "eth0";

void *rx_ring_code( void *unused_param )
{
    int i;

    const int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if( sock < 0 )
    {
        perror("socket");
        exit(1);
    }

    i = TPACKET_V3;
    if( setsockopt( sock, SOL_PACKET, PACKET_VERSION, &i, sizeof(i) ) < 0 )
    {
        perror("setsockopt");
        exit(1);
    }
/*  i = ( ( getpid() & 0xffff ) | (PACKET_FANOUT_CPU << 16));
    if( setsockopt( sock, SOL_PACKET, PACKET_FANOUT, &i, sizeof(i) ) < 0 )
    {
        perror("setsockopt");
        return NULL;
    }
*/

    struct tpacket_req3 req =
    {
        .tp_block_size = 1 << 22,
        .tp_frame_size = 1 << 11,
        .tp_block_nr = 64,
    };
    struct ifreq ifr;
    strcpy( ifr.ifr_name, card_name );
    if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("unable to get flags");
        return NULL;
    }
    ifr.ifr_flags |= ( IFF_PROMISC | IFF_UP );
    if( ioctl( sock, SIOCSIFFLAGS, &ifr ) == -1 )
    {
        perror("unable to set flags");
        return NULL;
    }
    req.tp_frame_nr = (req.tp_block_size * req.tp_block_nr) / req.tp_frame_size;

    if( setsockopt( sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(struct tpacket_req3) ) < 0 )
    {
        perror("setsockopt");
        exit(1);
    }

    uint8_t *const map = mmap( NULL, req.tp_block_size * req.tp_block_nr, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_LOCKED, sock, 0 );
    if( map == MAP_FAILED )
    {
        perror("mmap");
        exit(1);
    }

    struct sockaddr_ll ll =
    {
        .sll_family = PF_PACKET,
        .sll_protocol = htons(ETH_P_ALL),
        .sll_ifindex = if_nametoindex(ifr.ifr_name)
    };

    if (bind(sock, (struct sockaddr *) &ll, sizeof(ll)) < 0)
    {
        perror("bind");
        exit(1);
    }

    struct pollfd pfd = 
    {
        .fd = sock,
        .events = POLLIN | POLLERR,
        .revents = 0
    };

    int block_pos = 0;
    int pkt_num = 0;
    for( block_pos = 0; 1; block_pos = ((block_pos+1) % req.tp_block_nr) )
    {
        struct block_desc
        {
            uint32_t version;
            uint32_t offset_to_priv;
            struct tpacket_hdr_v1 h1;
        } *pbd = (struct block_desc *) ( map + (block_pos * req.tp_block_size) );

        if( ( pbd->h1.block_status & TP_STATUS_USER ) == 0 )
        {
            poll(&pfd, 1, -1);
            continue;
        }
        printf( "number of packets captured: %d\n", pbd->h1.num_pkts );
        struct tpacket3_hdr *ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + pbd->h1.offset_to_first_pkt);
        for( i = 0; i<pbd->h1.num_pkts; i++ )
        {
            printf( "packet Number: %d packet size: %d\n", pkt_num++, ppd->tp_snaplen );
            /*uint8_t *pkt_ptr = ((uint8_t *) ppd + ppd->tp_mac);
            int j;
            for( j=0; j<ppd->tp_snaplen; j++ )
            {
                printf( "%02X ", pkt_ptr[j] );
            }
            printf( "\n" );
            ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset);*/
        }
        pbd->h1.block_status = TP_STATUS_KERNEL;
    }

    munmap(map, req.tp_block_size * req.tp_block_nr);
    close(sock);
    return 0;
}

void * tx_ring_code( void *unused_param )
{
    const int c_packet_sz = 200;
    int fd_socket, j;
    uint32_t i;

    fd_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if( fd_socket == -1 )
    {
        perror("socket");
        return NULL;
    }
    struct sockaddr_ll my_addr =
    {
        .sll_family = AF_PACKET,
        .sll_protocol = htons(ETH_P_ALL),
        .sll_ifindex = (int)if_nametoindex(card_name)
    };

    /* bind port */
    if( bind( fd_socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll) ) == -1 )
    {
        perror("bind");
        return NULL;
    }
    /* prepare Tx ring request */
    struct tpacket_req s_packet_req =
    {
        .tp_block_size = 1<<12,
        .tp_frame_size = 1<<12,
        .tp_block_nr = 10
    };
    s_packet_req.tp_frame_nr = (s_packet_req.tp_block_size*s_packet_req.tp_block_nr)/s_packet_req.tp_frame_size;

    /* send TX ring request */
    if( setsockopt( fd_socket, SOL_PACKET, PACKET_TX_RING, (char *)&s_packet_req, sizeof(s_packet_req) ) < 0 )
    {
        perror( "setsockopt: PACKET_TX_RING" );
        return NULL;
    }

    /* mmap Tx ring buffers memory */
    struct tpacket_hdr * const map = mmap(0, s_packet_req.tp_block_size * s_packet_req.tp_block_nr, PROT_WRITE, MAP_SHARED, fd_socket, 0);
    if( map == MAP_FAILED )
    {
        perror("mmap");
        return NULL;
    }
    for( i=0; i<s_packet_req.tp_block_nr; i++ )
    {
        struct tpacket_hdr * ps_header = ((struct tpacket_hdr *)((void *)map + (s_packet_req.tp_block_size*i)));
#define my_TPACKET_ALIGN(x) (((x)+(uint64_t)(TPACKET_ALIGNMENT-1))&~((uint64_t)(TPACKET_ALIGNMENT-1)))
        char * pkt_ptr = ((void*) ps_header) + my_TPACKET_ALIGN(sizeof(struct tpacket_hdr));
        for( j=0; j<c_packet_sz; j++ )
        {
            pkt_ptr[j] = j; /* fill data in buffer */
        }
        /* update packet length */
        ps_header->tp_len = (uint32_t)c_packet_sz;
        ps_header->tp_status = TP_STATUS_SEND_REQUEST;
    }
    int total_pkts = 0, ec_send, total_bytes = 0;
    while( total_pkts<s_packet_req.tp_block_nr )
    {
        ec_send = sendto( fd_socket, NULL, 0, MSG_DONTWAIT, NULL, sizeof(struct sockaddr_ll) );
        if(ec_send < 0)
        {
            perror("send");
        }
        else
        {
            total_pkts += ec_send/(c_packet_sz);
            total_bytes += ec_send;
            printf("%s %d send %d packets (+%d bytes)\n", __func__, __LINE__, total_pkts, total_bytes );
        }
    }
    munmap( map, s_packet_req.tp_block_size * s_packet_req.tp_block_nr );
    close(fd_socket);

    return NULL;
}

int main()
{
    pthread_t rx_thread, tx_thread;
    if( pthread_create( &rx_thread, NULL, rx_ring_code, NULL ) )
    {
        fprintf( stderr, "%s %d\n", __func__, __LINE__ );
        return EXIT_FAILURE;
    }
    if( pthread_create( &tx_thread, NULL, tx_ring_code, NULL ) )
    {
        fprintf( stderr, "%s %d\n", __func__, __LINE__ );
        return EXIT_FAILURE;
    }
    if( pthread_join( rx_thread, NULL ) )
    {
        fprintf( stderr, "%s %d\n", __func__, __LINE__ );
        return EXIT_FAILURE;
    }
    if( pthread_join( tx_thread, NULL ) )
    {
        fprintf( stderr, "%s %d\n", __func__, __LINE__ );
        return EXIT_FAILURE;
    }
}

如果有一种方法只能捕获传入的数据包,可以有人帮我吗?

0 个答案:

没有答案