source: trunk/libtransmission/natpmp.c @ 2555

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

add portability wrapper for in_port_t...

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