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