source: trunk/libtransmission/natpmp.c @ 2311

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

clean up #includes a bit.

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