我正在编写一个程序,以便从pcap中的标题中获取某些信息。我不确定我是否做得对。它适用于我教授的所有测试,但是,我需要注意隐藏的测试。这是我不确定的TCP标志。它在索引47中工作,但不知道为什么,应该是46.(以太网报头(14)+ IPv4报头(20)+ TCP报头(13)-1中的第13个字节(考虑从0开始的数组)= 46)。这是一个侥幸,它在现场47工作?
这是我的代码:
#include <pcap/pcap.h>
#include <stdlib.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
/*
* Most of this file is the background functionality to open a capture file or to
* open an inteface for a live capture. You can ignore all this unless you are
* interested in an example of how pcap works.
*
* To use the file, simply insert your code in the "Put your code here" section and
* create a Makefile for compilation.
*/
/* Maximum time that the OS will buffer packets before giving them to your program. */
#define MAX_BUFFER_TIME_MS (300)
/* Maximum time the program will wait for a packet during live capture.
* Measured in MAX_BUFFER_TIME_MS units. Program closes when it expires. */
#define MAX_IDLE_TIME 100 /* 100*MAX_BUFFER_TIME_MS idle time at most */
/* Function that creates the structures necessary to perform a packet capture and
* determines capture source depending on arguments. Function will terminate the
* program on error, so return value always valid. */
pcap_t* setup_capture(int argc, char *argv[], char *use_file);
/* Cleanup the state of the capture. */
void cleanup_capture(pcap_t *handle);
/* Check for abnormal conditions during capture.
* 1 returned if a packet is ready, 0 if a packet is not available.
* Terminates program if an unrecoverable error occurs. */
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file);
int main(int argc, char *argv[]) {
pcap_t *pcap_handle = NULL; /* Handle for PCAP library */
struct pcap_pkthdr *packet_hdr = NULL; /* Packet header from PCAP */
const u_char *packet_data = NULL; /* Packet data from PCAP */
int ret = 0; /* Return value from library calls */
char use_file = 0; /* Flag to use file or live capture */
/* Setup the capture and get the valid handle. */
pcap_handle = setup_capture(argc, argv, &use_file);
/* Loop through all the packets in the trace file.
* ret will equal -2 when the trace file ends.
* ret will never equal -2 for a live capture. */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
struct ether_header
{
u_int8_t ether_dhost[6]; /* destination eth addr */
u_int8_t ether_shost[6]; /* source ether addr */
u_int16_t ether_type; /* packet type ID field */
};
struct ether_header *eptr;
char src[INET_ADDRSTRLEN];
char dst[INET_ADDRSTRLEN];
char src6[INET6_ADDRSTRLEN];
char dst6[INET6_ADDRSTRLEN];
while( ret != -2 ) {
if( valid_capture(ret, pcap_handle, use_file) ){
eptr = (struct ether_header *) packet_data;
fprintf(stdout,"%s -> ",ether_ntoa((const struct ether_addr *)&eptr->ether_shost));
fprintf(stdout,"%s \n",ether_ntoa((const struct ether_addr *)&eptr->ether_dhost));
if(packet_data[12] == 0x08 && packet_data[13] == 0x00)
{
printf(" [IPv4] ");
fprintf(stdout,"%s -> ", inet_ntop(AF_INET,(const void *)packet_data+26,src,INET_ADDRSTRLEN));
fprintf(stdout,"%s\n", inet_ntop(AF_INET,(const void *)packet_data+30,dst,INET_ADDRSTRLEN));
if(packet_data[23] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d ",packet_data[36]*256+packet_data[37]);
// printf("%02X ",packet_data[47]); //print out value of flag;
if(packet_data[47] & (1!=0))
printf("FIN \n");
else if((packet_data[47] == 0x02 || packet_data[47] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[23] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d \n",packet_data[36]*256+packet_data[37]);
}
else{
printf(" [%d] \n",packet_data[23]);
}
}
else if(packet_data[12] == 0x86 && packet_data[13] == 0xdd)
{
printf(" [IPv6] ");
printf("%s -> ", inet_ntop(AF_INET6, (const void *)packet_data+22, src6, INET6_ADDRSTRLEN));
printf("%s \n", inet_ntop(AF_INET6, (const void *)packet_data+38, dst6, INET6_ADDRSTRLEN));
if(packet_data[20] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d ",packet_data[56]*256+packet_data[57]);
// printf("%02X ",packet_data[67]); //print out value of flag
if(packet_data[67] & (1!=0))
printf("FIN \n");
else if((packet_data[67] == 0x02 || packet_data[67] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[20] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d \n",packet_data[56]*256+packet_data[57]);
}
else{
printf(" [%d] \n",packet_data[20]);
}
} else {
fprintf(stdout," [%d] \n",ntohs(eptr->ether_type));
}
}
/* Get the next packet */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
}
cleanup_capture(pcap_handle);
return 0;
}
pcap_t* setup_capture(int argc, char *argv[], char *use_file) {
char *trace_file = NULL; /* Trace file to process */
pcap_t *pcap_handle = NULL; /* Handle for PCAP library to return */
char pcap_buff[PCAP_ERRBUF_SIZE]; /* Error buffer used by pcap functions */
char *dev_name = NULL; /* Device name for live capture */
/* Check command line arguments */
if( argc > 2 ) {
fprintf(stderr, "Usage: %s [trace_file]\n", argv[0]);
exit(-1);
}
else if( argc > 1 ){
*use_file = 1;
trace_file = argv[1];
}
else {
*use_file = 0;
}
/* Open the trace file, if appropriate */
if( *use_file ){
pcap_handle = pcap_open_offline(trace_file, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening trace file \"%s\": %s\n", trace_file, pcap_buff);
exit(-1);
}
}
/* Lookup and open the default device if trace file not used */
else{
dev_name = pcap_lookupdev(pcap_buff);
if( dev_name == NULL ){
fprintf(stderr, "Error finding default capture device: %s\n", pcap_buff);
exit(-1);
}
/* Use buffer length as indication of warning, per pcap_open_live(3). */
pcap_buff[0] = 0;
pcap_handle = pcap_open_live(dev_name, BUFSIZ, 1, MAX_BUFFER_TIME_MS, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening capture device %s: %s\n", dev_name, pcap_buff);
exit(-1);
}
if( pcap_buff[0] != 0 ) {
printf("Warning: %s\n", pcap_buff);
}
printf("Capturing on interface '%s'\n", dev_name);
}
return pcap_handle;
}
void cleanup_capture(pcap_t *handle) {
/* Close the trace file or device */
pcap_close(handle);
}
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file) {
static int idle_count = 0; /* Count of idle periods with no packets */
char ret = 0; /* Return value, invalid by default */
/* A general error occurred */
if( return_value == -1 ) {
pcap_perror(pcap_handle, "Error processing packet:");
cleanup_capture(pcap_handle);
exit(-1);
}
/* Timeout occured for a live packet capture */
else if( (return_value == 0) && (use_file == 0) ){
if( ++idle_count >= MAX_IDLE_TIME ){
printf("Timeout waiting for additional packets on interface\n");
cleanup_capture(pcap_handle);
exit(0);
}
}
/* Unexpected/unknown return value */
else if( return_value != 1 ) {
fprintf(stderr, "Unexpected return value (%i) from pcap_next_ex()\n", return_value);
cleanup_capture(pcap_handle);
exit(-1);
}
/* Normal operation, packet arrived */
else{
idle_count = 0;
ret = 1;
}
return ret;
}
这里有几个样本打印输出:(左边是教授的结果,右边是我的,我有额外的打印输出来查看阵列中那个位置的内容)。感谢
0:0:86:5:80:da -> 0:60:97:7:69:ea 0:0:86:5:80:da -> 0:60:97:7:69:ea
[IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e [IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e
[TCP] 1022 -> 22 SYN | [TCP] 1022 -> 22 02 SYN
0:60:97:7:69:ea -> 0:0:86:5:80:da 0:60:97:7:69:ea -> 0:0:86:5:80:da
[IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da [IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da
[TCP] 22 -> 1022 SYN | [TCP] 22 -> 1022 12 SYN
答案 0 :(得分:1)
以下是如何找到TCP标志:
如果我们假设我们正在讨论以太网,那么以太网帧头将是14个字节:一个6字节的目标,后跟一个6字节的源,然后是一个2字节的以太网类型(对于802.3 / SNAP / Ethernet II,这是最有可能的)
如果从帧开头偏移12/13处的Ethertype包含0x0800,则表示您正在查看TCP / IP。
if(frame[12]==0x08 && frame[13]==0x00) { /* IP packet inside */ }
假设你有一个IP Ethertype,下一个字节将包含两个半字节大小的字段:IP版本号(可能是你的0x40),然后是IP头长度(可能是0x05)。把那些小吃放在一起,你就会有0x45坐在那个领域。检查该字段是非常重要的。你可以像这样掩盖上半字节:
ihl = frame[14]&0x0f;
获取IP头长度字段。此号码将告诉您在哪里可以找到下一个协议层的标头。通常你会有一个5(20字节标题),但如果有IP选项,这个数字会更大。让我们从这里得到这个数字并计算:
embedded_protocol_header = frame[ihl * 4];
接下来,您应该验证您确实拥有TCP数据包。这可以通过检查IP头中的字节偏移9来验证:
ip_header_start = frame[14];
embedded_protocol = ip_header_start[9];
if(embedded_protocol == 6) { tcp_header = embedded_protocol_header; }
现在我们知道它是TCP,我们可以获取TCP标志。这些将在TCP标题中的偏移量为13:
tcp_flags = tcp_header[13];
要检查SYN / ACK位,您可以屏蔽其他所有内容:
synack = tcp_flags & 0x3f;
您现在可以检查它是否是SYN ACK:
if(synack == 0x12) { /* SYN and ACK were set */
您可能想知道上面的0x3f掩码。原因是如果系统支持ECN,则TCP标志中的两个高位用于ECN。如果支持,则在这些位中的3次握手期间以及IP报头的TOS字节中的两个低位比特(差分服务字节)中发生ECN协商。而不是处理所有可能的情况,最简单的方法是完全关闭这些位并检查您是否仍然有SYN和ACK。