当前位置:网站首页>Raw socket usage

Raw socket usage

2022-06-12 10:04:00 wlf_ go

One 、 What can a raw socket do ?

Usually, programmers connect to the socket they touch (Socket) There are two types :

  1. Streaming socket (SOCK_STREAM): A connection oriented Socket, For connection oriented TCP Service application ;
  2. Datagram socket (SOCK_DGRAM): A connectionless Socket, Corresponds to unconnected UDP Service application .
From the user's point of view ,SOCK_STREAM、SOCK_DGRAM These two types of sockets do seem to cover TCP/IP All of the applications , Because it is based on TCP/IP Application , At the protocol stack level , In the transport layer, it can only be built on TCP or UDP The agreement above , and SOCK_STREAM、SOCK_DGRAM And corresponding to TCP and UDP, Therefore, almost all applications can be implemented with these two types of sockets .

however , When we face the following problems ,SOCK_STREAM、SOCK_DGRAM Will appear so helpless :
1. How to send a custom IP package ?
2. How to send a ICMP Agreement package ?
3. How to analyze all packets passing through the network , And whether or not the bag was sent to you ?
4. How to disguise local IP Address ?

This makes us have to face another profound theme —— Raw socket (SOCK_RAW).

Raw sockets are widely used in advanced network programming , It is also a broad means of hacking . The famous Internet sniffer( A network analysis method based on the principle of passive interception )、 Denial of service attacks (DOS)、IP Spoofing and so on can be realized through the original socket . Raw socket (SOCK_RAW) It can be used to self assemble packets , It can receive all the data frames on the local network card ( Data packets ), It is very useful for monitoring network traffic and analyzing network data . The original socket is based on IP Packet programming (SOCK_PACKET It's based on data link layer programming ). in addition , You must have administrator privileges to use raw sockets . Raw socket (SOCK_RAW) With standard sockets (SOCK_STREAM、SOCK_DGRAM) The difference is that the original socket is set directly “ root ” At the core of the operating system network (Network Core), and SOCK_STREAM、SOCK_DGRAM be “ suspension ” On TCP and UDP The periphery of the agreement .

Streaming sockets can only send and receive TCP Protocol data , Datagram socket can only send and receive UDP Protocol data , The original socket can send and receive packets that are not processed by the kernel .

Two 、 Raw socket programming

Raw socket programming and before UDP Programming is almost , After creating a socket , Receive data or send data through this socket . The difference lies in , The raw socket can self assemble packets ( Camouflage local IP, Local MAC), It can receive all the data frames on the local network card ( Data packets ). in addition , You must have administrator privileges to use raw sockets .

The creation of the original socket :

int socket ( int family, int type, int protocol );

Parameters :

family: Protocol family Write here PF_PACKET

type: Socket class , Write here SOCK_RAW

protocol: Type of agreement , Specifies the type of packet that can be received or sent , Can't write “0”, The values are as follows , Be careful , You need to use

htons() Do byte order conversion .

ETH_P_IP:IPV4 Data packets

ETH_P_ARP:ARP Data packets

ETH_P_ALL: Packets of any protocol type

Return value :

success ( >0 ): Socket , Here is the socket of the link layer

Failure ( <0 ): error

Examples are as follows :

//  Required header file     
#include <sys/socket.h>    
#include <netinet/ether.h>    
#include <stdio.h>  // perror    

int main(int argc,charchar *argv[])    
{    
    int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );    

    if(sock_raw_fd < 0){    
        perror("socket");    
        return -1;    
    }    

    return 0;    
}

【 Article Welfare 】 need C/C++ Linux Background server architect and audio and video learning materials plus group 812855908( The information includes C/C++,Linux,golang technology , kernel ,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK, Streaming media , Audio and video ,CDN,P2P,K8S,Docker,TCP/IP, coroutines ,DPDK,ffmpeg, Interview questions of Dachang etc. )

Get the packet function of the link layer :

ssize_t recvfrom( int sockfd, void *buf,  size_t nbytes,  
            int flags,  struct sockaddr *from,
              socklen_t *addrlen );

Parameters :

sockfd: Raw socket

buf: Receive data buffer

nbytes: The size of the receive data buffer

flags: Socket flag ( Often 0)

from: It's not useful here , Write NULL

addrlen: It's not useful here , Write NULL

Return value :

success : Number of characters received

Failure :-1

Examples are as follows :

#include <stdio.h>    
#include <netinet/in.h>    
#include <sys/socket.h>    
#include <netinet/ether.h>    

int main(int argc,charchar *argv[])    
{    
    unsigned char buf[1024] = {0};    
    int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    

    // Get the data packet of link layer     
    int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);    
    printf("len = %d\n", len);    

    return 0;    
}

Hybrid mode

By default , We receive data , The destination address is a local address , Will receive . Sometimes we want to receive all the data streams that pass through the network card , Whether or not the destination address is it , At this time, we need to set the network card to hybrid mode .

