Skip to content

Instantly share code, notes, and snippets.

@Tosainu
Last active June 14, 2016 13:13
Show Gist options
  • Save Tosainu/9e435b79ab134d26025287aa4d065bc4 to your computer and use it in GitHub Desktop.
Save Tosainu/9e435b79ab134d26025287aa4d065bc4 to your computer and use it in GitHub Desktop.
seccamp'16 選択問題4
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
//
// 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