pcap_file_save_as_by_condition

前言

今天在分析一个大包时,原始包是随便抓下来的,只有一部分包需要分析,而且怀疑分析时丢包了。
这时,想从原始的离线pcap文件中,按照自己设定的条件另存出一个pcap文件,里面只有自己关心的包信息。
以前就想写个这样的工具,可是没动手…,今天要用到这样的功能时,还得现写一个。
自己有个小想法,就动手搞。整出来以后,如果以后要用到,那要方便很多。

工程下载点

src_pcap_file_save_as_by_condition.7z

工程运行效果

================================================================================
[test_pcap_save_as_by_condition][1.0.0.1][2018-11-05 16:09]
================================================================================
psz_src_pcap_file = /var/log/test.pcap
psz_dst_pcap_file_save_to = /var/log/test_save_to.pcap
psz_capture_filter_condition = tcp port 5432 and host 192.168.16.128
if need stop grab packet, please press 'q'
>> thread_proc_grab_packet
pcap_lib_version = libpcap version 1.7.4
ok : pcap_open_offline(/var/log/test.pcap)
pcap version is 2.4
ok : is Ethernet support
ok : pcap_compile(tcp port 5432 and host 192.168.16.128)
ok : pcap_setfilter(tcp port 5432 and host 192.168.16.128)
pcap now ...
ok : open dump file : /var/log/test_save_to.pcap
dump... /var/log/test_save_to.pcap [106]bytes
dump... /var/log/test_save_to.pcap [188]bytes
dump... /var/log/test_save_to.pcap [258]bytes

...

pcap_loop exec over = 0, 
dump... /var/log/test_save_to.pcap [461155206]Bytes
close dump file : /var/log/test_save_to.pcap
<< thread_proc_grab_packet
if need stop grab packet, please press 'q'
q
bye
THE END

工程预览

// @file \pcap_file_save_as_by_condition\src\main.cpp
// @brief 

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <string>
#include <iostream>

#include "const_define.h"
#include "pcap.h"

#define PROG_NAME "test_pcap_save_as_by_condition"
#define PROG_VER "1.0.0.1"
#define PROG_CODE_LAST_TIME "2018-11-05 16:09"

#ifndef MAX_PATH
#define MAX_PATH 260
#endif // #ifndef MAX_PATH

#ifndef MAX_FILTER_LEN
#define MAX_FILTER_LEN 260
#endif // #ifndef MAX_FILTER_LEN

#define CONTEXT_SAVE_PCAP_PACKET_VERSION_V1 1000

// context : dump pcap packet to file
typedef struct _tag_context_save_pcap_packet_v1 {
	char sz_src_pcap_file[MAX_PATH]; // file base name, e.g. pcap_
	char sz_dst_pcap_file_save_to[MAX_PATH]; // file base name, e.g. pcap_1.pcap

	// tcp port 23 and host 10.0.0.5
	// tcp port 5432 and host 192.168.16.128
	// host 192.168.16.128 and port 5432
	char sz_capture_filter[MAX_FILTER_LEN];

	pcap_t* h_pcap; // the device pcap handle
	pcap_dumper_t* p_dumper; // dump file handle
	int i_max_packet_recv_by_pcap; // for packet recv number by pcap_loop

	bool b_cmd_quit; // quit command

	_tag_context_save_pcap_packet_v1() {
		clear();
	}
	
	void clear()
	{
		memset(sz_src_pcap_file, 0, sizeof(sz_src_pcap_file));
		memset(sz_dst_pcap_file_save_to, 0, sizeof(sz_dst_pcap_file_save_to));
		memset(sz_capture_filter, 0, sizeof(sz_capture_filter));
		
		h_pcap = NULL;
		p_dumper = NULL;
		i_max_packet_recv_by_pcap = -1;
		
		b_cmd_quit = false;
	}
} TAG_CONTEXT_SAVE_PCAP_PACKET_V1;

