Hybrid mode of network card under Linux
- Hybrid mode is to receive all packets passing through the network card, including packets not sent to the local machine, that is, the MAC address is not verified. In normal mode, the network card only receives packets sent to the local computer (including broadcast packets) and passes them to the upper layer program, and all other packets are discarded. Generally speaking, the hybrid mode will not affect the normal operation of the network card. It is mostly used on network monitoring tools.
The network card has the following working modes:
- Broad Cast Model: the frame whose physical address (MAC) is 0Xffffff is a broadcast frame, and the network card working in the broadcast mode receives the broadcast frame.
- MultiCast Model: the frame with multicast transmission address as the destination physical address can be received by other hosts in the group at the same time, but not by hosts outside the group. However, if the network card is set to multicast transmission mode, it can receive all multicast transmission frames, whether it is a member of the group or not.
- Direct Model: the network card working in direct mode only receives frames whose destination address is its own Mac address.
- Promiscuous Model: the network card working in promiscuous mode receives all frames flowing through the network card, and the packet capture program runs in this mode.
The default working mode of the network card includes broadcast mode and direct mode, that is, it only receives broadcast frames and frames sent to itself. If the hybrid mode is adopted, the network card of a site will accept the data packets sent by all sites in the same network, so as to achieve the purpose of monitoring and capturing network information.
Tips:
- When tcpdump is used to capture packets, the network card will enter the hybrid mode, which can be seen in / var/log/messages
As shown in the following figure, after tcpdump packet capturing is enabled, the system log can be seen in the new window clone session tail -f /var/log/messages
kernel: device eth0 entered promiscuous mode
- In fact, whether the network card is in hybrid mode cannot be judged according to whether there is a PROMISC field in ifconfig. For example, when tcpdump packet capture is enabled, there is no PROMISC field in ifconfig. In fact, ifconfig is not the most direct basis for judging whether the network card is in the PROMISC mode. In other words, if ifconfig can see the PROMISC mark, it means that it must be in the hybrid mode, but if it is in the hybrid mode, it does not necessarily see the PROMISC mark. The kernel judges whether the network card is in hybrid mode by the value of / sys/class/net/eth0/flags. If 0x100 is set, it is in hybrid mode
[root@CentOS_DIY ~]# cat /usr/include/linux/if.h | grep -i promisc
#define IFF_PROMISC 0x100 /* receive all packets */
Summary:
- The default working mode of the network card includes broadcast mode and direct mode.
- Promiscuous patterns do not necessarily see PROMISC markers. The kernel determines whether the network card is in hybrid mode by looking at the value of / sys/class/net/eth0/flags.
- ifconfig can see that the promise flag indicates that it must be in hybrid mode.
- When tcpdump packet capture is enabled, ifconfig does not have the PROMISC field, and it will automatically go to the kernel to set the hybrid mode.
- Generally speaking, the hybrid mode will not affect the normal operation of the network card. It is mostly used on network monitoring tools.
Raw socket programming
-
Similar to UDP programming, it is to create a socket and receive or send data through the socket.
The difference is that the original socket can assemble data packets (masquerading as local IP and local MAC) and receive all data frames (data packets) on the local network card.
In addition, you must have administrator privileges to use the original socket. -
Creation of raw socket
int socket ( int family, int type, int protocol );
- Parameters:
family: The protocol family is written here PF_PACKET type: Socket class, written here SOCK_RAW protocol: Protocol category, which specifies the packet type that can be received or sent. It cannot write "0". The values are as follows. Note that it needs to be used when transmitting parameters htons() Byte order conversion. ETH_P_IP: IPV4 data packet ETH_P_ARP: ARP data packet ETH_P_ALL: Packets of any protocol type
- Return value:
success( >0 ): Socket, here is the socket of link layer fail( <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,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; }
-
SIOCGIFFLAGS, SIOCSIFFLAGS
- Read or set the activity flag word of the device. ifr_flags contains masked bits for the following values:
Equipment mark IFF_UP The interface is running. IFF_BROADCAST Valid broadcast address set. IFF_DEBUG Internal commissioning flag. IFF_LOOPBACK This is a self ring interface. IFF_POINTOPOINT This is a point-to-point link interface. IFF_RUNNING Resources allocated. IFF_NOARP nothing arp agreement, Layer 2 destination address is not set. IFF_PROMISC Interface is hash(promiscuous)pattern. IFF_NOTRAILERS Avoid using trailer . IFF_ALLMULTI Receive all multicast(multicast)message. IFF_MASTER Main load balancing group(bundle). IFF_SLAVE From load balancing group(bundle). IFF_MULTICAST Support multicast(multicast). IFF_PORTSEL Can pass ifmap Select media(media)type. IFF_AUTOMEDIA Auto select media. IFF_DYNAMIC Drop address when interface is closed.
- Obtain data packets 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:Size of receive data buffer flags: Socket flag(Usually 0) from: It's no use writing here NULL addrlen: It's no use writing here NULL
- Return value:
Success: number of characters received Failed:-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)); //Obtain data packets of link layer int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL); printf("len = %d\n", len); return 0; }
promiscuous mode
-
By default, we receive data only when the destination address is a local address. Sometimes we want to receive all data streams passing through the network card, regardless of whether the destination address is it or not. At this time, we need to set the network card to hybrid mode.
-
The hybrid mode of network card is generally used by network administrators when analyzing network data as a means of network fault diagnosis. At the same time, this mode is also used by network hackers as an entrance for network data eavesdropping. Administrator privileges are required when setting the network card hybrid mode in the Linux operating system. In both Windows operating system and Linux operating system, there are packet capture tools using hybrid mode, such as the famous open source software Wireshark.
Set the mixed mode for the Linux network card through the command (administrator permission is required)
-
Set hybrid mode: ifconfig eth0 promisc
-
Cancel hybrid mode: ifconfig eth0 - promise
-
Set hybrid mode for Linux network card through code
- The code is as follows:
// // Set network card hybrid mode int CGpIpTools::rawSoketInit() { int sockfd; // Original socket struct ifreq ifr; // Network interface address struct sockaddr_ll local_addr; /* Create original socket */ if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { LOGERROR("socket fail\n"); return -1; } /* Set to hybrid mode */ strcpy(ifr.ifr_name, "eth0"); // Specify the network card name if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) // Get network interface { LOGERROR("ioctl fail\n"); close(sockfd); return -1; } ifr.ifr_flags |= IFF_PROMISC; // Network card setting hybrid mode if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { LOGERROR("ioctl fail\n"); close(sockfd); return -1; } /* Get physical network card interface index */ strcpy(ifr.ifr_name, "eth0"); if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { LOGERROR("ioctl fail\n"); close(sockfd); return -1; } /* Bind physical network card */ local_addr.sll_family = PF_PACKET; local_addr.sll_ifindex = ifr.ifr_ifindex; local_addr.sll_protocol = htons(ETH_P_ALL); if (bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { LOGERROR("bind fail\n"); close(sockfd); return -1; } return sockfd; }
- 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:Size of send data buffer flags: Generally 0 to: The local network interface refers to the network card of the local machine from which the data should be sent, rather than the previous destination address addrlen: to Length of content pointed to
- Return value:
Success: number of characters to send data Failed: -1
-
Definition of local network interface
-
Send the complete code 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 struct sockaddr_ll sll; // Raw 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 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 is not defined here. Let's simulate it int len = sendto(sock_raw_fd, send_msg, msg_len, 0 , (struct sockaddr *)&sll, sizeof(sll)); if(len == -1) { perror("sendto"); } /*udp can also be used for sending and receiving*/ // // Initialize udp socket int CGpIpTools::localSocketInit() { int sockFd = 0; struct sockaddr_in sockAddr; if ((sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { LOGERROR("socket error.\n"); return -1; } sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); sockAddr.sin_port = htons(5566); if (bind(sockFd, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0) { LOGERROR("bind error.\n"); return -1; } int val = 1; setsockopt(sockFd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)); setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); return sockFd; } // // Main function entry int main(int argc, char **argv) { int recvLen; int dwCrc; int rawSockFd = 0, localSockFd = 0; struct sockaddr_ll remoteAddr; struct sockaddr_in clientAddr; int addrLen = sizeof(remoteAddr); char recvBuf[1024] = { 0 }; char sendBuf[1024] = { 0 }; back_up_net_interface(); rawSockFd = rawSoketInit(); localSockFd = localSocketInit(); if ((rawSockFd < 0) || (localSockFd < 0)) { printf("create socket error.\n"); return -1; } clientAddr.sin_family = AF_INET; clientAddr.sin_addr.s_addr = INADDR_BROADCAST; clientAddr.sin_port = htons(8000); pid_t pid = getpid(); struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(pid, SCHED_FIFO, ¶m); while (1) { bzero(recvBuf, sizeof(recvBuf)); recvLen = recvfrom(localSockFd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&remoteAddr, &addrLen); DataHead *pHead = (DataHead *)recvBuf; //printf("magic:0x%x\n",ntohl(pHead->mMgic)); if (MAGIC == pHead->mMgic) { printf("data len%d\n", pHead->mLen); bzero(sendBuf, sizeof(sendBuf)); parseCmd(pHead->mPackType, recvBuf, sendBuf); if (((DataHead *)sendBuf)->mPackType == ACK_INVALID_CMD) continue; int ret = sendto(localSockFd, (char *)sendBuf, ((DataHead *)sendBuf)->mLen, 0, (struct sockaddr *)&clientAddr, sizeof(clientAddr)); //perror("send error.\n"); printf("data len:%d,send len:%d\n", ((DataHead *)sendBuf)->mLen, ret); } usleep(1000 * 20); } close(rawSockFd); close(localSockFd); return 0; }