The hybrid mode of network card is usually used by network administrator when analyzing network data as a means of network fault diagnosis , At the same time, this mode is also used by network hackers as the entrance of network data eavesdropping . stay Linux When setting network card hybrid mode in the operating system, administrator's permission is required . stay Windows Operating system and Linux The operating system has the use of hybrid mode packet capture tools , Like the famous open source software Wireshark.

By order to Linux Network card set hybrid mode ( Administrator privileges required )

Set hybrid mode :ifconfig eth0 promisc

Cancel hybrid mode :ifconfig eth0 -promisc

Give to by code Linux Network card set hybrid mode

The core code is as follows :

struct ifreq ethreq;    // Network interface address     

strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);         // Specify the network card name     
if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, &ethreq)) // Get the network interface     
{    
    perror("ioctl");    
    close(sock_raw_fd);    
    exit(-1);    
}    

ethreq.ifr_flags |= IFF_PROMISC;    
if(-1 == ioctl(sock_raw_fd, SIOCSIFINDEX, &ethreq)) // Network card set hybrid mode     
{    
    perror("ioctl");    
    close(sock_raw_fd);    
    exit(-1);    
}

Send custom packets :

ssize_t sendto( int sockfd,const void *buf,
            size_t nbytes,int flags,
            const struct sockaddr *to,socklen_t addrlen );

Parameters :

sockfd: Raw socket

buf: Send data buffer

nbytes: The size of the send data buffer

flags: It's usually 0

to: Local network interface , It refers to the network card from which the data should be sent out , Instead of the previous destination address

addrlen:to The length of the pointed content

Return value :

success : Number of characters to send data
Failure : -1

 Send the complete code as follows :
struct sockaddr_ll sll;                 // Original socket address structure     
struct ifreq ethreq;                    // Network interface address     

strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);         // Specify the network card name     
if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq))    // Get the network interface     
{    
    perror("ioctl");    
    close(sock_raw_fd);    
    exit(-1);    
}    

/* Assign the network interface to the original socket address structure */    
bzero(&sll, sizeof(sll));    
sll.sll_ifindex = ethreq.ifr_ifindex;    

//  send data     
// send_msg, msg_len  There is no definition here , Simulate     
int len = sendto(sock_raw_fd, send_msg, msg_len, 0 , (struct sockaddr *)&sll, sizeof(sll));    
if(len == -1)    
{    
    perror("sendto");    
}

Here the header file is as follows :

#include <net/if.h>// struct ifreq    
#include <sys/ioctl.h> // ioctl、SIOCGIFADDR    
#include <sys/socket.h> // socket    
#include <netinet/ether.h> // ETH_P_ALL    
#include <netpacket/packet.h> // struct sockaddr_ll 

3、 ... and 、 Original socket instance :MAC Header message analysis

I know from the above , We can use the original socket and recvfrom( ) You can get the data packets of the link layer , What kind of link layer packets do we receive ?

Link layer packet format

MAC Head ( Wired LAN )

Be careful :CRC、PAD It can be ignored when packaging
One of the cases of link layer packets :

unsigned char msg[1024] = {    
    //-------------- Group MAC--------14------    
    0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst_mac: b8:88:e3:e1:10:e6    
    0xc8, 0x9c, 0xdc, 0xb7, 0x0f, 0x19, // src_mac: c8:9c:dc:b7:0f:19    
    0x08, 0x00,                         //  type :0x0800 IP agreement     
    // …… ……    
    // …… ……    
};

Received link layer packets , And make a simple analysis of it :

#include <stdio.h>    
#include <string.h>    
#include <stdlib.h>    
#include <sys/socket.h>    
#include <netinet/in.h>    
#include <arpa/inet.h>    
#include <netinet/ether.h>    

int main(int argc,charchar *argv[])    
{    
    int i = 0;    
    unsigned char buf[1024] = "";    
    int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    
    while(1)    
    {    
        unsigned char src_mac[18] = "";    
        unsigned char dst_mac[18] = "";    
        // Get the data frame of link layer     
        recvfrom(sock_raw_fd, buf, sizeof(buf),0,NULL,NULL);    
        // from buf To extract the purpose of mac、 Source mac    
        sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);    
        sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);    
        // Judge whether it is IP Data packets     
        if(buf[12]==0x08 && buf[13]==0x00)    
        {       
            printf("______________IP The datagram _______________\n");    
            printf("MAC:%s >> %s\n",src_mac,dst_mac);    
        }// Judge whether it is ARP Data packets     
        else if(buf[12]==0x08 && buf[13]==0x06)    
        {    
            printf("______________ARP The datagram _______________\n");    
            printf("MAC:%s >> %s\n",src_mac,dst_mac);    
        }// Judge whether it is RARP Data packets     
        else if(buf[12]==0x80 && buf[13]==0x35)    
        {    
            printf("______________RARP The datagram _______________\n");    
            printf("MAC:%s>>%s\n",src_mac,dst_mac);    
        }    
    }    
    return 0;    
}

Remember to run the program with administrator privileges :

原网站

版权声明
本文为[wlf_ go]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/163/202206120958491557.html