1 /** @file 2 3 ink_inet unit tests. 4 5 @section license License 6 7 Licensed to the Apache Software Foundation (ASF) under one 8 or more contributor license agreements. See the NOTICE file 9 distributed with this work for additional information 10 regarding copyright ownership. The ASF licenses this file 11 to you under the Apache License, Version 2.0 (the 12 "License"); you may not use this file except in compliance 13 with the License. You may obtain a copy of the License at 14 15 http://www.apache.org/licenses/LICENSE-2.0 16 17 Unless required by applicable law or agreed to in writing, software 18 distributed under the License is distributed on an "AS IS" BASIS, 19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 See the License for the specific language governing permissions and 21 limitations under the License. 22 */ 23 24 #include "tscpp/util/TextView.h" 25 #include "tscore/BufferWriter.h" 26 #include "tscore/ink_inet.h" 27 #include <catch.hpp> 28 #include <iostream> 29 #include "ts/apidefs.h" 30 #include "tscore/ink_inet.h" 31 #include "tscore/BufferWriter.h" 32 33 using namespace std::literals; 34 35 TEST_CASE("ink_inet", "[libts][inet][ink_inet]") 36 { 37 // Use TextView because string_view(nullptr) fails. Gah. 38 struct ip_parse_spec { 39 ts::TextView hostspec; 40 ts::TextView host; 41 ts::TextView port; 42 ts::TextView rest; 43 }; 44 45 constexpr ip_parse_spec names[] = { 46 {{"::"}, {"::"}, {nullptr}, {nullptr}}, 47 {{"[::1]:99"}, {"::1"}, {"99"}, {nullptr}}, 48 {{"127.0.0.1:8080"}, {"127.0.0.1"}, {"8080"}, {nullptr}}, 49 {{"127.0.0.1:8080-Bob"}, {"127.0.0.1"}, {"8080"}, {"-Bob"}}, 50 {{"127.0.0.1:"}, {"127.0.0.1"}, {nullptr}, {":"}}, 51 {{"foo.example.com"}, {"foo.example.com"}, {nullptr}, {nullptr}}, 52 {{"foo.example.com:99"}, {"foo.example.com"}, {"99"}, {nullptr}}, 53 {{"ffee::24c3:3349:3cee:0143"}, {"ffee::24c3:3349:3cee:0143"}, {nullptr}, {nullptr}}, 54 {{"fe80:88b5:4a:20c:29ff:feae:1c33:8080"}, {"fe80:88b5:4a:20c:29ff:feae:1c33:8080"}, {nullptr}, {nullptr}}, 55 {{"[ffee::24c3:3349:3cee:0143]"}, {"ffee::24c3:3349:3cee:0143"}, {nullptr}, {nullptr}}, 56 {{"[ffee::24c3:3349:3cee:0143]:80"}, {"ffee::24c3:3349:3cee:0143"}, {"80"}, {nullptr}}, 57 {{"[ffee::24c3:3349:3cee:0143]:8080x"}, {"ffee::24c3:3349:3cee:0143"}, {"8080"}, {"x"}}, 58 }; 59 60 for (auto const &s : names) { 61 std::string_view host, port, rest; 62 63 REQUIRE(0 == ats_ip_parse(s.hostspec, &host, &port, &rest)); 64 REQUIRE(s.host == host); 65 REQUIRE(s.port == port); 66 REQUIRE(s.rest == rest); 67 } 68 } 69 70 TEST_CASE("ats_ip_pton", "[libts][inet][ink_inet]") 71 { 72 IpEndpoint ep; 73 IpAddr addr; 74 IpAddr lower, upper; 75 76 REQUIRE(0 == ats_ip_pton("76.14.64.156", &ep.sa)); 77 REQUIRE(0 == addr.load("76.14.64.156")); 78 REQUIRE(addr.family() == ep.family()); 79 80 switch (addr.family()) { 81 case AF_INET: 82 REQUIRE(ep.sin.sin_addr.s_addr == addr._addr._ip4); 83 break; 84 case AF_INET6: 85 REQUIRE(0 == memcmp(&ep.sin6.sin6_addr, &addr._addr._ip6, sizeof(in6_addr))); 86 break; 87 default:; 88 } 89 90 REQUIRE(TS_SUCCESS != addr.load("Evil Dave Rulz!")); 91 92 REQUIRE(TS_SUCCESS == ats_ip_range_parse("1.1.1.1-2.2.2.2"sv, lower, upper)); 93 REQUIRE(TS_SUCCESS != ats_ip_range_parse("172.16.39.0/", lower, upper)); 94 REQUIRE(TS_SUCCESS == ats_ip_range_parse("172.16.39.0/24", lower, upper)); 95 REQUIRE(TS_SUCCESS != ats_ip_range_parse("172.16.39.0-", lower, upper)); 96 REQUIRE(TS_SUCCESS != ats_ip_range_parse("172.16.39.0/35", lower, upper)); 97 REQUIRE(TS_SUCCESS != ats_ip_range_parse("172.16.39.0/-20", lower, upper)); 98 REQUIRE(TS_SUCCESS != ats_ip_range_parse("Thanks, Persia! You're the best.", lower, upper)); 99 100 addr.load("172.16.39.0"); 101 REQUIRE(addr == lower); 102 addr.load("172.16.39.255"); 103 REQUIRE(addr == upper); 104 105 REQUIRE(TS_SUCCESS == ats_ip_range_parse("10.169.243.105/23", lower, upper)); 106 addr.load("10.169.242.0"); 107 REQUIRE(lower == addr); 108 addr.load("10.169.243.255"); 109 REQUIRE(upper == addr); 110 111 REQUIRE(TS_SUCCESS == ats_ip_range_parse("192.168.99.22", lower, upper)); 112 REQUIRE(lower == upper); 113 REQUIRE(lower != IpAddr{INADDR_ANY}); 114 115 REQUIRE(TS_SUCCESS == ats_ip_range_parse("0/0", lower, upper)); 116 REQUIRE(lower == IpAddr{INADDR_ANY}); 117 REQUIRE(upper == IpAddr{INADDR_BROADCAST}); 118 119 REQUIRE(TS_SUCCESS == ats_ip_range_parse("c600::-d900::"sv, lower, upper)); 120 REQUIRE(TS_SUCCESS == ats_ip_range_parse("1300::/96", lower, upper)); 121 REQUIRE(TS_SUCCESS != ats_ip_range_parse("ffee::24c3:3349:3cee:0143/", lower, upper)); 122 123 REQUIRE(TS_SUCCESS == ats_ip_range_parse("ffee:1337:beef:dead:24c3:3349:3cee:0143/80", lower, upper)); 124 addr.load("ffee:1337:beef:dead:24c3::"sv); 125 REQUIRE(lower == addr); 126 addr.load("ffee:1337:beef:dead:24c3:FFFF:FFFF:FFFF"sv); 127 REQUIRE(upper == addr); 128 129 REQUIRE(TS_SUCCESS == ats_ip_range_parse("ffee:1337:beef:dead:24c3:3349:3cee:0143/57", lower, upper)); 130 addr.load("ffee:1337:beef:de80::"sv); 131 REQUIRE(lower == addr); 132 addr.load("ffee:1337:beef:deff:FFFF:FFFF:FFFF:FFFF"sv); 133 REQUIRE(upper == addr); 134 135 REQUIRE(TS_SUCCESS == ats_ip_range_parse("ffee::24c3:3349:3cee:0143", lower, upper)); 136 REQUIRE(lower == upper); 137 138 REQUIRE(TS_SUCCESS == ats_ip_range_parse("::/0", lower, upper)); 139 REQUIRE(lower._addr._u64[0] == 0); 140 REQUIRE(lower._addr._u64[1] == 0); 141 REQUIRE(upper._addr._u64[0] == ~static_cast<uint64_t>(0)); 142 REQUIRE(upper._addr._u64[1] == static_cast<uint64_t>(-1)); 143 144 REQUIRE(TS_SUCCESS == ats_ip_range_parse("c000::/32", lower, upper)); 145 addr.load("c000::"); 146 REQUIRE(addr == lower); 147 addr.load("c000::ffff:ffff:ffff:ffff:ffff:ffff"); 148 REQUIRE(addr == upper); 149 } 150 151 TEST_CASE("inet formatting", "[libts][ink_inet][bwformat]") 152 { 153 IpEndpoint ep; 154 std::string_view addr_1{"[ffee::24c3:3349:3cee:143]:8080"}; 155 std::string_view addr_2{"172.17.99.231:23995"}; 156 std::string_view addr_3{"[1337:ded:BEEF::]:53874"}; 157 std::string_view addr_4{"[1337::ded:BEEF]:53874"}; 158 std::string_view addr_5{"[1337:0:0:ded:BEEF:0:0:956]:53874"}; 159 std::string_view addr_6{"[1337:0:0:ded:BEEF:0:0:0]:53874"}; 160 std::string_view addr_7{"172.19.3.105:4951"}; 161 std::string_view addr_null{"[::]:53874"}; 162 ts::LocalBufferWriter<1024> w; 163 164 REQUIRE(0 == ats_ip_pton(addr_1, &ep.sa)); 165 w.print("{}", ep); 166 REQUIRE(w.view() == addr_1); 167 w.reset().print("{::p}", ep); 168 REQUIRE(w.view() == "8080"); 169 w.reset().print("{::a}", ep); 170 REQUIRE(w.view() == addr_1.substr(1, 24)); // check the brackets are dropped. 171 w.reset().print("[{::a}]", ep); 172 REQUIRE(w.view() == addr_1.substr(0, 26)); // check the brackets are dropped. 173 w.reset().print("[{0::a}]:{0::p}", ep); 174 REQUIRE(w.view() == addr_1); // check the brackets are dropped. 175 w.reset().print("{::=a}", ep); 176 REQUIRE(w.view() == "ffee:0000:0000:0000:24c3:3349:3cee:0143"); 177 w.reset().print("{:: =a}", ep); 178 REQUIRE(w.view() == "ffee: 0: 0: 0:24c3:3349:3cee: 143"); 179 ep.setToLoopback(AF_INET6); 180 w.reset().print("{::a}", ep); 181 REQUIRE(w.view() == "::1"); 182 REQUIRE(0 == ats_ip_pton(addr_3, &ep.sa)); 183 w.reset().print("{::a}", ep); 184 REQUIRE(w.view() == "1337:ded:beef::"); 185 REQUIRE(0 == ats_ip_pton(addr_4, &ep.sa)); 186 w.reset().print("{::a}", ep); 187 REQUIRE(w.view() == "1337::ded:beef"); 188 189 REQUIRE(0 == ats_ip_pton(addr_5, &ep.sa)); 190 w.reset().print("{:X:a}", ep); 191 REQUIRE(w.view() == "1337::DED:BEEF:0:0:956"); 192 193 REQUIRE(0 == ats_ip_pton(addr_6, &ep.sa)); 194 w.reset().print("{::a}", ep); 195 REQUIRE(w.view() == "1337:0:0:ded:beef::"); 196 197 REQUIRE(0 == ats_ip_pton(addr_null, &ep.sa)); 198 w.reset().print("{::a}", ep); 199 REQUIRE(w.view() == "::"); 200 201 REQUIRE(0 == ats_ip_pton(addr_2, &ep.sa)); 202 w.reset().print("{::a}", ep); 203 REQUIRE(w.view() == addr_2.substr(0, 13)); 204 w.reset().print("{0::a}", ep); 205 REQUIRE(w.view() == addr_2.substr(0, 13)); 206 w.reset().print("{::ap}", ep); 207 REQUIRE(w.view() == addr_2); 208 w.reset().print("{::f}", ep); 209 REQUIRE(w.view() == IP_PROTO_TAG_IPV4); 210 w.reset().print("{::fpa}", ep); 211 REQUIRE(w.view() == "172.17.99.231:23995 ipv4"); 212 w.reset().print("{0::a} .. {0::p}", ep); 213 REQUIRE(w.view() == "172.17.99.231 .. 23995"); 214 w.reset().print("<+> {0::a} <+> {0::p}", ep); 215 REQUIRE(w.view() == "<+> 172.17.99.231 <+> 23995"); 216 w.reset().print("<+> {0::a} <+> {0::p} <+>", ep); 217 REQUIRE(w.view() == "<+> 172.17.99.231 <+> 23995 <+>"); 218 w.reset().print("{:: =a}", ep); 219 REQUIRE(w.view() == "172. 17. 99.231"); 220 w.reset().print("{::=a}", ep); 221 REQUIRE(w.view() == "172.017.099.231"); 222 w.reset().print("{}", ts::bwf::Hex_Dump(ep)); 223 REQUIRE(w.view() == "ac1163e7"); 224 w.reset().print("{:#X}", ts::bwf::Hex_Dump(ep)); 225 REQUIRE(w.view() == "0XAC1163E7"); 226 227 // Documentation examples 228 REQUIRE(0 == ats_ip_pton(addr_7, &ep.sa)); 229 w.reset().print("To {}", ep); 230 REQUIRE(w.view() == "To 172.19.3.105:4951"); 231 w.reset().print("To {0::a} on port {0::p}", ep); // no need to pass the argument twice. 232 REQUIRE(w.view() == "To 172.19.3.105 on port 4951"); 233 w.reset().print("To {::=}", ep); 234 REQUIRE(w.view() == "To 172.019.003.105:04951"); 235 w.reset().print("{::a}", ep); 236 REQUIRE(w.view() == "172.19.3.105"); 237 w.reset().print("{::=a}", ep); 238 REQUIRE(w.view() == "172.019.003.105"); 239 w.reset().print("{::0=a}", ep); 240 REQUIRE(w.view() == "172.019.003.105"); 241 w.reset().print("{:: =a}", ep); 242 REQUIRE(w.view() == "172. 19. 3.105"); 243 w.reset().print("{:>20:a}", ep); 244 REQUIRE(w.view() == " 172.19.3.105"); 245 w.reset().print("{:>20:=a}", ep); 246 REQUIRE(w.view() == " 172.019.003.105"); 247 w.reset().print("{:>20: =a}", ep); 248 REQUIRE(w.view() == " 172. 19. 3.105"); 249 w.reset().print("{:<20:a}", ep); 250 REQUIRE(w.view() == "172.19.3.105 "); 251 252 w.reset().print("{:p}", reinterpret_cast<sockaddr const *>(0x1337beef)); 253 REQUIRE(w.view() == "0x1337beef"); 254 255 ats_ip_pton(addr_1, &ep.sa); 256 w.reset().print("{}", ts::bwf::Hex_Dump(ep)); 257 REQUIRE(w.view() == "ffee00000000000024c333493cee0143"); 258 } 259