OpenDDS  Snapshot(2023/04/28-20:55)
Ice.cpp
Go to the documentation of this file.
1 /*
2  *
3  *
4  * Distributed under the OpenDDS License.
5  * See: http://www.opendds.org/license.html
6  */
7 #ifdef OPENDDS_SECURITY
8 
9 #include "Ice.h"
10 
11 #include "AgentImpl.h"
13 #include "dds/DCPS/debug.h"
14 #include <dds/DCPS/LogAddr.h>
15 
17 
18 namespace OpenDDS {
19 namespace ICE {
20 
21 bool candidates_sorted(const Candidate& x, const Candidate& y)
22 {
23  if (x.address != y.address) {
24  return x.address < y.address;
25  }
26 
27  if (x.base != y.base) {
28  return x.base < y.base;
29  }
30 
31  return x.priority > y.priority;
32 }
33 
34 bool candidates_equal(const Candidate& x, const Candidate& y)
35 {
36  return x.address == y.address && x.base == y.base;
37 }
38 
39 // TODO(jrw972): Implement RFC8421.
40 
41 // TODO(jrw972): Implement NAT64 and DNS64 considerations.
42 
43 // TODO(jrw972): For IPV6, prefer temporary addresses to permanent addresses.
44 
45 // TODO(jrw972): If gathering one or more host candidates that
46 // correspond to an IPv6 address that was generated using a mechanism
47 // that prevents location tracking [RFC7721], host candidates that
48 // correspond to IPv6 addresses that do allow location tracking, are
49 // configured on the same interface, and are part of the same network
50 // prefix MUST NOT be gathered. Similarly, when host candidates
51 // corresponding to an IPv6 address generated using a mechanism that
52 // prevents location tracking are gathered, then host candidates
53 // corresponding to IPv6 link-local addresses [RFC4291] MUST NOT be
54 // gathered.
55 
56 ACE_UINT32 local_priority(const ACE_INET_Addr& addr)
57 {
58  if (addr.get_type() == AF_INET6) {
59  return 65535;
60  }
61  return 65534;
62 }
63 
65 {
66  Candidate candidate;
67  candidate.address = address;
68  candidate.foundation = std::string("H") + DCPS::LogAddr::ip(address) + "U";
69  // See https://tools.ietf.org/html/rfc8445#section-5.1.2.1 for an explanation of the formula below.
70  candidate.priority = (126 << 24) + (local_priority(address) << 8) + ((256 - 1) << 0); // No local preference, component 1.
71  candidate.type = HOST;
72  candidate.base = address;
73  return candidate;
74 }
75 
76 Candidate make_server_reflexive_candidate(const ACE_INET_Addr& address, const ACE_INET_Addr& base, const ACE_INET_Addr& server_address)
77 {
78  Candidate candidate;
79  candidate.address = address;
80  candidate.foundation = std::string("S") + DCPS::LogAddr::ip(base) + "_" + DCPS::LogAddr::ip(server_address) + "U";
81  // See https://tools.ietf.org/html/rfc8445#section-5.1.2.1 for an explanation of the formula below.
82  candidate.priority = (100 << 24) + (local_priority(address) << 8) + ((256 - 1) << 0); // No local preference, component 1.
83  candidate.type = SERVER_REFLEXIVE;
84  candidate.base = base;
85  return candidate;
86 }
87 
88 Candidate make_peer_reflexive_candidate(const ACE_INET_Addr& address, const ACE_INET_Addr& base, const ACE_INET_Addr& server_address, ACE_UINT32 priority)
89 {
90  Candidate candidate;
91  candidate.address = address;
92  candidate.foundation = std::string("P") + DCPS::LogAddr::ip(base) + "_" + DCPS::LogAddr::ip(server_address) + "U";
93  candidate.priority = priority;
94  candidate.type = PEER_REFLEXIVE;
95  candidate.base = base;
96  return candidate;
97 }
98 
99 Candidate make_peer_reflexive_candidate(const ACE_INET_Addr& address, ACE_UINT32 priority, size_t q)
100 {
101  Candidate candidate;
102  candidate.address = address;
103  candidate.foundation = std::string("Q") + OpenDDS::DCPS::to_dds_string(q) + "U";
104  candidate.priority = priority;
105  candidate.type = PEER_REFLEXIVE;
106  return candidate;
107 }
108 
110 {
112 }
113 
114 struct AgentHolder {
116  : agent_impl(DCPS::make_rch<AgentImpl>())
117  {}
118 
120 };
121 
123 {
125 }
126 
129  size_t indication_count_limit,
130  const DCPS::GuidPrefix_t& guid_prefix)
131 {
132  timestamp_ = DCPS::MonotonicTimePoint::now();
133 
134  if (stun_server_address_ == ACE_INET_Addr() &&
135  address == ACE_INET_Addr()) {
136  // Do nothing.
137  return SRSM_None;
138  } else if (stun_server_address_ == ACE_INET_Addr() &&
139  address != ACE_INET_Addr()) {
140  return start(address, indication_count_limit, guid_prefix);
141  } else if (stun_server_address_ != ACE_INET_Addr() &&
142  address == ACE_INET_Addr()) {
143  return stop();
144  } else {
145  if (stun_server_address_ != address) {
146  const StateChange retval = stop();
147  start(address, indication_count_limit, guid_prefix);
148  return retval;
149  } else {
150  return next_send(indication_count_limit, guid_prefix);
151  }
152  }
153 }
154 
157 {
158  latency_ = DCPS::MonotonicTimePoint::now() - timestamp_;
159  latency_available_ = true;
160 
161  switch (message.class_) {
163  return success_response(message);
164 
166  return error_response(message);
167 
168  case STUN::REQUEST:
169  case STUN::INDICATION:
170  ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::receive: WARNING Unsupported STUN message class %d\n"), message.class_));
171  return SRSM_None;
172  }
173 
174  ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::receive: WARNING Unknown STUN message class %d\n"), message.class_));
175  return SRSM_None;
176 }
177 
180  size_t indication_count_limit,
181  const DCPS::GuidPrefix_t& guid_prefix)
182 {
183  OPENDDS_ASSERT(address != ACE_INET_Addr());
184  OPENDDS_ASSERT(stun_server_address_ == ACE_INET_Addr());
185 
186  // Send a binding request.
187  message_class_ = STUN::REQUEST;
188  send_count_ = 0;
189 
190  stun_server_address_ = address;
191  server_reflexive_address_ = ACE_INET_Addr();
192 
193  return next_send(indication_count_limit, guid_prefix);
194 }
195 
198 {
199  OPENDDS_ASSERT(stun_server_address_ != ACE_INET_Addr());
200  const StateChange retval = server_reflexive_address_ != ACE_INET_Addr() ? SRSM_Unset : SRSM_None;
201  unset_stun_server_address_ = stun_server_address_;
202  stun_server_address_ = ACE_INET_Addr();
203  server_reflexive_address_ = ACE_INET_Addr();
204  send_count_ = 0;
205  return retval;
206 }
207 
209 ServerReflexiveStateMachine::next_send(size_t indication_count_limit,
210  const DCPS::GuidPrefix_t& guid_prefix)
211 {
212  StateChange retval = SRSM_None;
213 
214  if (message_class_ == STUN::REQUEST &&
215  server_reflexive_address_ != ACE_INET_Addr() &&
216  send_count_ == indication_count_limit) {
217  // Reset.
218  retval = SRSM_Unset;
219  server_reflexive_address_ = ACE_INET_Addr();
220  unset_stun_server_address_ = stun_server_address_;
221  }
222 
223  // indication_count_limit is offset by 1 to account for sending the request.
224  if ((server_reflexive_address_ == ACE_INET_Addr()) ||
225  (message_class_ == STUN::INDICATION && send_count_ >= indication_count_limit + 1)) {
226  message_class_ = STUN::REQUEST;
227  send_count_ = 0;
228  }
229 
230  message_ = STUN::Message();
231  message_.class_ = message_class_;
232  message_.method = STUN::BINDING;
233  message_.generate_transaction_id();
234  message_.append_attribute(STUN::make_guid_prefix(guid_prefix));
235  message_.append_attribute(STUN::make_fingerprint());
236 
237  ++send_count_;
238 
239  return retval;
240 }
241 
244 {
245  std::vector<STUN::AttributeType> unknown_attributes = message.unknown_comprehension_required_attributes();
246 
247  if (!unknown_attributes.empty()) {
248  if (DCPS::DCPS_debug_level > 0) {
250  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::success_response: "
251  "WARNING Unknown comprehension required attributes\n")));
252  }
253  return SRSM_None;
254  }
255 
256  ACE_INET_Addr server_reflexive_address;
257 
258  if (!message.get_mapped_address(server_reflexive_address)) {
259  if (DCPS::DCPS_debug_level > 0) {
261  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::success_response: "
262  "WARNING No (XOR)_MAPPED_ADDRESS attribute\n")));
263  }
264  return SRSM_None;
265  }
266 
267  if (server_reflexive_address == ACE_INET_Addr()) {
268  if (DCPS::DCPS_debug_level > 0) {
270  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::success_response: "
271  "WARNING (XOR)_MAPPED_ADDRESS is not valid\n")));
272  }
273  return SRSM_None;
274  }
275 
276  message_class_ = STUN::INDICATION;
277  if (server_reflexive_address == server_reflexive_address_) {
278  return SRSM_None;
279  } else if (server_reflexive_address_ == ACE_INET_Addr()) {
280  server_reflexive_address_ = server_reflexive_address;
281  return SRSM_Set;
282  } else {
283  server_reflexive_address_ = server_reflexive_address;
284  return SRSM_Change;
285  }
286 }
287 
290 {
291  if (message.method != STUN::BINDING) {
292  if (DCPS::DCPS_debug_level > 0) {
294  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::error_response: "
295  "WARNING Unsupported STUN method\n")));
296  }
297  return SRSM_None;
298  }
299 
300 
301  if (!message.has_error_code()) {
302  if (DCPS::DCPS_debug_level > 0) {
303  ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::error_response: "
304  "WARNING No error code\n")));
305  }
306  return SRSM_None;
307  }
308 
309  if (DCPS::DCPS_debug_level > 0) {
311  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::error_response: "
312  "WARNING STUN error response code=%d reason=%C\n"),
313  message.get_error_code(),
314  message.get_error_reason().c_str()));
315 
316  if (message.get_error_code() == STUN::UNKNOWN_ATTRIBUTE && message.has_unknown_attributes()) {
317  std::vector<STUN::AttributeType> unknown_attributes = message.get_unknown_attributes();
318 
319  for (std::vector<STUN::AttributeType>::const_iterator pos = unknown_attributes.begin(),
320  limit = unknown_attributes.end(); pos != limit; ++pos) {
322  ACE_TEXT("(%P|%t) ServerReflexiveStateMachine::error_response: "
323  "WARNING Unknown STUN attribute %d\n"),
324  *pos));
325  }
326  }
327  }
328 
329  return SRSM_None;
330 }
331 
332 } // namespace ICE
333 } // namespace OpenDDS
334 
336 
337 #endif /* OPENDDS_SECURITY */
OpenDDS_Rtps_Export Attribute make_guid_prefix(const DCPS::GuidPrefix_t &guid_prefix)
Definition: Stun.cpp:163
StateChange start(const ACE_INET_Addr &address, size_t indication_count_limit, const DCPS::GuidPrefix_t &guid_prefix)
Definition: Ice.cpp:179
#define ACE_ERROR(X)
bool get_mapped_address(ACE_INET_Addr &address) const
Definition: Stun.cpp:643
StateChange error_response(const STUN::Message &message)
Definition: Ice.cpp:289
StateChange next_send(size_t indication_count_limit, const DCPS::GuidPrefix_t &guid_prefix)
Definition: Ice.cpp:209
ACE_INET_Addr base
Definition: Ice.h:55
String to_dds_string(unsigned short to_convert)
StateChange success_response(const STUN::Message &message)
Definition: Ice.cpp:243
RcHandle< T > make_rch()
Definition: RcHandle_T.h:256
#define OPENDDS_ASSERT(C)
Definition: Definitions.h:72
Candidate make_peer_reflexive_candidate(const ACE_INET_Addr &address, const ACE_INET_Addr &base, const ACE_INET_Addr &server_address, ACE_UINT32 priority)
Definition: Ice.cpp:88
std::vector< AttributeType > get_unknown_attributes() const
Definition: Stun.cpp:786
const ACE_UINT16 UNKNOWN_ATTRIBUTE
Definition: Stun.h:53
int get_type(void) const
ACE_INET_Addr address
Definition: Ice.h:46
Candidate make_host_candidate(const ACE_INET_Addr &address)
Definition: Ice.cpp:64
static TimePoint_T< MonotonicClock > now()
Definition: TimePoint_T.inl:41
bool has_unknown_attributes() const
Definition: Stun.cpp:775
StateChange send(const ACE_INET_Addr &address, size_t indication_count_limit, const DCPS::GuidPrefix_t &guid_prefix)
Definition: Ice.cpp:128
bool candidates_equal(const Candidate &x, const Candidate &y)
Definition: Ice.cpp:34
CandidateType type
Definition: Ice.h:51
ACE_UINT16 get_error_code() const
Definition: Stun.cpp:753
ACE_UINT32 local_priority(const ACE_INET_Addr &addr)
Definition: Ice.cpp:56
std::string foundation
Definition: Ice.h:48
LM_WARNING
StateChange receive(const STUN::Message &message)
Definition: Ice.cpp:156
DCPS::RcHandle< AgentImpl > agent_impl
Definition: Ice.cpp:119
bool has_error_code() const
Definition: Stun.cpp:742
ACE_TEXT("TCP_Factory")
Attribute make_fingerprint()
Definition: Stun.cpp:139
static TYPE * instance(void)
OpenDDS_Dcps_Export unsigned int DCPS_debug_level
Definition: debug.cpp:30
std::string get_error_reason() const
Definition: Stun.cpp:764
octet GuidPrefix_t[12]
Definition: DdsDcpsGuid.idl:19
RcHandle< T > static_rchandle_cast(const RcHandle< U > &h)
Definition: RcHandle_T.h:202
static DCPS::RcHandle< Agent > instance()
Definition: Ice.cpp:122
static Configuration * instance()
Definition: Ice.cpp:109
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
static const String ip(const ACE_INET_Addr &addr)
Definition: LogAddr.cpp:15
Candidate make_server_reflexive_candidate(const ACE_INET_Addr &address, const ACE_INET_Addr &base, const ACE_INET_Addr &server_address)
Definition: Ice.cpp:76
std::vector< AttributeType > unknown_comprehension_required_attributes() const
Definition: Stun.cpp:616
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
ACE_UINT32 priority
Definition: Ice.h:50
bool candidates_sorted(const Candidate &x, const Candidate &y)
Definition: Ice.cpp:21