source: trunk/libtransmission/natpmp.c @ 2343

Last change on this file since 2343 was 2343, checked in by joshe, 14 years ago

Change a couple functions to take an in_addr pointer instead of an in_addr.
Forward declare struct in_addr and include the relevant headers in the .c files where it's used.

  • Property svn:keywords set to Date Rev Author Id
File size: 22.7 KB
Line 
1/******************************************************************************
2 * $Id: natpmp.c 2343 2007-07-14 16:29:21Z joshe $
3 *
4 * Copyright (c) 2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29
30#include "transmission.h"
31#include "natpmp.h"
32#include "net.h"
33
34#define PMP_PORT                5351
35#define PMP_MCAST_ADDR          "224.0.0.1"
36#define PMP_INITIAL_DELAY       250     /* ms, 1/4 second */
37#define PMP_TOTAL_DELAY         120000  /* ms, 2 minutes */
38#define PMP_VERSION             0
39#define PMP_OPCODE_GETIP        0
40#define PMP_OPCODE_ADDUDP       1
41#define PMP_OPCODE_ADDTCP       2
42#define PMP_LIFETIME            3600    /* secs, one hour */
43#define PMP_RESULT_OK           0
44#define PMP_RESULT_BADVERS      1
45#define PMP_RESULT_REFUSED      2
46#define PMP_RESULT_NETDOWN      3
47#define PMP_RESULT_NOMEM        4
48#define PMP_RESULT_BADOPCODE    5
49
50#define PMP_OPCODE_FROM_RESPONSE( op )  ( 0x80 ^ (op) )
51#define PMP_OPCODE_TO_RESPONSE( op )    ( 0x80 | (op) )
52#define PMP_OPCODE_IS_RESPONSE( op )    ( 0x80 & (op) )
53#define PMP_TOBUF16( buf, num ) ( *( (uint16_t *) (buf) ) = htons( (num) ) )
54#define PMP_TOBUF32( buf, num ) ( *( (uint32_t *) (buf) ) = htonl( (num) ) )
55#define PMP_FROMBUF16( buf )    ( htons( *( (uint16_t *) (buf) ) ) )
56#define PMP_FROMBUF32( buf )    ( htonl( *( (uint32_t *) (buf) ) ) )
57
58typedef struct tr_natpmp_uptime_s
59{
60    time_t   when;
61    uint32_t uptime;
62} tr_natpmp_uptime_t;
63
64typedef struct tr_natpmp_req_s
65{
66    unsigned int         adding : 1;
67    unsigned int         nobodyhome : 1;
68    unsigned int         tmpfail : 1;
69    int                  fd;
70    int                  delay;
71    uint64_t             retry;
72    uint64_t             timeout;
73    int                  askport;
74    int                  gotport;
75} tr_natpmp_req_t;
76
77struct tr_natpmp_s
78{
79#define PMP_STATE_IDLE          1
80#define PMP_STATE_ADDING        2
81#define PMP_STATE_DELETING      3
82#define PMP_STATE_MAPPED        4
83#define PMP_STATE_FAILED        5
84#define PMP_STATE_NOBODYHOME    6
85#define PMP_STATE_TMPFAIL       7
86    char               state;
87    unsigned int       active : 1;
88    unsigned int       mapped : 1;
89    struct in_addr     dest;
90    int                newport;
91    int                mappedport;
92    uint64_t           renew;
93    tr_natpmp_req_t *  req;
94    tr_natpmp_uptime_t uptime;
95    int                mcastfd;
96};
97
98typedef struct tr_natpmp_parse_s
99{
100    unsigned int tmpfail : 1;
101    uint32_t     seconds;
102    uint16_t     port;
103    uint32_t     lifetime;
104}
105tr_natpmp_parse_t;
106
107static void
108unmap( tr_natpmp_t * pmp );
109static int
110checktime( tr_natpmp_uptime_t * uptime, uint32_t seen );
111static void
112killsock( int * fd );
113static tr_natpmp_req_t *
114newreq( int adding, struct in_addr addr, int port );
115static void
116killreq( tr_natpmp_req_t ** req );
117static void
118resetreq( tr_natpmp_req_t * req );
119static tr_tristate_t
120pulsereq( tr_natpmp_t * req );
121static int
122sendreq( tr_natpmp_req_t * req );
123static int
124mcastsetup();
125static void
126mcastpulse( tr_natpmp_t * pmp );
127static tr_tristate_t
128parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse );
129
130tr_natpmp_t *
131tr_natpmpInit()
132{
133    tr_natpmp_t * pmp;
134
135    pmp = calloc( 1, sizeof( *pmp ) );
136    if( NULL == pmp )
137    {
138        return NULL;
139    }
140
141    pmp->state       = PMP_STATE_IDLE;
142    pmp->mcastfd     = -1;
143
144    if( tr_getDefaultRoute( &pmp->dest ) || INADDR_ANY == pmp->dest.s_addr )
145    {
146        pmp->dest.s_addr = INADDR_NONE;
147    }
148
149    if( INADDR_NONE == pmp->dest.s_addr )
150    {
151        tr_dbg( "nat-pmp device is unknown" );
152    }
153    else
154    {
155        char addrstr[INET_ADDRSTRLEN];
156        tr_netNtop( &pmp->dest, addrstr, sizeof( addrstr ) );
157        tr_dbg( "nat-pmp device is %s", addrstr );
158    }
159
160    return pmp;
161}
162
163void
164tr_natpmpStart( tr_natpmp_t * pmp )
165{
166    if( !pmp->active )
167    {
168        tr_inf( "starting nat-pmp" );
169        pmp->active = 1;
170        if( 0 > pmp->mcastfd )
171        {
172            pmp->mcastfd = mcastsetup();
173        }
174    }
175}
176
177void
178tr_natpmpStop( tr_natpmp_t * pmp )
179{
180    if( pmp->active )
181    {
182        tr_inf( "stopping nat-pmp" );
183        pmp->active = 0;
184        killsock( &pmp->mcastfd );
185        unmap( pmp );
186    }
187}
188
189int
190tr_natpmpStatus( tr_natpmp_t * pmp )
191{
192    int ret;
193   
194    if( !pmp->active )
195    {
196        ret = ( PMP_STATE_DELETING == pmp->state ?
197                TR_NAT_TRAVERSAL_UNMAPPING : TR_NAT_TRAVERSAL_DISABLED );
198    }
199    else if( pmp->mapped )
200    {
201        ret = TR_NAT_TRAVERSAL_MAPPED;
202    }
203    else
204    {
205        switch( pmp->state )
206        {
207            case PMP_STATE_IDLE:
208            case PMP_STATE_ADDING:
209            case PMP_STATE_DELETING:
210                ret = TR_NAT_TRAVERSAL_MAPPING;
211                break;
212            case PMP_STATE_FAILED:
213            case PMP_STATE_TMPFAIL:
214                ret = TR_NAT_TRAVERSAL_ERROR;
215                break;
216            case PMP_STATE_NOBODYHOME:
217                ret = TR_NAT_TRAVERSAL_NOTFOUND;
218                break;
219            case PMP_STATE_MAPPED:
220            default:
221                /* if pmp->state is PMP_STATE_MAPPED then pmp->mapped
222                   should be true */
223                assert( 0 );
224                ret = TR_NAT_TRAVERSAL_ERROR;
225                break;
226        }
227    }
228
229    return ret;
230}
231
232void
233tr_natpmpForwardPort( tr_natpmp_t * pmp, int port )
234{
235    tr_inf( "nat-pmp set port %i", port );
236    pmp->newport = port;
237}
238
239void
240tr_natpmpRemoveForwarding( tr_natpmp_t * pmp )
241{
242    tr_inf( "nat-pmp unset port" );
243    pmp->newport = -1;
244    unmap( pmp );
245}
246
247void
248tr_natpmpClose( tr_natpmp_t * pmp )
249{
250    /* try to send at least one delete request if we have a port mapping */
251    tr_natpmpStop( pmp );
252    tr_natpmpPulse( pmp, NULL );
253
254    killreq( &pmp->req );
255    free( pmp );
256}
257
258void
259tr_natpmpPulse( tr_natpmp_t * pmp, int * publicPort )
260{
261    if( 0 <= pmp->mcastfd )
262    {
263        mcastpulse( pmp );
264    }
265
266    if( NULL != publicPort )
267    {
268        *publicPort = -1;
269    }
270
271    if( pmp->active || PMP_STATE_DELETING == pmp->state )
272    {
273        switch( pmp->state )
274        {
275            case PMP_STATE_IDLE:
276            case PMP_STATE_TMPFAIL:
277                if( 0 < pmp->newport )
278                {
279                    tr_dbg( "nat-pmp state %s -> add with port %i",
280                            ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ),
281                            pmp->newport );
282                    pmp->state = PMP_STATE_ADDING;
283                }
284                break;
285
286            case PMP_STATE_ADDING:
287                if( NULL == pmp->req )
288                {
289                    if( 0 >= pmp->newport )
290                    {
291                        tr_dbg( "nat-pmp state add -> idle, no port" );
292                        pmp->state = PMP_STATE_IDLE;
293                    }
294                    else if( INADDR_NONE == pmp->dest.s_addr )
295                    {
296                        tr_dbg( "nat-pmp state add -> fail, no default route" );
297                        pmp->state = PMP_STATE_FAILED;
298                    }
299                    else
300                    {
301                        pmp->req = newreq( 1, pmp->dest, pmp->newport );
302                        if( NULL == pmp->req )
303                        {
304                            pmp->state = PMP_STATE_FAILED;
305                            tr_dbg( "nat-pmp state add -> fail on req init" );
306                        }
307                    }
308                }
309                if( PMP_STATE_ADDING == pmp->state )
310                {
311                    switch( pulsereq( pmp ) )
312                    {
313                        case TR_NET_ERROR:
314                            if( pmp->req->nobodyhome )
315                            {
316                                pmp->state = PMP_STATE_NOBODYHOME;
317                                tr_dbg( "nat-pmp state add -> nobodyhome on pulse" );
318                            }
319                            else if( pmp->req->tmpfail )
320                            {
321                                pmp->state = PMP_STATE_TMPFAIL;
322                                tr_dbg( "nat-pmp state add -> err on pulse" );
323                                if( pmp->req->askport == pmp->newport )
324                                {
325                                    pmp->newport = 0;
326                                }
327                            }
328                            else
329                            {
330                                pmp->state = PMP_STATE_FAILED;
331                                tr_dbg( "nat-pmp state add -> fail on pulse" );
332                            }
333                            killreq( &pmp->req );
334                            break;
335                        case TR_NET_OK:
336                            pmp->mappedport = pmp->req->gotport;
337                            if( pmp->mappedport != pmp->newport &&
338                                pmp->newport == pmp->req->askport )
339                            {
340                                pmp->newport = pmp->req->gotport;
341                            }
342                            killreq( &pmp->req );
343                            pmp->state = PMP_STATE_MAPPED;
344                            pmp->mapped = 1;
345                            tr_dbg( "nat-pmp state add -> mapped with port %i",
346                                    pmp->mappedport);
347                            tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
348                            if( NULL != publicPort )
349                            {
350                                *publicPort = pmp->mappedport;
351                            }
352                            break;
353                        case TR_NET_WAIT:
354                            break;
355                    }
356                }
357                break;
358
359            case PMP_STATE_DELETING:
360                if( NULL == pmp->req )
361                {
362                    assert( 0 < pmp->mappedport );
363                    pmp->req = newreq( 0, pmp->dest, pmp->mappedport );
364                    if( NULL == pmp->req )
365                    {
366                        pmp->state = PMP_STATE_FAILED;
367                        tr_dbg( "nat-pmp state del -> fail on req init" );
368                    }
369                }
370                if( PMP_STATE_DELETING == pmp->state )
371                {
372                    switch( pulsereq( pmp ) )
373                    {
374                        case TR_NET_ERROR:
375                            if( pmp->req->nobodyhome )
376                            {
377                                pmp->mapped = 0;
378                                pmp->state = PMP_STATE_NOBODYHOME;
379                                tr_dbg( "nat-pmp state del -> nobodyhome on pulse" );
380                            }
381                            else if( pmp->req->tmpfail )
382                            {
383                                pmp->mapped = 0;
384                                pmp->state = PMP_STATE_TMPFAIL;
385                                tr_dbg( "nat-pmp state del -> err on pulse" );
386                                pmp->mappedport = -1;
387                            }
388                            else
389                            {
390                                pmp->state = PMP_STATE_FAILED;
391                                tr_dbg( "nat-pmp state del -> fail on pulse" );
392                            }
393                            killreq( &pmp->req );
394                            break;
395                        case TR_NET_OK:
396                            tr_dbg( "nat-pmp state del -> idle with port %i",
397                                    pmp->req->askport);
398                            tr_inf( "nat-pmp unmapped port %i",
399                                    pmp->req->askport );
400                            pmp->mapped = 0;
401                            pmp->mappedport = -1;
402                            killreq( &pmp->req );
403                            pmp->state = PMP_STATE_IDLE;
404                            break;
405                        case TR_NET_WAIT:
406                            break;
407                    }
408                }
409                break;
410
411            case PMP_STATE_MAPPED:
412                if( pmp->newport != pmp->mappedport )
413                {
414                    tr_dbg( "nat-pmp state mapped -> del, port from %i to %i",
415                            pmp->mappedport, pmp->newport );
416                    pmp->state = PMP_STATE_DELETING;
417                }
418                else if( tr_date() > pmp->renew )
419                {
420                    pmp->state = PMP_STATE_ADDING;
421                    tr_dbg( "nat-pmp state mapped -> add for renewal" );
422                }
423                break;
424
425            case PMP_STATE_FAILED:
426            case PMP_STATE_NOBODYHOME:
427                break;
428
429            default:
430                assert( 0 );
431                break;
432        }
433    }
434}
435
436void
437unmap( tr_natpmp_t * pmp )
438{
439    switch( pmp->state )
440    {
441        case PMP_STATE_IDLE:
442            break;
443        case PMP_STATE_ADDING:
444            if( NULL == pmp->req )
445            {
446                pmp->state = PMP_STATE_IDLE;
447                tr_dbg( "nat-pmp state add -> idle" );
448            }
449            else
450            {
451                pmp->mappedport = pmp->req->gotport;
452                killreq( &pmp->req );
453                pmp->state = PMP_STATE_DELETING;
454                tr_dbg( "nat-pmp state add -> del" );
455            }
456            break;
457        case PMP_STATE_DELETING:
458            break;
459        case PMP_STATE_MAPPED:
460            pmp->state = PMP_STATE_DELETING;
461            tr_dbg( "nat-pmp state mapped -> del" );
462            break;
463        case PMP_STATE_FAILED:
464        case PMP_STATE_NOBODYHOME:
465        case PMP_STATE_TMPFAIL:
466            break;
467        default:
468            assert( 0 );
469            break;
470    }
471}
472
473static int
474checktime( tr_natpmp_uptime_t * uptime, uint32_t cursecs )
475{
476    time_t   now;
477    int      ret;
478    uint32_t estimated;
479
480    now = time( NULL );
481    ret = 0;
482    if( 0 < uptime->when )
483    {
484        estimated = ( ( now - uptime->when ) * 7 / 8 ) + uptime->uptime;
485        if( estimated > cursecs )
486        {
487            ret = 1;
488        }
489    }
490
491    uptime->when   = now;
492    uptime->uptime = cursecs;
493
494    return ret;
495}
496
497static void
498killsock( int * fd )
499{
500    if( 0 <= *fd )
501    {
502        tr_netClose( *fd );
503        *fd = -1;
504    }
505}
506
507static tr_natpmp_req_t *
508newreq( int adding, struct in_addr addr, int port )
509{
510    tr_natpmp_req_t * ret;
511
512    ret = calloc( 1, sizeof( *ret ) );
513    if( NULL == ret )
514    {
515        return NULL;
516    }
517
518    ret->fd = tr_netOpenUDP( &addr, htons( PMP_PORT ), 1 );
519    if( 0 > ret->fd )
520    {
521        free( ret );
522        return NULL;
523    }
524
525    ret->adding  = adding;
526    ret->askport = port;
527    ret->gotport = port;
528    resetreq( ret );
529    if( sendreq( ret ) )
530    {
531        killreq( &ret );
532        return NULL;
533    }
534
535    return ret;
536}
537
538static void
539killreq( tr_natpmp_req_t ** req )
540{
541    if( NULL != *req )
542    {
543        killsock( &(*req)->fd );
544        free( *req );
545        *req = NULL;
546    }
547}
548
549static void
550resetreq( tr_natpmp_req_t * req )
551{
552    uint64_t now;
553
554    now          = tr_date();
555    req->delay   = PMP_INITIAL_DELAY;
556    req->retry   = now;
557    req->timeout = now + PMP_TOTAL_DELAY;
558}
559
560static tr_tristate_t
561pulsereq( tr_natpmp_t * pmp )
562{
563    tr_natpmp_req_t  * req = pmp->req;
564    struct sockaddr_in sin;
565    uint8_t            buf[16];
566    int                res;
567    uint64_t           now;
568    tr_tristate_t      ret;
569    tr_natpmp_parse_t  parse;
570
571    now = tr_date();
572    /* check for timeout */
573    if( now >= req->timeout )
574    {
575        tr_dbg( "nat-pmp request timed out" );
576        req->nobodyhome = 1;
577        return TR_NET_ERROR;
578    }
579    /* send another request  if it's been long enough */
580    if( now >= req->retry && sendreq( req ) )
581    {
582        return TR_NET_ERROR;
583    }
584
585    /* check for incoming packets */
586    res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
587    if( TR_NET_BLOCK & res )
588    {
589        return TR_NET_WAIT;
590    }
591    else if( TR_NET_CLOSE & res )
592    {
593        if( ECONNRESET == errno || ECONNREFUSED == errno )
594        {
595            tr_dbg( "nat-pmp not supported by device" );
596            req->nobodyhome = 1;
597        }
598        else
599        {
600            tr_inf( "error reading nat-pmp response (%s)", strerror( errno ) );
601        }
602        return TR_NET_ERROR;
603    }
604
605    /* parse the packet */
606    tr_dbg( "nat-pmp read %i byte response", res );
607    ret = parseresponse( buf, res, req->askport, &parse );
608    req->tmpfail = parse.tmpfail;
609    /* check for device reset */
610    if( checktime( &pmp->uptime, parse.seconds ) )
611    {
612        pmp->renew = 0;
613        tr_inf( "detected nat-pmp device reset" );
614        resetreq( req );
615        ret = TR_NET_WAIT;
616    }
617    if( TR_NET_OK == ret && req->adding )
618    {
619        if( req->askport != parse.port )
620        {
621            tr_dbg( "nat-pmp received %i for public port instead of %i",
622                    parse.port, req->askport );
623            req->gotport = parse.port;
624        }
625        tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime );
626        pmp->renew = now + ( parse.lifetime / 2 * 1000 );
627    }
628
629    return ret;
630}
631
632static int
633sendreq( tr_natpmp_req_t * req )
634{
635    uint8_t buf[12];
636    int res;
637
638    memset( buf, 0, sizeof( buf ) );
639    buf[0] = PMP_VERSION;
640    buf[1] = PMP_OPCODE_ADDTCP;
641    PMP_TOBUF16( buf + 4, req->askport );
642    if( req->adding )
643    {
644        PMP_TOBUF16( buf + 6, req->askport );
645        PMP_TOBUF32( buf + 8, PMP_LIFETIME );
646    }
647
648    res = tr_netSend( req->fd, buf, sizeof( buf ) );
649    if( TR_NET_CLOSE & res && EHOSTUNREACH == errno )
650    {
651        res = TR_NET_BLOCK;
652    }
653    if( TR_NET_CLOSE & res )
654    {
655        tr_err( "failed to send nat-pmp request (%s)", strerror( errno ) );
656        return 1;
657    }
658    else if( !( TR_NET_BLOCK & res ) )
659    {
660        /* XXX is it all right to assume the entire thing is written? */
661        req->retry  = tr_date() + req->delay;
662        req->delay *= 2;
663    }
664    return 0;
665}
666
667static int
668mcastsetup()
669{
670    int fd;
671    struct in_addr addr;
672
673    addr.s_addr = inet_addr( PMP_MCAST_ADDR );
674    fd = tr_netMcastOpen( PMP_PORT, &addr );
675    if( 0 > fd )
676    {
677        return -1;
678    }
679
680    tr_dbg( "nat-pmp create multicast socket %i", fd );
681
682    return fd;
683}
684
685static void
686mcastpulse( tr_natpmp_t * pmp )
687{
688    struct sockaddr_in sin;
689    uint8_t            buf[16];
690    int                res;
691    char               dbgstr[INET_ADDRSTRLEN];
692    tr_natpmp_parse_t  parse;
693
694    res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin );
695    if( TR_NET_BLOCK & res )
696    {
697        return;
698    }
699    else if( TR_NET_CLOSE & res )
700    {
701        tr_err( "error reading nat-pmp multicast message" );
702        killsock( &pmp->mcastfd );
703        return;
704    }
705
706    tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) );
707    tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr );
708
709    if( pmp->dest.s_addr != sin.sin_addr.s_addr )
710    {
711        tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s",
712                dbgstr );
713        return;
714    }
715
716    if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) )
717    {
718        if( checktime( &pmp->uptime, parse.seconds ) )
719        {
720            pmp->renew = 0;
721            tr_inf( "detected nat-pmp device reset" );
722            if( NULL != pmp->req )
723            {
724                resetreq( pmp->req );
725            }
726        }
727        if( PMP_STATE_NOBODYHOME == pmp->state )
728        {
729            tr_dbg( "nat-pmp state notfound -> idle" );
730            pmp->state = PMP_STATE_IDLE;
731        }
732    }
733}
734
735static tr_tristate_t
736parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse )
737{
738    int version, respopcode, opcode, wantedopcode, rescode, privport;
739
740    memset( parse, 0, sizeof( *parse ) );
741
742    if( 8 > len )
743    {
744        tr_err( "read truncated %i byte nat-pmp response packet", len );
745        return TR_NET_ERROR;
746    }
747
748    /* parse the first 8 bytes: version, opcode, and result code */
749    version      = buf[0];
750    respopcode   = buf[1];
751    opcode       = PMP_OPCODE_FROM_RESPONSE( respopcode );
752    wantedopcode = ( 0 < port ? PMP_OPCODE_ADDTCP : PMP_OPCODE_GETIP );
753    rescode      = PMP_FROMBUF16( buf + 2 );
754
755    if( PMP_VERSION != version )
756    {
757        tr_err( "unknown nat-pmp version %hhu", buf[0] );
758        return TR_NET_ERROR;
759    }
760    if( !PMP_OPCODE_IS_RESPONSE( respopcode ) )
761    {
762        tr_dbg( "nat-pmp ignoring request packet" );
763        return TR_NET_WAIT;
764    }
765    if( wantedopcode != opcode )
766    {
767        tr_err( "unknown nat-pmp opcode %hhu", opcode );
768        return TR_NET_ERROR;
769    }
770
771    switch( rescode )
772    {
773        case PMP_RESULT_OK:
774            break;
775        case PMP_RESULT_REFUSED:
776            tr_err( "nat-pmp mapping failed: refused/unauthorized/disabled" );
777            parse->tmpfail = 1;
778            return TR_NET_ERROR;
779        case PMP_RESULT_NETDOWN:
780            tr_err( "nat-pmp mapping failed: network down" );
781            parse->tmpfail = 1;
782            return TR_NET_ERROR;
783        case PMP_RESULT_NOMEM:
784            tr_err( "nat-pmp mapping refused: insufficient resources" );
785            parse->tmpfail = 1;
786            return TR_NET_ERROR;
787        default:
788            tr_err( "nat-pmp mapping refused: unknown result code: %hu",
789                    rescode );
790            return TR_NET_ERROR;
791    }
792
793    parse->seconds = PMP_FROMBUF32( buf + 4 );
794    if( PMP_OPCODE_ADDTCP == opcode )
795    {
796        if( 16 > len )
797        {
798            tr_err( "read truncated %i byte nat-pmp response packet", len );
799            return TR_NET_ERROR;
800        }
801        privport        = PMP_FROMBUF16( buf + 8 );
802        parse->port     = PMP_FROMBUF16( buf + 10 );
803        parse->lifetime = PMP_FROMBUF32( buf + 12 );
804
805        if( port != privport )
806        {
807            tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
808                    privport, port );
809            return TR_NET_WAIT;
810        }
811    }
812
813    return TR_NET_OK;
814}
Note: See TracBrowser for help on using the repository browser.