1 /** @file
2
3 HTTP configuration support.
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 #pragma once
25
26 #include "tscore/ink_inet.h"
27 #include "tscore/ink_resolver.h"
28 #include "ts/apidefs.h"
29 #include "ts/apidefs.h"
30 #include "tscore/ink_assert.h"
31 #include "tscore/IpMap.h"
32 #include "tscore/MemArena.h"
33 #include <algorithm>
34 #include <array>
35
36 /// Load default inbound IP addresses from the configuration file.
37 void RecHttpLoadIp(const char *name, ///< Name of value in configuration file.
38 IpAddr &ip4, ///< [out] IPv4 address.
39 IpAddr &ip6 ///< [out] Ipv6 address.
40 );
41
42 /// Load up an IpMap with IP addresses from the configuration file.
43 void RecHttpLoadIpMap(const char *name, ///< Name of value in configuration file.
44 IpMap &ipmap ///< [out] IpMap.
45 );
46
47 /** A set of session protocols.
48 This depends on using @c SessionProtocolNameRegistry to get the indices.
49 */
50 class SessionProtocolSet
51 {
52 using self_type = SessionProtocolSet; ///< Self reference type.
53 /// Storage for the set - a bit vector.
54 uint32_t m_bits = 0;
55
56 public:
57 static constexpr int MAX = sizeof(m_bits) * CHAR_BIT;
58
59 /// Default constructor.
60 /// Constructs and empty set.
61 SessionProtocolSet() = default;
62
63 uint32_t
indexToMask(int idx)64 indexToMask(int idx) const
65 {
66 return 0 <= idx && idx < static_cast<int>(MAX) ? static_cast<uint32_t>(1) << idx : 0;
67 }
68
69 /// Mark the protocol at @a idx as present.
70 void
markIn(int idx)71 markIn(int idx)
72 {
73 m_bits |= this->indexToMask(idx);
74 }
75
76 /// Mark all the protocols in @a that as present in @a this.
77 void
markIn(self_type const & that)78 markIn(self_type const &that)
79 {
80 m_bits |= that.m_bits;
81 }
82 /// Mark the protocol at a idx as not present.
83 void
markOut(int idx)84 markOut(int idx)
85 {
86 m_bits &= ~this->indexToMask(idx);
87 }
88 /// Mark the protocols in @a that as not in @a this.
89 void
markOut(self_type const & that)90 markOut(self_type const &that)
91 {
92 m_bits &= ~(that.m_bits);
93 }
94 /// Test if a protocol is in the set.
95 bool
contains(int idx)96 contains(int idx) const
97 {
98 return 0 != (m_bits & this->indexToMask(idx));
99 }
100 /// Test if all the protocols in @a that are in @a this protocol set.
101 bool
contains(self_type const & that)102 contains(self_type const &that) const
103 {
104 return that.m_bits == (that.m_bits & m_bits);
105 }
106 /// Mark all possible protocols.
107 void
markAllIn()108 markAllIn()
109 {
110 m_bits = ~static_cast<uint32_t>(0);
111 }
112 /// Clear all protocols.
113 void
markAllOut()114 markAllOut()
115 {
116 m_bits = 0;
117 }
118
119 /// Check for intersection.
120 bool
intersects(self_type const & that)121 intersects(self_type const &that)
122 {
123 return 0 != (m_bits & that.m_bits);
124 }
125
126 /// Check for empty set.
127 bool
isEmpty()128 isEmpty() const
129 {
130 return m_bits == 0;
131 }
132
133 /// Equality (identical sets).
134 bool
135 operator==(self_type const &that) const
136 {
137 return m_bits == that.m_bits;
138 }
139 };
140
141 // Predefined sets of protocols, useful for configuration.
142 extern SessionProtocolSet HTTP_PROTOCOL_SET;
143 extern SessionProtocolSet HTTP2_PROTOCOL_SET;
144 extern SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET;
145 extern SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET;
146 extern SessionProtocolSet DEFAULT_QUIC_SESSION_PROTOCOL_SET;
147
148 const char *RecNormalizeProtoTag(const char *tag);
149
150 /** Registered session protocol names.
151
152 We do this to avoid lots of string compares. By normalizing the string names we can just compare
153 their indices in this table.
154
155 @internal To simplify the implementation we limit the maximum number of strings to 32. That will
156 be sufficient for the foreseeable future. We can come back to this if it ever becomes a problem.
157
158 @internal Because we have so few strings we just use a linear search. If the size gets much
159 larger we should consider doing something more clever.
160
161 @internal This supports providing constant strings because those strings are exported to the
162 C API and this logic @b must return exactly those pointers.
163 */
164 class SessionProtocolNameRegistry
165 {
166 public:
167 static int constexpr MAX = SessionProtocolSet::MAX; ///< Maximum # of registered names.
168 static int constexpr INVALID = -1; ///< Normalized invalid index value.
169
170 static std::string_view convert_openssl_alpn_wire_format(int index);
171
172 using TextView = ts::TextView;
173
174 /// Default constructor.
175 /// Creates empty registry with no names.
176 SessionProtocolNameRegistry() = default;
177
178 /** Get the index for @a name, registering it if needed.
179 The name is copied internally.
180 @return The index for the registered @a name.
181 */
182 int toIndex(TextView name);
183
184 /** Get the index for @a name, registering it if needed.
185 The caller @b guarantees @a name is persistent and immutable.
186 @return The index for the registered @a name.
187 */
188 int toIndexConst(TextView name);
189
190 /** Convert a @a name to an index.
191 @return The index for @a name or @c INVALID if it is not registered.
192 */
193 int indexFor(TextView name) const;
194
195 /** Convert an @a index to the corresponding name.
196 @return A pointer to the name or @c nullptr if the index isn't registered.
197 */
198 TextView nameFor(int index) const;
199
200 /** Convert an @a index to the corresponding name in OpenSSL ALPN wire format.
201
202 OpenSSL ALPN wire format (vector of non-empty, 8-bit length-prefixed, byte strings)
203 https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_alpn_protos.html
204
205 @return A pointer to the name or @c nullptr if the index isn't registered.
206 */
207 static TextView wireNameFor(int index);
208
209 /// Mark protocols as present in @a sp_set based on the names in @a value.
210 /// The names can be separated by ;/|,: and space.
211 /// @internal This is separated out to make it easy to access from the plugin API
212 /// implementation.
213 void markIn(const char *value, SessionProtocolSet &sp_set);
214
215 protected:
216 int m_n = 0; ///< Index of first unused slot.
217 std::array<TextView, MAX> m_names;
218 ts::MemArena m_arena; ///< Storage for non-constant strings.
219 };
220
221 extern SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
222
223 /** Description of an proxy port.
224
225 This consolidates the options needed for proxy ports, both data
226 and parsing. It provides a static global set of ports for
227 convenience although it can be used with an externally provided
228 set.
229
230 Options are described by a colon separated list of keywords
231 without spaces. The options are applied in left to right order. If
232 options do not conflict the order is irrelevant.
233
234 IPv6 addresses must be enclosed by brackets. Unfortunate but colon is
235 so overloaded there's no other option.
236 */
237 struct HttpProxyPort {
238 private:
239 typedef HttpProxyPort self; ///< Self reference type.
240 public:
241 /// Explicitly supported collection of proxy ports.
242 typedef std::vector<self> Group;
243
244 /// Type of transport on the connection.
245 enum TransportType {
246 TRANSPORT_NONE = 0, ///< Unspecified / uninitialized
247 TRANSPORT_DEFAULT, ///< Default (normal HTTP).
248 TRANSPORT_COMPRESSED, ///< Compressed HTTP.
249 TRANSPORT_BLIND_TUNNEL, ///< Blind tunnel (no processing).
250 TRANSPORT_SSL, ///< SSL connection.
251 TRANSPORT_PLUGIN, /// < Protocol plugin connection
252 TRANSPORT_QUIC, ///< SSL connection.
253 };
254
255 int m_fd; ///< Pre-opened file descriptor if present.
256 TransportType m_type = TRANSPORT_DEFAULT; ///< Type of connection.
257 in_port_t m_port = 0; ///< Port on which to listen.
258 uint8_t m_family = AF_INET; ///< IP address family.
259 /// True if proxy protocol is required on incoming requests.
260 bool m_proxy_protocol = false;
261 /// True if inbound connects (from client) are transparent.
262 bool m_inbound_transparent_p = false;
263 /// True if outbound connections (to origin servers) are transparent.
264 bool m_outbound_transparent_p = false;
265 // True if transparent pass-through is enabled on this port.
266 bool m_transparent_passthrough = false;
267 /// True if MPTCP is enabled on this port.
268 bool m_mptcp = false;
269 /// Local address for inbound connections (listen address).
270 IpAddr m_inbound_ip;
271 /// Local address for outbound connections (to origin server).
272 IpAddr m_outbound_ip4;
273 /// Local address for outbound connections (to origin server).
274 IpAddr m_outbound_ip6;
275 /// Ordered preference for DNS resolution family ( @c FamilyPrefence )
276 /// A value of @c PREFER_NONE indicates that entry and subsequent ones
277 /// are invalid.
278 HostResPreferenceOrder m_host_res_preference;
279 /// Static preference list that is the default value.
280 static HostResPreferenceOrder const DEFAULT_HOST_RES_PREFERENCE;
281 /// Enabled session transports for this port.
282 SessionProtocolSet m_session_protocol_preference;
283
284 /// Default constructor.
285 HttpProxyPort();
286
287 /** Select the local outbound address object.
288
289 @return The IP address for @a family
290 */
291 IpAddr &outboundIp(uint16_t family ///< IP address family.
292 );
293
294 /// Check for SSL port.
295 bool isSSL() const;
296
297 /// Check for QUIC port.
298 bool isQUIC() const;
299
300 /// Check for SSL port.
301 bool isPlugin() const;
302
303 /// Process options text.
304 /// @a opts should not contain any whitespace, only the option string.
305 /// This object's internal state is updated as specified by @a opts.
306 /// @return @c true if a port option was successfully processed, @c false otherwise.
307 bool processOptions(const char *opts ///< String containing the options.
308 );
309
310 /** Global instance.
311
312 This is provided because most of the work with this data is used as a singleton
313 and it's handy to encapsulate it here.
314 */
315 static std::vector<self> &global();
316
317 /// Check for SSL ports.
318 /// @return @c true if any port in @a ports is an SSL port.
319 static bool hasSSL(Group const &ports ///< Ports to check.
320 );
321
322 /// Check for SSL ports.
323 /// @return @c true if any global port is an SSL port.
324 static bool hasSSL();
325
326 /// Check for QUIC ports.
327 /// @return @c true if any port in @a ports is an QUIC port.
328 static bool hasQUIC(Group const &ports ///< Ports to check.
329 );
330
331 /// Check for QUIC ports.
332 /// @return @c true if any global port is an QUIC port.
333 static bool hasQUIC();
334
335 /** Load all relevant configuration data.
336
337 This is hardwired to look up the appropriate values in the
338 configuration files. It clears @a ports and then loads all found
339 values in to it.
340
341 @return @c true if at least one valid port description was
342 found, @c false if none.
343 */
344 static bool loadConfig(std::vector<self> &ports ///< Destination for found port data.
345 );
346
347 /** Load all relevant configuration data into the global ports.
348
349 @return @c true if at least one valid port description was
350 found, @c false if none.
351 */
352 static bool loadConfig();
353
354 /** Load ports from a value string.
355
356 Load ports from single string with port descriptors. Ports
357 found are added to @a ports. @a value may safely be @c nullptr or empty.
358
359 @note This is used primarily internally but is available if needed.
360 @return @c true if a valid port was found, @c false if none.
361 */
362 static bool loadValue(std::vector<self> &ports, ///< Destination for found port data.
363 const char *value ///< Source port data.
364 );
365
366 /** Load ports from a value string into the global ports.
367
368 Load ports from single string of port descriptors into the
369 global set of ports. @a value may safely be @c nullptr or empty.
370
371 @return @c true if a valid port was found, @c false if none.
372 */
373 static bool loadValue(const char *value ///< Source port data.
374 );
375
376 /// Load default value if @a ports is empty.
377 /// @return @c true if the default was needed / loaded.
378 static bool loadDefaultIfEmpty(std::vector<self> &ports ///< Load target.
379 );
380
381 /// Load default value into the global set if it is empty.
382 /// @return @c true if the default was needed / loaded.
383 static bool loadDefaultIfEmpty();
384
385 /** Find an HTTP port in @a ports.
386 If @a family is specified then only ports for that family
387 are checked.
388 @return The port if found, @c nullptr if not.
389 */
390 static const self *findHttp(Group const &ports, ///< Group to search.
391 uint16_t family = AF_UNSPEC ///< Desired address family.
392 );
393
394 /** Find an HTTP port in the global ports.
395 If @a family is specified then only ports for that family
396 are checked.
397 @return The port if found, @c nullptr if not.
398 */
399 static const self *findHttp(uint16_t family = AF_UNSPEC);
400
401 /** Create text description to be used for inter-process access.
402 Prints the file descriptor and then any options.
403
404 @return The number of characters used for the description.
405 */
406 int print(char *out, ///< Output string.
407 size_t n ///< Maximum output length.
408 );
409
410 static const char *const PORTS_CONFIG_NAME; ///< New unified port descriptor.
411
412 /// Default value if no other values can be found.
413 static const char *const DEFAULT_VALUE;
414
415 // Keywords (lower case versions, but compares should be case insensitive)
416 static const char *const OPT_FD_PREFIX; ///< Prefix for file descriptor value.
417 static const char *const OPT_OUTBOUND_IP_PREFIX; ///< Prefix for inbound IP address.
418 static const char *const OPT_INBOUND_IP_PREFIX; ///< Prefix for outbound IP address.
419 static const char *const OPT_IPV6; ///< IPv6.
420 static const char *const OPT_IPV4; ///< IPv4
421 static const char *const OPT_TRANSPARENT_INBOUND; ///< Inbound transparent.
422 static const char *const OPT_TRANSPARENT_OUTBOUND; ///< Outbound transparent.
423 static const char *const OPT_TRANSPARENT_FULL; ///< Full transparency.
424 static const char *const OPT_TRANSPARENT_PASSTHROUGH; ///< Pass-through non-HTTP.
425 static const char *const OPT_SSL; ///< SSL (experimental)
426 static const char *const OPT_QUIC; ///< QUIC (experimental)
427 static const char *const OPT_PROXY_PROTO; ///< Proxy Protocol
428 static const char *const OPT_PLUGIN; ///< Protocol Plugin handle (experimental)
429 static const char *const OPT_BLIND_TUNNEL; ///< Blind tunnel.
430 static const char *const OPT_COMPRESSED; ///< Compressed.
431 static const char *const OPT_HOST_RES_PREFIX; ///< Set DNS family preference.
432 static const char *const OPT_PROTO_PREFIX; ///< Transport layer protocols.
433 static const char *const OPT_MPTCP; ///< MPTCP.
434
435 static std::vector<self> &m_global; ///< Global ("default") data.
436
437 protected:
438 /// Process @a value for DNS resolution family preferences.
439 void processFamilyPreference(const char *value);
440 /// Process @a value for session protocol preferences.
441 void processSessionProtocolPreference(const char *value);
442
443 /** Check a prefix option and find the value.
444 @return The address of the start of the value, or @c nullptr if the prefix doesn't match.
445 */
446
447 const char *checkPrefix(char const *src ///< Input text
448 ,
449 const char *prefix ///< Keyword prefix
450 ,
451 size_t prefix_len ///< Length of keyword prefix.
452 );
453 };
454
455 inline bool
isSSL()456 HttpProxyPort::isSSL() const
457 {
458 return TRANSPORT_SSL == m_type;
459 }
460 inline bool
isQUIC()461 HttpProxyPort::isQUIC() const
462 {
463 return TRANSPORT_QUIC == m_type;
464 }
465 inline bool
isPlugin()466 HttpProxyPort::isPlugin() const
467 {
468 return TRANSPORT_PLUGIN == m_type;
469 }
470
471 inline IpAddr &
outboundIp(uint16_t family)472 HttpProxyPort::outboundIp(uint16_t family)
473 {
474 static IpAddr invalid; // dummy to make compiler happy about return.
475 if (AF_INET == family)
476 return m_outbound_ip4;
477 else if (AF_INET6 == family)
478 return m_outbound_ip6;
479 ink_release_assert(!"Invalid family for outbound address on proxy port.");
480 return invalid; // never happens but compiler insists.
481 }
482
483 inline bool
loadValue(const char * value)484 HttpProxyPort::loadValue(const char *value)
485 {
486 return self::loadValue(m_global, value);
487 }
488 inline bool
loadConfig()489 HttpProxyPort::loadConfig()
490 {
491 return self::loadConfig(m_global);
492 }
493 inline bool
loadDefaultIfEmpty()494 HttpProxyPort::loadDefaultIfEmpty()
495 {
496 return self::loadDefaultIfEmpty(m_global);
497 }
498 inline std::vector<HttpProxyPort> &
global()499 HttpProxyPort::global()
500 {
501 return m_global;
502 }
503 inline bool
hasSSL()504 HttpProxyPort::hasSSL()
505 {
506 return self::hasSSL(m_global);
507 }
508 inline bool
hasQUIC()509 HttpProxyPort::hasQUIC()
510 {
511 return self::hasQUIC(m_global);
512 }
513 inline const HttpProxyPort *
findHttp(uint16_t family)514 HttpProxyPort::findHttp(uint16_t family)
515 {
516 return self::findHttp(m_global, family);
517 }
518
519 /** Session Protocol initialization.
520 This must be called before any proxy port parsing is done.
521 */
522 extern void ts_session_protocol_well_known_name_indices_init();
523