Last active
June 14, 2016 13:13
-
-
Save Tosainu/9e435b79ab134d26025287aa4d065bc4 to your computer and use it in GitHub Desktop.
seccamp'16 選択問題4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: parser | |
parser: ./rhp.cc | |
clang++ -std=c++14 -Wall -Wextra -pedantic -O2 -march=native $< -o $@ | |
debug: parser_debug | |
parser_debug: ./rhp.cc | |
clang++ -std=c++14 -Wall -Wextra -pedantic -g -O0 $< -o $@ | |
test: parser_test | |
./parser_test | |
parser_test: ./rhp.cc | |
clang++ -std=c++14 -Wall -Wextra -pedantic -DRHP_UNIT_TEST $< -o $@ | |
clean: | |
rm parser parser_test parser_debug |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RH packet parser | |
// | |
// usage: | |
// $ clang++ -march=native -O2 -std=c++14 rhp.cc -o rhp | |
// $ ./rhp pyonpyon.rh | |
// | |
// $ clang++ -std=c++14 -DRHP_UNIT_TEST rhp.cc | |
// $ ./a.out | |
// | |
// tested env: Arch Linux x86_64, clang 3.8.0, gcc 6.1.1, boost 1.60 | |
// | |
#include <algorithm> | |
#include <fstream> | |
#include <iostream> | |
#include <stdexcept> | |
#include <vector> | |
#include <boost/algorithm/string.hpp> | |
inline uint64_t rdtsc() { | |
uint64_t low, high; | |
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); | |
return (high << 32) | low; | |
} | |
// RH packet | |
struct packet_t { | |
char magic[2]; // Magic | |
char source[20]; // Source | |
char destination[20]; // Destination | |
uint32_t length; // DataLength | |
std::string data; // Data | |
}; | |
std::vector<packet_t> parse(const std::string& filename) { | |
// filenameを開く | |
std::ifstream ifs(filename, std::ifstream::binary); | |
if (!ifs) { | |
throw std::runtime_error("Failed to open the file"); | |
} | |
// ファイルサイズの確認 | |
ifs.seekg(0, ifs.end); | |
const auto file_size = ifs.tellg(); | |
ifs.seekg(0, ifs.beg); | |
std::vector<packet_t> packets; | |
while (ifs.tellg() < file_size) { | |
packet_t p; | |
// 各データを読み込む | |
ifs.read(p.magic, 2); // Magic (2byte) | |
ifs.read(p.source, 20); // Source (20byte) | |
ifs.read(p.destination, 20); // Destination (20byte) | |
// DataLength (4byte) | |
p.length = [&ifs] { | |
// とりあえず4byte読み込んで | |
char buf[4]; | |
ifs.read(buf, 4); | |
// LEに並べ替える | |
// https://en.wikipedia.org/wiki/Endianness#Files_and_byte_swap | |
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); | |
}(); | |
// Data (p.length byte) | |
p.data.reserve(p.length); // 長さがわかっているので予め確保しておく | |
std::copy_n(std::istream_iterator<char>(ifs), p.length, std::back_inserter(p.data)); | |
packets.push_back(p); | |
} | |
return packets; | |
} | |
bool check(const packet_t& packet) { | |
using boost::algorithm::equals; // 大文字小文字を区別する文字列比較 | |
using boost::algorithm::iequals; // 大文字小文字を区別しない文字列比較 | |
// const auto s = rdtsc(); | |
// cond. 1: Magicが{'R', 'H'}である | |
if (packet.magic[0] != 'R' || packet.magic[1] != 'H') { | |
return false; | |
} | |
// cond. 2: Sourceが”rise-san”または”cocoa-san”である (case-insensitive) | |
if (!iequals(packet.source, "rise-san") && !iequals(packet.source, "cocoa-san")) { | |
return false; | |
} | |
// cond. 3: Destinationが”Chino-chan”または”Chino"である (case-insensitive) | |
if (!iequals(packet.destination, "chino-chan") && !iequals(packet.destination, "chino")) { | |
return false; | |
} | |
// cond. 4: Sourceが”cocoa-san”かつDestinationが”Chino”でない | |
if (equals(packet.source, "cocoa-san") && equals(packet.destination, "Chino")) { | |
return false; | |
} | |
// cond. 6: Dataに下記の文字列を厳密に含まない | |
const static std::string invalid_order_brand[] = { | |
"DandySoda", | |
"FrozenEvergreen" | |
}; | |
auto cond6 = std::none_of(std::begin(invalid_order_brand), std::end(invalid_order_brand), | |
[&packet](auto& s) { return packet.data.find(s) != std::string::npos; }); | |
if (!cond6) { | |
return false; | |
} | |
// cond. 5: Dataに下記の文字列を厳密に含む | |
const static std::string valid_order_brand[] = { | |
"BlueMountain", | |
"Columbia", | |
"OriginalBlend" | |
}; | |
auto cond5 = std::any_of(std::begin(valid_order_brand), std::end(valid_order_brand), | |
[&packet](auto& s) { return packet.data.find(s) != std::string::npos; }); | |
if (!cond5) { | |
return false; | |
} | |
// const auto e = rdtsc(); | |
// std::cout << e - s << std::endl; | |
// 全ての条件にマッチすればPASS | |
return true; | |
} | |
#if !defined RHP_UNIT_TEST | |
auto main(int argc, char** argv) -> int { | |
if (argc < 2) { | |
std::cerr << "usage: " << argv[0] << " <RH packet dump>" << std::endl; | |
return -1; | |
} | |
try { | |
const auto packets = parse(argv[1]); | |
for (auto&& p : packets) { | |
// std::cout << " Magic: " << p.magic[0] << p.magic[1] << "\n" | |
// << " Source: " << p.source << "\n" | |
// << " Destination: " << p.destination << "\n" | |
// << " DataLength: " << p.length << "\n" | |
// << " Data: " << p.data << std::endl; | |
std::cout << (check(p) ? "PASS" : "REJECTED") << std::endl; | |
} | |
} catch (std::exception& e) { | |
std::cerr << e.what() << std::endl; | |
return -1; | |
} catch (...) { | |
std::cerr << "Unknown error" << std::endl; | |
return -1; | |
} | |
} | |
#else | |
#define BOOST_TEST_MODULE RH_PROTCOL | |
#include <boost/test/included/unit_test.hpp> | |
BOOST_AUTO_TEST_CASE(cond1) { | |
packet_t p1{{'R', 'H'}, "cocoa-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p1)); | |
p1.magic[1] = 'T'; | |
BOOST_TEST(!check(p1)); | |
} | |
BOOST_AUTO_TEST_CASE(cond2) { | |
packet_t p1{{'R', 'H'}, "Cocoa-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p1)); | |
packet_t p2{{'R', 'H'}, "rise-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p2)); | |
packet_t p3{{'R', 'H'}, "RiSe-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p3)); | |
packet_t p4{{'R', 'H'}, "AoyamaBlueMountain", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(!check(p4)); | |
packet_t p5{{'R', 'H'}, "nise-cocoa-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(!check(p5)); | |
} | |
BOOST_AUTO_TEST_CASE(cond3) { | |
packet_t p1{{'R', 'H'}, "rise-san", "Chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p1)); | |
packet_t p2{{'R', 'H'}, "rise-san", "Chino", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p2)); | |
packet_t p3{{'R', 'H'}, "cocoa-san", "rise-san", 13, "OriginalBlend"}; | |
BOOST_TEST(!check(p3)); | |
} | |
BOOST_AUTO_TEST_CASE(cond4) { | |
packet_t p1{{'R', 'H'}, "cocoa-san", "Chino", 13, "OriginalBlend"}; | |
BOOST_TEST(!check(p1)); | |
} | |
BOOST_AUTO_TEST_CASE(cond5_cond6) { | |
packet_t p1{{'R', 'H'}, "cocoa-san", "chino-chan", 22, "DandySodaOriginalBlend"}; | |
BOOST_TEST(!check(p1)); | |
packet_t p2{{'R', 'H'}, "cocoa-san", "chino-chan", 27, "BlueMountainFrozenEvergreen"}; | |
BOOST_TEST(!check(p2)); | |
packet_t p3{{'R', 'H'}, "cocoa-san", "chino-chan", 13, "OriginalBlend"}; | |
BOOST_TEST(check(p3)); | |
packet_t p4{{'R', 'H'}, "cocoa-san", "chino-chan", 14, "ColumbiaCoffee"}; | |
BOOST_TEST(check(p4)); | |
packet_t p5{{'R', 'H'}, "cocoa-san", "chino-chan", 18, "AoyamaBlueMountain"}; | |
BOOST_TEST(check(p5)); | |
packet_t p6{{'R', 'H'}, "cocoa-san", "chino-chan", 5, "Mocha"}; | |
BOOST_TEST(!check(p6)); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment