Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "sip/siptransport.h"
19 : #include "connectivity/sip_utils.h"
20 :
21 : #include "jamidht/abstract_sip_transport.h"
22 : #include "jamidht/channeled_transport.h"
23 :
24 : #include "compiler_intrinsics.h"
25 : #include "sip/sipvoiplink.h"
26 :
27 : #include <pjsip.h>
28 : #include <pjsip/sip_types.h>
29 : #include <pjsip/sip_transport_tls.h>
30 : #include <pj/ssl_sock.h>
31 : #include <pjnath.h>
32 : #include <pjnath/stun_config.h>
33 : #include <pjlib.h>
34 : #include <pjlib-util.h>
35 :
36 : #include <dhtnet/multiplexed_socket.h>
37 : #include <dhtnet/ip_utils.h>
38 : #include <dhtnet/tls_session.h>
39 :
40 : #include <opendht/crypto.h>
41 :
42 : #include <stdexcept>
43 : #include <sstream>
44 : #include <algorithm>
45 :
46 : #define RETURN_IF_FAIL(A, VAL, ...) \
47 : if (!(A)) { \
48 : JAMI_ERR(__VA_ARGS__); \
49 : return (VAL); \
50 : }
51 :
52 : namespace jami {
53 :
54 : constexpr const char* TRANSPORT_STATE_STR[] = {"CONNECTED",
55 : "DISCONNECTED",
56 : "SHUTDOWN",
57 : "DESTROY",
58 : "UNKNOWN STATE"};
59 : constexpr const size_t TRANSPORT_STATE_SZ = std::size(TRANSPORT_STATE_STR);
60 :
61 : void
62 1392 : SipTransport::deleteTransport(pjsip_transport* t)
63 : {
64 1392 : pjsip_transport_dec_ref(t);
65 1392 : }
66 :
67 1392 : SipTransport::SipTransport(pjsip_transport* t)
68 1392 : : transport_(nullptr, deleteTransport)
69 : {
70 1392 : if (not t or pjsip_transport_add_ref(t) != PJ_SUCCESS)
71 0 : throw std::runtime_error("Invalid transport");
72 :
73 : // Set pointer here, right after the successful pjsip_transport_add_ref
74 1392 : transport_.reset(t);
75 :
76 4176 : JAMI_DEBUG("SipTransport@{} tr={} rc={:d}",
77 : fmt::ptr(this),
78 : fmt::ptr(transport_.get()),
79 : pj_atomic_get(transport_->ref_cnt));
80 1392 : }
81 :
82 0 : SipTransport::SipTransport(pjsip_transport* t, const std::shared_ptr<TlsListener>& l)
83 0 : : SipTransport(t)
84 : {
85 0 : tlsListener_ = l;
86 0 : }
87 :
88 1368 : SipTransport::SipTransport(pjsip_transport* t,
89 1368 : const std::shared_ptr<dht::crypto::Certificate>& peerCertficate)
90 1368 : : SipTransport(t)
91 : {
92 1368 : tlsInfos_.peerCert = peerCertficate;
93 1368 : }
94 :
95 1392 : SipTransport::~SipTransport()
96 : {
97 4176 : JAMI_DEBUG("~SipTransport@{} tr={} rc={:d}",
98 : fmt::ptr(this),
99 : fmt::ptr(transport_.get()),
100 : pj_atomic_get(transport_->ref_cnt));
101 1392 : }
102 :
103 : bool
104 13 : SipTransport::isAlive(pjsip_transport_state state)
105 : {
106 2 : return state != PJSIP_TP_STATE_DISCONNECTED && state != PJSIP_TP_STATE_SHUTDOWN
107 15 : && state != PJSIP_TP_STATE_DESTROY;
108 : }
109 :
110 : const char*
111 2621 : SipTransport::stateToStr(pjsip_transport_state state)
112 : {
113 2621 : return TRANSPORT_STATE_STR[std::min<size_t>(state, TRANSPORT_STATE_SZ - 1)];
114 : }
115 :
116 : void
117 849 : SipTransport::stateCallback(pjsip_transport_state state, const pjsip_transport_state_info* info)
118 : {
119 849 : connected_ = state == PJSIP_TP_STATE_CONNECTED;
120 :
121 849 : auto extInfo = static_cast<const pjsip_tls_state_info*>(info->ext_info);
122 849 : if (isSecure() && extInfo && extInfo->ssl_sock_info && extInfo->ssl_sock_info->established) {
123 0 : auto tlsInfo = extInfo->ssl_sock_info;
124 0 : tlsInfos_.proto = (pj_ssl_sock_proto) tlsInfo->proto;
125 0 : tlsInfos_.cipher = tlsInfo->cipher;
126 0 : tlsInfos_.verifyStatus = (pj_ssl_cert_verify_flag_t) tlsInfo->verify_status;
127 0 : if (!tlsInfos_.peerCert) {
128 0 : const auto& peers = tlsInfo->remote_cert_info->raw_chain;
129 0 : std::vector<std::pair<const uint8_t*, const uint8_t*>> bits;
130 0 : bits.resize(peers.cnt);
131 0 : std::transform(peers.cert_raw,
132 0 : peers.cert_raw + peers.cnt,
133 : std::begin(bits),
134 0 : [](const pj_str_t& crt) {
135 0 : return std::make_pair((uint8_t*) crt.ptr,
136 0 : (uint8_t*) (crt.ptr + crt.slen));
137 : });
138 0 : tlsInfos_.peerCert = std::make_shared<dht::crypto::Certificate>(bits);
139 0 : }
140 : } else {
141 849 : tlsInfos_ = {};
142 : }
143 :
144 849 : std::vector<SipTransportStateCallback> cbs;
145 : {
146 849 : std::lock_guard lock(stateListenersMutex_);
147 849 : cbs.reserve(stateListeners_.size());
148 963 : for (auto& l : stateListeners_)
149 114 : cbs.push_back(l.second);
150 849 : }
151 963 : for (auto& cb : cbs)
152 114 : cb(state, info);
153 849 : }
154 :
155 : void
156 319 : SipTransport::addStateListener(uintptr_t lid, SipTransportStateCallback cb)
157 : {
158 319 : std::lock_guard lock(stateListenersMutex_);
159 319 : auto pair = stateListeners_.insert(std::make_pair(lid, cb));
160 319 : if (not pair.second)
161 1 : pair.first->second = cb;
162 319 : }
163 :
164 : bool
165 317 : SipTransport::removeStateListener(uintptr_t lid)
166 : {
167 317 : std::lock_guard lock(stateListenersMutex_);
168 317 : auto it = stateListeners_.find(lid);
169 317 : if (it != stateListeners_.end()) {
170 25 : stateListeners_.erase(it);
171 25 : return true;
172 : }
173 292 : return false;
174 317 : }
175 :
176 : uint16_t
177 340 : SipTransport::getTlsMtu()
178 : {
179 340 : return 1232; /* Hardcoded yes (it's the IPv6 value).
180 : * This method is broken by definition.
181 : * A MTU should not be defined at this layer.
182 : * And a correct value should come from the underlying transport itself,
183 : * not from a constant…
184 : */
185 : }
186 :
187 33 : SipTransportBroker::SipTransportBroker(pjsip_endpoint* endpt)
188 33 : : endpt_(endpt)
189 33 : {}
190 :
191 33 : SipTransportBroker::~SipTransportBroker()
192 : {
193 33 : shutdown();
194 :
195 33 : udpTransports_.clear();
196 33 : transports_.clear();
197 :
198 33 : JAMI_DBG("Destroying SipTransportBroker@%p…", this);
199 33 : }
200 :
201 : void
202 2621 : SipTransportBroker::transportStateChanged(pjsip_transport* tp,
203 : pjsip_transport_state state,
204 : const pjsip_transport_state_info* info)
205 : {
206 2621 : JAMI_DBG("pjsip transport@%p %s → %s", tp, tp->info, SipTransport::stateToStr(state));
207 :
208 : // First ensure that this transport is handled by us
209 : // and remove it from any mapping if destroy pending or done.
210 :
211 2621 : std::shared_ptr<SipTransport> sipTransport;
212 2621 : std::lock_guard lock(transportMapMutex_);
213 2621 : auto key = transports_.find(tp);
214 2621 : if (key == transports_.end())
215 0 : return;
216 :
217 2621 : sipTransport = key->second.lock();
218 :
219 2621 : if (!isDestroying_ && state == PJSIP_TP_STATE_DESTROY) {
220 : // maps cleanup
221 1251 : JAMI_DBG("unmap pjsip transport@%p {SipTransport@%p}", tp, sipTransport.get());
222 1251 : transports_.erase(key);
223 :
224 : // If UDP
225 1251 : const auto type = tp->key.type;
226 1251 : if (type == PJSIP_TRANSPORT_UDP or type == PJSIP_TRANSPORT_UDP6) {
227 0 : const auto updKey = std::find_if(udpTransports_.cbegin(),
228 : udpTransports_.cend(),
229 0 : [tp](const std::pair<dhtnet::IpAddr, pjsip_transport*>& pair) {
230 0 : return pair.second == tp;
231 : });
232 0 : if (updKey != udpTransports_.cend())
233 0 : udpTransports_.erase(updKey);
234 : }
235 : }
236 :
237 : // Propagate the event to the appropriate transport
238 : // Note the SipTransport may not be in our mappings if marked as dead
239 2621 : if (sipTransport)
240 849 : sipTransport->stateCallback(state, info);
241 2621 : }
242 :
243 : std::shared_ptr<SipTransport>
244 409 : SipTransportBroker::addTransport(pjsip_transport* t)
245 : {
246 409 : if (t) {
247 409 : std::lock_guard lock(transportMapMutex_);
248 :
249 409 : auto key = transports_.find(t);
250 409 : if (key != transports_.end()) {
251 409 : if (auto sipTr = key->second.lock())
252 409 : return sipTr;
253 : }
254 :
255 0 : auto sipTr = std::make_shared<SipTransport>(t);
256 0 : if (key != transports_.end())
257 0 : key->second = sipTr;
258 : else
259 0 : transports_.emplace(std::make_pair(t, sipTr));
260 0 : return sipTr;
261 409 : }
262 :
263 0 : return nullptr;
264 : }
265 :
266 : void
267 66 : SipTransportBroker::shutdown()
268 : {
269 66 : std::unique_lock lock(transportMapMutex_);
270 66 : isDestroying_ = true;
271 318 : for (auto& t : transports_) {
272 252 : if (auto transport = t.second.lock()) {
273 0 : pjsip_transport_shutdown(transport->get());
274 252 : }
275 : }
276 66 : }
277 :
278 : std::shared_ptr<SipTransport>
279 28 : SipTransportBroker::getUdpTransport(const dhtnet::IpAddr& ipAddress)
280 : {
281 28 : std::lock_guard lock(transportMapMutex_);
282 28 : auto itp = udpTransports_.find(ipAddress);
283 28 : if (itp != udpTransports_.end()) {
284 19 : auto it = transports_.find(itp->second);
285 19 : if (it != transports_.end()) {
286 19 : if (auto spt = it->second.lock()) {
287 4 : JAMI_DBG("Reusing transport %s", ipAddress.toString(true).c_str());
288 4 : return spt;
289 : } else {
290 : // Transport still exists but have not been destroyed yet.
291 15 : JAMI_WARN("Recycling transport %s", ipAddress.toString(true).c_str());
292 15 : auto ret = std::make_shared<SipTransport>(itp->second);
293 15 : it->second = ret;
294 15 : return ret;
295 34 : }
296 : } else {
297 0 : JAMI_WARN("Cleaning up UDP transport %s", ipAddress.toString(true).c_str());
298 0 : udpTransports_.erase(itp);
299 : }
300 : }
301 9 : auto ret = createUdpTransport(ipAddress);
302 9 : if (ret) {
303 9 : udpTransports_[ipAddress] = ret->get();
304 9 : transports_[ret->get()] = ret;
305 : }
306 9 : return ret;
307 28 : }
308 :
309 : std::shared_ptr<SipTransport>
310 9 : SipTransportBroker::createUdpTransport(const dhtnet::IpAddr& ipAddress)
311 : {
312 9 : RETURN_IF_FAIL(ipAddress, nullptr, "Unable to determine IP address for this transport");
313 :
314 : pjsip_udp_transport_cfg pj_cfg;
315 9 : pjsip_udp_transport_cfg_default(&pj_cfg, ipAddress.getFamily());
316 9 : pj_cfg.bind_addr = ipAddress;
317 9 : pjsip_transport* transport = nullptr;
318 9 : if (pj_status_t status = pjsip_udp_transport_start2(endpt_, &pj_cfg, &transport)) {
319 0 : JAMI_ERR("pjsip_udp_transport_start2 failed with error %d: %s",
320 : status,
321 : sip_utils::sip_strerror(status).c_str());
322 0 : JAMI_ERR("UDP IPv%s Transport did not start on %s",
323 : ipAddress.isIpv4() ? "4" : "6",
324 : ipAddress.toString(true).c_str());
325 0 : return nullptr;
326 : }
327 :
328 9 : JAMI_DBG("Created UDP transport on address %s", ipAddress.toString(true).c_str());
329 9 : return std::make_shared<SipTransport>(transport);
330 : }
331 :
332 : std::shared_ptr<TlsListener>
333 0 : SipTransportBroker::getTlsListener(const dhtnet::IpAddr& ipAddress, const pjsip_tls_setting* settings)
334 : {
335 0 : RETURN_IF_FAIL(settings, nullptr, "TLS settings not specified");
336 0 : RETURN_IF_FAIL(ipAddress, nullptr, "Unable to determine IP address for this transport");
337 0 : JAMI_DEBUG("Creating TLS listener on {:s}…", ipAddress.toString(true));
338 : #if 0
339 : JAMI_DBG(" ca_list_file : %s", settings->ca_list_file.ptr);
340 : JAMI_DBG(" cert_file : %s", settings->cert_file.ptr);
341 : JAMI_DBG(" ciphers_num : %d", settings->ciphers_num);
342 : JAMI_DBG(" verify server %d client %d client_cert %d", settings->verify_server, settings->verify_client, settings->require_client_cert);
343 : JAMI_DBG(" reuse_addr : %d", settings->reuse_addr);
344 : #endif
345 :
346 0 : pjsip_tpfactory* listener = nullptr;
347 : const pj_status_t status
348 0 : = pjsip_tls_transport_start2(endpt_, settings, ipAddress.pjPtr(), nullptr, 1, &listener);
349 0 : if (status != PJ_SUCCESS) {
350 0 : JAMI_ERR("TLS listener did not start: %s", sip_utils::sip_strerror(status).c_str());
351 0 : return nullptr;
352 : }
353 0 : return std::make_shared<TlsListener>(listener);
354 : }
355 :
356 : std::shared_ptr<SipTransport>
357 0 : SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l,
358 : const dhtnet::IpAddr& remote,
359 : const std::string& remote_name)
360 : {
361 0 : if (!l || !remote)
362 0 : return nullptr;
363 0 : dhtnet::IpAddr remoteAddr {remote};
364 0 : if (remoteAddr.getPort() == 0)
365 0 : remoteAddr.setPort(pjsip_transport_get_default_port_for_type(l->get()->type));
366 :
367 0 : JAMI_DBG("Get new TLS transport to %s", remoteAddr.toString(true).c_str());
368 : pjsip_tpselector sel;
369 0 : sel.type = PJSIP_TPSELECTOR_LISTENER;
370 0 : sel.u.listener = l->get();
371 0 : sel.disable_connection_reuse = PJ_FALSE;
372 :
373 : pjsip_tx_data tx_data;
374 0 : tx_data.dest_info.name = pj_str_t {(char*) remote_name.data(), (pj_ssize_t) remote_name.size()};
375 :
376 0 : pjsip_transport* transport = nullptr;
377 0 : pj_status_t status = pjsip_endpt_acquire_transport2(endpt_,
378 0 : l->get()->type,
379 0 : remoteAddr.pjPtr(),
380 0 : remoteAddr.getLength(),
381 : &sel,
382 0 : remote_name.empty() ? nullptr : &tx_data,
383 : &transport);
384 :
385 0 : if (!transport || status != PJ_SUCCESS) {
386 0 : JAMI_ERR("Unable to get new TLS transport: %s", sip_utils::sip_strerror(status).c_str());
387 0 : return nullptr;
388 : }
389 0 : auto ret = std::make_shared<SipTransport>(transport, l);
390 0 : pjsip_transport_dec_ref(transport);
391 : {
392 0 : std::lock_guard lock(transportMapMutex_);
393 0 : transports_[ret->get()] = ret;
394 0 : }
395 0 : return ret;
396 0 : }
397 :
398 : std::shared_ptr<SipTransport>
399 1367 : SipTransportBroker::getChanneledTransport(const std::shared_ptr<SIPAccountBase>& account,
400 : const std::shared_ptr<dhtnet::ChannelSocket>& socket,
401 : onShutdownCb&& cb)
402 : {
403 1367 : if (!socket)
404 0 : return {};
405 1367 : auto sips_tr = std::make_unique<tls::ChanneledSIPTransport>(endpt_,
406 : socket,
407 1367 : std::move(cb));
408 1368 : auto tr = sips_tr->getTransportBase();
409 1368 : auto sip_tr = std::make_shared<SipTransport>(tr, socket->peerCertificate());
410 1368 : sip_tr->setDeviceId(socket->deviceId().toString());
411 1368 : sip_tr->setAccount(account);
412 :
413 : {
414 1368 : std::lock_guard lock(transportMapMutex_);
415 : // we do not check for key existence as we've just created it
416 : // (member of new SipIceTransport instance)
417 1368 : transports_.emplace(tr, sip_tr);
418 1368 : }
419 :
420 1368 : sips_tr->start();
421 1368 : sips_tr.release(); // managed by PJSIP now
422 1368 : return sip_tr;
423 1368 : }
424 :
425 : } // namespace jami
|