Coverage Report

Created: 2026-07-16 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/Tuple.hxx
Line
Count
Source
1
#if !defined(RESIP_TUPLE_HXX)
2
#define RESIP_TUPLE_HXX
3
4
#ifdef HAVE_CONFIG_H
5
#include "config.h"
6
#endif
7
8
#include <memory>
9
#include <vector>
10
11
#include "rutil/Socket.hxx"
12
#include "rutil/compat.hxx"
13
14
#include "rutil/HashMap.hxx"
15
#include "rutil/TransportType.hxx"
16
#include "rutil/HeapInstanceCounter.hxx"
17
#include "rutil/Data.hxx"
18
19
#if defined(WIN32)
20
#include <Ws2tcpip.h>
21
#else
22
#include <netinet/in.h>
23
#endif
24
25
namespace resip
26
{
27
28
struct GenericIPAddress;
29
struct AddressMask;   // defined below (embeds a Tuple, so it follows the Tuple class)
30
31
// WARNING!!
32
// When you change this structure, make sure to update the hash function,
33
// operator== and operator< to be consistent with the new structure. Be
34
// careful not to include members that change value in the Tuple over
35
// its lifetime (they must not be included in the hash or comparisons). 
36
37
typedef unsigned long FlowKey;
38
typedef unsigned long TransportKey;
39
40
/**
41
   @ingroup resip_crit
42
   @brief Represents a network address.
43
44
   This includes:
45
      - IP address
46
      - port
47
      - protocol (TransportType)
48
      - TLS hostname (since this is integral to connection establishment)
49
50
   Internally the class is aware of the struct
51
   sockaddr/sin_addr/sin6addr binary representation of the address.
52
   The sa_family of struct sockaddr is used to keep track of whether a
53
   Tuple is representing a an IPv4 or IPv6 address.
54
55
   Also included are some comparator classes that can be used for
56
   containers of Tuple.
57
*/
58
class Tuple
59
{
60
   public:
61
      RESIP_HeapCount(Tuple);
62
63
      Tuple();
64
65
      explicit Tuple(const GenericIPAddress& genericAddress, 
66
                     TransportType type=UNKNOWN_TRANSPORT, 
67
                     const Data& targetDomain = Data::Empty);
68
69
      Tuple(const Data& printableAddress, 
70
            int port, 
71
            IpVersion ipVer, 
72
            TransportType type=UNKNOWN_TRANSPORT, 
73
            const Data& targetDomain = Data::Empty,
74
            const Data& netNs = Data::Empty);
75
76
      Tuple(const Data& printableAddress, 
77
            int port, 
78
            TransportType type, 
79
            const Data& targetDomain = Data::Empty,
80
            const Data& netNs = Data::Empty);
81
82
      Tuple(const in_addr& pipv4, 
83
            int pport,
84
            TransportType ptype, 
85
            const Data& targetDomain = Data::Empty,
86
            const Data& netNs = Data::Empty);
87
88
      Tuple(const sockaddr& addr, 
89
            TransportType ptype, 
90
            const Data& targetDomain = Data::Empty);
91
92
#ifdef IPPROTO_IPV6
93
      // enable this if the current platform supports IPV6; the USE_IPV6 #define
94
      // will determine if this c'tor is actually implemented.
95
      // ?bwc? Is there a more standard preprocessor macro for this?
96
      // ?bwc? Is there a way we can add something more informative to the 
97
      // linker error we'll see if we compiled without USE_IPV6, on a platform
98
      // with IPV6, and someone tries to invoke this c'tor? (ie; "This library
99
      // was built with IPV6 support disabled")
100
      Tuple(const in6_addr& pipv6,  
101
            int pport, 
102
            TransportType ptype, 
103
            const Data& targetDomain = Data::Empty,
104
            const Data& netNs = Data::Empty);
105
#endif
106
      
107
      /// @brief Retrieve a const binary representation of the socket address
108
      /// for this tuple.
109
0
      const sockaddr& getSockaddr() const { return mSockaddr; }
110
111
      ///  @brief Retrieve the binary representation of the socket address for
112
      /// this tuple.
113
0
      sockaddr& getMutableSockaddr() { return mSockaddr; }
114
      ///  @brief Get a copy of the socket address including the interface and
115
      /// not the port number
116
      void copySockaddrAnyPort(sockaddr *sa);
117
118
      ///  @brief Set the internal binary representation of the socket address
119
      /// from the GenericIPAddress.
120
      void setSockaddr(const GenericIPAddress &);
121
122
0
      TransportType getType() const { return mTransportType; }
123
6.23k
      void setType(TransportType type) { mTransportType = type; }
124
      void setPort(int port);
125
      int getPort() const;
126
0
      inline FlowKey getFlowKey() const { return mFlowKey; }
127
0
      void setFlowKey(FlowKey flowKey) { mFlowKey = flowKey; }
128
129
      /// @deprecated use ipVersion()
130
      /// @todo !dcm! -- should deprecate asap
131
      bool isV4() const; 
132
133
      /// Returns V4 or V6 as appropriate.
134
      IpVersion ipVersion() const;
135
136
      ///  @brief TRUE if this address is equal to the "INADDR_ANY" value for
137
      /// this address family.  
138
      bool isAnyInterface() const;
139
      socklen_t length() const; // of sockaddr
140
      bool isLoopback() const;
141
      bool isPrivateAddress() const;  // Return boolean based on definitions in RFC1918(v4) and RFC4193(v6)
142
      bool isSpecialPurposeAddress() const; // Return boolean based on definitions in RFC6890
143
      
144
      ///  @brief Compares TransportType, the binary address, port, and
145
      /// address family of the Tuple.
146
      bool operator<(const Tuple& rhs) const;
147
148
      ///  @brief Compares TransportType, the binary address, port, and
149
      /// address family of the Tuple.
150
      bool operator==(const Tuple& rhs) const;
151
152
      ///  @brief compares this tuple with the one passed in for family, port
153
      /// and address equality.  Potentially ignoring the port number and/or transport type.
154
      bool isEqual(const Tuple& tuple, bool ignorePort = false, bool ignoreTransport = false) const;
155
156
      /// Wrapper around the inet_top() method.
157
      Data presentationFormat() const;
158
      
159
      ///  @brief Converts a string representation of transport type,
160
      /// i.e. "UDP" to a TransportType
161
      static TransportType toTransport( const Data& );
162
163
      ///  @brief Converts the TransportType to a string representation of the
164
      /// transport type, e.g. "TCP"
165
      static const Data& toData( TransportType );
166
167
      static const Data& toDataLower(TransportType type);
168
169
      ///  @brief Converts the binary socket address to presentation format,
170
      /// via the DnsUtil::inet_ntop() method.
171
      static Data inet_ntop(const Tuple& tuple);
172
173
      // Creates a binary token from the provided Tuple - if salt is provided, then an HMAC is appended
174
      // to the end of the token
175
      static void writeBinaryToken(const Tuple& tuple, Data& container, const Data& salt=Data::Empty);
176
      // Creates a Tuple from the provided binary token - if salt is provided, then an HMAC is checked
177
      static Tuple makeTupleFromBinaryToken(const Data& binaryToken, const Data& salt=Data::Empty);
178
179
      GenericIPAddress toGenericIPAddress() const;
180
181
      /// This is a (largely) opaque key that subclasses of Transport will use
182
      /// to help record/find flows. For UDP and DTLS, this is just the FD, and
183
      /// the rest of the information about the flow is carried in the Tuple.
184
      /// For TCP and TLS, the FD of the connection is used.
185
      /// For protocols where using the FD would not be appropriate (SCTP),
186
      /// the transport may use whatever method to generate these it likes.
187
      /// (It is highly recommended that these ids are unique across all
188
      /// instances of a transport type)
189
      FlowKey mFlowKey;
190
      TransportKey mTransportKey;
191
192
      bool onlyUseExistingConnection;
193
194
      ///  @brief compares this tuple with the one passed in for family, port
195
      /// and address equality using the passed in address mask (mask
196
      /// is specified by number of bits)
197
      bool isEqualWithMask(const Tuple& tuple, short mask, bool ignorePort=false, bool ignoreTransport=false) const;
198
199
      ///  @brief Tests whether this address is permitted by the supplied allow/deny address lists.
200
      ///
201
      /// Deny wins: if this address matches any entry in @p denied the result is false.
202
      /// Otherwise, if @p allowed is non-empty, this address must match one of its entries to be
203
      /// permitted; an empty @p allowed list imposes no allow restriction.  Port and transport
204
      /// are ignored; address family must match for an entry to apply (so an IPv4 address is
205
      /// never permitted by an IPv6 allow entry, and vice versa).  Matching uses isEqualWithMask.
206
      bool isAddressAllowed(const std::vector<AddressMask>& allowed,
207
                            const std::vector<AddressMask>& denied) const;
208
209
      ///  @brief A "less than" comparator for Tuple, for use in map
210
      /// containers etc. Comparison is based on transport type, and
211
      /// if those are equal, it is based on port number.
212
      class AnyInterfaceCompare
213
      {
214
         public:
215
            bool operator()(const Tuple& x,
216
                            const Tuple& y) const;
217
      };
218
      friend class AnyInterfaceCompare;
219
220
      ///  @brief A "less than" comparator for Tuple, for use in map
221
      /// containers etc. Comparison is based on transport type, and
222
      /// if those are equal, it is based on the binary representation
223
      /// of the socket internet address (v4 or v6, whichever is
224
      /// appropriate).
225
      class AnyPortCompare
226
      {
227
         public:
228
            bool operator()(const Tuple& x,
229
                            const Tuple& y) const;
230
      };
231
      friend class AnyPortCompare;
232
233
      ///  @brief A "less than" comparator for Tuple, for use in map
234
      /// containers etc. Comparison is based only on transport type
235
      class AnyPortAnyInterfaceCompare
236
      {
237
         public:
238
            bool operator()(const Tuple& x,
239
                            const Tuple& y) const;
240
      };
241
      friend class AnyPortAnyInterfaceCompare;
242
243
      class FlowKeyCompare
244
      {
245
         public:
246
            bool operator()(const Tuple& x,
247
                            const Tuple& y) const;
248
      };
249
      friend class FlowKeyCompare;
250
251
      ///  @brief Set the domain name this address tuple intends to represent.
252
      void setTargetDomain(const Data& target)
253
0
      {
254
0
         mTargetDomain = target;
255
0
      }
256
      
257
      ///  @brief Get the domain name this address tuple intends to represent.
258
      /// Useful with DnsUtil, for example.
259
      const Data& getTargetDomain() const
260
0
      {
261
0
         return mTargetDomain;
262
0
      }
263
264
      /// @brief Set the netns (network namespace) for this Tuple
265
      void setNetNs(const Data& netNs)
266
0
      {
267
0
          mNetNs = netNs;
268
0
      }
269
270
      /// @brief Get the netns for this Tuple
271
      const Data& getNetNs() const
272
0
      {
273
0
          return(mNetNs);
274
0
      }
275
276
      /**
277
         @brief Creates a 32-bit hash based on the contents of this Tuple.
278
      */
279
      size_t hash() const;   
280
281
private:
282
      union 
283
      {
284
            sockaddr mSockaddr;
285
            sockaddr_in m_anonv4;
286
#ifdef IPPROTO_IPV6
287
            // enable this if the current platform supports IPV6
288
            // ?bwc? Is there a more standard preprocessor macro for this?
289
            sockaddr_in6 m_anonv6;
290
#endif
291
            char pad[RESIP_MAX_SOCKADDR_SIZE]; //< this make union same size if v6 is in or out
292
      };
293
      TransportType mTransportType;
294
      Data mTargetDomain; 
295
296
      Data mNetNs;  ///< The network namespace to which the address and port are scoped
297
298
      friend EncodeStream& operator<<(EncodeStream& strm, const Tuple& tuple);
299
      friend class DnsResult;
300
};
301
302
303
EncodeStream&
304
operator<<(EncodeStream& ostrm, const Tuple& tuple);
305
306
/// @brief An IP address paired with a CIDR prefix length (number of mask bits),
307
/// for use in address-based access control lists.
308
///
309
/// The address is held in a Tuple (only its family and binary address are
310
/// significant for matching; port and transport are ignored).  mMaskBits is the
311
/// number of leading bits that must match: 1..32 for IPv4, 1..128 for IPv6.
312
/// Matching is performed with Tuple::isEqualWithMask.
313
struct AddressMask
314
{
315
   Tuple mAddress;
316
   short mMaskBits = 0;
317
};
318
319
EncodeStream&
320
operator<<(EncodeStream& ostrm, const AddressMask& addressMask);
321
322
}
323
324
HashValue(resip::Tuple);
325
326
#endif
327
/* ====================================================================
328
 * The Vovida Software License, Version 1.0 
329
 * 
330
 * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
331
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
332
 * 
333
 * Redistribution and use in source and binary forms, with or without
334
 * modification, are permitted provided that the following conditions
335
 * are met:
336
 * 
337
 * 1. Redistributions of source code must retain the above copyright
338
 *    notice, this list of conditions and the following disclaimer.
339
 * 
340
 * 2. Redistributions in binary form must reproduce the above copyright
341
 *    notice, this list of conditions and the following disclaimer in
342
 *    the documentation and/or other materials provided with the
343
 *    distribution.
344
 * 
345
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
346
 *    and "Vovida Open Communication Application Library (VOCAL)" must
347
 *    not be used to endorse or promote products derived from this
348
 *    software without prior written permission. For written
349
 *    permission, please contact vocal@vovida.org.
350
 *
351
 * 4. Products derived from this software may not be called "VOCAL", nor
352
 *    may "VOCAL" appear in their name, without prior written
353
 *    permission of Vovida Networks, Inc.
354
 * 
355
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
356
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
357
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
358
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
359
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
360
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
361
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
362
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
363
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
364
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
365
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
366
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
367
 * DAMAGE.
368
 * 
369
 * ====================================================================
370
 * 
371
 * This software consists of voluntary contributions made by Vovida
372
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
373
 * Inc.  For more information on Vovida Networks, Inc., please see
374
 * <http://www.vovida.org/>.
375
 *
376
 */