source: trunk/libtransmission/blocklist.c @ 11709

Last change on this file since 11709 was 11709, checked in by jordan, 11 years ago

Update the copyright year in the source code comments.

The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli.

Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.

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