使用raw socket发送以太网帧

/*
 * send a raw ethernet frame
 */

#include             //memcpy()
#include            //strxxx()
#include            //close()
#include        //socket()
#include         //htons()
#include          //struct ifreq
#include    //ETH_ALEN(6),ETH_HLEN(14),ETH_FRAME_LEN(1514),struct ethhdr
#include   //struct sockaddr_ll
#include         //ioctl()

union ethframe {
    struct {
        struct ethhdr header;
        char data[ETH_DATA_LEN];
    } field;
    char buffer[ETH_FRAME_LEN];
};

int main(void)
{
    char *iface = "ext1";
    char dest[ETH_ALEN] = {0x00, 0x12, 0x34, 0x56, 0x78, 0x90};
    short proto = 0x1234;
    char *data = "hello world";
    unsigned short data_len = strlen(data);

    int s;
    if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
        printf("Error: could not open socket\n");
        return -1;
    }

    struct ifreq buffer;
    memset(&buffer, 0x00, sizeof(buffer));
    strncpy(buffer.ifr_name, iface, IFNAMSIZ);

    if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
        printf("Error: could not get interface index\n");
        close(s);
        return -1;
    }
    int ifindex;
    ifindex = buffer.ifr_ifindex;

    unsigned char source[ETH_ALEN];
    if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
        printf("Error: could not get interface address\n");
        close(s);
        return -1;
    }
    memcpy(source, buffer.ifr_hwaddr.sa_data, ETH_ALEN);

    union ethframe frame;
    memcpy(frame.field.header.h_dest, dest, ETH_ALEN);
    memcpy(frame.field.header.h_source, source, ETH_ALEN);
    frame.field.header.h_proto = htons(proto);
    memcpy(frame.field.data, data, data_len);

    unsigned int frame_len = data_len + ETH_HLEN;

    struct sockaddr_ll saddrll;
    memset(&saddrll, 0, sizeof(saddrll));
    saddrll.sll_family = PF_PACKET;
    saddrll.sll_ifindex = ifindex;
    saddrll.sll_halen = ETH_ALEN;
    memcpy(saddrll.sll_addr, dest, ETH_ALEN);

    if (sendto(s, frame.buffer, frame_len, 0, (struct sockaddr*)&saddrll, sizeof(saddrll)) > 0)
        printf("Success!\n");
    else
        printf("Error, could not send\n");

    close(s);
    return 0;
}
$ gcc -Wall a.c && sudo ./a.out
$ sudo tcpdump -ni ext1 -vv -XX not ip6 and proto not 89
tcpdump: listening on ext1, link-type EN10MB (Ethernet), capture size 262144 bytes
10:07:59.629576 fa:16:3e:d5:0e:e0 > 00:12:34:56:78:90, ethertype Unknown (0x1234), length 25:
        0x0000:  0012 3456 7890 fa16 3ed5 0ee0 1234 6865  ..4Vx...>....4he
        0x0010:  6c6c 6f20 776f 726c 64                   llo.world
^C
1 packet captured
1 packet received by filter
0 packets dropped by kernel

参考

http://hacked10bits.blogspot.fi/2011/12/sending-raw-ethernet-frames-in-6-easy.html

你可能感兴趣的:(使用raw socket发送以太网帧)