source: trunk/libtransmission/natpmp.c @ 2576

Last change on this file since 2576 was 2576, checked in by charles, 16 years ago

get the socket/net code working on win32 too

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