source: trunk/libtransmission/natpmp.c @ 3773

Last change on this file since 3773 was 3773, checked in by charles, 14 years ago

on Darwin, use NSCParameterAssert() instead of assert().

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