source: trunk/libtransmission/natpmp.c @ 1460

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

Clean up NAT-PMP code a little.
Correctly handle a NAT-PMP device mapping a different public port than requested.

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