typedef struct _tag_context_save_pcap_packet {
	int iTagVer; // this version number to determine below member
	TAG_CONTEXT_SAVE_PCAP_PACKET_V1 v1;

	_tag_context_save_pcap_packet()
	{
		iTagVer = CONTEXT_SAVE_PCAP_PACKET_VERSION_V1;
		v1.clear();
	}
} TAG_CONTEXT_SAVE_PCAP_PACKET;

void* thread_proc_grab_packet(void* pctx);

void callback_pcap_handler(
	u_char *user,
	const struct pcap_pkthdr *h,
	const u_char *bytes);

int main(int argc, char* argv[])
{
	TAG_CONTEXT_SAVE_PCAP_PACKET context_save_pcap_packet;
	pthread_t pthread_grab_packet = 0;
	char c_input = '\0';

	const char* psz_src_pcap_file = NULL;
	const char* psz_dst_pcap_file_save_to = NULL;
	const char* psz_capture_filter_condition = NULL;

	MYLOG_D("================================================================================\n");
	MYLOG_D("[%s][%s][%s]\n", PROG_NAME, PROG_VER, PROG_CODE_LAST_TIME);
	MYLOG_D("================================================================================\n");

	do {
		if (argc != 4) {
			MYLOG_D("usage : %s '%s' '%s' '%s'\n", PROG_NAME, "src_pacp_file", "dst_pcap_file_save_to", "capture_filter_condition");		
			MYLOG_D("%s\n", 
				"e.g. ./test_pcap_save_as_by_condition /var/log/test.pcap /var/log/test_save_to.pcap 'tcp port 5432 and host 192.168.16.128'");
		
			break;
		}

		psz_src_pcap_file = argv[1];
		psz_dst_pcap_file_save_to = argv[2];
		psz_capture_filter_condition = argv[3];

		MYLOG_D("psz_src_pcap_file = %s\n", psz_src_pcap_file);
		MYLOG_D("psz_dst_pcap_file_save_to = %s\n", psz_dst_pcap_file_save_to);
		MYLOG_D("psz_capture_filter_condition = %s\n", psz_capture_filter_condition);

		// initial context
		context_save_pcap_packet.v1.clear();
		context_save_pcap_packet.v1.i_max_packet_recv_by_pcap = -1;
		strcpy(context_save_pcap_packet.v1.sz_src_pcap_file, psz_src_pcap_file);
		strcpy(context_save_pcap_packet.v1.sz_dst_pcap_file_save_to , psz_dst_pcap_file_save_to);
		strcpy(context_save_pcap_packet.v1.sz_capture_filter , psz_capture_filter_condition);

		pthread_create(&pthread_grab_packet, NULL, thread_proc_grab_packet, (void*)&context_save_pcap_packet);

		do {
			MYLOG_D("if need stop grab packet, please press 'q'\n");
			std::cin >> c_input;
			if ('q' == c_input) {
				MYLOG_D("bye\n");
				break;
			}
		} while (1);

		context_save_pcap_packet.v1.b_cmd_quit = true;
		if (NULL != context_save_pcap_packet.v1.h_pcap) {
			pcap_breakloop(context_save_pcap_packet.v1.h_pcap);
		}
		pthread_join(pthread_grab_packet, NULL);
		pthread_grab_packet = 0;
	} while (0);
	
    MYLOG_D("THE END\n");
    return EXIT_SUCCESS;
}

/** run result
================================================================================
[test_pcap_save_as_by_condition][1.0.0.1][2018-11-05 16:09]
================================================================================
psz_src_pcap_file = /var/log/test.pcap
psz_dst_pcap_file_save_to = /var/log/test_save_to.pcap
psz_capture_filter_condition = tcp port 5432 and host 192.168.16.128
if need stop grab packet, please press 'q'
>> thread_proc_grab_packet
pcap_lib_version = libpcap version 1.7.4
ok : pcap_open_offline(/var/log/test.pcap)
pcap version is 2.4
ok : is Ethernet support
ok : pcap_compile(tcp port 5432 and host 192.168.16.128)
ok : pcap_setfilter(tcp port 5432 and host 192.168.16.128)
pcap now ...
ok : open dump file : /var/log/test_save_to.pcap
dump... /var/log/test_save_to.pcap [106]bytes
dump... /var/log/test_save_to.pcap [188]bytes
dump... /var/log/test_save_to.pcap [258]bytes

...

pcap_loop exec over = 0, 
dump... /var/log/test_save_to.pcap [461155206]Bytes
close dump file : /var/log/test_save_to.pcap
<< thread_proc_grab_packet
if need stop grab packet, please press 'q'
q
bye
THE END
*/

