linux kernel raw packet的接收与发送

Q:如果我要在linux上写一个程序,程序的功能是接收网络数据包,根据接收到的包再决定发送网络数据包,但这里的网络数据包并非TCP/UDP类型的数据包,而是仅包含以太头的原始数据包raw packet,那么这个的程序应该怎样编写呢?

为了使贴上来的程序完整,不至于只包含一部分代码,我先将各文件的完整代码附上,之后再针对各个需要注意的点逐一介绍。

先定义一个原始包处理的类,类的接口包括发送与接收、socket的创建与关闭、混杂模式的打开与关闭。头文件如下

#ifndef __RAWPKT_PROCESSOR_H__
#define __RAWPKT_PROCESSOR_H__

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

class RawPktProcessor
{
   
public:
    RawPktProcessor()=default;
    ~RawPktProcessor()=default;
    
    static void initSocket();
    static void closeSocket();
    static int32_t ifnameToIndex();
    static void setPromiscMode(bool enable);
    static int32_t send(const std::vector<uint8_t> &data);
    static int32_t recv(std::vector<uint8_t> &data);
private:
    static std::string s_ifName;
    static struct sockaddr_ll s_srcSaddr, s_dstSaddr;
    static int32_t s_sfd;
};

#endif

源文件如下

#include 
#include 
#include 
#include 
#include "rawpkt_processor.h"

/* change the s_ifName to your own NIC's name */
std::string RawPktProcessor::s_ifName = std::string("eth0");
struct sockaddr_ll RawPktProcessor::s_srcSaddr;
struct sockaddr_ll RawPktProcessor::s_dstSaddr;
int32_t RawPktProcessor::s_sfd = -1;

void RawPktProcessor::initSocket()
{
   
    s_sfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (-1 == s_sfd)
    {
   
        std::cout << "create socket failed" << std::endl;
        return;
    }
    
    int ifIndex = ifnameToIndex();
    if (ifIndex <= 0)
    {
   
        std::cout << "get ifIndex failed" << std::endl;
        return;
    }
    
    memset(&s_srcSaddr, 0, sizeof(s_srcSaddr));
    memset(&s_dstSaddr, 0, sizeof(s_dstSaddr));
    
    s_srcSaddr.sll_family = AF_PACKET;
    s_srcSaddr.sll_protocol = htons(ETH_P_ALL);
    s_srcSaddr.sll_ifindex = ifIndex;
    s_srcSaddr.sll_pkttype = PACKET_OUTGOING;
    s_srcSaddr.sll_halen = ETH_ALEN;
    
    s_dstSaddr.sll_family = AF_PACKET;
    s_dstSaddr.sll_protocol = htons(ETH_P_ALL);
    s_dstSaddr.sll_ifindex = ifIndex;
    s_dstSaddr.sll_pkttype = PACKET_HOST;
    s_dstSaddr.sll_halen = ETH_ALEN;
    if (bind(s_sfd, (struct sockaddr *)&s_dstSaddr, sizeof(s_dstSaddr)) == -1) {
   
        std::cout << "bind failed" << std::endl;
    }
}

int32_t RawPktProcessor::ifnameToIndex()
{
   
    if (s_sfd == -1)
    {
   
        std::cout << "there is no socket to be create" << std::endl;
        return -1;
    }
    struct ifreq req;
    memset(&req, 0, sizeof(req));
    strncpy(req.ifr_name, s_ifName.c_str(), s_ifName.size()<

你可能感兴趣的:(linux,kernel,开发,linux,kernel,socket,bind,协议栈)