使用raw socket发送以太网帧

/*
 * send a raw ethernet frame
 */

#include <stdio.h>            //memcpy()
#include <string.h>           //strxxx()
#include <unistd.h>           //close()
#include <sys/socket.h>       //socket()
#include <arpa/inet.h>        //htons()
#include <linux/if.h>         //struct ifreq
#include <linux/if_ether.h>   //ETH_ALEN(6),ETH_HLEN(14),ETH_FRAME_LEN(1514),struct ethhdr
#include <linux/if_packet.h>  //struct sockaddr_ll
#include <sys/ioctl.h>        //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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 《西游记》作为我们古典小说的四大名著之一,人人皆知。而六小龄童版的《西游记》电视剧更是家喻户晓,至今仍是寒暑假被重...
    173388a75016阅读 4,879评论 7 6
  • “进来玩吗?” 我看着眼前这位画着浓妆嘴里叼着香烟的女人,有些嫌恶的避了避视线,看向房间里,倒在一名陌生男人肩头的...
    香椿十里阅读 3,003评论 0 0
  • 天灾人祸都是无法避免的,昨天听见朋友被讹被群殴,今日自己就撞邪了,走在大马路上就被人家自行车事故给挤在中间,很明显...
    潇湘阁主阅读 1,306评论 0 0
  • 1900年,有三件事,促使慈禧太后向世界宣战。 第一件。江苏粮道罗嘉杰得到一个小道消息,说是各国公使准备努力让慈禧...
    点石教育永生阅读 7,751评论 0 8