user-0 提问: 如何获取 tcp header

回复:
user: user-1
content: 用sock试试

user: user-2
content: recv获取到的是应用层的数据得不到tcp header。 个人建议可以使用Libpacp库获得从物理层得到的数据，然后层层解析，就可以得到你想要的tcp header

user: user-3
content: 数据已经到应用层了, 肯定取不到TCP header, 如果想取TCP数据, 需要先将网卡设置成混杂模式, 然后创建PF_PACKET 类型socket, 这样你才能取到tcp的数据.  例子可以参照下面楼我写的demo, 修改一下网卡名TARGET_INTERFACE就可以用了.  #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h>  #include <net/if.h> #include <netinet/in.h> #include <linux/if_ether.h> #include <linux/tcp.h>  #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>   #include <errno.h>  ////////////////////////////////////////////////////////////////////////////// #define TARGET_INTERFACE "eth0"  typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long int uint64_t;  //////////////////////////////////////////////////////////////////////////////  typedef enum _tcpFlag { 	TH_FIN	= 0x01, /* finish, no more data from sender(Last package from sender) */ 	TH_SYN	= 0x02, /* Synchronize sequence numbers */ 	TH_RST	= 0x04, /* Reset the connection */  	TH_PUSH = 0x08, /* Push function, Asks to push the buffered data to the receiving application */  	TH_ACK	= 0x10, /* indicates that the ACKnowledgment field is significant (Sometimes abbreviated by tcpdump as ".") */  	TH_URG	= 0x20, /* ndicates that the URGent pointer field is significant */  	TH_ECE	= 0x40, /* ECN Echo */ 	TH_CWR	= 0x80, /* ECN Cwnd Reduced */ }tcpFlag_t;  /* Structure of an Ethernet header.*/ typedef struct _eth_hdr { 	uint8_t 	dstmac[6];	/* dest mac addr */ 	uint8_t 	srcmac[6];	/* source mac addr */ 	uint16_t	type;		/* Ethernet type */ } eth_hdr;  /* Structure of an internet header, naked of options */ typedef struct _ip_hdr { #ifdef LITTLE_ENDIAN 	uint8_t 	ip_hlen:4;	/* Internet Header Length(means the count of 32bit words) */ 	uint8_t 	ip_ver:4;	/* version */ #else /* LITTLE_ENDIAN */ 	uint8_t 	ip_ver:4;	/* version */ 	uint8_t 	ip_hlen:4;	/* Internet Header Length */ #endif /* LITTLE_ENDIAN */ 	uint8_t 	ip_tos; 	/* type of service */ 	uint16_t	ip_len; 	/* total length */ 	uint16_t	ip_id;		/* identification */ 	uint16_t	ip_off; 	/* fragment offset field */ 	uint8_t 	ip_ttl; 	/* time to live */ 	uint8_t 	ip_p;		/* protocol */ 	uint16_t	ip_sum; 	/* checksum */ 	uint32_t	ip_src; 	/* source address */ 	uint32_t	ip_dst; 	/* dest address */ 	uint8_t 	options[0]; /* ip options */ } ip_hdr;  /* Structure of an TCP header */ typedef struct _tcp_hdr { 	uint16_t	th_sport;	/* source port */ 	uint16_t	th_dport;	/* destination port */ 	uint32_t	th_seq; 	/* sequence number */ 	uint32_t	th_ack; 	/* acknowledgement number */ #ifdef LITTLE_ENDIAN 	uint8_t 	th_rsvd:3;	/* reversed */ 	uint8_t 	th_ns:1;	/* ns flag */ 	uint8_t 	th_oft:4;	/* data offset */ #else  /* LITTLE_ENDIAN */ 	uint8_t 	th_oft:4;	/* data offset */ 	uint8_t 	th_rsvd:3;	/* reversed */ 	uint8_t 	th_ns:1;	/* ns flag */ #endif /* LITTLE_ENDIAN */ 	uint8_t 	th_flags;	/* tcp flag */ 	uint16_t	th_win; 	/* window */ 	uint16_t	th_sum; 	/* checksum */ 	uint16_t	th_urp; 	/* urgent pointer */ 	uint8_t 	options[0]; /* tcp options */ } tcp_hdr;  /* Structure of an TCP session, used for calc relative seq and ack */ typedef struct _tcp_sess_hash { 	struct _tcp_sess_hash* next; 	uint64_t ip; 	uint32_t seq; 	uint32_t ack; 	uint8_t* data; 	uint16_t data_len; } tcp_sess_hash_t;  #define TCP_SESS_HASH_COUNT (1000) static tcp_sess_hash_t tcp_sess_hash_bucket[TCP_SESS_HASH_COUNT];  typedef struct _tcp_show { 	uint8_t direction; 	uint8_t optlen; /* tcp option lenght */ 	uint16_t length; /* real data length */ 	uint32_t seq; /* relative seq */ 	uint32_t ack; /* relative ack */ 	uint32_t abs_seq; /* orgin seq */ 	uint32_t abs_ack; /* orgin ack */ } tcp_show_t;  /* these two macros for print mac address */ #define PNTMAC(mac) \ 	((unsigned char*)&mac)[0], \ 	((unsigned char*)&mac)[1], \ 	((unsigned char*)&mac)[2], \ 	((unsigned char*)&mac)[3], \ 	((unsigned char*)&mac)[4], \ 	((unsigned char*)&mac)[5] #define PNTMAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"  /* these two macros for print ipv4 address */ #define NIPQUAD(addr) \ 	((unsigned char *)&addr)[0], \ 	((unsigned char *)&addr)[1], \ 	((unsigned char *)&addr)[2], \ 	((unsigned char *)&addr)[3] #define NIPQUAD_FMT "%u.%u.%u.%u"  ///////////////////////////////////////////////////////////////////////////// int setPromiscuous(int sock, char* ethx); void procPacket(char* buf, ssize_t len);  ////////////////////////////////////////////////////////////////////////////// int main(void) { 	int sock; 	ssize_t sRet = 0; 	char buf[4096];  	//create a PACKET socket 	sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 	if (sock < 0) { 		perror("socket failed"); 		exit(EXIT_FAILURE); 	}  	//set promiscuous mode,if you are root 	sRet = setPromiscuous(sock, TARGET_INTERFACE); 	if (sRet < 0) { 		close(sock); 		perror("ioctl failed"); 		exit(EXIT_FAILURE); 	}  	//receive packet 	while (1) { 		sRet = recv(sock, buf, sizeof(buf), 0); 		if (sRet < 0) { 			perror("recv failed"); 			break; 		} 		else if(0 == sRet) { 			printf("peer point performed an shutdown\n"); 			break; 		} 		else { 			procPacket(buf, sRet); 		} 	} 	 	close(sock);  	return 0; }   ////////////////////////////////////////////////////////////////////////////// int setPromiscuous(int sock, char* ethx) {	 	uid_t uid = 0; 	struct ifreq ethreq;  	uid = getuid(); 	if (uid != 0) { 		printf("You are not root, can't change %s to Promiscuous Mode\n", ethx); 		return 0; 	}  	strncpy(ethreq.ifr_name, ethx, IFNAMSIZ); 	 	if (ioctl(sock, SIOCGIFFLAGS, ðreq) < 0) { 		return -1; 	} 	 	ethreq.ifr_flags |= IFF_PROMISC; 	if( ioctl(sock, SIOCSIFFLAGS, ðreq) < 0) { 		return -2; 	}  	return 0; }  ////////////////////////////////////////////////////////////////////////////// static char* getTcpFlags(uint8_t flag) { 	static char buf[32];  	memset(buf, 0x00, sizeof(buf)); 	if (flag & TH_FIN)	strcat(buf, "F"); 	if (flag & TH_SYN)	strcat(buf, "S"); 	if (flag & TH_RST)	strcat(buf, "R"); 	if (flag & TH_PUSH)	strcat(buf, "P"); 	if (flag & TH_URG) 	strcat(buf, "U"); 	if (flag & TH_ECE)	strcat(buf, "E"); 	if (flag & TH_CWR)	strcat(buf, "W"); 	if (flag & TH_ACK)	strcat(buf, "."); 	 	return buf; }   static char* getTcpOptions(uint8_t* option, tcp_show_t* show) {  	uint8_t i = 0; 	uint8_t loop = 0; 	int loop_flag = 1; 	uint8_t count = 0; 	uint32_t s,e; 	char tmp[32]; 	static char buf[1024];  	if (show->optlen == 0) { 		return ","; 	}  	memset(buf, 0x00, sizeof(buf)); 	strcpy(buf, ", options ["); 	while (loop_flag) {  		if (loop >= show->optlen) { 			goto FINISH; 		}  		switch (option[loop]) { 		case 0: /* EOL : End of Option List */ 			loop_flag = 0; 			break; 		 		case 1: /* NOP : No-Operation */ 			strcat(buf, "nop,"); 			loop++; 			break; 			 		case 2: /* MSS : Maximum Segment Size */ 			sprintf(tmp, "mss %u,", ntohs(*(uint16_t*)(option + loop + 2))); 			strcat(buf, tmp); 			loop += option[loop + 1]; 			break; 			 		case 3: 			sprintf(tmp, "wscale %u,", (*(uint8_t*)(option + loop + 2))); 			strcat(buf, tmp); 			loop += option[loop + 1]; 			break; 			 		case 4: 			strcat(buf, "sackOK,"); 			loop += option[loop + 1]; 			break; 			 		case 5: 			count = (option[loop + 1] - 2) / 8; 			sprintf(tmp, "sack %d ", count); 			strcat(buf, tmp); 			for (i = 0; i < count; i++) { 				s = ntohl(*(uint32_t*)(option + loop + 2 + i * 8)); 				e = ntohl(*(uint32_t*)(option + loop + 6 + i * 8)); 	 				if (show->direction) { 					sprintf(tmp, "{%u,%u}", s - show->abs_seq, e - show->abs_seq); 				} else { 					sprintf(tmp, "{%u,%u}", s - show->abs_ack, e - show->abs_ack); 				} 				strcat(buf, tmp); 			} 			strcat(buf, ","); 			loop += option[loop + 1]; 			break; 			 		case 8: 			strcat(buf, "TSOPT,"); 			loop += option[loop + 1]; 			break;  		default: 			loop += option[loop + 1]; 			break; 		} 	}  FINISH: 	strcpy(buf + strlen(buf) - 1, "],"); 	return buf; }   int procSession(ip_hdr* ip, tcp_hdr* tcp, tcp_show_t* show) { 	tcp_sess_hash_t* sess = NULL; 	uint64_t ip_combine = 0; 	uint32_t hash = 0; 	 	static char buf[128] = {0};  	show->seq = ntohl(tcp->th_seq); 	show->ack = ntohl(tcp->th_ack); 	 	if (tcp->th_sport > tcp->th_dport) { 		show->direction = 1; 		hash = ((uint32_t)tcp->th_dport << 16 + tcp->th_sport) % TCP_SESS_HASH_COUNT; 		ip_combine = (uint64_t)ip->ip_dst << 32 + ip->ip_src; 	} 	else { 		show->direction = 0; 		hash = ((uint32_t)tcp->th_sport << 16 + tcp->th_dport) % TCP_SESS_HASH_COUNT; 		ip_combine = (uint64_t)ip->ip_src << 32 + ip->ip_dst; 	}  	for (sess = &tcp_sess_hash_bucket[hash]; sess->next; sess = sess->next) { 		if (sess->ip == ip_combine) { 			break; 		} 	}  	if (!sess->next || (tcp->th_flags & TH_SYN)) { 		if (!sess->next) { 			sess->next = (tcp_sess_hash_t*)calloc(1, sizeof(tcp_sess_hash_t)); 			if (!sess->next) { 				printf("<ERROR> calloc failed\n"); 				return -1; 			} 		}  		sess->ip = ip_combine; 		if (show->direction) { 			sess->seq = show->ack - 1; 			sess->ack = show->seq; 		} else { 			sess->seq = show->seq; 			sess->ack = show->ack - 1; 		} 	} else { 		if (show->direction) { 			show->seq -= sess->ack; 			show->ack -= sess->seq; 		} else { 			show->seq -= sess->seq; 			show->ack -= sess->ack; 		} 	}  	show->length = ntohs(ip->ip_len)- (ip->ip_hlen + tcp->th_oft) * 4; 	show->optlen = (tcp->th_oft - 5) * 4; 	show->abs_ack = sess->ack; 	show->abs_seq = sess->seq;  	sess->data_len += show->length;  	return 0; }  void procPacket(char* buf, ssize_t len) { 	eth_hdr* eth = (eth_hdr*)buf; 	ip_hdr* ip = (ip_hdr*)(buf + sizeof(eth_hdr)); 	tcp_hdr* tcp = (tcp_hdr*)((void*)ip + sizeof(ip_hdr)); 	tcp_show_t show;   	/* just process the IPv4 TCP packet */ 	if ((ip->ip_p != IPPROTO_TCP) || (ip->ip_ver != 4)){ 		return; 	} 	procSession(ip, tcp, &show); 	printf("[TCP] "NIPQUAD_FMT".%d > "NIPQUAD_FMT".%d: Flags [%s], seq %u, ack %u, win:%u%s length %u\n", \ 		NIPQUAD(ip->ip_src), ntohs(tcp->th_sport), \ 		NIPQUAD(ip->ip_dst), ntohs(tcp->th_dport), \ 		getTcpFlags(tcp->th_flags),  \ 		show.seq, show.ack, ntohs(tcp->th_win), \ 		getTcpOptions(tcp->options, &show), \ 		show.length); }

user: user-0
content: 顶.............