4
4
* This file is licensed by the GPL version 2. Works owned by the
5
5
* Transmission project are granted a special exemption to clause 2(b)
6
* so that the bulk of its code can remain under the MIT license.
6
* so that the bulk of its code can remain under the MIT license.
7
7
* This exemption does not extend to derived works not owned by
8
8
* the Transmission project.
10
* $Id: natpmp.c 6332 2008-07-15 03:26:53Z charles $
10
* $Id: natpmp.c 7009 2008-11-01 16:39:57Z charles $
13
13
#include <assert.h>
16
16
#include <inttypes.h>
19
#include <winsock2.h> /* inet_ntoa */
21
#include <arpa/inet.h> /* inet_ntoa */
24
18
#define ENABLE_STRNATPMPERR
25
19
#include <libnatpmp/natpmp.h>
27
21
#include "transmission.h"
28
22
#include "natpmp.h"
23
#include "net.h" /* inet_ntoa() */
29
24
#include "port-forwarding.h"
32
27
#define LIFETIME_SECS 3600
33
28
#define COMMAND_WAIT_SECS 8
35
static const char * getKey( void ) { return _( "Port Forwarding (NAT-PMP)" ); }
31
getKey( void ) { return _( "Port Forwarding (NAT-PMP)" ); }
66
logVal( const char * func, int ret )
62
logVal( const char * func,
68
65
if( ret == NATPMP_TRYAGAIN )
71
tr_ninf( getKey(), _( "%s succeeded (%d)" ), func, ret );
68
tr_ninf( getKey( ), _( "%s succeeded (%d)" ), func, ret );
73
tr_ndbg( getKey(), "%s failed. natpmp returned %d (%s); errno is %d (%s)",
74
func, ret, strnatpmperr(ret), errno, tr_strerror(errno) );
72
"%s failed. natpmp returned %d (%s); errno is %d (%s)",
73
func, ret, strnatpmperr( ret ), errno, tr_strerror( errno ) );
79
77
tr_natpmpInit( void )
81
79
struct tr_natpmp * nat;
82
81
nat = tr_new0( struct tr_natpmp, 1 );
83
82
nat->state = TR_NATPMP_DISCOVER;
99
98
canSendCommand( const struct tr_natpmp * nat )
101
return time(NULL) >= nat->commandTime;
100
return time( NULL ) >= nat->commandTime;
105
104
setCommandTime( struct tr_natpmp * nat )
107
nat->commandTime = time(NULL) + COMMAND_WAIT_SECS;
106
nat->commandTime = time( NULL ) + COMMAND_WAIT_SECS;
111
tr_natpmpPulse( struct tr_natpmp * nat, int port, int isEnabled )
110
tr_natpmpPulse( struct tr_natpmp * nat,
126
127
if( ( nat->state == TR_NATPMP_RECV_PUB ) && canSendCommand( nat ) )
128
129
natpmpresp_t response;
129
const int val = readnatpmpresponseorretry( &nat->natpmp, &response );
130
const int val = readnatpmpresponseorretry( &nat->natpmp,
130
132
logVal( "readnatpmpresponseorretry", val );
132
tr_ninf( getKey(), _( "Found public address \"%s\"" ), inet_ntoa( response.pnu.publicaddress.addr ) );
135
tr_ninf( getKey( ), _(
136
"Found public address \"%s\"" ),
137
inet_ntoa( response.pnu.publicaddress.addr ) );
133
138
nat->state = TR_NATPMP_IDLE;
134
} else if( val != NATPMP_TRYAGAIN ) {
140
else if( val != NATPMP_TRYAGAIN )
135
142
nat->state = TR_NATPMP_ERR;
145
152
if( ( nat->state == TR_NATPMP_SEND_UNMAP ) && canSendCommand( nat ) )
147
const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, nat->port, nat->port, 0 );
155
sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP,
156
nat->port, nat->port,
148
158
logVal( "sendnewportmappingrequest", val );
149
159
nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP;
150
160
setCommandTime( nat );
153
163
if( nat->state == TR_NATPMP_RECV_UNMAP )
155
165
natpmpresp_t resp;
156
const int val = readnatpmpresponseorretry( &nat->natpmp, &resp );
166
const int val = readnatpmpresponseorretry( &nat->natpmp, &resp );
157
167
logVal( "readnatpmpresponseorretry", val );
159
tr_ninf( getKey(), _( "no longer forwarding port %d" ), nat->port );
160
nat->state = TR_NATPMP_IDLE;
163
} else if( val != NATPMP_TRYAGAIN ) {
170
const int port = resp.pnu.newportmapping.privateport;
171
tr_ninf( getKey( ), _( "no longer forwarding port %d" ), port );
172
if( nat->port == port )
175
nat->state = TR_NATPMP_IDLE;
179
else if( val != NATPMP_TRYAGAIN )
164
181
nat->state = TR_NATPMP_ERR;
170
187
if( isEnabled && !nat->isMapped && nat->hasDiscovered )
171
188
nat->state = TR_NATPMP_SEND_MAP;
173
else if( nat->isMapped && time(NULL) >= nat->renewTime )
190
else if( nat->isMapped && time( NULL ) >= nat->renewTime )
174
191
nat->state = TR_NATPMP_SEND_MAP;
177
194
if( ( nat->state == TR_NATPMP_SEND_MAP ) && canSendCommand( nat ) )
179
const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, port, port, LIFETIME_SECS );
197
sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP,
180
201
logVal( "sendnewportmappingrequest", val );
181
202
nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP;
182
203
setCommandTime( nat );
185
206
if( nat->state == TR_NATPMP_RECV_MAP )
187
208
natpmpresp_t resp;
188
const int val = readnatpmpresponseorretry( &nat->natpmp, &resp );
209
const int val = readnatpmpresponseorretry( &nat->natpmp, &resp );
189
210
logVal( "readnatpmpresponseorretry", val );
191
213
nat->state = TR_NATPMP_IDLE;
192
214
nat->isMapped = 1;
193
215
nat->renewTime = time( NULL ) + LIFETIME_SECS;
194
216
nat->port = resp.pnu.newportmapping.privateport;
195
tr_ninf( getKey(), _( "Port %d forwarded successfully" ), nat->port );
196
} else if( val != NATPMP_TRYAGAIN ) {
217
tr_ninf( getKey( ), _(
218
"Port %d forwarded successfully" ), nat->port );
220
else if( val != NATPMP_TRYAGAIN )
197
222
nat->state = TR_NATPMP_ERR;
201
switch( nat->state ) {
202
case TR_NATPMP_IDLE: ret = nat->isMapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; break;
203
case TR_NATPMP_DISCOVER: ret = TR_PORT_UNMAPPED; break;
229
ret = nat->isMapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; break;
231
case TR_NATPMP_DISCOVER:
232
ret = TR_PORT_UNMAPPED; break;
204
234
case TR_NATPMP_RECV_PUB:
205
235
case TR_NATPMP_SEND_MAP:
206
case TR_NATPMP_RECV_MAP: ret = TR_PORT_MAPPING; break;
236
case TR_NATPMP_RECV_MAP:
237
ret = TR_PORT_MAPPING; break;
207
239
case TR_NATPMP_SEND_UNMAP:
208
case TR_NATPMP_RECV_UNMAP: ret = TR_PORT_UNMAPPING; break;
209
default: ret = TR_PORT_ERROR; break;
240
case TR_NATPMP_RECV_UNMAP:
241
ret = TR_PORT_UNMAPPING; break;
244
ret = TR_PORT_ERROR; break;