1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
/*
* Copyright (c) 2011 Tobias Markmann
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Network/NATPMPInterface.h>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <Swiften/Base/Log.h>
// This has to be included after the previous headers, because of WIN32 macro
// being defined somewhere.
#include <natpmp.h>
#pragma GCC diagnostic ignored "-Wold-style-cast"
namespace Swift {
struct NATPMPInterface::Private {
natpmp_t natpmp;
};
NATPMPInterface::NATPMPInterface() : p(boost::make_shared<Private>()) {
initnatpmp(&p->natpmp, 0, 0);
}
NATPMPInterface::~NATPMPInterface() {
closenatpmp(&p->natpmp);
}
bool NATPMPInterface::isAvailable() {
return getPublicIP();
}
boost::optional<HostAddress> NATPMPInterface::getPublicIP() {
if (sendpublicaddressrequest(&p->natpmp) < 0) {
SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl;
return boost::optional<HostAddress>();
}
int r = 0;
natpmpresp_t response;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(p->natpmp.s, &fds);
getnatpmprequesttimeout(&p->natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&p->natpmp, &response);
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
return boost::optional<HostAddress>(HostAddress(reinterpret_cast<const unsigned char*>(&(response.pnu.publicaddress.addr)), 4));
}
else {
SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl;
return boost::optional<HostAddress>();
}
}
boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) {
NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP);
if (sendnewportmappingrequest(
&p->natpmp,
mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP,
boost::numeric_cast<uint16_t>(mapping.getLocalPort()),
boost::numeric_cast<uint16_t>(mapping.getPublicPort()),
mapping.getLeaseInSeconds()) < 0) {
SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl;
return boost::optional<NATPortMapping>();
}
int r = 0;
natpmpresp_t response;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(p->natpmp.s, &fds);
getnatpmprequesttimeout(&p->natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&p->natpmp, &response);
} while(r == NATPMP_TRYAGAIN);
if (r == 0) {
NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, response.pnu.newportmapping.lifetime);
return result;
}
else {
SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl;
return boost::optional<NATPortMapping>();
}
}
bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) {
if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.getLocalPort()) < 0) {
SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl;
return false;
}
int r = 0;
natpmpresp_t response;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(p->natpmp.s, &fds);
getnatpmprequesttimeout(&p->natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&p->natpmp, &response);
} while(r == NATPMP_TRYAGAIN);
if (r == 0) {
return true;
}
else {
SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl;
return false;
}
}
}
|