void* thread_proc_grab_packet(void* pctx)
{
	int iRc = 0;
    bpf_u_int32 net = 0;        /* The IP of our sniffing device */
    char errbuf[PCAP_ERRBUF_SIZE];
    int i_pcap_major_ver = 0;
    int i_pcap_minor_ver = 0;
    struct bpf_program my_bpf_program;
    bool b_valid_bpf = false;
	std::string str;
	TAG_CONTEXT_SAVE_PCAP_PACKET* p_context = NULL;

	MYLOG_D(">> thread_proc_grab_packet\n");
	do {
		if (NULL == pctx) {
			MYLOG_D("context can't be NULL\n");
			break;
		}

		p_context = (TAG_CONTEXT_SAVE_PCAP_PACKET*)pctx;
		str = pcap_lib_version();
		MYLOG_D("pcap_lib_version = %s\n", str.c_str());
		// pcap_lib_version = libpcap version 1.7.4

		// open offline pcap file
		p_context->v1.h_pcap = pcap_open_offline(p_context->v1.sz_src_pcap_file, errbuf);
		if (NULL == p_context->v1.h_pcap) {
			MYLOG_E("error : pcap_open_offline(%s, %s)\n", p_context->v1.sz_src_pcap_file, errbuf);
			break;
		}
		
		MYLOG_E("ok : pcap_open_offline(%s)\n", p_context->v1.sz_src_pcap_file);
	
		i_pcap_major_ver = pcap_major_version(p_context->v1.h_pcap);
		i_pcap_minor_ver = pcap_minor_version(p_context->v1.h_pcap);
	
		// pcap version is 2.4
		MYLOG_D("pcap version is %d.%d\n", i_pcap_major_ver, i_pcap_minor_ver);
		
		if (pcap_datalink(p_context->v1.h_pcap) != DLT_EN10MB) {
			MYLOG_E("pcap Device doesn't provide Ethernet headers - not supported\n");
			break;
		}
		MYLOG_D("ok : is Ethernet support\n");
	
		// compile BPF
		if (pcap_compile(p_context->v1.h_pcap, &my_bpf_program, p_context->v1.sz_capture_filter, 0, net) == -1) {
			MYLOG_D("Couldn't parse filter [%s]: %s\n", 
				p_context->v1.sz_capture_filter, 
				pcap_geterr(p_context->v1.h_pcap));
			
			break;
		}
		
		b_valid_bpf = true;
		MYLOG_D("ok : pcap_compile(%s)\n", p_context->v1.sz_capture_filter);
	
		// set BPF filter
		if (pcap_setfilter(p_context->v1.h_pcap, &my_bpf_program) == -1) {
			MYLOG_E("Couldn't install filter %s: %s\n", 
				p_context->v1.sz_capture_filter, 
				pcap_geterr(p_context->v1.h_pcap));
			break;
		}
		MYLOG_D("ok : pcap_setfilter(%s)\n", p_context->v1.sz_capture_filter);
	
		MYLOG_D("pcap now ...\n");
		
		// pcap_dispatch only entry callback once
		// pcap_loop can entry callback per packet/1 times :)
		iRc = pcap_loop(
			p_context->v1.h_pcap, 
			p_context->v1.i_max_packet_recv_by_pcap, // packet number to capture
			callback_pcap_handler, // call back function
			(u_char*)p_context); // user data, my pcap opt context
			
		MYLOG_D("pcap_loop exec over = %d, %s\n", iRc, pcap_geterr(p_context->v1.h_pcap));
		if (NULL != p_context->v1.p_dumper) {
			MYLOG_D("dump... %s [%ld]Bytes\n",
				p_context->v1.sz_dst_pcap_file_save_to, 
				pcap_dump_ftell(p_context->v1.p_dumper));

			pcap_dump_flush(p_context->v1.p_dumper);
			pcap_dump_close(p_context->v1.p_dumper);

			MYLOG_D("close dump file : %s\n", 
				p_context->v1.sz_dst_pcap_file_save_to);

			p_context->v1.p_dumper = NULL;
		}
	} while (0);
	
	if (b_valid_bpf) {
		b_valid_bpf = false;
		pcap_freecode(&my_bpf_program);
	}
	
	if (NULL != p_context->v1.h_pcap) {
		pcap_close(p_context->v1.h_pcap);
		p_context->v1.h_pcap = NULL;
	}

	MYLOG_D("<< thread_proc_grab_packet\n");
	MYLOG_D("if need stop grab packet, please press 'q'\n");

	return (void*)NULL;
}

