source: trunk/libtransmission/natpmp.c @ 1720

Last change on this file since 1720 was 1720, checked in by joshe, 15 years ago

Don't try port mapping if binding the port fails.

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