still must match obs first
[ghsmtp.git] / IP6.cpp
blobb454c5ea5eb0c40102d21267b64c0f5864b79af5
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<range<'0', '1'>, rep<2, DIGIT>>,
42 rep_min_max<1, 2, DIGIT>> {};
44 struct ipv4_address
45 : seq<dec_octet, dot, dec_octet, dot, dec_octet, dot, dec_octet> {};
47 struct h16 : rep_min_max<1, 4, HEXDIG> {};
49 struct ls32 : sor<seq<h16, colon, h16>, ipv4_address> {};
51 struct dcolon : two<':'> {};
53 struct ipv6_address : sor<seq< rep<6, h16, colon>, ls32>,
54 seq< dcolon, rep<5, h16, colon>, ls32>,
55 seq<opt<h16 >, dcolon, rep<4, h16, colon>, ls32>,
56 seq<opt<h16, opt< colon, h16>>, dcolon, rep<3, h16, colon>, ls32>,
57 seq<opt<h16, rep_opt<2, colon, h16>>, dcolon, rep<2, h16, colon>, ls32>,
58 seq<opt<h16, rep_opt<3, colon, h16>>, dcolon, h16, colon, ls32>,
59 seq<opt<h16, rep_opt<4, colon, h16>>, dcolon, ls32>,
60 seq<opt<h16, rep_opt<5, colon, h16>>, dcolon, h16>,
61 seq<opt<h16, rep_opt<6, colon, h16>>, dcolon >> {};
63 struct ipv6_address_literal
64 : seq<TAO_PEGTL_ISTRING(lit_pfx), ipv6_address, TAO_PEGTL_ISTRING(lit_sfx)> {};
66 struct ipv6_address_only : seq<ipv6_address, eof> {};
67 struct ipv6_address_literal_only : seq<ipv6_address_literal, eof> {};
68 // clang-format on
70 // <https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses>
72 bool is_private(std::string_view addr)
74 // CHECK(is_address(addr));
75 return istarts_with(addr, "fd");
78 bool is_address(std::string_view addr)
80 memory_input<> in{addr.data(), addr.size(), "ip6"};
81 return parse<IP6::ipv6_address_only>(in);
84 bool is_address_literal(std::string_view addr)
86 memory_input<> in{addr.data(), addr.size(), "ip6"};
87 return parse<IP6::ipv6_address_literal_only>(in);
90 std::string to_address_literal(std::string_view addr)
92 // CHECK(is_address(addr));
93 return fmt::format("{}{}{}", lit_pfx, addr, lit_sfx);
96 std::string reverse(std::string_view addr_str)
98 in6_addr addr{};
100 static_assert(sizeof(addr) == 16, "in6_addr is the wrong size");
102 const auto addr_void{reinterpret_cast<void*>(&addr)};
103 const auto addr_uint{reinterpret_cast<uint8_t const*>(&addr)};
105 CHECK_EQ(1, inet_pton(AF_INET6, addr_str.data(), addr_void));
107 auto q{std::string{}};
108 q.reserve(4 * NS_IN6ADDRSZ);
110 for (auto n{NS_IN6ADDRSZ - 1}; n >= 0; --n) {
111 const auto ch = addr_uint[n];
113 const auto lo = ch & 0xF;
114 const auto hi = (ch >> 4) & 0xF;
116 constexpr auto hex_digits = "0123456789abcdef";
118 q += hex_digits[lo];
119 q += '.';
120 q += hex_digits[hi];
121 q += '.';
124 return q;
126 } // namespace IP6