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
need C/C++ Linux Server architect learning materials plus group 812855908( The information includes C/C++,Linux,golang technology ,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK, Streaming media ,CDN,P2P,K8S,Docker,TCP/IP, coroutines ,DPDK,ffmpeg etc. )
Examples are as follows :
// Required header file
#include <sys/socket.h>
#include <netinet/ether.h>
#include <stdio.h> // perror
int main(int argc,char *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;
}
Get the data packet of 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,char *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 = %dn", 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 code is as follows :
struct ifreq req; // Network interface address
strncpy(req.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);
}
req.ifr_flags |= IFF_PROMISC;
if(-1 == ioctl(sock_raw_fd, SIOCSIFINDEX, &req)) // 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
Definition of native network interface
Send the complete code as follows :
struct sockaddr_ll sll; // Original socket address structure
struct ifreq req; // Network interface address
strncpy(req.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 = req.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