void callback_pcap_handler(
	u_char *user,
	const struct pcap_pkthdr *h,
	const u_char *bytes)
{
	// if pcap_dispatch grab 6 packet, only entry here once
	TAG_CONTEXT_SAVE_PCAP_PACKET* p_context = NULL;

	do {
		if (NULL == user) {
			break;
		}

		p_context = (TAG_CONTEXT_SAVE_PCAP_PACKET*)user;
		if (CONTEXT_SAVE_PCAP_PACKET_VERSION_V1 != p_context->iTagVer) {
			break;
		}

		if ((NULL == p_context->v1.p_dumper) && (NULL != p_context->v1.h_pcap)) {
			p_context->v1.p_dumper = pcap_dump_open(p_context->v1.h_pcap, p_context->v1.sz_dst_pcap_file_save_to);
			MYLOG_D("%s : open dump file : %s\n", 
				(NULL != p_context->v1.p_dumper) ? "ok" : "failed", 
				p_context->v1.sz_dst_pcap_file_save_to);
		}

		if (NULL != p_context->v1.p_dumper) {
			pcap_dump((u_char*)p_context->v1.p_dumper, h, bytes);
			
			MYLOG_D("dump... %s [%ld]bytes\n",
				p_context->v1.sz_dst_pcap_file_save_to, 
				pcap_dump_ftell(p_context->v1.p_dumper));
		}
	} while (0);
}


// @file const_define.h

#if not defined(__CONST_DEFINE_H__)
#define __CONST_DEFINE_H__

#include <string.h>
#include <stdint.h>
#include <syslog.h>

#include <string>
#include <list>

typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned long long ull;

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
    if (NULL != (p)) { \
        delete (p); \
        (p) = NULL; \
    }
#endif // #ifndef SAFE_DELETE

#ifndef SAFE_DELETE_ARY
#define SAFE_DELETE_ARY(p) \
    if (NULL != (p)) { \
        delete[] (p); \
        (p) = NULL; \
    }
#endif // #ifndef SAFE_DELETE

#define TITLE_LINE80 "================================================================================"
#define LINE80 "--------------------------------------------------------------------------------"

#if not defined(MYLOG_D)

// 为了用gdb调试时, 不被printf干扰, 在调试时, 定义USE_SYSLOG, 发行时去掉定义USE_SYSLOG
// #define USE_SYSLOG

#ifdef USE_SYSLOG
#define MYLOG_V(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_V", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);

#define MYLOG_D(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_D", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);

#define MYLOG_I(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_I", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);

#define MYLOG_W(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_W", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);

#define MYLOG_E(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_E", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);

#define MYLOG_F(fmt, ...) \
	syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MYLOG_F", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
#else // #ifdef USE_SYSLOG
#define MYLOG_V printf
#define MYLOG_D printf
#define MYLOG_I printf
#define MYLOG_W printf
#define MYLOG_E printf
#define MYLOG_F printf
#endif // #ifdef USE_SYSLOG

