Skip to content

Commit

Permalink
Merge pull request #4 from idofront/feature/#3_json_serializer
Browse files Browse the repository at this point in the history
JsonSerializer 実装経過
  • Loading branch information
idofront authored Aug 16, 2024
2 parents 8b3fd6c + 7773247 commit 0467424
Show file tree
Hide file tree
Showing 51 changed files with 1,084 additions and 502 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.pcap
*.json
build/
bin/
include/
3 changes: 2 additions & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
],
"defines": [],
"compilerPath": "/usr/bin/clang++",
"cStandard": "gnu17",
"cStandard": "gnu20",
"cppStandard": "gnu++20",
"std": "c++20",
"intelliSenseMode": "gcc-x64"
}
],
Expand Down
9 changes: 8 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/PacketBuilder",
"args": [],
"args": [
"-l",
"debug",
"-i",
"sample.json",
"-o",
"output.pcap"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
Expand Down
5 changes: 4 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@
"--target",
"clean"
],
"group": "build",
"group": {
"kind": "build",
"isDefault": true,
},
"problemMatcher": [
"$gcc"
],
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.10)
project(Builder)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# proj 以下の CMakeLists.txt が存在するディレクトリをサブプロジェクトとして追加
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
# PacketBuilder

## Install

```bash
apt install \
libpcap-dev \
libspdlog-dev \
nlohmann-json3-dev \
libboost-all-dev \
libfmt-dev
```
92 changes: 58 additions & 34 deletions main/PacketBuilder.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#include <EthernetHeader.hpp>
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE

#include <Binary.hpp>
#include <EntityService.hpp>
#include <Ethernet.hpp>
#include <Ipv4.hpp>
#include <PacketBuilder.hpp>
#include <PcapFileHeader.hpp>
#include <PcapPacketHeader.hpp>
#include <Stackable.hpp>
#include <Udp.hpp>
#include <Utility/Utility.hpp>
#include <arpa/inet.h>
#include <cmdline.h>
#include <cstring>
Expand All @@ -30,73 +33,94 @@ int main(int argc, char **argv)
return 1;
}

spdlog::set_level(options.LogLevel());
spdlog::set_level(options.LogLevel.Value());

std::vector<PacketBuilder::StackablePtr> stackables;
const auto isProcessingInputFile = true;
if (isProcessingInputFile)
{
auto inputFilename = options.InputFilename.Value();
auto inputStream = std::ifstream(inputFilename);
auto inputJson = nlohmann::json::parse(inputStream);
auto entity = PacketEntity::EntityService::FromJson(inputJson);
}

auto ether = PacketBuilder::EthernetHeaderPtr(new PacketBuilder::EthernetHeader());
auto ipv4 = PacketBuilder::Ipv4Ptr(new PacketBuilder::Ipv4());
auto udp = PacketBuilder::UdpPtr(new PacketBuilder::Udp());
auto payload = PacketBuilder::StackablePtr(new PacketBuilder::Stackable(32));
std::vector<Packet::StackablePtr> stackables;

auto ether = Packet::EthernetPtr(new Packet::Ethernet());
auto ipv4 = Packet::Ipv4Ptr(new Packet::Ipv4());
auto udp = Packet::UdpPtr(new Packet::Udp());
auto payload = Packet::BinaryPtr(new Packet::Binary(4));

// Ether header
{
ether->DestinationMac((uint8_t *)"\x00\x00\x00\x00\x00\x00");
ether->SourceMac((uint8_t *)"\x00\x00\x00\x00\x00\x00");
ether->EthernetType(ETHERTYPE_IP);
ether->DestinationMac.Value((uint8_t *)"\x00\x00\x00\x00\x00\x00");
ether->SourceMac.Value((uint8_t *)"\x00\x00\x00\x00\x00\x00");
ether->EthernetType.Value(ETHERTYPE_IP);
}
// IP header
{
struct sockaddr_in sourceAddress;
struct sockaddr_in destinationAddress;
inet_pton(AF_INET, "192.168.0.1", &(sourceAddress.sin_addr));
inet_pton(AF_INET, "172.16.0.1", &(destinationAddress.sin_addr));
ipv4->SourceIp(sourceAddress);
ipv4->DestinationIp(destinationAddress);
ipv4->SourceAddress.Value(sourceAddress);
ipv4->DestinationAddress.Value(destinationAddress);
}

// UDP header
{
udp->SourcePort(60000);
udp->DestinationPort(40000);
udp->DestinationPort(50000);
}

std::memset(payload->DataArray().get(), 0, 10);
std::memset(payload->DataArray().get(), 0, payload->Length());

