1 /** @file
2     WCCP (v2) support API.
3 
4     @section license License
5 
6     Licensed to the Apache Software Foundation (ASF) under one
7     or more contributor license agreements.  See the NOTICE file
8     distributed with this work for additional information
9     regarding copyright ownership.  The ASF licenses this file
10     to you under the Apache License, Version 2.0 (the
11     "License"); you may not use this file except in compliance
12     with the License.  You may obtain a copy of the License at
13 
14     http://www.apache.org/licenses/LICENSE-2.0
15 
16     Unless required by applicable law or agreed to in writing, software
17     distributed under the License is distributed on an "AS IS" BASIS,
18     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19     See the License for the specific language governing permissions and
20     limitations under the License.
21  */
22 
23 #pragma once
24 
25 #include <memory.h>
26 
27 #include "tscore/TsBuffer.h"
28 #include "tscore/Errata.h"
29 #include "tscore/ink_defs.h"
30 #include "tscore/ink_memory.h"
31 // Nasty, defining this with no prefix. The value is still available
32 // in TS_VERSION_STRING.
33 #undef VERSION
34 
35 // INADDR_ANY
36 #include <netinet/in.h>
37 
38 #include <string_view>
39 
40 /// WCCP Support.
41 namespace wccp
42 {
43 /// Forward declare implementation classes.
44 class Impl;
45 class CacheImpl;
46 class RouterImpl;
47 
48 /// Namespace for implementation details.
49 namespace detail
50 {
51   /// Cache implementation details.
52   namespace cache
53   {
54     struct GroupData;
55   }
56   namespace router
57   {
58     struct GroupData;
59   }
60 } // namespace detail
61 
62 /// Basic time unit for WCCP in seconds
63 /// @note Sec 4.14: HERE_I_AM_T.
64 static time_t const TIME_UNIT   = 10;
65 static time_t const ASSIGN_WAIT = (3 * TIME_UNIT) / 2;
66 static time_t const RAPID_TIME  = TIME_UNIT / 10;
67 
68 /// Service group related constants.
69 /// @internal In a struct so enum values can be imported to more than
70 /// one class.
71 struct ServiceConstants {
72   /// Methods for forwarding intercepted packets to cache.
73   /// @internal Enumerations values match protocol values.
74   enum PacketStyle {
75     NO_PACKET_STYLE = 0, ///< Undefined or invalid.
76     GRE             = 1, ///< GRE tunnel only. [default]
77     L2              = 2, ///< L2 rewrite only.
78     GRE_OR_L2       = 3  ///< L2 rewrite or GRE tunnel.
79   };
80 
81   /// Cache assignment supported methods.
82   /// @internal Enumerations values match protocol values.
83   enum CacheAssignmentStyle {
84     NO_CACHE_ASSIGN_STYLE = 0, ///< Undefined or invalid.
85     HASH_ONLY             = 1, ///< Use only hash assignment. [default]
86     MASK_ONLY             = 2, ///< Use only mask assignment.
87     HASH_OR_MASK          = 3  ///< Use hash or mask assignment.
88   };
89 };
90 
91 /** Service group definition.
92 
93     Also used as serialized layout internally by ServiceGroupElt. This is kept
94     in serialized form because it is copied to and from message data far more
95     often then it is accessed directly.
96  */
97 class ServiceGroup : public ServiceConstants
98 {
99 public:
100   typedef ServiceGroup self; ///< Self reference type.
101 
102   /// Type of service.
103   enum Type : uint8_t {
104     STANDARD = 0, ///< Well known service.
105     DYNAMIC  = 1  ///< Dynamic (locally defined) service.
106   };
107 
108   /// Result codes for service definition.
109   enum Result {
110     DEFINED  = 0, ///< Service group was created by the call.
111     EXISTS   = 1, ///< Service group already existed.
112     CONFLICT = 2  ///< Service group existed but didn't match new definition.
113   };
114 
115   /// @name Well known (standard) services.
116   //@{
117   /// HTTP
118   static uint8_t const HTTP = 0;
119   //@}
120   /// Service IDs of this value or less are reserved.
121   static uint8_t const RESERVED = 50;
122 
123   /// Number of ports in component (defined by protocol).
124   static size_t const N_PORTS = 8;
125 
126   /// @name Flag mask values.
127   //@{
128   /// Source IP address hash
129   static uint32_t const SRC_IP_HASH = 1 << 0;
130   /// Destination IP address hash
131   static uint32_t const DST_IP_HASH = 1 << 1;
132   /// Source port hash.
133   static uint32_t const SRC_PORT_HASH = 1 << 2;
134   /// Destination port hash
135   static uint32_t const DST_PORT_HASH = 1 << 3;
136   /// @a m_ports has port information.
137   static uint32_t const PORTS_DEFINED = 1 << 4;
138   /// @a m_ports has source ports (otherwise destination ports).
139   static uint32_t const PORTS_SOURCE = 1 << 5;
140   /// Alternate source IP address hash
141   static uint32_t const SRC_IP_ALT_HASH = 1 << 8;
142   /// Alternate destination IP address hash
143   static uint32_t const DST_IP_ALT_HASH = 1 << 9;
144   /// Alternate source port hash
145   static uint32_t const SRC_PORT_ALT_HASH = 1 << 10;
146   /// Alternate destination port hash
147   static uint32_t const DST_PORT_ALT_HASH = 1 << 11;
148   /// All hash related flags.
149   static uint32_t const HASH_FLAGS = SRC_IP_HASH | DST_IP_HASH | SRC_PORT_HASH | DST_PORT_HASH | SRC_IP_ALT_HASH | DST_IP_ALT_HASH |
150                                      SRC_PORT_ALT_HASH | DST_PORT_ALT_HASH;
151   //@}
152 
153   /// Default constructor - no member initialization.
154   ServiceGroup();
155   /// Test for equivalent.
156   bool operator==(self const &that) const;
157   /// Test for not equivalent.
158   bool operator!=(self const &that) const;
159 
160   /// @name Accessors
161   //@{
162   ServiceGroup::Type getSvcType() const; ///< Get service type field.
163                                          /** Set the service type.
164                                              If @a svc is @c SERVICE_STANDARD then all fields except the
165                                              component header and service id are set to zero as required
166                                              by the protocol.
167                                          */
168   self &setSvcType(ServiceGroup::Type svc);
169 
170   uint8_t getSvcId() const;   ///< Get service ID field.
171   self &setSvcId(uint8_t id); ///< Set service ID field to @a id.
172 
173   uint8_t getPriority() const;    ///< Get priority field.
174   self &setPriority(uint8_t pri); ///< Set priority field to @a p.
175 
176   uint8_t getProtocol() const;  ///< Get protocol field.
177   self &setProtocol(uint8_t p); ///< Set protocol field to @a p.
178 
179   uint32_t getFlags() const;  ///< Get flags field.
180   self &setFlags(uint32_t f); ///< Set the flags flags in field to @a f.
181   /// Set the flags in the flag field that are set in @a f.
182   /// Other flags are unchanged.
183   self &enableFlags(uint32_t f);
184   /// Clear the flags in the flag field that are set in @a f.
185   /// Other flags are unchanged.
186   self &disableFlags(uint32_t f);
187 
188   /// Get a port value.
189   uint16_t getPort(int idx ///< Index of target port.
190   ) const;
191   /// Set a port value.
192   self &setPort(int idx,      ///< Index of port.
193                 uint16_t port ///< Value for port.
194   );
195   /// Zero (clear) all ports.
196   self &clearPorts();
197   //@}
198 
199 protected:
200   Type m_svc_type;           ///< @ref Type.
201   uint8_t m_svc_id;          ///< ID for service type.
202   uint8_t m_priority;        ///< Redirection priority ordering.
203   uint8_t m_protocol;        ///< IP protocol for service.
204   uint32_t m_flags;          ///< Flags.
205   uint16_t m_ports[N_PORTS]; ///< Service ports.
206 };
207 
208 /// Security component option (sub-type)
209 enum SecurityOption {
210   SECURITY_NONE = 0, ///< No security @c WCCP2_NO_SECURITY
211   SECURITY_MD5  = 1  ///< MD5 security @c WCCP2_MD5_SECURITY
212 };
213 
214 class EndPoint
215 {
216 public:
217   typedef EndPoint self; ///< Self reference type.
218   typedef Impl ImplType; ///< Implementation type.
219 
220   /** Set the identifying IP address.
221       This is also used as the address for the socket.
222   */
223   self &setAddr(uint32_t addr ///< IP address.
224   );
225 
226   /** Check if this endpoint is ready to use.
227       @return @c true if the address has been set and services
228       have been added.
229   */
230   bool isConfigured() const;
231 
232   /** Open a socket for communications.
233 
234       If @a addr is @c INADDR_ANY then the identifying address is used.
235       If that is not set this method will attempt to find an arbitrary
236       local address and use that as the identifying address.
237 
238       Otherwise @a addr replaces any previously set address.
239 
240       @return 0 on success, -ERRNO on failure.
241       @see setAddr
242   */
243   int open(uint32_t addr = INADDR_ANY ///< Local IP address for socket.
244   );
245 
246   /// Get the internal socket.
247   /// Useful primarily for socket options and using
248   /// in @c select.
249   int getSocket() const;
250 
251   /// Use MD5 based security with @a key.
252   void useMD5Security(std::string_view const key ///< Shared hash key.
253   );
254 
255   /// Perform house keeping, including sending outbound messages.
256   int housekeeping();
257 
258   /// Receive and process a message on the socket.
259   /// @return 0 for success, -ERRNO on system error.
260   ts::Rv<int> handleMessage();
261 
262 protected:
263   /// Default constructor.
264   EndPoint();
265   /// Copy constructor.
266   EndPoint(self const &that);
267   /// Force virtual destructor
268   virtual ~EndPoint();
269 
270   ts::IntrusivePtr<ImplType> m_ptr; ///< Implementation instance.
271 
272   /** Get a pointer to the implementation instance, creating it if needed.
273       @internal This is paired with @c make so that the implementation check
274       can be done non-virtually inline, while still allowing the actual
275       implementation instantiation to be virtual so the correct type is
276       created.
277    */
278   ImplType *instance();
279 
280   virtual ImplType *make() = 0; ///< Create a new implementation instance.
281 };
282 
283 class Cache : public EndPoint
284 {
285 public:
286   typedef Cache self;         ///< Self reference type.
287   typedef EndPoint super;     ///< Parent type.
288   typedef CacheImpl ImplType; ///< Implementation type.
289 
290   class Service;
291 
292   /// Default constructor.
293   Cache();
294   /// Destructor
295   ~Cache() override;
296 
297   /// Define services from a configuration file.
298   ts::Errata loadServicesFromFile(char const *path ///< Path to file.
299   );
300 
301   /** Define a service group.
302 
303       Return a service reference object which references the group.
304 
305       If @a result is not @c NULL then its target is set to
306       - @c ServiceGroup::DEFINED if the service was created.
307       - @c ServiceGroup::EXISTS if the service matches the existing service.
308       - @c ServiceGroup::CONFLICT if the service doesn't match the existing service.
309    */
310   Service defineServiceGroup(ServiceGroup const &svc, ///< Service group description.
311                              ServiceGroup::Result *result = nullptr);
312 
313   /** Add a seed router to the service group.
314 
315       A seed router is one that is defined at start up and is where
316       initial messages will be sent. Other routers will be added as
317       discovered. The protocol cannot start successfully without at
318       least one seed router.
319 
320       Seed routers are removed when a reply is received from that router.
321 
322   */
323   self &addSeedRouter(uint8_t id,   ///< Service group ID.
324                       uint32_t addr ///< IP address of router.
325   );
326 
327   /// Number of seconds until next housekeeping activity is due.
328   time_t waitTime() const;
329 
330 protected:
331   /// Get implementation instance, creating if needed.
332   ImplType *instance();
333   /// Get the current implementation instance cast to correct type.
334   ImplType *impl();
335   /// Get the current implementation instance cast to correct type.
336   ImplType const *impl() const;
337   /// Create a new implementation instance.
338   super::ImplType *make() override;
339 };
340 
341 /** Hold a reference to a service group in this end point.
342     This is useful when multiple operations are to be done on the
343     same group, rather than doing a lookup by id every time.
344 */
345 class Cache::Service : public ServiceConstants
346 {
347 public:
348   typedef Service self; ///< Self reference type.
349 
350   /// Default constructor (invalid reference).
351   Service();
352 
353   /// Add an address for a seed router.
354   self &addSeedRouter(uint32_t addr ///< Router IP address.
355   );
356   /// Set the security key.
357   self &setKey(char const *key /// Shared key.
358   );
359   /// Set the service local security option.
360   self &setSecurity(SecurityOption opt ///< Security style to use.
361   );
362   /// Set intercepted packet forwarding style.
363   self &setForwarding(PacketStyle style ///< Type of forwarding supported.
364   );
365   /// Enable or disable packet return by layer 2 rewrite.
366   self &setReturn(PacketStyle style ///< Type of return supported.
367   );
368 
369   /// Set cache assignment style.
370   self &setCacheAssignment(CacheAssignmentStyle style ///< Style to use.
371   );
372 
373 private:
374   Service(Cache const &cache, detail::cache::GroupData &group);
375   Cache m_cache;                               ///< Parent cache.
376   detail::cache::GroupData *m_group = nullptr; ///< Service Group data.
377   friend class Cache;
378 };
379 
380 class Router : public EndPoint
381 {
382 public:
383   typedef Router self;         ///< Self reference type.
384   typedef EndPoint super;      ///< Parent type.
385   typedef RouterImpl ImplType; ///< Implementation type.
386 
387   /// Default constructor
388   Router();
389   /// Destructor.
390   ~Router() override;
391 
392   /// Transmit pending messages.
393   int sendPendingMessages();
394 
395 protected:
396   /// Get implementation instance, creating if needed.
397   ImplType *instance();
398   /// Get the current implementation instance cast to correct type.
399   ImplType *impl();
400   /// Create a new implementation instance.
401   super::ImplType *make() override;
402 };
403 
404 // ------------------------------------------------------
405 inline bool
406 ServiceGroup::operator!=(self const &that) const
407 {
408   return !(*this == that);
409 }
410 
411 inline ServiceGroup::Type
getSvcType()412 ServiceGroup::getSvcType() const
413 {
414   return static_cast<ServiceGroup::Type>(m_svc_type);
415 }
416 inline uint8_t
getSvcId()417 ServiceGroup::getSvcId() const
418 {
419   return m_svc_id;
420 }
421 
422 inline ServiceGroup &
setSvcId(uint8_t id)423 ServiceGroup::setSvcId(uint8_t id)
424 {
425   m_svc_id = id;
426   return *this;
427 }
428 
429 inline uint8_t
getPriority()430 ServiceGroup::getPriority() const
431 {
432   return m_priority;
433 }
434 
435 inline ServiceGroup &
setPriority(uint8_t pri)436 ServiceGroup::setPriority(uint8_t pri)
437 {
438   m_priority = pri;
439   return *this;
440 }
441 
442 inline uint8_t
getProtocol()443 ServiceGroup::getProtocol() const
444 {
445   return m_protocol;
446 }
447 
448 inline ServiceGroup &
setProtocol(uint8_t proto)449 ServiceGroup::setProtocol(uint8_t proto)
450 {
451   m_protocol = proto;
452   return *this;
453 }
454 
455 inline uint32_t
getFlags()456 ServiceGroup::getFlags() const
457 {
458   return ntohl(m_flags);
459 }
460 
461 inline ServiceGroup &
setFlags(uint32_t flags)462 ServiceGroup::setFlags(uint32_t flags)
463 {
464   m_flags = htonl(flags);
465   return *this;
466 }
467 
468 inline ServiceGroup &
enableFlags(uint32_t flags)469 ServiceGroup::enableFlags(uint32_t flags)
470 {
471   m_flags |= htonl(flags);
472   return *this;
473 }
474 
475 inline ServiceGroup &
disableFlags(uint32_t flags)476 ServiceGroup::disableFlags(uint32_t flags)
477 {
478   m_flags &= ~htonl(flags);
479   return *this;
480 }
481 
482 inline uint16_t
getPort(int idx)483 ServiceGroup::getPort(int idx) const
484 {
485   return ntohs(m_ports[idx]);
486 }
487 
488 inline ServiceGroup &
setPort(int idx,uint16_t port)489 ServiceGroup::setPort(int idx, uint16_t port)
490 {
491   m_ports[idx] = htons(port);
492   return *this;
493 }
494 
495 inline ServiceGroup &
clearPorts()496 ServiceGroup::clearPorts()
497 {
498   memset(m_ports, 0, sizeof(m_ports));
499   return *this;
500 }
501 
Service()502 inline Cache::Service::Service() {}
503 
Service(Cache const & cache,detail::cache::GroupData & group)504 inline Cache::Service::Service(Cache const &cache, detail::cache::GroupData &group) : m_cache(cache), m_group(&group) {}
505 
506 // ------------------------------------------------------
507 
508 } // namespace wccp
509