~ubuntu-branches/ubuntu/jaunty/transmission/jaunty-security

« back to all changes in this revision

Viewing changes to libtransmission/natpmp.c

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2008-11-28 15:33:48 UTC
  • mfrom: (1.1.19 upstream)
  • Revision ID: james.westby@ubuntu.com-20081128153348-it70trfnxiroblmc
Tags: 1.40-0ubuntu1
* New upstream release (LP: #302672)
  - Tracker communication uses fewer resources
  - More accurate bandwidth limits
  - Reduce disk fragmentation by preallocating files (LP: #287726)
  - Stability, security and performance improvements to the RPC /
    Web UI server (closes LP: #290423)
  - Support compression when serving Web UI and RPC responses
  - Simplify the RPC whitelist
  - Fix bug that prevented handshakes with encrypted BitComet peers
  - Fix 1.3x bug that could re-download some data unnecessarily
    (LP: #295040)
  - Option to automatically update the blocklist weekly
  - Added off-hour bandwidth scheduling
  - Simplify file/priority selection in the details dialog
  - Fix a couple of crashes
  - New / updated translations
  - Don't inhibit hibernation by default (LP: #292929)
  - Use "close" animation when sending to notification area (LP: #130811)
  - Fix resize problems (LP: #269872)
  - Support "--version" option when launching from command line
    (LP: #292011)
  - Correctly parse announce URLs that have leading or trailing
    spaces (LP: #262411)
  - Display an error when "Open Torrent" fails (LP: #281463)
* Dropped 10_fix_crasher_from_upstream.dpatch: Fix is in this
  upstream release.
* debian/control: Don't just build-depend on libcurl-dev, which is
  a virtual package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 *
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.
9
9
 *
10
 
 * $Id: natpmp.c 6332 2008-07-15 03:26:53Z charles $
 
10
 * $Id: natpmp.c 7009 2008-11-01 16:39:57Z charles $
11
11
 */
12
12
 
13
13
#include <assert.h>
15
15
#include <time.h>
16
16
#include <inttypes.h>
17
17
 
18
 
#ifdef WIN32
19
 
#include <winsock2.h> /* inet_ntoa */
20
 
#else
21
 
#include <arpa/inet.h> /* inet_ntoa */
22
 
#endif
23
 
 
24
18
#define ENABLE_STRNATPMPERR
25
19
#include <libnatpmp/natpmp.h>
26
20
 
27
21
#include "transmission.h"
28
22
#include "natpmp.h"
 
23
#include "net.h" /* inet_ntoa() */
29
24
#include "port-forwarding.h"
30
25
#include "utils.h"
31
26
 
32
27
#define LIFETIME_SECS 3600
33
28
#define COMMAND_WAIT_SECS 8
34
29
 
35
 
static const char * getKey( void ) { return _( "Port Forwarding (NAT-PMP)" ); }
 
30
static const char *
 
31
getKey( void ) { return _( "Port Forwarding (NAT-PMP)" ); }
36
32
 
37
33
typedef enum
38
34
{
46
42
    TR_NATPMP_RECV_UNMAP
47
43
}
48
44
tr_natpmp_state;
49
 
    
 
45
 
50
46
struct tr_natpmp
51
47
{
52
 
    int port;
53
 
    unsigned int isMapped      : 1;
54
 
    unsigned int hasDiscovered : 1;
55
 
    time_t renewTime;
56
 
    time_t commandTime;
57
 
    tr_natpmp_state state;
58
 
    natpmp_t natpmp;
 
48
    int                port;
 
49
    unsigned int       isMapped      : 1;
 
50
    unsigned int       hasDiscovered : 1;
 
51
    time_t             renewTime;
 
52
    time_t             commandTime;
 
53
    tr_natpmp_state    state;
 
54
    natpmp_t           natpmp;
59
55
};
60
56
 
61
57
/**
63
59
**/
64
60
 
65
61
static void
66
 
logVal( const char * func, int ret )
 
62
logVal( const char * func,
 
63
        int          ret )
67
64
{
68
65
    if( ret == NATPMP_TRYAGAIN )
69
66
        return;
70
67
    if( ret >= 0 )
71
 
        tr_ninf( getKey(), _( "%s succeeded (%d)" ), func, ret );
 
68
        tr_ninf( getKey( ), _( "%s succeeded (%d)" ), func, ret );
72
69
    else
73
 
        tr_ndbg( getKey(), "%s failed.  natpmp returned %d (%s); errno is %d (%s)",
74
 
                 func, ret, strnatpmperr(ret), errno, tr_strerror(errno) );
75
 
 
 
70
        tr_ndbg(
 
71
             getKey( ),
 
72
            "%s failed.  natpmp returned %d (%s); errno is %d (%s)",
 
73
            func, ret, strnatpmperr( ret ), errno, tr_strerror( errno ) );
76
74
}
77
75
 
78
76
struct tr_natpmp*
79
77
tr_natpmpInit( void )
80
78
{
81
79
    struct tr_natpmp * nat;
 
80
 
82
81
    nat = tr_new0( struct tr_natpmp, 1 );
83
82
    nat->state = TR_NATPMP_DISCOVER;
84
83
    nat->port = -1;
98
97
static int
99
98
canSendCommand( const struct tr_natpmp * nat )
100
99
{
101
 
    return time(NULL) >= nat->commandTime;
 
100
    return time( NULL ) >= nat->commandTime;
102
101
}
103
102
 
104
103
static void
105
104
setCommandTime( struct tr_natpmp * nat )
106
105
{
107
 
    nat->commandTime = time(NULL) + COMMAND_WAIT_SECS;
 
106
    nat->commandTime = time( NULL ) + COMMAND_WAIT_SECS;
108
107
}
109
108
 
110
109
int
111
 
tr_natpmpPulse( struct tr_natpmp * nat, int port, int isEnabled )
 
110
tr_natpmpPulse( struct tr_natpmp * nat,
 
111
                int                port,
 
112
                int                isEnabled )
112
113
{
113
114
    int ret;
114
115
 
126
127
    if( ( nat->state == TR_NATPMP_RECV_PUB ) && canSendCommand( nat ) )
127
128
    {
128
129
        natpmpresp_t response;
129
 
        const int val = readnatpmpresponseorretry( &nat->natpmp, &response );
 
130
        const int    val = readnatpmpresponseorretry( &nat->natpmp,
 
131
                                                      &response );
130
132
        logVal( "readnatpmpresponseorretry", val );
131
 
        if( val >= 0 ) {
132
 
            tr_ninf( getKey(), _( "Found public address \"%s\"" ), inet_ntoa( response.pnu.publicaddress.addr ) );
 
133
        if( val >= 0 )
 
134
        {
 
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 ) {
 
139
        }
 
140
        else if( val != NATPMP_TRYAGAIN )
 
141
        {
135
142
            nat->state = TR_NATPMP_ERR;
136
143
        }
137
144
    }
144
151
 
145
152
    if( ( nat->state == TR_NATPMP_SEND_UNMAP ) && canSendCommand( nat ) )
146
153
    {
147
 
        const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, nat->port, nat->port, 0 );
 
154
        const int val =
 
155
            sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP,
 
156
                                       nat->port, nat->port,
 
157
                                       0 );
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 )
154
164
    {
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 );
158
 
        if( val >= 0 ) {
159
 
            tr_ninf( getKey(), _( "no longer forwarding port %d" ), nat->port );
160
 
            nat->state = TR_NATPMP_IDLE;
161
 
            nat->port = -1;
162
 
            nat->isMapped = 0;
163
 
        } else if( val != NATPMP_TRYAGAIN ) {
 
168
        if( val >= 0 )
 
169
        {
 
170
            const int port = resp.pnu.newportmapping.privateport;
 
171
            tr_ninf( getKey( ), _( "no longer forwarding port %d" ), port );
 
172
            if( nat->port == port )
 
173
            {
 
174
                nat->port = -1;
 
175
                nat->state = TR_NATPMP_IDLE;
 
176
                nat->isMapped = 0;
 
177
            }
 
178
        }
 
179
        else if( val != NATPMP_TRYAGAIN )
 
180
        {
164
181
            nat->state = TR_NATPMP_ERR;
165
182
        }
166
183
    }
170
187
        if( isEnabled && !nat->isMapped && nat->hasDiscovered )
171
188
            nat->state = TR_NATPMP_SEND_MAP;
172
189
 
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;
175
192
    }
176
193
 
177
194
    if( ( nat->state == TR_NATPMP_SEND_MAP ) && canSendCommand( nat ) )
178
195
    {
179
 
        const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, port, port, LIFETIME_SECS );
 
196
        const int val =
 
197
            sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP,
 
198
                                       port,
 
199
                                       port,
 
200
                                       LIFETIME_SECS );
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 )
186
207
    {
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 );
190
 
        if( val >= 0 ) {
 
211
        if( val >= 0 )
 
212
        {
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 );
 
219
        }
 
220
        else if( val != NATPMP_TRYAGAIN )
 
221
        {
197
222
            nat->state = TR_NATPMP_ERR;
198
223
        }
199
224
    }
200
225
 
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;
 
226
    switch( nat->state )
 
227
    {
 
228
        case TR_NATPMP_IDLE:
 
229
            ret = nat->isMapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; break;
 
230
 
 
231
        case TR_NATPMP_DISCOVER:
 
232
            ret = TR_PORT_UNMAPPED; break;
 
233
 
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;
 
238
 
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;
 
242
 
 
243
        default:
 
244
            ret = TR_PORT_ERROR; break;
210
245
    }
211
246
    return ret;
212
247
}
 
248