udp->Stack(payload);
ipv4->Stack(udp);
ether->Stack(ipv4);
udp->Stack.Value(payload);
ipv4->Stack.Value(udp);
ether->Stack.Value(ipv4);

for (auto i = 0; i < 5; i++)
for (auto i = 0; i < 1; i++)
{
auto composed = PacketBuilder::Stackable::Compose(ether);
stackables.push_back(composed);
// Compose しないと意図せず値が変わってしまうが,動作確認用に Compose せず stackables に追加する.
// 必要に応じて Compose する.
if (false)
{
auto composed = Packet::Stackable::Compose(ether);
stackables.push_back(composed);
}
else
{
stackables.push_back(ether);
}
}

if (options.OutputFileType() == FileType::None)
if (options.OutputFileType.Value() == FileType::None)
{
return 0;
}

if (options.OutputFileType() == FileType::Pcap)
if (options.OutputFileType.Value() == FileType::Pcap)
{
SPDLOG_DEBUG("Output to pcap file");
auto pcapFileHeader = PacketBuilder::PcapFileHeaderPtr(new PacketBuilder::PcapFileHeader());
SPDLOG_DEBUG("File Header: \n{}", PacketBuilder::Stackable::HexDump(pcapFileHeader));
auto pcapFileHeader = Packet::PcapFileHeaderPtr(new Packet::PcapFileHeader());
SPDLOG_DEBUG("File Header: \n{}", Packet::Stackable::HexDump(pcapFileHeader));

std::for_each(stackables.begin(), stackables.end(), [&pcapFileHeader](PacketBuilder::StackablePtr stackable) {
auto pcapPacketHeader = PacketBuilder::PcapPacketHeaderPtr(new PacketBuilder::PcapPacketHeader());
pcapPacketHeader->Stack(stackable);
std::for_each(stackables.begin(), stackables.end(), [&pcapFileHeader](Packet::StackablePtr stackable) {
auto pcapPacketHeader = Packet::PcapPacketHeaderPtr(new Packet::PcapPacketHeader());
pcapPacketHeader->Stack.Value(stackable);

auto tail = PacketBuilder::Stackable::Tail(pcapFileHeader);
tail->Stack(pcapPacketHeader);
SPDLOG_DEBUG("Packet Header: \n{}", PacketBuilder::Stackable::HexDump(pcapPacketHeader));
auto tail = Packet::Stackable::Tail(pcapFileHeader);
tail->Stack.Value(pcapPacketHeader);
SPDLOG_DEBUG("Packet Header: \n{}", Packet::Stackable::HexDump(pcapPacketHeader));
});

std::ofstream fs(options.OutputFilename(), std::ios::out | std::ios::binary);
auto composed = PacketBuilder::Stackable::Compose(pcapFileHeader);
auto json = pcapFileHeader->StackableEntity()->ToJson();
SPDLOG_DEBUG("\n{}", json.dump(4));

std::ofstream fs(options.OutputFilename.Value(), std::ios::out | std::ios::binary);
auto composed = Packet::Stackable::Compose(pcapFileHeader);

auto dump = PacketBuilder::Stackable::HexDump(composed);
auto dump = Packet::Stackable::HexDump(composed);
SPDLOG_TRACE("Dump: \n{}", dump);

auto ptr = (const char *)composed->DataArray().get();
Expand Down
118 changes: 79 additions & 39 deletions main/PacketBuilder.hpp
Original file line number Diff line number Diff line change
@@ -1,54 +1,89 @@
#ifndef PACKET_BUILDER__PACKET_BUILDER_HPP__
#define PACKET_BUILDER__PACKET_BUILDER_HPP__

#include <Utility/Utility.hpp>
#include <NotifyProperty.hpp>
#include <algorithm>
#include <boost/format.hpp>
#include <cmdline.h>
#include <filesystem>
#include <spdlog/spdlog.h>

enum FileType
{
Pcap,
None
};
class Options
{
public:
Options() = default;
std::filesystem::path OutputFilename() const
{
return _OutputFilename;
}

void OutputFilename(std::filesystem::path outputFilename)
{
_OutputFilename = outputFilename;
}

FileType OutputFileType() const
{
auto extension = _OutputFilename.extension().string();
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char c) { return std::tolower(c); });

std::map<std::string, FileType> fileTypeMap = {{".pcap", FileType::Pcap}};
auto type = fileTypeMap.find(extension);
return type == fileTypeMap.end() ? FileType::None : type->second;
}

spdlog::level::level_enum LogLevel() const
std::string FileTypeToString(FileType fileType)
{
switch (fileType)
{
return _LogLevel;
case FileType::Pcap:
return "Pcap";
case FileType::None:
return "None";
default:
return "Unknown";
}
}

void LogLevel(spdlog::level::level_enum logLevel)
class Options
{
public:
Options()
: InputFilename(std::filesystem::path()), OutputFilename(std::filesystem::path()),
OutputFileType(FileType::None), LogLevel(spdlog::level::info)
{
_LogLevel = logLevel;
}

private:
std::filesystem::path _OutputFilename;
spdlog::level::level_enum _LogLevel;
InputFilename.RegisterCallback([](std::filesystem::path oldPath, std::filesystem::path newPath) {
if (std::filesystem::exists(newPath))
{
auto msgfmt = boost::format("Input file: %1%") % newPath.string();
SPDLOG_INFO(msgfmt.str());
}
else
{
auto msgfmt = boost::format("Input file %1% does not exist") % newPath.string();
throw std::runtime_error(msgfmt.str());
}
});

OutputFilename.RegisterCallback([this](std::filesystem::path oldPath, std::filesystem::path newPath) {
if (newPath.empty())
{
SPDLOG_INFO("Output is disabled");
return;
}

if (std::filesystem::exists(newPath))
{
auto msgfmt = boost::format("Output file: %1%") % newPath.string();
SPDLOG_INFO(msgfmt.str());

auto extension = newPath.extension().string();
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char c) { return std::tolower(c); });

std::map<std::string, FileType> fileTypeMap = {{".pcap", FileType::Pcap}};
auto type = fileTypeMap.find(extension);
this->OutputFileType.Value(type == fileTypeMap.end() ? FileType::None : type->second);
}
else
{
auto msgfmt = boost::format("Output file %1% does not exist") % newPath.string();
throw std::runtime_error(msgfmt.str());
}
});

OutputFileType.RegisterCallback([](FileType oldType, FileType newType) {
auto msgfmt = boost::format("Output file type: %1%(%2%)") % newType % FileTypeToString(newType);
SPDLOG_INFO(msgfmt.str());
});
};

