source: branches/1.9x/libtransmission/blocklist.c @ 10604

Last change on this file since 10604 was 10604, checked in by livings124, 12 years ago

(1.9x) #3041 blocklist should not try to add invalid lines to the blocklist, and should not print those invalid lines to the message queue

  • Property svn:keywords set to Date Rev Author Id
File size: 6.5 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 10604 2010-05-01 15:00:17Z livings124 $
11 */
12
13#include <stdio.h>
14#include <stdlib.h> /* free() */
15#include <string.h>
16
17#ifdef WIN32
18 #include <windows.h>
19#endif
20
21#ifndef WIN32
22 #include <sys/mman.h>
23#endif
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <assert.h>
29
30#include "ggets.h"
31
32#include "transmission.h"
33#include "platform.h"
34#include "blocklist.h"
35#include "net.h"
36#include "utils.h"
37
38
39/***
40****  PRIVATE
41***/
42
43struct tr_ip_range
44{
45    uint32_t    begin;
46    uint32_t    end;
47};
48
49struct tr_blocklist
50{
51    tr_bool               isEnabled;
52    int                   fd;
53    size_t                ruleCount;
54    size_t                byteCount;
55    char *                filename;
56    struct tr_ip_range *  rules;
57};
58
59static void
60blocklistClose( tr_blocklist * b )
61{
62    if( b->rules )
63    {
64        munmap( b->rules, b->byteCount );
65        close( b->fd );
66        b->rules = NULL;
67        b->ruleCount = 0;
68        b->byteCount = 0;
69        b->fd = -1;
70    }
71}
72
73static void
74blocklistLoad( tr_blocklist * b )
75{
76    int          fd;
77    struct stat  st;
78    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
79
80    blocklistClose( b );
81
82    if( stat( b->filename, &st ) == -1 )
83        return;
84
85    fd = open( b->filename, O_RDONLY );
86    if( fd == -1 )
87    {
88        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
89        return;
90    }
91
92#ifndef WIN32
93    b->rules = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
94#else
95    b->rules = mmap( NULL, st.st_size, 0, 0, fd, 0 );
96#endif
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
230int
231_tr_blocklistSetContent( tr_blocklist * b,
232                         const char *   filename )
233{
234    FILE *       in;
235    FILE *       out;
236    char *       line;
237    int          inCount = 0;
238    int          outCount = 0;
239    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
240
241    if( !filename )
242    {
243        blocklistDelete( b );
244        return 0;
245    }
246
247    in = fopen( filename, "r" );
248    if( !in )
249    {
250        tr_err( err_fmt, filename, tr_strerror( errno ) );
251        return 0;
252    }
253
254    blocklistClose( b );
255
256    out = fopen( b->filename, "wb+" );
257    if( !out )
258    {
259        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
260        fclose( in );
261        return 0;
262    }
263
264    while( !fggets( &line, in ) )
265    {
266        char * rangeBegin;
267        char * rangeEnd;
268        char * crpos;
269        tr_address  addr;
270        struct tr_ip_range range;
271
272        ++inCount;
273
274        rangeBegin = strrchr( line, ':' );
275        if( !rangeBegin ){ free( line ); continue; }
276        ++rangeBegin;
277
278        rangeEnd = strchr( rangeBegin, '-' );
279        if( !rangeEnd ){ free( line ); continue; }
280        *rangeEnd++ = '\0';
281        if(( crpos = strchr( rangeEnd, '\r' )))
282            *crpos = '\0';
283
284        if( !tr_pton( rangeBegin, &addr ) )
285        {
286            tr_err( _( "blocklist skipped invalid address at line %d" ), inCount );
287            free( line );
288            continue;
289        }
290        range.begin = ntohl( addr.addr.addr4.s_addr );
291
292        if( !tr_pton( rangeEnd, &addr ) )
293        {
294            tr_err( _( "blocklist skipped invalid address at line %d" ), inCount );
295            free( line );
296            continue;
297        }
298        range.end = ntohl( addr.addr.addr4.s_addr );
299
300        free( line );
301
302        if( fwrite( &range, sizeof( struct tr_ip_range ), 1, out ) != 1 )
303        {
304            tr_err( _(
305                       "Couldn't save file \"%1$s\": %2$s" ), b->filename,
306                   tr_strerror( errno ) );
307            break;
308        }
309
310        ++outCount;
311    }
312
313    {
314        char * base = tr_basename( b->filename );
315        tr_inf( _( "Blocklist \"%1$s\" updated with %2$'d entries" ), base, outCount );
316        tr_free( base );
317    }
318
319    fclose( out );
320    fclose( in );
321
322    blocklistLoad( b );
323
324    return outCount;
325}
326
Note: See TracBrowser for help on using the repository browser.