blob: 846553f4d0be3d048e118f9b575032a21955ef0e [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraud612b55b2023-05-29 10:42:04 -04005 * it under the terms of the GNU General Public License as published by
Adrien Béraudcb753622023-07-17 22:32:49 -04006 * the Free Software Foundation, either version 3 of the License, or
Adrien Béraud612b55b2023-05-29 10:42:04 -04007 * (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
Adrien Béraudcb753622023-07-17 22:32:49 -040011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Adrien Béraud612b55b2023-05-29 10:42:04 -040012 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
Adrien Béraudcb753622023-07-17 22:32:49 -040015 * along with this program. If not, see <https://www.gnu.org/licenses/>.
Adrien Béraud612b55b2023-05-29 10:42:04 -040016 */
Morteza Namvar5f639522023-07-04 17:08:58 -040017#include "upnp/mapping.h"
18// #include "logger.h"
Adrien Béraud33a03ba2023-06-21 11:35:54 -040019#include "igd.h"
Adrien Béraud612b55b2023-05-29 10:42:04 -040020
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040021namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040022namespace upnp {
23
Adrien Berauda8731ac2023-08-17 12:19:39 -040024using namespace std::literals;
25
Adrien Béraud612b55b2023-05-29 10:42:04 -040026Mapping::Mapping(PortType type, uint16_t portExternal, uint16_t portInternal, bool available)
27 : type_(type)
28 , externalPort_(portExternal)
29 , internalPort_(portInternal)
30 , internalAddr_()
31 , igd_()
32 , available_(available)
33 , state_(MappingState::PENDING)
34 , notifyCb_(nullptr)
35 , autoUpdate_(false)
36#if HAVE_LIBNATPMP
37 , renewalTime_(sys_clock::now())
38#endif
39{}
40
41Mapping::Mapping(const Mapping& other)
42{
Adrien Béraud024c46f2024-03-02 23:53:18 -050043 std::lock_guard lock(other.mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -040044
45 internalAddr_ = other.internalAddr_;
46 internalPort_ = other.internalPort_;
47 externalPort_ = other.externalPort_;
48 type_ = other.type_;
49 igd_ = other.igd_;
50 available_ = other.available_;
51 state_ = other.state_;
52 notifyCb_ = other.notifyCb_;
53 autoUpdate_ = other.autoUpdate_;
54#if HAVE_LIBNATPMP
55 renewalTime_ = other.renewalTime_;
56#endif
57}
58
59void
60Mapping::updateFrom(const Mapping::sharedPtr_t& other)
61{
62 updateFrom(*other);
63}
64
65void
66Mapping::updateFrom(const Mapping& other)
67{
68 if (type_ != other.type_) {
Morteza Namvar5f639522023-07-04 17:08:58 -040069 // JAMI_ERR("The source and destination types must match");
Adrien Béraud612b55b2023-05-29 10:42:04 -040070 return;
71 }
72
73 internalAddr_ = std::move(other.internalAddr_);
74 internalPort_ = other.internalPort_;
75 externalPort_ = other.externalPort_;
76 igd_ = other.igd_;
77 state_ = other.state_;
78}
79
80void
81Mapping::setAvailable(bool val)
82{
Morteza Namvar5f639522023-07-04 17:08:58 -040083 // JAMI_DBG("Changing mapping %s state from %s to %s",
84 // toString().c_str(),
85 // available_ ? "AVAILABLE" : "UNAVAILABLE",
86 // val ? "AVAILABLE" : "UNAVAILABLE");
Adrien Béraud612b55b2023-05-29 10:42:04 -040087
Adrien Béraud024c46f2024-03-02 23:53:18 -050088 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -040089 available_ = val;
90}
91
92void
93Mapping::setState(const MappingState& state)
94{
Adrien Béraud024c46f2024-03-02 23:53:18 -050095 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -040096 state_ = state;
97}
98
99const char*
100Mapping::getStateStr() const
101{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500102 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400103 return getStateStr(state_);
104}
105
106std::string
107Mapping::toString(bool extraInfo) const
108{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500109 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400110 std::ostringstream descr;
111 descr << UPNP_MAPPING_DESCRIPTION_PREFIX << "-" << getTypeStr(type_);
112 descr << ":" << std::to_string(internalPort_);
113
114 if (extraInfo) {
115 descr << " (state=" << getStateStr(state_)
116 << ", auto-update=" << (autoUpdate_ ? "YES" : "NO") << ")";
117 }
118
119 return descr.str();
120}
121
122bool
123Mapping::isValid() const
124{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500125 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400126 if (state_ == MappingState::FAILED)
127 return false;
128 if (internalPort_ == 0)
129 return false;
130 if (externalPort_ == 0)
131 return false;
132 if (not igd_ or not igd_->isValid())
133 return false;
134 IpAddr intAddr(internalAddr_);
135 return intAddr and not intAddr.isLoopback();
136}
137
138bool
139Mapping::hasValidHostAddress() const
140{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500141 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400142
143 IpAddr intAddr(internalAddr_);
144 return intAddr and not intAddr.isLoopback();
145}
146
147bool
148Mapping::hasPublicAddress() const
149{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500150 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400151
152 return igd_ and igd_->getPublicIp() and not igd_->getPublicIp().isPrivate();
153}
154
155Mapping::key_t
156Mapping::getMapKey() const
157{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500158 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400159
160 key_t mapKey = internalPort_;
161 if (type_ == PortType::UDP)
162 mapKey |= 1 << (sizeof(uint16_t) * 8);
163 return mapKey;
164}
165
166PortType
167Mapping::getTypeFromMapKey(key_t key)
168{
169 return (key >> (sizeof(uint16_t) * 8)) ? PortType::UDP : PortType::TCP;
170}
171
172std::string
173Mapping::getExternalAddress() const
174{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500175 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400176 if (igd_)
177 return igd_->getPublicIp().toString();
178 return {};
179}
180
181void
182Mapping::setExternalPort(uint16_t port)
183{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500184 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400185 externalPort_ = port;
186}
187
188uint16_t
189Mapping::getExternalPort() const
190{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500191 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400192 return externalPort_;
193}
194
195std::string
196Mapping::getExternalPortStr() const
197{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500198 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400199 return std::to_string(externalPort_);
200}
201
202void
203Mapping::setInternalAddress(const std::string& addr)
204{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500205 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400206 internalAddr_ = addr;
207}
208
209std::string
210Mapping::getInternalAddress() const
211{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500212 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400213 return internalAddr_;
214}
215
216void
217Mapping::setInternalPort(uint16_t port)
218{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500219 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400220 internalPort_ = port;
221}
222
223uint16_t
224Mapping::getInternalPort() const
225{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500226 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400227 return internalPort_;
228}
229
230std::string
231Mapping::getInternalPortStr() const
232{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500233 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400234 return std::to_string(internalPort_);
235}
236
237PortType
238Mapping::getType() const
239{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500240 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400241 return type_;
242}
243
244const char*
245Mapping::getTypeStr() const
246{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500247 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400248 return getTypeStr(type_);
249}
250
251bool
252Mapping::isAvailable() const
253{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500254 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400255 return available_;
256}
257
258std::shared_ptr<IGD>
259Mapping::getIgd() const
260{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500261 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400262 return igd_;
263}
264
265NatProtocolType
266Mapping::getProtocol() const
267{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500268 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400269 if (igd_)
270 return igd_->getProtocol();
271 return NatProtocolType::UNKNOWN;
272}
Adrien Berauda8731ac2023-08-17 12:19:39 -0400273
274std::string_view
Adrien Béraud612b55b2023-05-29 10:42:04 -0400275Mapping::getProtocolName() const
276{
Adrien Berauda8731ac2023-08-17 12:19:39 -0400277 switch(getProtocol()) {
278 case NatProtocolType::NAT_PMP:
279 return "NAT-PMP"sv;
280 case NatProtocolType::PUPNP:
281 return "PUPNP"sv;
282 default:
283 return "UNKNOWN"sv;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400284 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400285}
286
287void
288Mapping::setIgd(const std::shared_ptr<IGD>& igd)
289{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500290 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400291 igd_ = igd;
292}
293
294MappingState
295Mapping::getState() const
296{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500297 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400298 return state_;
299}
300
301Mapping::NotifyCallback
302Mapping::getNotifyCallback() const
303{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500304 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400305 return notifyCb_;
306}
307
308void
309Mapping::setNotifyCallback(NotifyCallback cb)
310{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500311 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400312 notifyCb_ = std::move(cb);
313}
314
315void
316Mapping::enableAutoUpdate(bool enable)
317{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500318 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400319 autoUpdate_ = enable;
320}
321
322bool
323Mapping::getAutoUpdate() const
324{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500325 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400326 return autoUpdate_;
327}
328
329#if HAVE_LIBNATPMP
330sys_clock::time_point
331Mapping::getRenewalTime() const
332{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500333 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400334 return renewalTime_;
335}
336
337void
338Mapping::setRenewalTime(sys_clock::time_point time)
339{
Adrien Béraud024c46f2024-03-02 23:53:18 -0500340 std::lock_guard lock(mutex_);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400341 renewalTime_ = time;
342}
343#endif
344
345} // namespace upnp
Sébastien Blin464bdff2023-07-19 08:02:53 -0400346} // namespace dhtnet