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