From 6da1c57c362105773b68aec9a1e6f0f3b8cd1d70 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 25 Sep 2016 15:56:37 -0700 Subject: [PATCH] Starting over --- .gitignore | 55 +---- BUILD | 6 + Makefile | 18 +- WORKSPACE | 0 auth-client.cc | 56 ----- auth-server.cc | 33 --- crypto.cc | 536 ------------------------------------------ crypto.h | 167 ------------- gen-key.cc | 21 -- gen-keypair.cc | 23 -- lib/BUILD | 9 + lib/tun_tap_device.cc | 1 + lib/tun_tap_device.h | 21 ++ nl80211.py | 466 ------------------------------------ notes.txt | 31 +++ test.cc | 87 +++++++ tlv.cc | 114 --------- tlv.h | 28 --- 18 files changed, 158 insertions(+), 1514 deletions(-) create mode 100644 BUILD create mode 100644 WORKSPACE delete mode 100644 auth-client.cc delete mode 100644 auth-server.cc delete mode 100644 crypto.cc delete mode 100644 crypto.h delete mode 100644 gen-key.cc delete mode 100644 gen-keypair.cc create mode 100644 lib/BUILD create mode 100644 lib/tun_tap_device.cc create mode 100644 lib/tun_tap_device.h delete mode 100755 nl80211.py create mode 100644 notes.txt create mode 100644 test.cc delete mode 100644 tlv.cc delete mode 100644 tlv.h diff --git a/.gitignore b/.gitignore index db4561e..ac51a05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.cache -nosetests.xml -coverage.xml - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ +bazel-* diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..b90e4b4 --- /dev/null +++ b/BUILD @@ -0,0 +1,6 @@ +cc_binary( + name = "test", + srcs = [ + "test.cc", + ], +) diff --git a/Makefile b/Makefile index aed4660..b82b018 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,2 @@ -all: auth-client auth-server gen-key gen-keypair - -%.o: %.cc *.h Makefile - g++ -I/usr/local/include -std=c++11 -g -c -o $@ $< - -auth-client: auth-client.o crypto.o tlv.o - g++ -L/usr/local/lib -o auth-client auth-client.o crypto.o tlv.o -lsodium -levent - -auth-server: auth-server.o crypto.o tlv.o - g++ -L/usr/local/lib -o auth-server auth-server.o crypto.o tlv.o -lsodium -levent - -gen-key: gen-key.o crypto.o tlv.o - g++ -L/usr/local/lib -o gen-key gen-key.o crypto.o tlv.o -lsodium -levent - -gen-keypair: gen-keypair.o crypto.o tlv.o - g++ -L/usr/local/lib -o gen-keypair gen-keypair.o crypto.o tlv.o -lsodium -levent +all: + bazel build //... diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..e69de29 diff --git a/auth-client.cc b/auth-client.cc deleted file mode 100644 index 87737d2..0000000 --- a/auth-client.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -#include - -#include "crypto.h" - -static const struct option long_options[] = { - {"secret_key_filename", required_argument, NULL, 's'}, - {"server_public_key_filename", required_argument, NULL, 'r'}, - {"server_address", required_argument, NULL, 'a'}, - {"server_port", required_argument, NULL, 't'}, -}; - -int main(int argc, char *argv[]) { - std::string secret_key_filename; - std::string public_key_filename; - std::string server_public_key_filename; - std::string server_address; - std::string server_port; - { - int option, option_index; - while ((option = getopt_long(argc, argv, "s:", long_options, &option_index)) != -1) { - switch (option) { - case 's': - secret_key_filename = optarg; - break; - case 'p': - public_key_filename = optarg; - break; - case 'r': - server_public_key_filename = optarg; - break; - case 'a': - server_address = optarg; - break; - case 't': - server_port = optarg; - break; - } - } - } - - sodium_init(); - - SecretKey secret_key; - secret_key.ReadFromFile(secret_key_filename); - - PublicKey server_public_key; - server_public_key.ReadFromFile(server_public_key_filename); - - auto client = CryptoPubClient::FromHostname(server_address, server_port, secret_key, server_public_key); - client->Loop(); - - std::cerr << "Shutting down" << std::endl; -} diff --git a/auth-server.cc b/auth-server.cc deleted file mode 100644 index 722793f..0000000 --- a/auth-server.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -#include "crypto.h" - -static const struct option long_options[] = { - {"secret_key_filename", required_argument, NULL, 's'}, -}; - -int main(int argc, char *argv[]) { - std::string secret_key_filename; - { - int option, option_index; - while ((option = getopt_long(argc, argv, "s:", long_options, &option_index)) != -1) { - switch (option) { - case 's': - secret_key_filename = optarg; - break; - } - } - } - - sodium_init(); - - SecretKey secret_key; - secret_key.ReadFromFile(secret_key_filename); - - CryptoPubServer server(secret_key); - server.Loop(); - - std::cerr << "Shutting down" << std::endl; -} diff --git a/crypto.cc b/crypto.cc deleted file mode 100644 index c907793..0000000 --- a/crypto.cc +++ /dev/null @@ -1,536 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "crypto.h" - - -#define TLV_TYPE_ENCRYPTED_BLOB 0x0000 -#define TLV_TYPE_NONCE 0x0001 -#define TLV_TYPE_PUBLIC_KEY 0x0002 -#define TLV_TYPE_OPAQUE 0x0003 -#define TLV_TYPE_DOWNSTREAM_BITRATE 0x0004 - -#define TLV_TYPE_ENCRYPTED 0x8000 -#define TLV_TYPE_HANDSHAKE 0x8001 -#define TLV_TYPE_HANDSHAKE_SECURE 0x8002 -#define TLV_TYPE_PING 0x8003 -#define TLV_TYPE_PONG 0x8004 -#define TLV_TYPE_TUNNEL_REQUEST 0x8005 -#define TLV_TYPE_CHANNEL 0x8006 - - -void CryptoUtil::GenKey(SharedKey* key) { - randombytes_buf(key->MutableKey(), crypto_secretbox_KEYBYTES); - key->MarkSet(); -} - -void CryptoUtil::GenKeyPair(SecretKey* secret_key, PublicKey* public_key) { - assert(!crypto_box_keypair(public_key->MutableKey(), secret_key->MutableKey())); - public_key->MarkSet(); - secret_key->MarkSet(); -} - -void CryptoUtil::DerivePublicKey(const SecretKey& secret_key, PublicKey* public_key) { - assert(!crypto_scalarmult_base(public_key->MutableKey(), secret_key.Key())); - public_key->MarkSet(); -} - -void CryptoUtil::PrecalculateKey(const SecretKey& secret_key, const PublicKey& public_key, PrecalcKey* precalc_key) { - assert(!crypto_box_beforenm(precalc_key->MutableKey(), public_key.Key(), secret_key.Key())); - precalc_key->MarkSet(); -} - -std::unique_ptr CryptoUtil::EncodeEncrypt(const PrecalcKey& precalc_key, const TLVNode& input) { - std::string encoded; - input.Encode(&encoded); - - size_t encrypted_bytes = encoded.length() + crypto_box_MACBYTES; - - unsigned char nonce[crypto_box_NONCEBYTES]; - randombytes_buf(nonce, crypto_box_NONCEBYTES); - - unsigned char output[encrypted_bytes]; - assert(!crypto_box_easy_afternm(output, (const unsigned char*)encoded.data(), encoded.length(), nonce, precalc_key.Key())); - - std::unique_ptr encrypted(new TLVNode(TLV_TYPE_ENCRYPTED)); - encrypted->AppendChild(new TLVNode(TLV_TYPE_NONCE, std::string((char*)nonce, crypto_box_NONCEBYTES))); - encrypted->AppendChild(new TLVNode(TLV_TYPE_ENCRYPTED_BLOB, std::string((char*)output, encrypted_bytes))); - - return encrypted; -} - -std::unique_ptr CryptoUtil::DecryptDecode(const PrecalcKey& precalc_key, const TLVNode& input) { - assert(input.GetType() == TLV_TYPE_ENCRYPTED); - - auto nonce = input.FindChild(TLV_TYPE_NONCE); - if (!nonce || nonce->GetValue().length() != crypto_box_NONCEBYTES) { - return nullptr; - } - auto encrypted = input.FindChild(TLV_TYPE_ENCRYPTED_BLOB); - if (!encrypted || encrypted->GetValue().length() < crypto_box_MACBYTES) { - return nullptr; - } - - size_t decrypted_bytes = encrypted->GetValue().length() - crypto_box_MACBYTES; - - unsigned char output[decrypted_bytes]; - if (crypto_box_open_easy_afternm(output, (const unsigned char*)encrypted->GetValue().data(), encrypted->GetValue().length(), (const unsigned char*)nonce->GetValue().data(), precalc_key.Key())) { - return nullptr; - } - - return TLVNode::Decode(std::string((char*)output, decrypted_bytes)); -} - - -CryptoKey::CryptoKey(const size_t key_bytes) - : key_bytes_(key_bytes), - is_set_(false), - key_((unsigned char*)sodium_malloc(key_bytes)) { - assert(key_); -} - -CryptoKey::~CryptoKey() { - if (key_) { - sodium_free(key_); - } -} - -void CryptoKey::WriteToFile(const std::string& filename) const { - assert(key_); - assert(is_set_); - int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0400); - assert(fd != -1); - assert(write(fd, key_, key_bytes_) == key_bytes_); - assert(!close(fd)); -} - -void CryptoKey::ReadFromFile(const std::string& filename) { - assert(key_); - assert(!is_set_); - int fd = open(filename.c_str(), O_RDONLY); - assert(fd != -1); - assert(read(fd, key_, key_bytes_ + 1) == key_bytes_); - assert(!close(fd)); - MarkSet(); -} - -const unsigned char* CryptoKey::Key() const { - assert(key_); - assert(is_set_); - return key_; -} - -bool CryptoKey::IsSet() const { - assert(key_); - return is_set_; -} - -unsigned char* CryptoKey::MutableKey() { - assert(key_); - assert(!is_set_); - return key_; -} - -void CryptoKey::MarkSet() { - assert(key_); - assert(!is_set_); - is_set_ = true; - assert(!sodium_mprotect_readonly(key_)); -} - -void CryptoKey::Clear() { - sodium_free(key_); - key_ = nullptr; -} - - -SharedKey::SharedKey() - : CryptoKey(crypto_secretbox_KEYBYTES) {} - - -SecretKey::SecretKey() - : CryptoKey(crypto_box_SECRETKEYBYTES) {} - - -PublicKey::PublicKey() - : CryptoKey(crypto_box_PUBLICKEYBYTES) {} - -std::string PublicKey::AsString() const { - assert(is_set_); - return std::string((char*)key_, key_bytes_); -} - -std::string PublicKey::ToHex() const { - static const char hex[] = "0123456789abcdef"; - std::string ret; - ret.reserve(key_bytes_ * 2); - for (int i = 0; i < key_bytes_; i++) { - ret.push_back(hex[(key_[i] & 0xf0) >> 4]); - ret.push_back(hex[key_[i] & 0x0f]); - } - return ret; -} - -void PublicKey::FromString(const std::string& str) { - assert(!is_set_); - assert(str.length() == key_bytes_); - memcpy(key_, str.data(), key_bytes_); - MarkSet(); -} - - -PrecalcKey::PrecalcKey() - : CryptoKey(crypto_box_BEFORENMBYTES) {} - - -std::ostream& CryptoBase::Log(void *obj) { - char buf[64]; - snprintf(buf, 64, "[%p] ", obj ? obj : this); - return std::cerr << buf; -} - - -CryptoPubConnBase::CryptoPubConnBase(const SecretKey& secret_key) - : secret_key_(secret_key), - state_(AWAITING_HANDSHAKE) { - CryptoUtil::DerivePublicKey(secret_key_, &public_key_); -} - -CryptoPubConnBase::~CryptoPubConnBase() { - bufferevent_free(bev_); -} - -void CryptoPubConnBase::LogFatal(const std::string& msg, void *obj) { - Log(obj) << msg << std::endl; - delete this; - return; -} - -std::unique_ptr CryptoPubConnBase::BuildSecureHandshake() { - PublicKey ephemeral_public_key; - CryptoUtil::GenKeyPair(&ephemeral_secret_key_, &ephemeral_public_key); - - if (peer_ephemeral_public_key_.IsSet()) { - CryptoUtil::PrecalculateKey(ephemeral_secret_key_, peer_ephemeral_public_key_, &ephemeral_precalc_key_); - ephemeral_secret_key_.Clear(); - peer_ephemeral_public_key_.Clear(); - } - - TLVNode secure_handshake(TLV_TYPE_HANDSHAKE_SECURE); - secure_handshake.AppendChild(new TLVNode(TLV_TYPE_PUBLIC_KEY, ephemeral_public_key.AsString())); - return CryptoUtil::EncodeEncrypt(precalc_key_, secure_handshake); -} - -std::unique_ptr CryptoPubConnBase::BuildHandshake() { - auto secure_handshake = BuildSecureHandshake(); - - std::unique_ptr handshake(new TLVNode(TLV_TYPE_HANDSHAKE)); - handshake->AppendChild(new TLVNode(TLV_TYPE_PUBLIC_KEY, public_key_.AsString())); - handshake->AppendChild(secure_handshake.release()); - - return handshake; -} - -void CryptoPubConnBase::SendHandshake() { - auto handshake = BuildHandshake(); - std::string out; - handshake->Encode(&out); - bufferevent_write(bev_, out.data(), out.length()); -} - -bool CryptoPubConnBase::HandleSecureHandshake(const TLVNode& node) { - assert(node.GetType() == TLV_TYPE_ENCRYPTED); - - std::unique_ptr decrypted(CryptoUtil::DecryptDecode(precalc_key_, node)); - if (!decrypted.get()) { - LogFatal("Protocol error (handshake; decryption failure)"); - return false; - } - - auto peer_ephemeral_public_key = decrypted->FindChild(TLV_TYPE_PUBLIC_KEY); - if (!peer_ephemeral_public_key) { - LogFatal("Protocol error (handshake; no ephemeral public key)"); - return false; - } - if (peer_ephemeral_public_key->GetValue().length() != crypto_box_PUBLICKEYBYTES) { - LogFatal("Protocol error (handshake; wrong ephemeral public key length)"); - return false; - } - peer_ephemeral_public_key_.FromString(peer_ephemeral_public_key->GetValue()); - if (ephemeral_secret_key_.IsSet()) { - CryptoUtil::PrecalculateKey(ephemeral_secret_key_, peer_ephemeral_public_key_, &ephemeral_precalc_key_); - ephemeral_secret_key_.Clear(); - peer_ephemeral_public_key_.Clear(); - } - return true; -} - -bool CryptoPubConnBase::HandleHandshake(const TLVNode& node) { - if (node.GetType() != TLV_TYPE_HANDSHAKE) { - LogFatal("Protocol error (handshake; wrong message type)"); - return false; - } - - auto peer_public_key = node.FindChild(TLV_TYPE_PUBLIC_KEY); - if (!peer_public_key) { - LogFatal("Protocol error (handshake; no public key)"); - return false; - } - if (peer_public_key->GetValue().length() != crypto_box_PUBLICKEYBYTES) { - LogFatal("Protocol error (handshake; wrong public key length)"); - return false; - } - if (peer_public_key_.IsSet()) { - // We're the client and already know the server public key; we expect these to match. - // Eventually, we can do smarter things here to allow key rotation. - if (peer_public_key_.AsString() != peer_public_key->GetValue()) { - LogFatal("Protocol error (handshake; public key mismatch)"); - return false; - } - } else { - peer_public_key_.FromString(peer_public_key->GetValue()); - CryptoUtil::PrecalculateKey(secret_key_, peer_public_key_, &precalc_key_); - } - auto encrypted = node.FindChild(TLV_TYPE_ENCRYPTED); - if (!encrypted) { - LogFatal("Protocol error (handshake; no encrypted portion)"); - return false; - } - - return HandleSecureHandshake(*encrypted); -} - -void CryptoPubConnBase::EncryptSend(const TLVNode& node) { - auto encrypted = CryptoUtil::EncodeEncrypt(ephemeral_precalc_key_, node); - std::string out; - encrypted->Encode(&out); - bufferevent_write(bev_, out.data(), out.length()); -} - -void CryptoPubConnBase::OnReadable_(struct bufferevent* bev, void* this__) { - auto this_ = (CryptoPubConnBase*)this__; - this_->OnReadable(); -} - -void CryptoPubConnBase::OnReadable() { - char buf[UINT16_MAX]; - int bytes = bufferevent_read(bev_, buf, UINT16_MAX); - const std::string input(buf, bytes); - std::unique_ptr decoded(TLVNode::Decode(input)); - - if (!decoded.get()) { - // TODO: re-buffer? - return; - } - - if (state_ == AWAITING_HANDSHAKE) { - OnHandshake(*decoded); - return; - } - - if (decoded->GetType() != TLV_TYPE_ENCRYPTED) { - LogFatal("Protocol error (wrong message type)"); - return; - } - - std::unique_ptr decrypted(CryptoUtil::DecryptDecode(ephemeral_precalc_key_, *decoded)); - if (!decrypted.get()) { - LogFatal("Protocol error (decryption failure)"); - return; - } - - if (!OnMessage(*decrypted)) { - LogFatal("Protocol error (message handling)"); - return; - } -} - - -CryptoPubServer::CryptoPubServer(const SecretKey& secret_key) - : secret_key_(secret_key), - event_base_(event_base_new()) { - sigevent_ = evsignal_new(event_base_, SIGINT, &CryptoPubServer::Shutdown_, this); - event_add(sigevent_, NULL); - - struct sockaddr_in6 server_addr = {0}; - server_addr.sin6_family = AF_INET6; - server_addr.sin6_addr = in6addr_any; - server_addr.sin6_port = htons(4990); - - listener_ = evconnlistener_new_bind(event_base_, &CryptoPubServer::OnNewConn_, this, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&server_addr, sizeof(server_addr)); -} - -CryptoPubServer::~CryptoPubServer() { - event_free(sigevent_); - evconnlistener_free(listener_); - event_base_free(event_base_); -} - -void CryptoPubServer::OnNewConn_(struct evconnlistener* listener, int client_fd, struct sockaddr* client_addr_, int client_addrlen, void* this__) { - auto this_ = (CryptoPubServer*)this__; - this_->OnNewConn(client_fd, client_addr_, client_addrlen); -} - -void CryptoPubServer::OnNewConn(int client_fd, struct sockaddr* client_addr_, int client_addrlen) { - assert(client_addr_->sa_family == AF_INET6); - auto client_addr = (struct sockaddr_in6*)client_addr_; - - char buf[128]; - inet_ntop(AF_INET6, &client_addr->sin6_addr, buf, 128); - - auto bev = bufferevent_socket_new(this->event_base_, client_fd, BEV_OPT_CLOSE_ON_FREE); - bufferevent_enable(bev, EV_READ); - bufferevent_enable(bev, EV_WRITE); - auto peer = new CryptoPubServerConnection(bev, this->secret_key_); - bufferevent_setcb(bev, &CryptoPubServerConnection::OnReadable_, NULL, &CryptoPubServerConnection::OnError_, peer); - - Log(peer) << "New connection from [" << buf << "]:" << ntohs(client_addr->sin6_port) << std::endl; -} - -void CryptoPubServer::Loop() { - event_base_dispatch(event_base_); -} - -void CryptoPubServer::Shutdown_(evutil_socket_t sig, short events, void *this__) { - auto this_ = (CryptoPubServer*)this__; - this_->Shutdown(); -} - -void CryptoPubServer::Shutdown() { - event_base_loopexit(event_base_, NULL); -} - - -CryptoPubServerConnection::CryptoPubServerConnection(struct bufferevent* bev, const SecretKey& secret_key) - : CryptoPubConnBase(secret_key) { - bev_ = bev; -} - -CryptoPubServerConnection::~CryptoPubServerConnection() { - Log() << "Connection closed" << std::endl; -} - -void CryptoPubServerConnection::OnHandshake(const TLVNode& decoded) { - if (!HandleHandshake(decoded)) { - return; - } - - SendHandshake(); - - this->state_ = READY; - Log() << "Handshake successful (client ID: " << peer_public_key_.ToHex() << ")" << std::endl; -} - -bool CryptoPubServerConnection::OnMessage(const TLVNode& message) { - switch (message.GetType()) { - case TLV_TYPE_TUNNEL_REQUEST: - return OnTunnelRequest(message); - default: - return false; - } -} - -bool CryptoPubServerConnection::OnTunnelRequest(const TLVNode& message) { - Log() << "New tunnel request" << std::endl; - for (auto child : message.GetChildren()) { - if (child->GetType() != TLV_TYPE_CHANNEL) { - continue; - } - Log() << "Channel" << std::endl; - } - return true; -} - -void CryptoPubServerConnection::OnError_(struct bufferevent* bev, const short what, void* this__) { - auto this_ = (CryptoPubServerConnection*)this__; - this_->OnError(what); -} - -void CryptoPubServerConnection::OnError(const short what) { - delete this; -} - - -CryptoPubClient::CryptoPubClient(struct sockaddr* addr, socklen_t addrlen, const SecretKey& secret_key, const PublicKey& server_public_key) - : CryptoPubConnBase(secret_key), - event_base_(event_base_new()) { - bev_ = bufferevent_socket_new(event_base_, -1, BEV_OPT_CLOSE_ON_FREE); - peer_public_key_.FromString(server_public_key.AsString()); - CryptoUtil::PrecalculateKey(secret_key_, peer_public_key_, &precalc_key_); - - bufferevent_setcb(bev_, &CryptoPubClient::OnReadable_, NULL, &CryptoPubClient::OnConnectOrError_, this); - bufferevent_enable(bev_, EV_READ); - bufferevent_enable(bev_, EV_WRITE); - bufferevent_socket_connect(bev_, addr, addrlen); -} - -CryptoPubClient::~CryptoPubClient() { - event_base_free(event_base_); -} - -CryptoPubClient* CryptoPubClient::FromHostname(const std::string& server_address, const std::string& server_port, const SecretKey& secret_key, const PublicKey& server_public_key) { - struct addrinfo* res; - int gai_ret = getaddrinfo(server_address.c_str(), server_port.c_str(), NULL, &res); - if (gai_ret) { - std::cerr << "Failed to resolve server_address: " << gai_strerror(gai_ret) << std::endl; - return nullptr; - } - auto ret = new CryptoPubClient((struct sockaddr*)res->ai_addr, res->ai_addrlen, secret_key, server_public_key); - freeaddrinfo(res); - return ret; -} - -void CryptoPubClient::OnHandshake(const TLVNode& decoded) { - if (!HandleHandshake(decoded)) { - return; - } - - this->state_ = READY; - Log() << "Handshake successful" << std::endl; -} - -bool CryptoPubClient::OnMessage(const TLVNode& message) { - switch (message.GetType()) { - default: - return false; - } -} - -void CryptoPubClient::OnConnectOrError_(struct bufferevent* bev, const short what, void* this__) { - auto this_ = (CryptoPubClient*)this__; - if (what == BEV_EVENT_CONNECTED) { - this_->OnConnect(); - } else { - this_->OnError(); - } -} - -void CryptoPubClient::OnConnect() { - Log() << "Connected to server" << std::endl; - SendHandshake(); -} - -void CryptoPubClient::OnError() { - Log() << "Connection error" << std::endl; -} - -void CryptoPubClient::Loop() { - event_base_dispatch(event_base_); -} diff --git a/crypto.h b/crypto.h deleted file mode 100644 index 7ee79cf..0000000 --- a/crypto.h +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "tlv.h" - -class CryptoKey { - public: - CryptoKey(const size_t key_bytes); - ~CryptoKey(); - void ReadFromFile(const std::string& filename); - void WriteToFile(const std::string& filename) const; - - const unsigned char* Key() const; - bool IsSet() const; - - unsigned char* MutableKey(); - void MarkSet(); - - void Clear(); - - protected: - unsigned char* key_; - bool is_set_; - const size_t key_bytes_; -}; - -class SharedKey : public CryptoKey { - public: - SharedKey(); -}; - -class SecretKey : public CryptoKey { - public: - SecretKey(); -}; - -class PublicKey : public CryptoKey { - public: - PublicKey(); - - std::string AsString() const; - std::string ToHex() const; - void FromString(const std::string& str); -}; - -class PrecalcKey : public CryptoKey { - public: - PrecalcKey(); -}; - -class CryptoUtil { - public: - static void GenKey(SharedKey* key); - static void GenKeyPair(SecretKey* secret_key, PublicKey* public_key); - static void DerivePublicKey(const SecretKey& secret_key, PublicKey* public_key); - static void PrecalculateKey(const SecretKey& secret_key, const PublicKey& public_key, PrecalcKey* precalc_key); - - static std::unique_ptr EncodeEncrypt(const PrecalcKey& precalc_key, const TLVNode& input); - static std::unique_ptr DecryptDecode(const PrecalcKey& precalc_key, const TLVNode& input); -}; - -class CryptoBase { - protected: - std::ostream& Log(void *obj=nullptr); -}; - -class CryptoPubConnBase : public CryptoBase { - protected: - CryptoPubConnBase(const SecretKey& secret_key); - virtual ~CryptoPubConnBase(); - - void LogFatal(const std::string& msg, void *obj=nullptr); - - std::unique_ptr BuildSecureHandshake(); - std::unique_ptr BuildHandshake(); - void SendHandshake(); - - bool HandleSecureHandshake(const TLVNode& node); - bool HandleHandshake(const TLVNode& node); - - void EncryptSend(const TLVNode& node); - - static void OnReadable_(struct bufferevent* bev, void* this__); - void OnReadable(); - virtual void OnHandshake(const TLVNode& decoded) = 0; - virtual bool OnMessage(const TLVNode& node) = 0; - - enum { - AWAITING_HANDSHAKE, - READY, - } state_; - - struct bufferevent* bev_; - - const SecretKey& secret_key_; - PublicKey public_key_; - PublicKey peer_public_key_; - PrecalcKey precalc_key_; - - SecretKey ephemeral_secret_key_; - PublicKey peer_ephemeral_public_key_; - PrecalcKey ephemeral_precalc_key_; -}; - -class CryptoPubServerConnection; - -class CryptoPubServer : public CryptoBase { - public: - CryptoPubServer(const SecretKey& secret_key); - ~CryptoPubServer(); - void Loop(); - void Shutdown(); - - private: - static void Shutdown_(evutil_socket_t sig, short events, void *this__); - - static void OnNewConn_(struct evconnlistener* listener, int fd, struct sockaddr* client_addr, int client_addrlen, void* this__); - void OnNewConn(int fd, struct sockaddr* client_addr, int client_addrlen); - - struct event_base* event_base_; - struct evconnlistener* listener_; - struct event* sigevent_; - - const SecretKey& secret_key_; -}; - -class CryptoPubServerConnection : public CryptoPubConnBase { - public: - CryptoPubServerConnection(struct bufferevent* bev, const SecretKey& secret_key); - ~CryptoPubServerConnection(); - - private: - void OnHandshake(const TLVNode& decoded); - bool OnMessage(const TLVNode& node); - bool OnTunnelRequest(const TLVNode& node); - - static void OnError_(struct bufferevent* bev, const short what, void* this__); - void OnError(const short what); - - friend CryptoPubServer; -}; - -class CryptoPubClient : public CryptoPubConnBase { - public: - CryptoPubClient(struct sockaddr* addr, socklen_t addrlen, const SecretKey& secret_key, const PublicKey& server_public_key); - ~CryptoPubClient(); - - static CryptoPubClient* FromHostname(const std::string& server_address, const std::string& server_port, const SecretKey& secret_key, const PublicKey& server_public_key); - - void Loop(); - - private: - void OnHandshake(const TLVNode& decoded); - bool OnMessage(const TLVNode& node); - - static void OnConnectOrError_(struct bufferevent* bev, const short what, void* this__); - void OnConnect(); - void OnError(); - - void SendTunnelRequest(); - - struct event_base* event_base_; -}; diff --git a/gen-key.cc b/gen-key.cc deleted file mode 100644 index 4244430..0000000 --- a/gen-key.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include - -#include "crypto.h" - -int main(int argc, char *argv[]) { - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " key_filename" << std::endl; - return 1; - } - - sodium_init(); - - SharedKey key; - CryptoUtil::GenKey(&key); - - key.WriteToFile(argv[1]); - - return 0; -} diff --git a/gen-keypair.cc b/gen-keypair.cc deleted file mode 100644 index cf11324..0000000 --- a/gen-keypair.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -#include "crypto.h" - -int main(int argc, char *argv[]) { - if (argc < 3) { - std::cerr << "Usage: " << argv[0] << " secret_key_filename public_key_filename" << std::endl; - return 1; - } - - sodium_init(); - - SecretKey secret_key; - PublicKey public_key; - CryptoUtil::GenKeyPair(&secret_key, &public_key); - - secret_key.WriteToFile(argv[1]); - public_key.WriteToFile(argv[2]); - - return 0; -} diff --git a/lib/BUILD b/lib/BUILD new file mode 100644 index 0000000..da46865 --- /dev/null +++ b/lib/BUILD @@ -0,0 +1,9 @@ +cc_library( + name = "tun_tap_device_lib", + hdrs = [ + "tun_tap_device.h", + ], + srcs = [ + "tun_tap_device.cc", + ], +) diff --git a/lib/tun_tap_device.cc b/lib/tun_tap_device.cc new file mode 100644 index 0000000..efbab63 --- /dev/null +++ b/lib/tun_tap_device.cc @@ -0,0 +1 @@ +#include "lib/tun_tap_device.h" diff --git a/lib/tun_tap_device.h b/lib/tun_tap_device.h new file mode 100644 index 0000000..1acb8cc --- /dev/null +++ b/lib/tun_tap_device.h @@ -0,0 +1,21 @@ +#include + +#include + +class TapTunDevice { + public: + static const auto kTunFormat = IFF_TUN; + static const auto kTapFormat = IFF_TAP; + static const auto kNoPacketInfo = IFF_NO_PI; + + TapTunDevice(const std::string& name, uint64_t flags); + TapTunDevice(uint64_t flags); + + const std::string& Name() { + return name_; + } + + private: + std::string name_; +}; + diff --git a/nl80211.py b/nl80211.py deleted file mode 100755 index 75f991f..0000000 --- a/nl80211.py +++ /dev/null @@ -1,466 +0,0 @@ -#!/usr/bin/python2.7 - -import fcntl -import os -import Queue -import threading -import socket -import struct -import weakref - - -class Iterator(object): - def __init__(self, data, offset=0, length=None): - self.data = data - self.offset = offset - self.length = len(self.data) if length is None else length - assert self.length <= len(self.data) - - def __str__(self): - data = self.data[self.offset:self.length] - return '(%d bytes): %r' % (len(data), data) - - def Advance(self, offset_incr): - assert offset_incr <= self.Remaining(), 'Want %d bytes, have %d' % (offset_incr, self.Remaining()) - self.offset += offset_incr - - def Extract(self, length): - assert length <= self.Remaining(), 'Want %d bytes, have %d' % (length, self.Remaining()) - ret = self.data[self.offset:self.offset + length] - self.Advance(length) - return ret - - def ExtractIterator(self, length): - assert length <= self.Remaining(), 'Want %d bytes, have %d' % (length, self.Remaining()) - ret = Iterator(self.data, self.offset, self.offset + length) - self.Advance(length) - return ret - - def Remaining(self): - return self.length - self.offset - - def AtEnd(self): - return not self.Remaining() - - -class Accumulator(object): - def __init__(self): - self._parts = [] - - def __str__(self): - return ''.join(self._parts) - - def __len__(self): - return sum(len(part) for part in self._parts) - - def Append(self, value): - self._parts.append(value) - - -class SingleStructParser(struct.Struct): - def Unpack(self, iterator): - values = self.unpack_from(iterator.data, iterator.offset) - iterator.Advance(self.size) - assert len(values) == 1 - return values[0] - - def Pack(self, accumulator, value): - accumulator.Append(self.pack(value)) - - -class StructParser(struct.Struct): - def __init__(self, format, fields=None): - super(StructParser, self).__init__(format) - self._fields = fields - - def Unpack(self, iterator): - values = self.unpack_from(iterator.data, iterator.offset) - iterator.Advance(self.size) - return dict(zip(self._fields, values)) - - def Pack(self, accumulator, **values): - ordered_values = [] - for field in self._fields: - ordered_values.append(values[field]) - accumulator.Append(self.pack(*ordered_values)) - - -class StringParser(object): - def Unpack(self, iterator): - return iterator.Extract(iterator.Remaining()) - - def Pack(self, accumulator, value): - accumulator.Append(value) - - -class EmptyParser(object): - def Unpack(self, iterator): - return True - - def Pack(self, accumulator, value=None): - pass - - -class Attribute(object): - _nlattr = StructParser('HH', ('len', 'type')) - - def __init__(self, attributes): - super(Attribute, self).__init__() - self._attributes = attributes - - def Unpack(self, iterator): - nlattr = self._nlattr.Unpack(iterator) - value = iterator.data[iterator.offset:iterator.offset + nlattr['len'] - self._nlattr.size] - name, sub_parser = self._attributes.get(nlattr['type'], (None, None)) - assert sub_parser, 'Unknown attribute type %d, len %d' % (nlattr['type'], nlattr['len']) - sub_len = nlattr['len'] - self._nlattr.size - sub_iterator = iterator.ExtractIterator(sub_len) - ret = { - name: sub_parser.Unpack(sub_iterator) - } - assert sub_iterator.AtEnd(), '%d bytes remaining' % sub_iterator.Remaining() - - padding = ((nlattr['len'] + 4 - 1) & ~3) - nlattr['len'] - iterator.Advance(padding) - - return ret - - def Pack(self, accumulator, attrtype, value): - sub_parser = self._attributes[attrtype][1] - sub_accumulator = Accumulator() - sub_parser.Pack(sub_accumulator, value) - attrlen = self._nlattr.size + len(sub_accumulator) - self._nlattr.Pack(accumulator, len=attrlen, type=attrtype) - accumulator.Append(str(sub_accumulator)) - - padding = ((attrlen + 4 - 1) & ~3) - attrlen - if padding: - accumulator.Append('\0' * padding) - - -class Attributes(object): - def __init__(self, attributes): - super(Attributes, self).__init__() - self._attribute_idx = dict((v[0], k) for k, v in attributes.iteritems()) - self._attribute = Attribute(attributes) - - def Unpack(self, iterator): - ret = {} - while not iterator.AtEnd(): - ret.update(self._attribute.Unpack(iterator)) - return ret - - def Pack(self, accumulator, **attrs): - for name, value in attrs.iteritems(): - self._attribute.Pack(accumulator, self._attribute_idx[name], value) - - -class Array(object): - _arrayhdr = StructParser('HH', ('len', 'index')) - - def __init__(self, child): - super(Array, self).__init__() - self._child = child - - def Unpack(self, iterator): - ret = [] - while not iterator.AtEnd(): - hdr = self._arrayhdr.Unpack(iterator) - sub_len = hdr['len'] - self._arrayhdr.size - sub_iterator = iterator.ExtractIterator(sub_len) - ret.append(self._child.Unpack(sub_iterator)) - assert sub_iterator.AtEnd(), '%d bytes remaining' % sub_iterator.Remaining() - return ret - - -flag = EmptyParser() -string = StringParser() -u8 = SingleStructParser('B') -u16 = SingleStructParser('H') -u32 = SingleStructParser('L') -u64 = SingleStructParser('Q') - - -class Netlink(object): - _NLMSG_F_REQUEST = 0x01 - _NLMSG_F_MULTI = 0x02 - _NLMSG_F_ACK = 0x04 - _NLMSG_F_ECHO = 0x08 - _NLMSG_F_DUMP_INTR = 0x10 - - flags = { - 'root': 0x100, - 'match': 0x200, - 'atomic': 0x400, - 'dump': 0x100 | 0x200, - } - - _NLMSG_DONE = 3 - - _nlmsghdr = StructParser('LHHLL', ('length', 'type', 'flags', 'seq', 'pid')) - - _seq = 0 - - def __init__(self): - self._sock = socket.socket(socket.AF_NETLINK, socket.SOCK_DGRAM, 16) - self._sock.bind((0, 0)) - self._seq_lock = threading.Lock() - self._response_queues = {} - thread = threading.Thread( - target=self._Receiver, - args=(weakref.proxy(self),)) - thread.daemon = True - thread.start() - - @staticmethod - def _Receiver(self): - while True: - data = self._sock.recv(4096) - iterator = Iterator(data) - while not iterator.AtEnd(): - hdr = self._nlmsghdr.Unpack(iterator) - sublen = hdr['length'] - self._nlmsghdr.size - self._response_queues[hdr['seq']].put((hdr, iterator.ExtractIterator(sublen))) - - def _NextSeq(self): - with self._seq_lock: - self._seq += 1 - return self._seq - - def Send(self, msgtype, flags, msg): - flagint = self._NLMSG_F_REQUEST - for flag in flags: - flagint |= self.flags[flag] - accumulator = Accumulator() - seq = self._NextSeq() - self._nlmsghdr.Pack( - accumulator, - length=len(msg) + self._nlmsghdr.size, - type=msgtype, - flags=flagint, - seq=seq, - pid=os.getpid()) - accumulator.Append(msg) - self._response_queues[seq] = Queue.Queue() - self._sock.send(str(accumulator)) - return seq - - def Recv(self, seq): - while True: - myhdr, subiter = self._response_queues[seq].get() - if myhdr['type'] == self._NLMSG_DONE: - del self._response_queues[seq] - return - yield (myhdr['type'], subiter) - if not myhdr['flags'] & self._NLMSG_F_MULTI: - del self._response_queues[seq] - return - - -class GenericNetlink(object): - _genlmsghdr = StructParser('BBH', ('cmd', 'version', 'reserved')) - - _op_attr = Attributes({ - 1: ('id', u32), - 2: ('flags', u32), - }) - - _mcast_grp_attr = Attributes({ - 1: ('name', string), - 2: ('id', u32), - }) - - _ctrl_attr = Attributes({ - 1: ('family_id', u16), - 2: ('family_name', string), - 3: ('version', u32), - 4: ('hdrsize', u32), - 5: ('maxattr', u32), - 6: ('ops', Array(_op_attr)), - 7: ('mcast_groups', Array(_mcast_grp_attr)), - }) - - def __init__(self): - self._msgtypes = [ - { - 'id': 0x10, - 'name': 'nlctrl', - 'parser': self._ctrl_attr, - 'commands': { - 'newfamily': 1, - 'getfamily': 3, - }, - }, - ] - - self._netlink = Netlink() - self._UpdateMsgTypes() - for msg in self.Query('nlctrl', ['dump'], 'getfamily', 1): - assert msg['cmd'] == 'newfamily', msg['cmd'] - family_name = msg['attrs']['family_name'].rstrip('\0') - if family_name in self._msgtypes_by_name: - assert msg['attrs']['family_id'] == self._msgtypes_by_name[family_name]['id'], msg['attrs']['family_id'] - else: - self._msgtypes.append({ - 'id': msg['attrs']['family_id'], - 'name': family_name, - 'parser': None, - 'commands': None, - }) - self._UpdateMsgTypes() - - def _UpdateMsgTypes(self): - self._msgtypes_by_id = dict((i['id'], i) for i in self._msgtypes) - self._msgtypes_by_name = dict((i['name'], i) for i in self._msgtypes) - - def RegisterMsgType(self, family_name, parser, commands): - self._msgtypes_by_name[family_name]['parser'] = parser - self._msgtypes_by_name[family_name]['commands'] = commands - - def Send(self, msgtype, flags, cmd, version, **attrs): - msgtype = self._msgtypes_by_name[msgtype] - - accumulator = Accumulator() - self._genlmsghdr.Pack( - accumulator, - cmd=msgtype['commands'][cmd], - version=version, - reserved=0) - - msgtype['parser'].Pack( - accumulator, - **attrs) - - return self._netlink.Send(msgtype['id'], flags, str(accumulator)) - - def Recv(self, seq): - for msgtype_id, iterator in self._netlink.Recv(seq): - genlhdr = self._genlmsghdr.Unpack(iterator) - msgtype = self._msgtypes_by_id[msgtype_id] - yield { - 'cmd': [k for k, v in msgtype['commands'].iteritems() if v == genlhdr['cmd']][0], - 'attrs': msgtype['parser'].Unpack(iterator), - } - - def Query(self, msgtype, flags, cmd, version, **attrs): - seq = self.Send(msgtype, flags, cmd, version, **attrs) - return self.Recv(seq) - - -def RegisterNL80211(gnl): - rate_info = Attributes({ - 1: ('bitrate', u16), - 2: ('mcs', u8), - 4: ('short_gi', flag), - 5: ('bitrate32', u32), - 9: ('80p80_mhz_width', u32), - 10: ('160_mhz_width', u32), - }) - - bss_param = Attributes({ - 2: ('short_preamble', flag), - 3: ('short_slot_time', flag), - 4: ('dtim_period', u8), - 5: ('beacon_interval', u16), - }) - - sta_info = Attributes({ - 1: ('inactive_time', u32), - 2: ('rx_bytes', u32), - 3: ('tx_bytes', u32), - 7: ('signal', u8), - 8: ('tx_bitrate', rate_info), - 9: ('rx_packets', u32), - 10: ('tx_packets', u32), - 11: ('tx_retries', u32), - 12: ('tx_failed', u32), - 13: ('signal_avg', u8), - 14: ('rx_bitrate', rate_info), - 15: ('bss_param', bss_param), - 16: ('connected_time', u32), - 17: ('sta_flags', StructParser('LL', ('mask', 'values'))), - 18: ('beacon_loss', u32), - 23: ('rx_bytes_64', u64), - 24: ('tx_bytes_64', u64), - }) - - supported_iftypes = Attributes({ - 1: ('adhoc', flag), - 2: ('station', flag), - 3: ('ap', flag), - 4: ('ap_vlan', flag), - 5: ('wds', flag), - 6: ('monitor', flag), - 7: ('mesh_point', flag), - 8: ('p2p_client', flag), - 9: ('p2p_go', flag), - 10: ('p2p_device', flag), - }) - - nl80211_attr = Attributes({ - 1: ('wiphy', u32), - 2: ('wiphy_name', string), - 3: ('ifindex', u32), - 6: ('mac', string), - 21: ('sta_info', sta_info), - 22: ('wiphy_bands', string), # XXX - 32: ('supported_iftypes', supported_iftypes), - 43: ('max_num_scan_ssids', u8), - 46: ('generation', u32), - 50: ('supported_commands', string), # XXX - 56: ('max_scan_ie_len', u16), - 57: ('cipher_suites', string), # XXX - 61: ('wiphy_retry_short', u8), - 62: ('wiphy_retry_long', u8), - 63: ('wiphy_frag_threshold', u32), - 64: ('wiphy_rts_threshold', u32), - 86: ('max_num_pmkids', u8), - 89: ('wiphy_coverage_class', u8), - 99: ('tx_frame_types', string), # XXX - 100: ('rx_frame_types', string), # XXX - 102: ('control_port_ethertype', flag), # XXX - 104: ('support_ibss_rsn', flag), - 108: ('offchannel_tx_ok', flag), - 113: ('wiphy_antenna_avail_tx', u32), - 114: ('wiphy_antenna_avail_rx', u32), - 115: ('support_mesh_auth', flag), - 120: ('interface_combinations', string), # XXX - 121: ('software_iftypes', supported_iftypes), - 123: ('max_num_sched_scan_ssids', u8), - 124: ('max_num_sched_scan_ie_len', u16), - 133: ('max_match_sets', u8), - 143: ('feature_flags', u32), - 148: ('ht_capability_mask', string), # XXX - 169: ('ext_capa', string), # XXX - 170: ('ext_capa_mask', string), # XXX - 176: ('vht_capability_mask', string), # XXX - }) - - commands = { - 'get_wiphy': 1, - 'new_wiphy': 3, - 'get_station': 17, - } - - # STA_FLAG_AUTHORIZED = 1 << 0 - # STA_FLAG_SHORT_PREAMBLE = 1 << 1 - # STA_FLAG_WME = 1 << 2 - # STA_FLAG_MFP = 1 << 3 - # STA_FLAG_AUTHENTICATED = 1 << 4 - # STA_FLAG_TDLS_PEER = 1 << 5 - # STA_FLAG_ASSOCIATED = 1 << 6 - - gnl.RegisterMsgType('nl80211', nl80211_attr, commands) - - -def GetIfIndex(if_name): - SIOCGIFINDEX = 0x8933 - sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ifreq = struct.pack('16si', if_name, 0) - res = fcntl.ioctl(sockfd, SIOCGIFINDEX, ifreq) - return struct.unpack("16si", res)[1] - - -gnl = GenericNetlink() -RegisterNL80211(gnl) -print list(gnl.Query('nl80211', ['dump'], 'get_wiphy', 0)) diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..a2f17f6 --- /dev/null +++ b/notes.txt @@ -0,0 +1,31 @@ +priority buckets: + std::array [ differentiated service ] +fairness buckets: + intrusive unordered set [ source address ] + intrusive unordered set [ dest address ] + intrusive unordered set [ protocol, port pair ] +per-bucket queue: + intrusive doubly linked list +global size queue (for binpacking): + intrusive multiset [ packet size ] + +siphash for unordered sets + +pop algorithm: + find first non-empty priority + keep iterator to 3 tiers of next bucket in rotation + pop first N from bucket queue until picking next packet would exceed size limit + use global size queue find packets with size <= remaining space; largest-first binpacking + + +HonestQueue + std::array[ differentiated service ] -> PriorityBucket + intrusive unordered set [ source address ] -> FairSrcBucket + intrusive unordered set [ dest address ] -> FairDestBucket + intrusive unordered set [ protocol, port pair ] -> FairFlowBucket + intrusive double-linked list -> Packet + statistics + + intrusive multiset [ packet size ] -> Packet + + statistics diff --git a/test.cc b/test.cc new file mode 100644 index 0000000..b8791d3 --- /dev/null +++ b/test.cc @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int tun_alloc(char *dev, int flags) { + + struct ifreq ifr; + int fd, err; + const char *clonedev = "/dev/net/tun"; + + /* Arguments taken by the function: + * + * char *dev: the name of an interface (or '\0'). MUST have enough + * space to hold the interface name if '\0' is passed + * int flags: interface flags (eg, IFF_TUN etc.) + */ + + /* open the clone device */ + if( (fd = open(clonedev, O_RDWR)) < 0 ) { + return fd; + } + + /* preparation of the struct ifr, of type "struct ifreq" */ + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ + + if (*dev) { + /* if a device name was specified, put it in the structure; otherwise, + * the kernel will try to allocate the "next" device of the + * specified type */ + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + } + + /* try to create the device */ + if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { + close(fd); + return err; + } + + /* if the operation was successful, write back the name of the + * interface to the variable "dev", so the caller can know + * it. Note that the caller MUST reserve space in *dev (see calling + * code below) */ + strcpy(dev, ifr.ifr_name); + + /* this is the special file descriptor that the caller will use to talk + * with the virtual interface */ + return fd; +} + +int main(int argc, char *argv[]) { + char tun_name[IFNAMSIZ]; + + /* Connect to the device */ + strcpy(tun_name, "tun77"); + int tun_fd = tun_alloc(tun_name, IFF_TUN); /* tun interface */ + + if(tun_fd < 0){ + perror("Allocating interface"); + exit(1); + } + + char buffer[2048]; + /* Now read data coming from the kernel */ + while(1) { + /* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */ + int nread = read(tun_fd,buffer,sizeof(buffer)); + if(nread < 0) { + perror("Reading from interface"); + close(tun_fd); + exit(1); + } + + /* Do whatever with the data */ + printf("Read %d bytes from device %s\n", nread, tun_name); + } + return 0; +} diff --git a/tlv.cc b/tlv.cc deleted file mode 100644 index dbb8774..0000000 --- a/tlv.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include - -#include -#include - -#include "tlv.h" - -struct header { - uint16_t type; - uint16_t value_length; -}; - -TLVNode::TLVNode(const uint16_t type) - : type_(type) {} - -TLVNode::TLVNode(const uint16_t type, const std::string value) - : type_(type), - value_(value) {} - -TLVNode::~TLVNode() { - for (auto child : children_) { - delete child; - } -} - -void TLVNode::Encode(std::string *output) const { - assert(value_.length() <= UINT16_MAX); - struct header header = { - .type = htons(type_), - .value_length = htons((uint16_t)value_.length()), - }; - size_t header_start = output->length(); - output->append((char*)&header, sizeof(header)); - - if (IsContainer()) { - for (auto child : children_) { - child->Encode(output); - } - size_t total_child_length = output->length() - header_start - sizeof(header); - assert(total_child_length <= UINT16_MAX); - header.value_length = htons((uint16_t)total_child_length); - output->replace(header_start, sizeof(header), (char*)&header, sizeof(header)); - } else { - output->append(value_); - } -} - -std::unique_ptr TLVNode::Decode(const std::string& input) { - if (input.length() < sizeof(struct header)) { - return nullptr; - } - auto header = (struct header*)input.data(); - if (input.length() < sizeof(*header) + htons(header->value_length)) { - return nullptr; - } - - if (htons(header->type) & 0x8000) { - // Container - std::unique_ptr container(new TLVNode(htons(header->type))); - - size_t cursor = sizeof(*header); - while (cursor < input.length()) { - auto next_header = (struct header*)(input.data() + cursor); - size_t sub_length = sizeof(*next_header) + htons(next_header->value_length); - if (cursor + sub_length > input.length()) { - return nullptr; - } - std::unique_ptr child(Decode(input.substr(cursor, sub_length))); - if (!child.get()) { - return nullptr; - } - container->AppendChild(child.release()); - cursor += sub_length; - } - - return container; - } else { - // Scalar - return std::unique_ptr(new TLVNode(htons(header->type), input.substr(sizeof(*header), htons(header->value_length)))); - } -} - -void TLVNode::AppendChild(TLVNode* child) { - assert(this->IsContainer()); - children_.push_back(child); -} - -TLVNode* TLVNode::FindChild(const uint16_t type) const { - assert(this->IsContainer()); - for (auto child : children_) { - if (child->GetType() == type) { - return child; - } - } - return nullptr; -} - -bool TLVNode::IsContainer() const { - return type_ & 0x8000; -} - -uint16_t TLVNode::GetType() const { - return type_; -} - -const std::string& TLVNode::GetValue() const { - assert(!this->IsContainer()); - return value_; -} - -const std::list& TLVNode::GetChildren() const { - assert(this->IsContainer()); - return children_; -} diff --git a/tlv.h b/tlv.h deleted file mode 100644 index 0432cfe..0000000 --- a/tlv.h +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include -#include -#include - -class TLVNode { - public: - TLVNode(const uint16_t type); - TLVNode(const uint16_t type, const std::string value); - ~TLVNode(); - - static std::unique_ptr Decode(const std::string& input); - - void AppendChild(TLVNode* child); - - TLVNode* FindChild(const uint16_t type) const; - void Encode(std::string* output) const; - bool IsContainer() const; - uint16_t GetType() const; - const std::string& GetValue() const; - const std::list& GetChildren() const; - - private: - const uint16_t type_; - const std::string value_; - std::list children_; -};