链路层原始套接字源码

发送端

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>// close()
#include <string.h>// strcpy, memset(), and memcpy()
#include <netdb.h> // struct addrinfo
#include <sys/types.h>  // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h>  // needed for socket()
#include <netinet/in.h> // IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>// struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h>  // defines values for argument "request" of ioctl.
#include <net/if.h> // struct ifreq
#include <linux/if_ether.h> // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet)
#include <net/ethernet.h>
#include <errno.h> // errno, perror()
#define ETH_P_DEAN 0x8874 //自定义的以太网协议type


int main (int argc, char **argv)
{
    int i, datalen,frame_length, sd, bytes;
    char *interface="ens33";;
    uint8_t data[IP_MAXPACKET];
    uint8_t src_mac[6];
    uint8_t dst_mac[6];;
    uint8_t ether_frame[IP_MAXPACKET];
    struct sockaddr_ll device;

    if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) 
    {
        perror ("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    // Use ioctl() to look up interface name and get its MAC address.
    struct ifreq ifr;
    memset (&ifr, 0, sizeof (ifr));
    snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);

    if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) 
    {
        perror ("ioctl() failed to get source MAC address ");
        return (EXIT_FAILURE);
    }

    memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6);// Copy source MAC address.
    memset (&device, 0, sizeof (device));
    if (ioctl (sd, SIOCGIFINDEX, &ifr) < 0) 
    {
        perror ("ioctl() failed to get source MAC address ");
        return (EXIT_FAILURE);
    }
    device.sll_ifindex = ifr.ifr_ifindex;
    // Set destination MAC address: you need to fill these out
    // 00:0c:29:38:90:56
    dst_mac[0] = 0x00;
    dst_mac[1] = 0x0c;
    dst_mac[2] = 0x29;
    dst_mac[3] = 0x38;
    dst_mac[4] = 0x90;
    dst_mac[5] = 0x56;

    device.sll_family = AF_PACKET;
    memcpy (device.sll_addr, src_mac, 6);
    device.sll_halen = htons (6);
    // 发送的data,但是抓包时看到最小数据长度为46,以太网协议规定以太网帧数据域最小为46字节,不足的自动补零处理
    sprintf(data,"%s","hello,world!");
    datalen = strlen(data);
    
    // 填充以太网帧
    memcpy (ether_frame, dst_mac, 6);
    memcpy (ether_frame + 6, src_mac, 6);
    ether_frame[12] = ETH_P_DEAN / 256;
    ether_frame[13] = ETH_P_DEAN % 256;
    memcpy (ether_frame + 14 , data, datalen);
    frame_length = 6 + 6 + 2 + datalen;

    if ((bytes = sendto (sd, ether_frame, frame_length, 0, (struct sockaddr *) &device, sizeof (device))) <= 0) 
    {
        perror ("sendto() failed");
        exit (EXIT_FAILURE);
    }

    close (sd);
    return (EXIT_SUCCESS);
}
复制代码

 

接收端

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>// close()
#include <string.h>// strcpy, memset(), and memcpy()
#include <netdb.h> // struct addrinfo
#include <sys/types.h>  // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h>  // needed for socket()
#include <netinet/in.h> // IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>// struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h>  // defines values for argument "request" of ioctl.
#include <net/if.h> // struct ifreq
#include <linux/if_ether.h> // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet)
#include <net/ethernet.h>
#include <errno.h> // errno, perror()
#define ETH_P_DEAN 0x8874 //自定义的以太网协议type


int main (int argc, char **argv)
{
    int sd;
    uint8_t data[IP_MAXPACKET];
    uint8_t src_mac[32];
    uint8_t dst_mac[32];;
    
    if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_DEAN))) < 0) 
    {
        perror ("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    while(1)
    {
        memset(src_mac, 0, sizeof(src_mac));
        memset(dst_mac, 0, sizeof(dst_mac));
        recvfrom(sd, data, sizeof(data), 0, NULL, NULL);
        sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x",data[0],data[1],data[2],data[3],data[4],data[5]);
        sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x",data[6],data[7],data[8],data[9],data[10],data[11]);
        printf("%s->%s\n",src_mac,dst_mac);
    }

    close (sd);
    return (EXIT_SUCCESS);
}
复制代码

 

posted @   roverqqq  阅读(108)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示