source: trunk/libtransmission/blocklist.c @ 10816

Last change on this file since 10816 was 10816, checked in by charles, 12 years ago

(trunk) more win32 fixes from rb07 in #3311

  • Property svn:keywords set to Date Rev Author Id
File size: 7.8 KB
Line 
1/*
2 * This file Copyright (C) 2008-2010 Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: blocklist.c 10816 2010-06-22 00:12:52Z charles $
11 */
12
13#include <stdio.h>
14#include <stdlib.h> /* free() */
15#include <string.h>
16
17#ifdef WIN32
18 #include <w32api.h>
19 #define WINVER  WindowsXP
20 #include <windows.h>
21#endif
22
23#ifndef WIN32
24 #include <sys/mman.h>
25#endif
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <assert.h>
31
32#include "transmission.h"
33#include "platform.h"
34#include "blocklist.h"
35#include "net.h"
36#include "utils.h"
37
38#ifndef O_BINARY
39 #define O_BINARY 0
40#endif
41
42
43/***
44****  PRIVATE
45***/
46
47struct tr_ip_range
48{
49    uint32_t    begin;
50    uint32_t    end;
51};
52
53struct tr_blocklist
54{
55    tr_bool               isEnabled;
56    int                   fd;
57    size_t                ruleCount;
58    size_t                byteCount;
59    char *                filename;
60    struct tr_ip_range *  rules;
61};
62
63static void
64blocklistClose( tr_blocklist * b )
65{
66    if( b->rules )
67    {
68        munmap( b->rules, b->byteCount );
69        close( b->fd );
70        b->rules = NULL;
71        b->ruleCount = 0;
72        b->byteCount = 0;
73        b->fd = -1;
74    }
75}
76
77static void
78blocklistLoad( tr_blocklist * b )
79{
80    int          fd;
81    struct stat  st;
82    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
83
84    blocklistClose( b );
85
86    if( stat( b->filename, &st ) == -1 )
87        return;
88
89    fd = open( b->filename, O_RDONLY | O_BINARY );
90    if( fd == -1 )
91    {
92        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
93        return;
94    }
95
96    b->rules = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
97    if( !b->rules )
98    {
99        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
100        close( fd );
101        return;
102    }
103
104    b->byteCount = st.st_size;
105    b->ruleCount = st.st_size / sizeof( struct tr_ip_range );
106    b->fd = fd;
107
108    {
109        char * base = tr_basename( b->filename );
110        tr_inf( _( "Blocklist \"%s\" contains %'zu entries" ), base, b->ruleCount );
111        tr_free( base );
112    }
113}
114
115static void
116blocklistEnsureLoaded( tr_blocklist * b )
117{
118    if( !b->rules )
119        blocklistLoad( b );
120}
121
122static int
123compareAddressToRange( const void * va,
124                       const void * vb )
125{
126    const uint32_t *           a = va;
127    const struct tr_ip_range * b = vb;
128
129    if( *a < b->begin ) return -1;
130    if( *a > b->end ) return 1;
131    return 0;
132}
133
134static void
135blocklistDelete( tr_blocklist * b )
136{
137    blocklistClose( b );
138    unlink( b->filename );
139}
140
141/***
142****  PACKAGE-VISIBLE
143***/
144
145tr_blocklist *
146_tr_blocklistNew( const char * filename,
147                  int          isEnabled )
148{
149    tr_blocklist * b;
150
151    b = tr_new0( tr_blocklist, 1 );
152    b->fd = -1;
153    b->filename = tr_strdup( filename );
154    b->isEnabled = isEnabled;
155
156    return b;
157}
158
159const char*
160_tr_blocklistGetFilename( const tr_blocklist * b )
161{
162    return b->filename;
163}
164
165void
166_tr_blocklistFree( tr_blocklist * b )
167{
168    blocklistClose( b );
169    tr_free( b->filename );
170    tr_free( b );
171}
172
173int
174_tr_blocklistExists( const tr_blocklist * b )
175{
176    struct stat st;
177
178    return !stat( b->filename, &st );
179}
180
181int
182_tr_blocklistGetRuleCount( const tr_blocklist * b )
183{
184    blocklistEnsureLoaded( (tr_blocklist*)b );
185
186    return b->ruleCount;
187}
188
189int
190_tr_blocklistIsEnabled( tr_blocklist * b )
191{
192    return b->isEnabled;
193}
194
195void
196_tr_blocklistSetEnabled( tr_blocklist * b,
197                         int            isEnabled )
198{
199    b->isEnabled = isEnabled ? 1 : 0;
200}
201
202int
203_tr_blocklistHasAddress( tr_blocklist     * b,
204                         const tr_address * addr )
205{
206    uint32_t                   needle;
207    const struct tr_ip_range * range;
208
209    assert( tr_isAddress( addr ) );
210
211    if( !b->isEnabled || addr->type == TR_AF_INET6 )
212        return 0;
213
214    blocklistEnsureLoaded( b );
215
216    if( !b->rules || !b->ruleCount )
217        return 0;
218
219    needle = ntohl( addr->addr.addr4.s_addr );
220
221    range = bsearch( &needle,
222                     b->rules,
223                     b->ruleCount,
224                     sizeof( struct tr_ip_range ),
225                     compareAddressToRange );
226
227    return range != NULL;
228}
229
230/*
231 * level1 format: "comment:x.x.x.x-y.y.y.y"
232 */
233static tr_bool
234parseLine1( const char * line, struct tr_ip_range * range )
235{
236    char * walk;
237    int b[4];
238    int e[4];
239    char str[64];
240    tr_address addr;
241
242    walk = strrchr( line, ':' );
243    if( !walk )
244        return FALSE;
245    ++walk; /* walk past the colon */
246
247    if( sscanf( walk, "%d.%d.%d.%d-%d.%d.%d.%d",
248                &b[0], &b[1], &b[2], &b[3],
249                &e[0], &e[1], &e[2], &e[3] ) != 8 )
250        return FALSE;
251
252    tr_snprintf( str, sizeof( str ), "%d.%d.%d.%d", b[0], b[1], b[2], b[3] );
253    if( tr_pton( str, &addr ) == NULL )
254        return FALSE;
255    range->begin = ntohl( addr.addr.addr4.s_addr );
256
257    tr_snprintf( str, sizeof( str ), "%d.%d.%d.%d", e[0], e[1], e[2], e[3] );
258    if( tr_pton( str, &addr ) == NULL )
259        return FALSE;
260    range->end = ntohl( addr.addr.addr4.s_addr );
261
262    return TRUE;
263}
264
265/*
266 * "000.000.000.000 - 000.255.255.255 , 000 , invalid ip"
267 */
268static tr_bool
269parseLine2( const char * line, struct tr_ip_range * range )
270{
271    int unk;
272    int a[4];
273    int b[4];
274    char str[32];
275    tr_address addr;
276
277    if( sscanf( line, "%3d.%3d.%3d.%3d - %3d.%3d.%3d.%3d , %3d , ",
278                &a[0], &a[1], &a[2], &a[3],
279                &b[0], &b[1], &b[2], &b[3],
280                &unk ) != 9 )
281        return FALSE;
282
283    tr_snprintf( str, sizeof(str), "%d.%d.%d.%d", a[0], a[1], a[2], a[3] );
284    if( tr_pton( str, &addr ) == NULL )
285        return FALSE;
286    range->begin = ntohl( addr.addr.addr4.s_addr );
287
288    tr_snprintf( str, sizeof(str), "%d.%d.%d.%d", b[0], b[1], b[2], b[3] );
289    if( tr_pton( str, &addr ) == NULL )
290        return FALSE;
291    range->end = ntohl( addr.addr.addr4.s_addr );
292
293    return TRUE;
294}
295
296static int
297parseLine( const char * line, struct tr_ip_range * range )
298{
299    return parseLine1( line, range )
300        || parseLine2( line, range );
301}
302
303int
304_tr_blocklistSetContent( tr_blocklist * b,
305                         const char *   filename )
306{
307    FILE * in;
308    FILE * out;
309    int inCount = 0;
310    int outCount = 0;
311    char line[2048];
312    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
313
314    if( !filename )
315    {
316        blocklistDelete( b );
317        return 0;
318    }
319
320    in = fopen( filename, "rb" );
321    if( !in )
322    {
323        tr_err( err_fmt, filename, tr_strerror( errno ) );
324        return 0;
325    }
326
327    blocklistClose( b );
328
329    out = fopen( b->filename, "wb+" );
330    if( !out )
331    {
332        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
333        fclose( in );
334        return 0;
335    }
336
337    while( fgets( line, sizeof( line ), in ) != NULL )
338    {
339        char * walk;
340        struct tr_ip_range range;
341
342        ++inCount;
343
344        /* zap the linefeed */
345        if(( walk = strchr( line, '\r' ))) *walk = '\0'; 
346        if(( walk = strchr( line, '\n' ))) *walk = '\0'; 
347
348        if( !parseLine( line, &range ) )
349        {
350            /* don't try to display the actual lines - it causes issues */
351            tr_err( _( "blocklist skipped invalid address at line %d" ), inCount );
352            continue;
353        }
354
355        if( fwrite( &range, sizeof( struct tr_ip_range ), 1, out ) != 1 )
356        {
357            tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename,
358                   tr_strerror( errno ) );
359            break;
360        }
361
362        ++outCount;
363    }
364
365    {
366        char * base = tr_basename( b->filename );
367        tr_inf( _( "Blocklist \"%s\" updated with %'d entries" ), base, outCount );
368        tr_free( base );
369    }
370
371    fclose( out );
372    fclose( in );
373
374    blocklistLoad( b );
375
376    return outCount;
377}
378
Note: See TracBrowser for help on using the repository browser.