Utility::NotifyProperty<std::filesystem::path> InputFilename;
Utility::NotifyProperty<std::filesystem::path> OutputFilename;
Utility::NotifyProperty<FileType> OutputFileType;
Utility::NotifyProperty<spdlog::level::level_enum> LogLevel;
};

inline spdlog::level::level_enum LogLevelFromString(std::string str)
Expand All @@ -73,6 +108,8 @@ inline cmdline::parser GetArgumentParser()
// Output file name.
parser.add<std::string>("output", 'o', "Output file name", false, "");

parser.add<std::string>("input", 'i', "Input file name", false, "");

// Log level.
parser.add<std::string>("log", 'l', "Log level", false, "info",
cmdline::oneof<std::string>("trace", "debug", "info", "warn", "error", "critical"));
Expand All @@ -86,23 +123,26 @@ inline void ParseArguments(Options &options, int argc, char **argv, cmdline::par

auto filepathAsString = parser.get<std::string>("output");

auto filepath = std::filesystem::path(filepathAsString);
options.OutputFilename(filepath);
auto outputFilepath = std::filesystem::path(filepathAsString);
options.OutputFilename.Value(outputFilepath);

auto inputFilename = std::filesystem::path(parser.get<std::string>("input"));
options.InputFilename.Value(inputFilename);

options.LogLevel(LogLevelFromString(parser.get<std::string>("log")));
options.LogLevel.Value(LogLevelFromString(parser.get<std::string>("log")));
}

inline void ValidateOutputOption(const Options &options)
{
auto filepath = options.OutputFilename();
auto filepath = options.OutputFilename.Value();
if (filepath.empty())
{
SPDLOG_INFO("Output is disabled");
return;
}

auto validExtensions = {".pcap"};
auto extension = options.OutputFilename().extension();
auto extension = options.OutputFilename.Value().extension();

if (std::find(validExtensions.begin(), validExtensions.end(), extension) == validExtensions.end())
{
Expand Down
6 changes: 6 additions & 0 deletions proj/packet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ project(packet)

include_directories(${PROJECT_SOURCE_DIR}/src)

# packetentity ライブラリを追加
include_directories(${PROJECT_SOURCE_DIR}/../packetentity/src)

# utility ライブラリを追加
include_directories(${PROJECT_SOURCE_DIR}/../utility/src)

file(GLOB_RECURSE SRC_FILES "src/*.cpp")

# ライブラリを生成
Expand Down
Loading

0 comments on commit 0467424

Please sign in to comment.