#endif // #if not defined(MYLOG_D)

#define MAX_MSG_LENGTH (1024 * 4)

#endif // #if not defined(__CONST_DEFINE_H__)


# ==============================================================================
# @file makefile
# ==============================================================================
# @note 
# howto build project
# 		make BIN_NAME="bin_name_by_you_want" rebuild
# makefile code need tab key not sapce key

MY_MAKE_FILE_PATH_NAME = $(MAKEFILE_LIST)

# macro from Makefile command line
# BIN_NAME

# macro to C project
MAKE_FILE_MACRO__BIN_NAME="make_file_macro__bin_name"

# var define on Makefile
BIN = output_not_give_bin_name
IS_BUILD_TYPE_VALID = 0

ifdef BIN_NAME
	IS_BUILD_TYPE_VALID = 1
	BIN = $(BIN_NAME)
	MAKE_FILE_MACRO__BIN_NAME=$(BIN_NAME)
else
	IS_BUILD_TYPE_VALID = 0
endif

LINE80 = --------------------------------------------------------------------------------

# CC = g++ -std=c++98
CC = g++

# -Werror is "warning as error"
CFLAGS = -Wall -Werror -g

INC = -I. -I../third_party/libpcap/inc/ -I../third_party/libpcap/inc/pcap/

# libpcap component is link to ../third_party/libpcap/lib/libpcap.a
# when ldd after rebuild, can't see any libpcap*.so
LIBPATH = -L. -L/usr/lib/ -L/usr/local/lib/ -L../third_party/libpcap/lib/

ifeq (1, $(IS_BUILD_TYPE_VALID))
	LIBS = -lstdc++ -pthread -lpcap
else
	LIBS =
endif

DEPEND_CODE_DIR = ../common/ \

DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)

ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)

SUB_CODE_DIR = ./empty_dir
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)

.PHONY: help
help:
	clear
	@echo "usage:"
	@echo
	@echo "build project by given bin name"
	@echo "make BIN_NAME=\"bin_name_by_you_want\" rebuild"
	@echo

.PHONY: clean
clean:
	clear

	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo

	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo

	@echo
	@echo
	@echo
	@echo
	@echo

	@echo "make clean begin"
	@echo $(LINE80)

	@echo "@file $(MY_MAKE_FILE_PATH_NAME)"
	@echo "IS_BUILD_TYPE_VALID = $(IS_BUILD_TYPE_VALID)"
	@echo "BIN = $(BIN)"

	@echo $(LINE80)

	rm -f $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)

ifeq (1, $(IS_BUILD_TYPE_VALID))
	rm -f ./$(BIN)
endif

	@echo "make clean over"

.PHONY: all
all:$(BIN)
	@echo $(LINE80)
	@echo make all
	chmod 777 ./$(BIN)
	find . -name "$(BIN)"

$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
	$(CC) $(CFLAGS) -o $@ $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)

.cpp.o:
	$(CC) -c $(CFLAGS) -DMAKE_FILE_MACRO__BIN_NAME="\"$(MAKE_FILE_MACRO__BIN_NAME)\"" $^ -o $@ $(INC) $(LIBPATH) $(LIBS)

.PHONY: rebuild
rebuild:
	make -f $(MY_MAKE_FILE_PATH_NAME) clean

ifeq (1, $(IS_BUILD_TYPE_VALID))
	@echo $(LINE80)
	make -f $(MY_MAKE_FILE_PATH_NAME) all
	chmod 775 ./$(BIN)
	ldd ./$(BIN)
else
	@echo $(LINE80)
	@echo "error : Makefile command line input error, please see help"	
	@echo "please run => make help"	
	@echo $(LINE80)
endif


#!/bin/bash
# ==============================================================================
# @file build_all_project.sh
# ==============================================================================

make BIN_NAME="test_pcap_save_as_by_condition" rebuild


猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/83753666