We usually use network programming to send and receive data at the application layer. Each program can only receive data sent to itself, that is, each program can only receive data from the port bound to the program. The received data usually only includes the application layer data. In some cases, we need to perform more underlying operations, such as listening to all the data sent and received by the local machine, and modifying the header.
Through the original socket, we can capture all the IP packets sent to the local machine (including IP headers and TCP/UDP/ICMP headers ), you can also capture all frames received by the Local Machine (including the data link layer protocol header ). Ordinary sockets cannot process network packets such as ICMP and IGMP, while SOCK_RAW can. With the original socket, we can construct our own IP header.
There are two original sockets
One is to process the data on the IP layer. The first parameter of the socket is AF_INET to create the socket.
The other is to process the data on the data link layer. This socket is created by specifying AF_PACKET as the first parameter of the socket.
AF_INETObtains data starting from the network layer.
Socket (AF_INET, SOCK_RAW ,...)
When receiving a packet, the user obtains the complete packet containing the IP header, that is, the data starts from the IP header.
When a packet is sent, the user can only send packets containing the TCP header or UDP header or other transmission protocols. The IP header and Ethernet frame header are automatically blocked by the kernel. Unless the socket option of IP_HDRINCL is set.
If the second parameter is SOCK_STREAM and SOCK_DGRAM, the received data is directly the application layer data.
PF_PACKETIndicates that the obtained data starts from the data link layer.
Socket (PF_PACKET, SOCK_RAW, htos (ETH_P_IP): obtains the data link layer frame of IPV4, that is, the data contains the Ethernet frame header. 14 + 20 + (8: udp or 20: tcp)
ETH_P_IP: defined in <linux/if_ether.h>, you can view other protocols supported by this file.
Both SOCK_RAW and SOCK_DGRAM parameters can be used. The difference is that the data received by SOCK_DGRAM does not include the data link layer protocol header.
The summary is as follows:
Socket (AF_INET, SOCK_RAW, IPPROTO_TCP | IPPROTO_UDP | IPPROTO_ICMP) sends and receives ip Packets
Yes: This socket can receive ip packets sent to the local machine for the protocol type (tcp udp icmp, etc.)
No: Packets not sent to the local ip address are received (ip soft filter will discard these packets not sent to the local ip address)
No: receive the data packet sent from the Local Machine
You need to organize the tcp udp icmp and other headers for sending. You can use setsockopt to encapsulate the ip headers.
This socket is suitable for writing ping programs.
Socket (PF_PACKET, SOCK_RAW | SOCK_DGRAM, htons (ETH_P_IP | ETH_P_ARP | ETH_P_ALL) sends and receives Ethernet data frames
This socket is powerful and can listen to all data frames on the NIC.
Yes: receive data frames sent to the local mac
Yes: receive data frames sent from the Local Machine (3rd parameters need to be set to ETH_P_ALL)
Yes: receive data frames not sent to the local mac (NIC must be set to promisc hybrid mode)
There are four protocol types.
ETH_P_IP 0x800 only receives ip-type data frames sent to mac of the Local Machine
ETH_P_ARP 0x806 only accepts arp data frames sent to mac of the Local Machine
ETH_P_RARP 0x8035 only accept rarp data frames sent to mac of the Local Machine
ETH_P_ALL 0x3 receives all types of ip arp rarp data frames sent to the mac of the Local Machine and receives all types of data frames sent from the local machine. (When the hybrid mode is enabled, data frames not sent to the local mac will be received)
Example: capture all IP Packets
# Include <sys/types. h> # include <sys/socket. h> # include <sys/ioctl. h> # include <net/if. h> # include <string. h> # include <stdio. h> # include <stdlib. h> # include <linux/if_packet.h> # include <netinet/if_ether.h> # include <netinet/in. h> typedef struct _ iphdr // defines the IP header {unsigned char h_verlen; // The length of the 4-bit header + the 4-bit IP version number unsigned char tos; // 8-bit service type TOS unsigned short total_len; // 16-bit total length (bytes) unsigned short ident; // 16-bit identity unsig Ned short frag_and_flags; // 3-bit unsigned char ttl; // 8-bit TTL: unsigned char proto; // 8-bit protocol (TCP, UDP, or others) unsigned short checksum; // 16-bit IP header checksum and unsigned int sourceIP; // 32-bit source IP address unsigned int destIP; // 32-bit destination IP address} IP_HEADER; typedef struct _ udphdr // defines the UDP header {unsigned short uh_sport; // The 16-bit source port unsigned short uh_dport; // The 16-bit destination port unsigned int uh_len; // 16-bit UDP Packet Length: unsigned int uh_sum; // 16-bit checksum} UDP_HEADER; Typedef struct _ tcphdr // defines the TCP Header {unsigned short th_sport; // The 16-bit source port unsigned short th_dport; // The 16-bit destination port unsigned int th_seq; // 32-bit serial number unsigned int th_ack; // 32-bit validation number unsigned char th_lenres; // 4-bit header length/6-bit reserved characters unsigned char th_flag; // 6-bit unsigned short th_win; // 16-bit window size unsigned short th_sum; // 16-bit checksum and unsigned short th_urp; // 16-bit emergency data offset} TCP_HEADER; typedef struct _ icmphdr {unsigned char icmp_type; u Nsigned char icmp_code;/* type sub code */unsigned short icmp_cksum; unsigned short icmp_id; unsigned short icmp_seq;/* This is not the std header, but we reserve space for time */unsigned short icmp_timestamp;} ICMP_HEADER; void analyseIP (IP_HEADER * ip); void analyseTCP (TCP_HEADER * tcp); void analyseUDP (UDP_HEADER * udp ); void analyseICMP (ICMP_HEADER * icmp); int main (void) {int sockfd; IP_HEADER * I P; char buf [10240]; ssize_t n;/* capture ip datatewithout ethernet header */if (sockfd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP ))) =-1) {printf ("socket error! \ N "); return 1;} while (1) {n = recv (sockfd, buf, sizeof (buf), 0); if (n =-1) {printf ("recv error! \ N "); break;} else if (n = 0) continue; // the received data does not include the data link frame header ip = (IP_HEADER *) (buf ); analyseIP (ip); size_t iplen = (ip-> h_verlen & 0x0f) * 4; TCP_HEADER * tcp = (TCP_HEADER *) (buf + iplen ); if (ip-> proto = IPPROTO_TCP) {TCP_HEADER * tcp = (TCP_HEADER *) (buf + iplen); analyseTCP (tcp );} else if (ip-> proto = IPPROTO_UDP) {UDP_HEADER * udp = (UDP_HEADER *) (buf + iplen); analyseUDP (udp);} else if (ip-> proto = = IPPROTO_ICMP) {ICMP_HEADER * icmp = (ICMP_HEADER *) (buf + iplen); analyseICMP (icmp);} else if (ip-> proto = IPPROTO_IGMP) {printf ("IGMP ---- \ n");} else {printf ("other protocol! \ N ");} printf (" \ n ");} close (sockfd); return 0;} void analyseIP (IP_HEADER * ip) {unsigned char * p = (unsigned char *) & ip-> sourceIP; printf ("Source IP \ t: % u. % u. % u. % u \ n ", p [0], p [1], p [2], p [3]); p = (unsigned char *) & ip-> destIP; printf ("Destination IP \ t: % u. % u. % u. % u \ n ", p [0], p [1], p [2], p [3]);} void analyseTCP (TCP_HEADER * tcp) {printf ("TCP ----- \ n"); printf ("Source port: % u \ n", ntohs (tcp-> th_sport); printf ("Dest port: % u \ n ", ntohs (tcp-> th_dport);} void analyseUDP (UDP_HEADER * udp) {printf (" UDP ----- \ n "); printf (" Source port: % u \ n ", ntohs (udp-> uh_sport); printf (" Dest port: % u \ n ", ntohs (udp-> uh_dport ));} void analyseICMP (ICMP_HEADER * icmp) {printf ("ICMP ----- \ n"); printf ("type: % u \ n", icmp-> icmp_type ); printf ("sub code: % u \ n", icmp-> icmp_code );}
Reference: http://baike.baidu.com/view/4263346.htm