accept more TLS versions, ignore zero return
[ghsmtp.git] / IP6.cpp
blob5c606c7aa8c6a56b80be4d841cb4cbdb0ef026a3
1 #include "IP6.hpp"
3 #include "DNS.hpp"
4 #include "iequal.hpp"
6 #include <fmt/format.h>
8 #include <arpa/inet.h>
9 #include <arpa/nameser.h>
11 #include <tao/pegtl.hpp>
12 #include <tao/pegtl/contrib/abnf.hpp>
14 using tao::pegtl::eof;
15 using tao::pegtl::memory_input;
16 using tao::pegtl::one;
17 using tao::pegtl::opt;
18 using tao::pegtl::parse;
19 using tao::pegtl::range;
20 using tao::pegtl::rep;
21 using tao::pegtl::rep_min_max;
22 using tao::pegtl::rep_opt;
23 using tao::pegtl::seq;
24 using tao::pegtl::sor;
25 using tao::pegtl::string;
26 using tao::pegtl::two;
28 using tao::pegtl::abnf::DIGIT;
29 using tao::pegtl::abnf::HEXDIG;
31 #include <glog/logging.h>
33 namespace IP6 {
35 using dot = one<'.'>;
36 using colon = one<':'>;
38 // clang-format off
39 struct dec_octet : sor<seq<string<'2','5'>, range<'0','5'>>,
40 seq<one<'2'>, range<'0','4'>, DIGIT>,
41 seq<one<'1'>, rep<2, DIGIT>>,
42 seq<range<'1', '9'>, DIGIT>,
43 DIGIT
44 > {};
45 struct ipv4_address
46 : seq<dec_octet, dot, dec_octet, dot, dec_octet, dot, dec_octet> {};
48 struct h16 : rep_min_max<1, 4, HEXDIG> {};
50 struct ls32 : sor<seq<h16, colon, h16>, ipv4_address> {};
52 struct dcolon : two<':'> {};
54 struct ipv6_address : sor<seq< rep<6, h16, colon>, ls32>,
55 seq< dcolon, rep<5, h16, colon>, ls32>,
56 seq<opt<h16 >, dcolon, rep<4, h16, colon>, ls32>,
57 seq<opt<h16, opt< colon, h16>>, dcolon, rep<3, h16, colon>, ls32>,
58 seq<opt<h16, rep_opt<2, colon, h16>>, dcolon, rep<2, h16, colon>, ls32>,
59 seq<opt<h16, rep_opt<3, colon, h16>>, dcolon, h16, colon, ls32>,
60 seq<opt<h16, rep_opt<4, colon, h16>>, dcolon, ls32>,
61 seq<opt<h16, rep_opt<5, colon, h16>>, dcolon, h16>,
62 seq<opt<h16, rep_opt<6, colon, h16>>, dcolon >> {};
64 struct ipv6_address_literal
65 : seq<TAO_PEGTL_ISTRING("[IPv6:"), ipv6_address, one<']'>> {};
67 struct ipv6_address_only : seq<ipv6_address, eof> {};
68 struct ipv6_address_literal_only : seq<ipv6_address_literal, eof> {};
69 // clang-format on
71 // <https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses>
73 auto is_private(std::string_view addr) -> bool
75 CHECK(is_address(addr));
76 return istarts_with(addr, "fd");
79 auto is_address(std::string_view addr) -> bool
81 memory_input<> in{addr.data(), addr.size(), "ip6"};
82 return parse<IP6::ipv6_address_only>(in);
85 auto is_address_literal(std::string_view addr) -> bool
87 memory_input<> in{addr.data(), addr.size(), "ip6"};
88 return parse<IP6::ipv6_address_literal_only>(in);
91 auto to_address_literal(std::string_view addr) -> std::string
93 CHECK(is_address(addr));
94 return fmt::format("{}{}{}", lit_pfx, addr, lit_sfx);
97 auto reverse(std::string_view addr_str) -> std::string
99 in6_addr addr{};
101 static_assert(sizeof(addr) == 16, "in6_addr is the wrong size");
103 const auto addr_void{reinterpret_cast<void*>(&addr)};
104 const auto addr_uint{reinterpret_cast<uint8_t const*>(&addr)};
106 CHECK_EQ(1, inet_pton(AF_INET6, addr_str.data(), addr_void));
108 auto q{std::string{}};
109 q.reserve(4 * NS_IN6ADDRSZ);
111 for (auto n{NS_IN6ADDRSZ - 1}; n >= 0; --n) {
112 const auto ch = addr_uint[n];
114 const auto lo = ch & 0xF;
115 const auto hi = (ch >> 4) & 0xF;
117 using namespace std::literals::string_view_literals;
118 auto constexpr hex_digits{"0123456789abcdef"sv};
120 q += hex_digits[lo];
121 q += '.';
122 q += hex_digits[hi];
123 q += '.';
126 return q;
128 } // namespace IP6