From cd85c3763dd53506e4704e2ca994f3c96680b32d Mon Sep 17 00:00:00 2001 From: malloc Date: Tue, 6 Mar 2018 14:47:32 -0600 Subject: [PATCH] ip man --- server/src/utils/net.cpp | 136 +++++++++++++++++++++++++++++++++++++++ server/src/utils/net.hpp | 40 +++++++++++- 2 files changed, 173 insertions(+), 3 deletions(-) diff --git a/server/src/utils/net.cpp b/server/src/utils/net.cpp index 777c15f..a945796 100644 --- a/server/src/utils/net.cpp +++ b/server/src/utils/net.cpp @@ -1,5 +1,141 @@ #include "net.hpp" +// BEGIN IPADDRESS CLASS + +sosc::net::IpAddress::IpAddress() { + for(int i = 0; i < 8; ++i) + this->parts[i] = std::make_pair(0, 0); +} + +bool sosc::net::IpAddress::Parse(const std::string& addr) { + std::string addr_trim = str::trim(addr); + + auto parts = str::split(addr_trim, '.'); + if(parts.size() == 4) + return ParseIPv4Parts(parts); + else if(parts.size() != 1) + return false; + + parts = str::split(addr_trim, "::"); + if(parts.size() == 1) { + if(ParseIPv6Part(parts[0], true) != 8) + return false; + } else if(parts.size() == 2) { + int left_cnt, right_cnt; + if((left_cnt = ParseIPv6Part(parts[0], true)) == -1) + return false; + if((right_cnt = ParseIPv6Part(parts[1], false)) == -1) + return false; + if(left_cnt + right_cnt > 8) + return false; + } else + return false; + + return true; +} + +bool sosc::net::IpAddress::ParseIPv4Parts + (const std::vector& parts) +{ + this->parts[5] = std::make_pair(0xFFFF, 0); + for(int i = 0; i < 4; ++i) { + addrpart_t* ptr = &(this->parts[i < 2 ? 6 : 7]); + std::string part = str::trim(parts[i]); + int part_int; + + if(part == "") + return false; + else if(part == "*") { + part_int = 0; + ptr->second |= (i % 2 == 0) ? 0xC : 0x3; + } else { + try { part_int = std::stoi(part); } + catch(...) { return false; } + } + + if(part_int < 0 || part_int > 255) + return false; + + ptr->first |= (i % 2 == 0) + ? part_int << 8 + : part_int; + } + + return true; +} + +int sosc::net::IpAddress::ParseIPv6Part + (const std::string& addr_part, bool from_start) +{ + if(str::trim(addr_part) == "") + return 0; + + auto parts = str::split(addr_part, ':'); + if(parts.size() > 8) + return -1; + + for(int i = 0; i < parts.size(); ++i) { + addrpart_t* ptr = + &(this->parts[from_start ? i : 8 - parts.size() + i]); + std::string part = str::trim(parts[i]); + int part_len = part.length(); + if(part_len > 4 || part_len == 0) + return -1; + + if(part == "*") { + ptr->first = 0; + ptr->second = 0x0F; + continue; + } + + for(int i = 0; i < part_len; ++i) { + if(part[i] == '*') { + part[i] = '0'; + ptr->second |= 1 << (part_len - i - 1); + } + } + + try { ptr->first = std::stoi(part, NULL, 16); } + catch(...) { return -1; } + } + + return parts.size(); +} + +sosc::net::IpAddress::operator std::string () const { + return this->ToString(); +} + +sosc::net::IpAddress::operator const char* () const { + return this->ToString().c_str(); +} + +std::string sosc::net::IpAddress::ToString(bool force_ipv6) const { + return "TODO THIS"; +} + +bool sosc::net::IpAddress::IsIdentical(const IpAddress& rhs) const { + for(int i = 0; i < 8; ++i) + if(this->parts[i] != rhs.parts[i]) + return false; + + return true; +} + +bool sosc::net::IpAddress::IsIPv4() const { + auto blank = std::make_pair(0, 0); + for(int i = 0; i < 5; ++i) + if(this->parts[i] != blank) + return false; + + if(this->parts[5] != std::make_pair(0xFFFF, 0)) + return false; + + return true; +} + +// END IPADDRESS CLASS + bool sosc::net::is_big_endian() { static uint16_t check = 0xFF00; if(check == 0xFF00) diff --git a/server/src/utils/net.hpp b/server/src/utils/net.hpp index 17e8b50..618ad77 100644 --- a/server/src/utils/net.hpp +++ b/server/src/utils/net.hpp @@ -5,6 +5,7 @@ #include #include #include +#include "string.hpp" #undef HTONS #undef HTONUS @@ -40,12 +41,45 @@ namespace sosc { namespace net { class IpAddress { public: + // all strings taken as arguments will accept both IPv4 and IPv6 addrs + // IPv4 addrs will be stored as IPv6 in this format: + // 127.126.0.255 + // -> ::FFFF:7F7E:FF + // ^ ^ ^ ^ + // |--|-|-|----- UNIQUE PREFIX VALUE (decimal 65535) + // |-|-|----- FIRST OCTET AS HEXADECIMAL (127 -> 7F) + // |-|----- SECOND OCTET AS HEXADECIMAL (126 -> 7E) + // |---+- THIRD OCTET IS HIDDEN SINCE FOURTH IS LOWER + // +- (0.255 -> 00FF -{equiv. to}-> FF) + IpAddress(); + bool Parse(const std::string& addr); + + operator std::string () const; + operator const char* () const; + std::string ToString(bool force_ipv6 = false) const; + + bool operator == (const IpAddress& rhs) const; + bool operator != (const IpAddress& rhs) const; + + bool IsIdentical(const IpAddress& rhs) const; + bool IsIPv4() const; private: - typedef std::pair addrpart_t; - addrpart_t parts[8] = {}; + // pair item 1 is the two bytes in an IPv6 address + // pair item 2 is a wildcard bitmask on the nibble in the address + // 4 msbits unused, 4 lsbits indicate wildcards if bit is set + // ex. ::F F F F (IPv6 address) + // 0 1 1 0 (bitmask) + // 4 3 2 1 (bit position where 1 is LSB) + // would treat the middle two nibbles as wildcards; so this ip + // would match eg. ::F00F, ::FAAF, ::FEAF etc. - static addrpart_t ParsePart(std::string part); + typedef std::pair addrpart_t; + std::string tostr_cache; + addrpart_t parts[8]; + + bool ParseIPv4Parts(const std::vector& parts); + int ParseIPv6Part(const std::string& addr_part, bool from_start); }; bool is_big_endian();