前言
今天在分析一个大包时,原始包是随便抓下来的,只有一部分包需要分析,而且怀疑分析时丢包了。
这时,想从原始的离线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