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