source: trunk/libtransmission/natpmp.c @ 3984

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

move tr_getDefaultRoute() to natpmp.c because it's the only code that uses it

  • Property svn:keywords set to Date Rev Author Id
File size: 31.6 KB
Line 
1/******************************************************************************
2 * $Id: natpmp.c 3984 2007-11-26 20:21:52Z 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 <unistd.h> /* close */
32#include <fcntl.h> /* fcntl */
33
34#ifdef __BEOS__
35    #include <netdb.h>
36#endif
37
38#include <sys/types.h>
39
40#include "transmission.h"
41#include "natpmp.h"
42#include "net.h"
43#include "utils.h"
44
45#define PMP_PORT                5351
46#define PMP_MCAST_ADDR          "224.0.0.1"
47#define PMP_INITIAL_DELAY       250     /* ms, 1/4 second */
48#define PMP_TOTAL_DELAY         120000  /* ms, 2 minutes */
49#define PMP_VERSION             0
50#define PMP_OPCODE_GETIP        0
51#define PMP_OPCODE_ADDUDP       1
52#define PMP_OPCODE_ADDTCP       2
53#define PMP_LIFETIME            3600    /* secs, one hour */
54#define PMP_RESULT_OK           0
55#define PMP_RESULT_BADVERS      1
56#define PMP_RESULT_REFUSED      2
57#define PMP_RESULT_NETDOWN      3
58#define PMP_RESULT_NOMEM        4
59#define PMP_RESULT_BADOPCODE    5
60
61#define PMP_OPCODE_FROM_RESPONSE( op )  ( 0x80 ^ (op) )
62#define PMP_OPCODE_TO_RESPONSE( op )    ( 0x80 | (op) )
63#define PMP_OPCODE_IS_RESPONSE( op )    ( 0x80 & (op) )
64#define PMP_TOBUF16( buf, num ) ( *( (uint16_t *) (buf) ) = htons( (num) ) )
65#define PMP_TOBUF32( buf, num ) ( *( (uint32_t *) (buf) ) = htonl( (num) ) )
66#define PMP_FROMBUF16( buf )    ( htons( *( (uint16_t *) (buf) ) ) )
67#define PMP_FROMBUF32( buf )    ( htonl( *( (uint32_t *) (buf) ) ) )
68
69static int tr_getDefaultRoute( struct in_addr * addr );
70
71typedef struct tr_natpmp_uptime_s
72{
73    time_t   when;
74    uint32_t uptime;
75} tr_natpmp_uptime_t;
76
77typedef struct tr_natpmp_req_s
78{
79    unsigned int         adding : 1;
80    unsigned int         nobodyhome : 1;
81    unsigned int         tmpfail : 1;
82    int                  fd;
83    int                  delay;
84    uint64_t             retry;
85    uint64_t             timeout;
86    int                  askport;
87    int                  gotport;
88} tr_natpmp_req_t;
89
90struct tr_natpmp
91{
92#define PMP_STATE_IDLE          1
93#define PMP_STATE_ADDING        2
94#define PMP_STATE_DELETING      3
95#define PMP_STATE_MAPPED        4
96#define PMP_STATE_FAILED        5
97#define PMP_STATE_NOBODYHOME    6
98#define PMP_STATE_TMPFAIL       7
99    char               state;
100    unsigned int       active : 1;
101    unsigned int       mapped : 1;
102    struct in_addr     dest;
103    int                newport;
104    int                mappedport;
105    uint64_t           renew;
106    tr_natpmp_req_t *  req;
107    tr_natpmp_uptime_t uptime;
108    int                mcastfd;
109};
110
111typedef struct tr_natpmp_parse_s
112{
113    unsigned int tmpfail : 1;
114    uint32_t     seconds;
115    uint16_t     port;
116    uint32_t     lifetime;
117}
118tr_natpmp_parse_t;
119
120static void
121unmap( tr_natpmp * pmp );
122static int
123checktime( tr_natpmp_uptime_t * uptime, uint32_t seen );
124static void
125killsock( int * fd );
126static tr_natpmp_req_t *
127newreq( int adding, struct in_addr addr, int port );
128static void
129killreq( tr_natpmp_req_t ** req );
130static void
131resetreq( tr_natpmp_req_t * req );
132static tr_tristate_t
133pulsereq( tr_natpmp * req );
134static int
135sendreq( tr_natpmp_req_t * req );
136static int
137mcastsetup();
138static void
139mcastpulse( tr_natpmp * pmp );
140static tr_tristate_t
141parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse );
142
143tr_natpmp *
144tr_natpmpInit()
145{
146    tr_natpmp * pmp;
147
148    pmp = calloc( 1, sizeof( *pmp ) );
149    if( NULL == pmp )
150    {
151        return NULL;
152    }
153
154    pmp->state       = PMP_STATE_IDLE;
155    pmp->mcastfd     = -1;
156
157    if( tr_getDefaultRoute( &pmp->dest ) || INADDR_ANY == pmp->dest.s_addr )
158    {
159        pmp->dest.s_addr = INADDR_NONE;
160    }
161
162    if( INADDR_NONE == pmp->dest.s_addr )
163    {
164        tr_dbg( "nat-pmp device is unknown" );
165    }
166    else
167    {
168        char addrstr[INET_ADDRSTRLEN];
169        tr_netNtop( &pmp->dest, addrstr, sizeof( addrstr ) );
170        tr_dbg( "nat-pmp device is %s", addrstr );
171    }
172
173    return pmp;
174}
175
176void
177tr_natpmpStart( tr_natpmp * pmp )
178{
179    if( !pmp->active )
180    {
181        tr_inf( "starting nat-pmp" );
182        pmp->active = 1;
183        if( 0 > pmp->mcastfd )
184        {
185            pmp->mcastfd = mcastsetup();
186        }
187    }
188}
189
190void
191tr_natpmpStop( tr_natpmp * pmp )
192{
193    if( pmp->active )
194    {
195        tr_inf( "stopping nat-pmp" );
196        pmp->active = 0;
197        killsock( &pmp->mcastfd );
198        unmap( pmp );
199    }
200}
201
202int
203tr_natpmpStatus( tr_natpmp * pmp )
204{
205    int ret;
206   
207    if( !pmp->active )
208    {
209        ret = ( PMP_STATE_DELETING == pmp->state ?
210                TR_NAT_TRAVERSAL_UNMAPPING : TR_NAT_TRAVERSAL_DISABLED );
211    }
212    else if( pmp->mapped )
213    {
214        ret = TR_NAT_TRAVERSAL_MAPPED;
215    }
216    else
217    {
218        switch( pmp->state )
219        {
220            case PMP_STATE_IDLE:
221            case PMP_STATE_ADDING:
222            case PMP_STATE_DELETING:
223                ret = TR_NAT_TRAVERSAL_MAPPING;
224                break;
225            case PMP_STATE_FAILED:
226            case PMP_STATE_TMPFAIL:
227                ret = TR_NAT_TRAVERSAL_ERROR;
228                break;
229            case PMP_STATE_NOBODYHOME:
230                ret = TR_NAT_TRAVERSAL_NOTFOUND;
231                break;
232            case PMP_STATE_MAPPED:
233            default:
234                /* if pmp->state is PMP_STATE_MAPPED then pmp->mapped
235                   should be true */
236                assert( 0 );
237                ret = TR_NAT_TRAVERSAL_ERROR;
238                break;
239        }
240    }
241
242    return ret;
243}
244
245void
246tr_natpmpForwardPort( tr_natpmp * pmp, int port )
247{
248    tr_inf( "nat-pmp set port %i", port );
249    pmp->newport = port;
250}
251
252void
253tr_natpmpRemoveForwarding( tr_natpmp * pmp )
254{
255    tr_inf( "nat-pmp unset port" );
256    pmp->newport = -1;
257    unmap( pmp );
258}
259
260void
261tr_natpmpClose( tr_natpmp * pmp )
262{
263    /* try to send at least one delete request if we have a port mapping */
264    tr_natpmpStop( pmp );
265    tr_natpmpPulse( pmp, NULL );
266
267    killreq( &pmp->req );
268    free( pmp );
269}
270
271void
272tr_natpmpPulse( tr_natpmp * pmp, int * publicPort )
273{
274    if( 0 <= pmp->mcastfd )
275    {
276        mcastpulse( pmp );
277    }
278
279    if( NULL != publicPort )
280    {
281        *publicPort = -1;
282    }
283
284    if( pmp->active || PMP_STATE_DELETING == pmp->state )
285    {
286        switch( pmp->state )
287        {
288            case PMP_STATE_IDLE:
289            case PMP_STATE_TMPFAIL:
290                if( 0 < pmp->newport )
291                {
292                    tr_dbg( "nat-pmp state %s -> add with port %i",
293                            ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ),
294                            pmp->newport );
295                    pmp->state = PMP_STATE_ADDING;
296                }
297                break;
298
299            case PMP_STATE_ADDING:
300                if( NULL == pmp->req )
301                {
302                    if( 0 >= pmp->newport )
303                    {
304                        tr_dbg( "nat-pmp state add -> idle, no port" );
305                        pmp->state = PMP_STATE_IDLE;
306                    }
307                    else if( INADDR_NONE == pmp->dest.s_addr )
308                    {
309                        tr_dbg( "nat-pmp state add -> fail, no default route" );
310                        pmp->state = PMP_STATE_FAILED;
311                    }
312                    else
313                    {
314                        pmp->req = newreq( 1, pmp->dest, pmp->newport );
315                        if( NULL == pmp->req )
316                        {
317                            pmp->state = PMP_STATE_FAILED;
318                            tr_dbg( "nat-pmp state add -> fail on req init" );
319                        }
320                    }
321                }
322                if( PMP_STATE_ADDING == pmp->state )
323                {
324                    switch( pulsereq( pmp ) )
325                    {
326                        case TR_NET_ERROR:
327                            if( pmp->req->nobodyhome )
328                            {
329                                pmp->state = PMP_STATE_NOBODYHOME;
330                                tr_dbg( "nat-pmp state add -> nobodyhome on pulse" );
331                            }
332                            else if( pmp->req->tmpfail )
333                            {
334                                pmp->state = PMP_STATE_TMPFAIL;
335                                tr_dbg( "nat-pmp state add -> err on pulse" );
336                                if( pmp->req->askport == pmp->newport )
337                                {
338                                    pmp->newport = 0;
339                                }
340                            }
341                            else
342                            {
343                                pmp->state = PMP_STATE_FAILED;
344                                tr_dbg( "nat-pmp state add -> fail on pulse" );
345                            }
346                            killreq( &pmp->req );
347                            break;
348                        case TR_NET_OK:
349                            pmp->mappedport = pmp->req->gotport;
350                            if( pmp->mappedport != pmp->newport &&
351                                pmp->newport == pmp->req->askport )
352                            {
353                                pmp->newport = pmp->req->gotport;
354                            }
355                            killreq( &pmp->req );
356                            pmp->state = PMP_STATE_MAPPED;
357                            pmp->mapped = 1;
358                            tr_dbg( "nat-pmp state add -> mapped with port %i",
359                                    pmp->mappedport);
360                            tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
361                            if( NULL != publicPort )
362                            {
363                                *publicPort = pmp->mappedport;
364                            }
365                            break;
366                        case TR_NET_WAIT:
367                            break;
368                    }
369                }
370                break;
371
372            case PMP_STATE_DELETING:
373                if( NULL == pmp->req )
374                {
375                    assert( 0 < pmp->mappedport );
376                    pmp->req = newreq( 0, pmp->dest, pmp->mappedport );
377                    if( NULL == pmp->req )
378                    {
379                        pmp->state = PMP_STATE_FAILED;
380                        tr_dbg( "nat-pmp state del -> fail on req init" );
381                    }
382                }
383                if( PMP_STATE_DELETING == pmp->state )
384                {
385                    switch( pulsereq( pmp ) )
386                    {
387                        case TR_NET_ERROR:
388                            if( pmp->req->nobodyhome )
389                            {
390                                pmp->mapped = 0;
391                                pmp->state = PMP_STATE_NOBODYHOME;
392                                tr_dbg( "nat-pmp state del -> nobodyhome on pulse" );
393                            }
394                            else if( pmp->req->tmpfail )
395                            {
396                                pmp->mapped = 0;
397                                pmp->state = PMP_STATE_TMPFAIL;
398                                tr_dbg( "nat-pmp state del -> err on pulse" );
399                                pmp->mappedport = -1;
400                            }
401                            else
402                            {
403                                pmp->state = PMP_STATE_FAILED;
404                                tr_dbg( "nat-pmp state del -> fail on pulse" );
405                            }
406                            killreq( &pmp->req );
407                            break;
408                        case TR_NET_OK:
409                            tr_dbg( "nat-pmp state del -> idle with port %i",
410                                    pmp->req->askport);
411                            tr_inf( "nat-pmp unmapped port %i",
412                                    pmp->req->askport );
413                            pmp->mapped = 0;
414                            pmp->mappedport = -1;
415                            killreq( &pmp->req );
416                            pmp->state = PMP_STATE_IDLE;
417                            break;
418                        case TR_NET_WAIT:
419                            break;
420                    }
421                }
422                break;
423
424            case PMP_STATE_MAPPED:
425                if( pmp->newport != pmp->mappedport )
426                {
427                    tr_dbg( "nat-pmp state mapped -> del, port from %i to %i",
428                            pmp->mappedport, pmp->newport );
429                    pmp->state = PMP_STATE_DELETING;
430                }
431                else if( tr_date() > pmp->renew )
432                {
433                    pmp->state = PMP_STATE_ADDING;
434                    tr_dbg( "nat-pmp state mapped -> add for renewal" );
435                }
436                break;
437
438            case PMP_STATE_FAILED:
439            case PMP_STATE_NOBODYHOME:
440                break;
441
442            default:
443                assert( 0 );
444                break;
445        }
446    }
447}
448
449void
450unmap( tr_natpmp * pmp )
451{
452    switch( pmp->state )
453    {
454        case PMP_STATE_IDLE:
455            break;
456        case PMP_STATE_ADDING:
457            if( NULL == pmp->req )
458            {
459                pmp->state = PMP_STATE_IDLE;
460                tr_dbg( "nat-pmp state add -> idle" );
461            }
462            else
463            {
464                pmp->mappedport = pmp->req->gotport;
465                killreq( &pmp->req );
466                pmp->state = PMP_STATE_DELETING;
467                tr_dbg( "nat-pmp state add -> del" );
468            }
469            break;
470        case PMP_STATE_DELETING:
471            break;
472        case PMP_STATE_MAPPED:
473            pmp->state = PMP_STATE_DELETING;
474            tr_dbg( "nat-pmp state mapped -> del" );
475            break;
476        case PMP_STATE_FAILED:
477        case PMP_STATE_NOBODYHOME:
478        case PMP_STATE_TMPFAIL:
479            break;
480        default:
481            assert( 0 );
482            break;
483    }
484}
485
486static int
487checktime( tr_natpmp_uptime_t * uptime, uint32_t cursecs )
488{
489    time_t   now;
490    int      ret;
491    uint32_t estimated;
492
493    now = time( NULL );
494    ret = 0;
495    if( 0 < uptime->when )
496    {
497        estimated = ( ( now - uptime->when ) * 7 / 8 ) + uptime->uptime;
498        if( estimated > cursecs )
499        {
500            ret = 1;
501        }
502    }
503
504    uptime->when   = now;
505    uptime->uptime = cursecs;
506
507    return ret;
508}
509
510static void
511killsock( int * fd )
512{
513    if( 0 <= *fd )
514    {
515        tr_netClose( *fd );
516        *fd = -1;
517    }
518}
519
520static tr_natpmp_req_t *
521newreq( int adding, struct in_addr addr, int port )
522{
523    tr_natpmp_req_t * ret;
524
525    ret = calloc( 1, sizeof( *ret ) );
526    if( NULL == ret )
527    {
528        return NULL;
529    }
530
531    ret->fd = tr_netOpenUDP( &addr, htons( PMP_PORT ), 1 );
532    if( 0 > ret->fd )
533    {
534        free( ret );
535        return NULL;
536    }
537
538    ret->adding  = adding;
539    ret->askport = port;
540    ret->gotport = port;
541    resetreq( ret );
542    if( sendreq( ret ) )
543    {
544        killreq( &ret );
545        return NULL;
546    }
547
548    return ret;
549}
550
551static void
552killreq( tr_natpmp_req_t ** req )
553{
554    if( NULL != *req )
555    {
556        killsock( &(*req)->fd );
557        free( *req );
558        *req = NULL;
559    }
560}
561
562static void
563resetreq( tr_natpmp_req_t * req )
564{
565    uint64_t now;
566
567    now          = tr_date();
568    req->delay   = PMP_INITIAL_DELAY;
569    req->retry   = now;
570    req->timeout = now + PMP_TOTAL_DELAY;
571}
572
573static tr_tristate_t
574pulsereq( tr_natpmp * pmp )
575{
576    tr_natpmp_req_t  * req = pmp->req;
577    struct sockaddr_in sin;
578    uint8_t            buf[16];
579    int                res;
580    uint64_t           now;
581    tr_tristate_t      ret;
582    tr_natpmp_parse_t  parse;
583
584    now = tr_date();
585    /* check for timeout */
586    if( now >= req->timeout )
587    {
588        tr_dbg( "nat-pmp request timed out" );
589        req->nobodyhome = 1;
590        return TR_NET_ERROR;
591    }
592    /* send another request  if it's been long enough */
593    if( now >= req->retry && sendreq( req ) )
594    {
595        return TR_NET_ERROR;
596    }
597
598    /* check for incoming packets */
599    res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
600    if( TR_NET_BLOCK & res )
601    {
602        return TR_NET_WAIT;
603    }
604    else if( TR_NET_CLOSE & res )
605    {
606        if( ECONNRESET == sockerrno || ECONNREFUSED == sockerrno )
607        {
608            tr_dbg( "nat-pmp not supported by device" );
609            req->nobodyhome = 1;
610        }
611        else
612        {
613            tr_inf( "error reading nat-pmp response (%s)", strerror( sockerrno ) );
614        }
615        return TR_NET_ERROR;
616    }
617
618    /* parse the packet */
619    tr_dbg( "nat-pmp read %i byte response", res );
620    ret = parseresponse( buf, res, req->askport, &parse );
621    req->tmpfail = parse.tmpfail;
622    /* check for device reset */
623    if( checktime( &pmp->uptime, parse.seconds ) )
624    {
625        pmp->renew = 0;
626        tr_inf( "detected nat-pmp device reset" );
627        resetreq( req );
628        ret = TR_NET_WAIT;
629    }
630    if( TR_NET_OK == ret && req->adding )
631    {
632        if( req->askport != parse.port )
633        {
634            tr_dbg( "nat-pmp received %i for public port instead of %i",
635                    parse.port, req->askport );
636            req->gotport = parse.port;
637        }
638        tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime );
639        pmp->renew = now + ( parse.lifetime / 2 * 1000 );
640    }
641
642    return ret;
643}
644
645static int
646sendreq( tr_natpmp_req_t * req )
647{
648    uint8_t buf[12];
649    int res;
650
651    memset( buf, 0, sizeof( buf ) );
652    buf[0] = PMP_VERSION;
653    buf[1] = PMP_OPCODE_ADDTCP;
654    PMP_TOBUF16( buf + 4, req->askport );
655    if( req->adding )
656    {
657        PMP_TOBUF16( buf + 6, req->askport );
658        PMP_TOBUF32( buf + 8, PMP_LIFETIME );
659    }
660
661    res = tr_netSend( req->fd, buf, sizeof( buf ) );
662    if( TR_NET_CLOSE & res && EHOSTUNREACH == sockerrno )
663    {
664        res = TR_NET_BLOCK;
665    }
666    if( TR_NET_CLOSE & res )
667    {
668        tr_err( "failed to send nat-pmp request (%s)", strerror( sockerrno ) );
669        return 1;
670    }
671    else if( !( TR_NET_BLOCK & res ) )
672    {
673        /* XXX is it all right to assume the entire thing is written? */
674        req->retry  = tr_date() + req->delay;
675        req->delay *= 2;
676    }
677    return 0;
678}
679
680static int
681mcastsetup()
682{
683    int fd;
684    struct in_addr addr;
685
686    addr.s_addr = inet_addr( PMP_MCAST_ADDR );
687    fd = tr_netMcastOpen( PMP_PORT, &addr );
688    if( 0 > fd )
689    {
690        return -1;
691    }
692
693    tr_dbg( "nat-pmp create multicast socket %i", fd );
694
695    return fd;
696}
697
698static void
699mcastpulse( tr_natpmp * pmp )
700{
701    struct sockaddr_in sin;
702    uint8_t            buf[16];
703    int                res;
704    char               dbgstr[INET_ADDRSTRLEN];
705    tr_natpmp_parse_t  parse;
706
707    res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin );
708    if( TR_NET_BLOCK & res )
709    {
710        return;
711    }
712    else if( TR_NET_CLOSE & res )
713    {
714        tr_err( "error reading nat-pmp multicast message" );
715        killsock( &pmp->mcastfd );
716        return;
717    }
718
719    tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) );
720    tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr );
721
722    if( pmp->dest.s_addr != sin.sin_addr.s_addr )
723    {
724        tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s",
725                dbgstr );
726        return;
727    }
728
729    if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) )
730    {
731        if( checktime( &pmp->uptime, parse.seconds ) )
732        {
733            pmp->renew = 0;
734            tr_inf( "detected nat-pmp device reset" );
735            if( NULL != pmp->req )
736            {
737                resetreq( pmp->req );
738            }
739        }
740        if( PMP_STATE_NOBODYHOME == pmp->state )
741        {
742            tr_dbg( "nat-pmp state notfound -> idle" );
743            pmp->state = PMP_STATE_IDLE;
744        }
745    }
746}
747
748static tr_tristate_t
749parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse )
750{
751    int version, respopcode, opcode, wantedopcode, rescode, privport;
752
753    memset( parse, 0, sizeof( *parse ) );
754
755    if( 8 > len )
756    {
757        tr_err( "read truncated %i byte nat-pmp response packet", len );
758        return TR_NET_ERROR;
759    }
760
761    /* parse the first 8 bytes: version, opcode, and result code */
762    version      = buf[0];
763    respopcode   = buf[1];
764    opcode       = PMP_OPCODE_FROM_RESPONSE( respopcode );
765    wantedopcode = ( 0 < port ? PMP_OPCODE_ADDTCP : PMP_OPCODE_GETIP );
766    rescode      = PMP_FROMBUF16( buf + 2 );
767
768    if( PMP_VERSION != version )
769    {
770        tr_err( "unknown nat-pmp version %hhu", buf[0] );
771        return TR_NET_ERROR;
772    }
773    if( !PMP_OPCODE_IS_RESPONSE( respopcode ) )
774    {
775        tr_dbg( "nat-pmp ignoring request packet" );
776        return TR_NET_WAIT;
777    }
778    if( wantedopcode != opcode )
779    {
780        tr_err( "unknown nat-pmp opcode %hhu", opcode );
781        return TR_NET_ERROR;
782    }
783
784    switch( rescode )
785    {
786        case PMP_RESULT_OK:
787            break;
788        case PMP_RESULT_REFUSED:
789            tr_err( "nat-pmp mapping failed: refused/unauthorized/disabled" );
790            parse->tmpfail = 1;
791            return TR_NET_ERROR;
792        case PMP_RESULT_NETDOWN:
793            tr_err( "nat-pmp mapping failed: network down" );
794            parse->tmpfail = 1;
795            return TR_NET_ERROR;
796        case PMP_RESULT_NOMEM:
797            tr_err( "nat-pmp mapping refused: insufficient resources" );
798            parse->tmpfail = 1;
799            return TR_NET_ERROR;
800        default:
801            tr_err( "nat-pmp mapping refused: unknown result code: %hu",
802                    rescode );
803            return TR_NET_ERROR;
804    }
805
806    parse->seconds = PMP_FROMBUF32( buf + 4 );
807    if( PMP_OPCODE_ADDTCP == opcode )
808    {
809        if( 16 > len )
810        {
811            tr_err( "read truncated %i byte nat-pmp response packet", len );
812            return TR_NET_ERROR;
813        }
814        privport        = PMP_FROMBUF16( buf + 8 );
815        parse->port     = PMP_FROMBUF16( buf + 10 );
816        parse->lifetime = PMP_FROMBUF32( buf + 12 );
817
818        if( port != privport )
819        {
820            tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
821                    privport, port );
822            return TR_NET_WAIT;
823        }
824    }
825
826    return TR_NET_OK;
827}
828
829/***
830****  tr_getDefaultRoute()
831***/
832
833#ifdef BSD
834
835#include <sys/types.h>
836#include <sys/socket.h>
837#include <netinet/in.h>
838#include <arpa/inet.h>
839#include <netinet/in.h> /* struct in_addr */
840#include <sys/sysctl.h>
841#include <net/route.h>
842
843static uint8_t *
844getroute( int * buflen );
845static int
846parseroutes( uint8_t * buf, int len, struct in_addr * addr );
847
848static int
849tr_getDefaultRoute( struct in_addr * addr )
850{
851    uint8_t * buf;
852    int len;
853
854    buf = getroute( &len );
855    if( NULL == buf )
856    {
857        tr_err( "failed to get default route (BSD)" );
858        return 1;
859    }
860
861    len = parseroutes( buf, len, addr );
862    free( buf );
863
864    return len;
865}
866
867#ifndef SA_SIZE
868#define ROUNDUP( a, size ) \
869    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
870#define SA_SIZE( sap ) \
871    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
872                    sizeof( u_long ) )
873#endif /* !SA_SIZE */
874#define NEXT_SA( sap ) \
875    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
876
877static uint8_t *
878getroute( int * buflen )
879{
880    int     mib[6];
881    size_t  len;
882    uint8_t * buf;
883
884    mib[0] = CTL_NET;
885    mib[1] = PF_ROUTE;
886    mib[2] = 0;
887    mib[3] = AF_INET;
888    mib[4] = NET_RT_FLAGS;
889    mib[5] = RTF_GATEWAY;
890
891    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
892    {
893        if( ENOENT != errno )
894        {
895            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
896                    strerror( sockerrno ) );
897        }
898        *buflen = 0;
899        return NULL;
900    }
901
902    buf = malloc( len );
903    if( NULL == buf )
904    {
905        *buflen = 0;
906        return NULL;
907    }
908
909    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
910    {
911        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
912                strerror( sockerrno ) );
913        free( buf );
914        *buflen = 0;
915        return NULL;
916    }
917
918    *buflen = len;
919
920    return buf;
921}
922
923static int
924parseroutes( uint8_t * buf, int len, struct in_addr * addr )
925{
926    uint8_t            * end;
927    struct rt_msghdr   * rtm;
928    struct sockaddr    * sa;
929    struct sockaddr_in * sin;
930    int                  ii;
931    struct in_addr       dest, gw;
932
933    end = buf + len;
934    while( end > buf + sizeof( *rtm ) )
935    {
936        rtm = (struct rt_msghdr *) buf;
937        buf += rtm->rtm_msglen;
938        if( end >= buf )
939        {
940            dest.s_addr = INADDR_NONE;
941            gw.s_addr   = INADDR_NONE;
942            sa = (struct sockaddr *) ( rtm + 1 );
943
944            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
945            {
946                if( buf < (uint8_t *) NEXT_SA( sa ) )
947                {
948                    break;
949                }
950
951                if( rtm->rtm_addrs & ( 1 << ii ) )
952                {
953                    if( AF_INET == sa->sa_family )
954                    {
955                        sin = (struct sockaddr_in *) sa;
956                        switch( ii )
957                        {
958                            case RTAX_DST:
959                                dest = sin->sin_addr;
960                                break;
961                            case RTAX_GATEWAY:
962                                gw = sin->sin_addr;
963                                break;
964                        }
965                    }
966                    sa = NEXT_SA( sa );
967                }
968            }
969
970            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
971            {
972                *addr = gw;
973                return 0;
974            }
975        }
976    }
977
978    return 1;
979}
980
981#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
982
983#include <linux/types.h>
984#include <linux/netlink.h>
985#include <linux/rtnetlink.h>
986
987#define SEQNUM 195909
988
989static int
990getsock( void );
991static uint8_t *
992getroute( int fd, unsigned int * buflen );
993static int
994parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
995
996int
997tr_getDefaultRoute( struct in_addr * addr )
998{
999    int fd, ret;
1000    unsigned int len;
1001    uint8_t * buf;
1002
1003    ret = 1;
1004    fd = getsock();
1005    if( 0 <= fd )
1006    {
1007        while( ret )
1008        {
1009            buf = getroute( fd, &len );
1010            if( NULL == buf )
1011            {
1012                break;
1013            }
1014            ret = parseroutes( buf, len, addr );
1015            free( buf );
1016        }
1017        close( fd );
1018    }
1019
1020    if( ret )
1021    {
1022        tr_err( "failed to get default route (Linux)" );
1023    }
1024
1025    return ret;
1026}
1027
1028static int
1029getsock( void )
1030{
1031    int fd, flags;
1032    struct
1033    {
1034        struct nlmsghdr nlh;
1035        struct rtgenmsg rtg;
1036    } req;
1037    struct sockaddr_nl snl;
1038
1039    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
1040    if( 0 > fd )
1041    {
1042        tr_err( "failed to create routing socket (%s)", strerror( sockerrno ) );
1043        return -1;
1044    }
1045
1046    flags = fcntl( fd, F_GETFL );
1047    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
1048    {
1049        tr_err( "failed to set socket nonblocking (%s)", strerror( sockerrno ) );
1050        close( fd );
1051        return -1;
1052    }
1053
1054    bzero( &snl, sizeof( snl ) );
1055    snl.nl_family = AF_NETLINK;
1056
1057    bzero( &req, sizeof( req ) );
1058    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
1059    req.nlh.nlmsg_type = RTM_GETROUTE;
1060    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
1061    req.nlh.nlmsg_seq = SEQNUM;
1062    req.nlh.nlmsg_pid = 0;
1063    req.rtg.rtgen_family = AF_INET;
1064
1065    if( 0 > sendto( fd, &req, sizeof( req ), 0,
1066                    (struct sockaddr *) &snl, sizeof( snl ) ) )
1067    {
1068        tr_err( "failed to write to routing socket (%s)", strerror( sockerrno ) );
1069        close( fd );
1070        return -1;
1071    }
1072
1073    return fd;
1074}
1075
1076static uint8_t *
1077getroute( int fd, unsigned int * buflen )
1078{
1079    void             * buf;
1080    unsigned int       len;
1081    ssize_t            res;
1082    struct sockaddr_nl snl;
1083    socklen_t          slen;
1084
1085    len = 8192;
1086    buf = calloc( 1, len );
1087    if( NULL == buf )
1088    {
1089        *buflen = 0;
1090        return NULL;
1091    }
1092
1093    for( ;; )
1094    {
1095        bzero( &snl, sizeof( snl ) );
1096        slen = sizeof( snl );
1097        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
1098        if( 0 > res )
1099        {
1100            if( EAGAIN != sockerrno )
1101            {
1102                tr_err( "failed to read from routing socket (%s)",
1103                        strerror( sockerrno ) );
1104            }
1105            free( buf );
1106            *buflen = 0;
1107            return NULL;
1108        }
1109        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
1110        {
1111            tr_err( "bad address" );
1112            free( buf );
1113            *buflen = 0;
1114            return NULL;
1115        }
1116
1117        if( 0 == snl.nl_pid )
1118        {
1119            break;
1120        }
1121    }
1122
1123    *buflen = res;
1124
1125    return buf;
1126}
1127
1128static int
1129parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
1130{
1131    struct nlmsghdr * nlm;
1132    struct nlmsgerr * nle;
1133    struct rtmsg    * rtm;
1134    struct rtattr   * rta;
1135    int               rtalen;
1136    struct in_addr    gw, dst;
1137
1138    nlm = ( struct nlmsghdr * ) buf;
1139    while( NLMSG_OK( nlm, len ) )
1140    {
1141        gw.s_addr = INADDR_ANY;
1142        dst.s_addr = INADDR_ANY;
1143        if( NLMSG_ERROR == nlm->nlmsg_type )
1144        {
1145            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
1146            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
1147                nlm->nlmsg_len )
1148            {
1149                tr_err( "truncated netlink error" );
1150            }
1151            else
1152            {
1153                tr_err( "netlink error (%s)", strerror( nle->error ) );
1154            }
1155            return 1;
1156        }
1157        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
1158                 getpid() == (pid_t) nlm->nlmsg_pid &&
1159                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
1160        {
1161            rtm = NLMSG_DATA( nlm );
1162            rta = RTM_RTA( rtm );
1163            rtalen = RTM_PAYLOAD( nlm );
1164
1165            while( RTA_OK( rta, rtalen ) )
1166            {
1167                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
1168                {
1169                    switch( rta->rta_type )
1170                    {
1171                        case RTA_GATEWAY:
1172                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
1173                            break;
1174                        case RTA_DST:
1175                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
1176                            break;
1177                    }
1178                }
1179                rta = RTA_NEXT( rta, rtalen );
1180            }
1181        }
1182
1183        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
1184            INADDR_ANY == dst.s_addr )
1185        {
1186            *addr = gw;
1187            return 0;
1188        }
1189
1190        nlm = NLMSG_NEXT( nlm, len );
1191    }
1192
1193    return 1;
1194}
1195
1196#else /* not BSD or Linux */
1197
1198int
1199tr_getDefaultRoute( struct in_addr * addr UNUSED )
1200{
1201    tr_inf( "don't know how to get default route on this platform" );
1202    return 1;
1203}
1204
1205#endif
Note: See TracBrowser for help on using the repository browser.