#include "socket_address.h" #include #include "baza.h" #include "baza_inter.h" #include #include #include #include #include #include namespace een9 { struct regexp_cmp_out{ std::vector prg; regexis024::track_var_list vars; }; regexp_cmp_out compile_regexp(const char* expr) { regexp_cmp_out res; std::string problem; int ret = regexis024::compile(expr, res.vars, res.prg, problem); ASSERT(ret == 0, "Can't compile regexp"); return res; } struct SocketAddressParser_Inner { regexp_cmp_out prg; regexis024::VirtualMachine vm; regexis024::tai_t tdiff_k; std::pair i4_k; std::pair i6_k; std::pair ip_k; regexis024::tai_t skip_k; #define reg_int4 "#4(0|[1-9][0-9]!r{0;2})" #define reg_int6 "#6(0|[1-9a-fA-F][0-9a-fA-F]!r{0;3})" #define reg_6RHT_rep(mt) "(:|(:" reg_int6 ")!r{1;" #mt "})" #define reg_6LFT_rep(ea) "(" reg_int6 ":)!r{" #ea "}" #define reg_6zs "#s:0;" #define reg_intp "#p(0|[1-9][0-9]!r{0;4})" #define reg_addr_in4 "(#t:1;" reg_int4 "." reg_int4 "." reg_int4 "." reg_int4 ":" reg_intp ")" #define reg_addr_in6_core "(" reg_6LFT_rep(7) reg_int6 "|" ":" reg_6zs reg_6RHT_rep(6) "|" \ reg_6LFT_rep(1) reg_6zs reg_6RHT_rep(5) "|" \ reg_6LFT_rep(2) reg_6zs reg_6RHT_rep(4) "|" \ reg_6LFT_rep(3) reg_6zs reg_6RHT_rep(3) "|" \ reg_6LFT_rep(4) reg_6zs reg_6RHT_rep(2) "|" \ reg_6LFT_rep(5) reg_6zs reg_6RHT_rep(1) "|" \ reg_6LFT_rep(6) reg_6zs ":" ")" #define reg_addr_in6 "(#t:2;\\[" reg_addr_in6_core "\\]:" reg_intp ")" SocketAddressParser_Inner(): prg(compile_regexp( reg_addr_in4 "|" reg_addr_in6 )), vm(prg.prg.size(), prg.prg.data(), UINT64_MAX, UINT16_MAX, UINT32_MAX, UINT32_MAX, UINT64_MAX) { ASSERT_pl(vm.initialize() == 0); tdiff_k = prg.vars.at("t").colarr_first; skip_k = prg.vars.at("s").colarr_first; auto obtain_range = [&](const std::string& name) -> std::pair { const regexis024::TrackingVariableInfo& vi = prg.vars.at(name); assert(vi.colarr_first > 0 && vi.colarr_second > 0); return {(regexis024::tai_t)vi.colarr_first, (regexis024::tai_t)vi.colarr_second}; }; i4_k = obtain_range("4"); i6_k = obtain_range("6"); ip_k = obtain_range("p"); } }; SocketAddressParser::SocketAddressParser() { opaque = new SocketAddressParser_Inner(); } SocketAddressParser::~SocketAddressParser() { delete (SocketAddressParser_Inner*)opaque; } int parse_socket_address(const std::string& addr, SocketAddress& res, SocketAddressParser& pdata) { #define reveal (*(SocketAddressParser_Inner*)pdata.opaque) reveal.vm.wipeToInit(); ASSERT_pl(reveal.vm.addNewMatchingThread() == 0); int ret; for (size_t i = 0; i < addr.size(); i++) { ret = reveal.vm.feedCharacter((uint64_t)addr[i], 1); // if (!reveal.vm.haveSurvivors()) { // printf("DEBUG: died on %s\n", addr.substr(0, i + 1).c_str()); // break; // } } if (reveal.vm.isMatched()) { std::vector ca = reveal.vm.getMatchedThreadCABranchReverse(); std::reverse(ca.begin(), ca.end()); size_t ci = 0; #define curKey() ca[ci].key #define curValue() ca[ci].value auto extractRange = [&](std::pair rk) -> std::string { assert(ca[ci].key == rk.first && ca[ci + 1].key == rk.second); size_t oci = ci; ci += 2; return getSubstring(addr, ca[oci].value, ca[oci + 1].value); }; assert(curKey() == reveal.tdiff_k); if (curValue() == 1) { ci++; uint32_t res_addr = 0; for (int i = 0; i < 4; i++) { std::string h = extractRange(reveal.i4_k); uint32_t p = std::stoul(h); if (p > 255) return -1; res_addr = ((res_addr << 8) | p); } uint32_t res_port = std::stoul(extractRange(reveal.ip_k)); if (res_port > 65535) return -1; res.v.gen.sa_family = AF_INET; res.v.sin.sin_port = htons(res_port); // host to network short res.v.sin.sin_addr.s_addr = htonl(res_addr); // host to network long res.addrLen = sizeof(sockaddr_in); } else if (curValue() == 2){ ci++; int skipped = 8; for (const regexis024::CAEvent& ev: ca) { if (ev.key == reveal.i6_k.first) skipped--; } assert(skipped == 0 || skipped >= 2); uint16_t res_u6_addr16[8]; size_t bi = 0; std::string h; while (bi < 8) { if (curKey() == reveal.i6_k.first) { h = extractRange(reveal.i6_k); assert(h.size() <= 4); uint32_t v = 0; for (char ch: h) { v <<= 4; if ('0' <= ch && ch <= '9') { v |= (uint32_t)(ch - '0'); } else if ('a' <= ch && ch <= 'z') { v |= (uint32_t)(ch - 'a' + 10); } else if ('A' <= ch && ch <= 'Z') { v |= (uint32_t)(ch - 'A' + 10); } else assert(false); } assert(v <= UINT16_MAX); res_u6_addr16[bi++] = (uint16_t)v; } else if (curKey() == reveal.skip_k) { ci++; for (int j = 0; j < skipped; j++) res_u6_addr16[bi++] = 0; } else assert(false); } assert(bi == 8); uint32_t res_port = std::stoul(extractRange(reveal.ip_k)); if (res_port > 65535) return -1; res.v.gen.sa_family = AF_INET6; res.v.sin6.sin6_port = htons(res_port); for (int i = 0; i < 8; i++) res.v.sin6.sin6_addr.__in6_u.__u6_addr16[i] = htons(res_u6_addr16[i]); res.addrLen = sizeof(sockaddr_in6); } else assert(false); assert(ci == ca.size()); return 0; } const std::string& up = "unix:"; if (beginsWith(addr, up)) { std::string path = addr.substr(up.size()); if (path.empty()) return -1; if (path.back() == '/') return -1; for (char ch: path) if (ch == 0) return -1; res.v.gen.sa_family = AF_UNIX; if (sizeof(res.v.sun.sun_path) > path.size()) THROW("path is too big"); memcpy(res.v.sun.sun_path, path.c_str(), path.size()); res.addrLen = offsetof(sockaddr_un, sun_path) + path.size(); return 0; } return -1; } std::string short2hex(uint16_t v) { if (v == 0) return "0"; std::string result; while (v) { result += (char)((v & 0xf) > 9 ? (v & 0xf) - 10 + 'a' : (v & 0xf) + '0'); v >>= 4; } std::reverse(result.begin(), result.end()); return result; } std::string stringify_socket_address(const SocketAddress &addr) { if (addr.v.gen.sa_family == AF_INET) { char buf[22]; uint32_t IP = ntohl(addr.v.sin.sin_addr.s_addr); uint16_t port = ntohs(addr.v.sin.sin_port); snprintf(buf, 22, "%u.%u.%u.%u:%hu", (IP >> 24) & 0xff, (IP >> 16) & 0xff, (IP >> 8) & 0xff, (IP >> 0) & 0xff, port); return buf; } else if (addr.v.gen.sa_family == AF_INET6) { uint16_t IP[8]; for (int i = 0; i < 8; i++) IP[i] = ntohs(addr.v.sin6.sin6_addr.__in6_u.__u6_addr16[i]); uint16_t port = ntohs(addr.v.sin6.sin6_port); int largest_sz = 0; int largest_start = 0; int cur_sz = 0; for (int i = 0; i < 8; i++) { if (IP[i] == 0) { cur_sz++; if (largest_sz < cur_sz) { largest_sz = cur_sz; largest_start = i + 1 - cur_sz; } } else { cur_sz = 0; } } std::string core; for (int i = 0; i < 8;) { if (largest_sz >= 2 && largest_start == i) { i += largest_sz; if (i == 8) core += "::"; else core += ":"; } else { if (i > 0) core += ":"; core += short2hex(IP[i]); i++; } } assert(core.size() <= 39); char buf[48]; snprintf(buf, 48, "[%s]:%hu", core.c_str(), port); return buf; } else if (addr.v.gen.sa_family == AF_UNIX) { assert(addr.addrLen > offsetof(sockaddr_un, sun_path)); size_t path_len = addr.addrLen - offsetof(sockaddr_un, sun_path); assert(path_len <= sizeof(addr.v.sun.sun_path)); std::string path(path_len, ')'); memcpy(path.data(), addr.v.sun.sun_path, path_len); return "unix:" + path; } else return "Socket address of unknown domain"; } void bind_to_socket_address(int sockfd, const SocketAddress &addr) { int ret; if (addr.v.gen.sa_family == AF_INET) { ret = bind(sockfd, (const sockaddr*)&addr.v.sin, addr.addrLen); } else if (addr.v.gen.sa_family == AF_INET6) { ret = bind(sockfd, (const sockaddr*)&addr.v.sin6, addr.addrLen); } else if (addr.v.gen.sa_family == AF_INET) { ret = bind(sockfd, (const sockaddr*)&addr.v.sun, addr.addrLen); } else THROW("binding socket to address of unsupported domain"); ASSERT_on_iret(ret, "binding socket"); } void get_peer_name_as_socket_address(int sockfd, SocketAddress &res) { socklen_t willbecome = sizeof(res.v); int ret = getpeername(sockfd, &res.v.gen, &willbecome); ASSERT_on_iret(ret, "getpeername"); assert(willbecome <= sizeof(res.v)); res.addrLen = willbecome; } }