source: branches/1.4x/libtransmission/blocklist.c @ 7254

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

(1.4x libT) #1552: Blocklists fail when Windows newlines are present

  • Property svn:keywords set to Date Rev Author Id
File size: 6.3 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
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 7254 2008-12-03 05:34:28Z charles $
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
29#include "ggets.h"
30
31#include "transmission.h"
32#include "platform.h"
33#include "blocklist.h"
34#include "net.h" /* tr_netResolve() */
35#include "utils.h"
36
37/***
38****  PRIVATE
39***/
40
41struct tr_ip_range
42{
43    uint32_t    begin;
44    uint32_t    end;
45};
46
47struct tr_blocklist
48{
49    unsigned int          isEnabled : 1;
50    int                   fd;
51    size_t                ruleCount;
52    size_t                byteCount;
53    char *                filename;
54    struct tr_ip_range *  rules;
55};
56
57static void
58blocklistClose( tr_blocklist * b )
59{
60    if( b->rules )
61    {
62        munmap( b->rules, b->byteCount );
63        close( b->fd );
64        b->rules = NULL;
65        b->ruleCount = 0;
66        b->byteCount = 0;
67        b->fd = -1;
68    }
69}
70
71static void
72blocklistLoad( tr_blocklist * b )
73{
74    int          fd;
75    struct stat  st;
76    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
77
78    blocklistClose( b );
79
80    if( stat( b->filename, &st ) == -1 )
81        return;
82
83    fd = open( b->filename, O_RDONLY );
84    if( fd == -1 )
85    {
86        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
87        return;
88    }
89
90#ifndef WIN32
91    b->rules = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
92#else
93    b->rules = mmap( NULL, st.st_size, 0, 0, fd, 0 );
94#endif
95    if( !b->rules )
96    {
97        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
98        close( fd );
99        return;
100    }
101
102    b->byteCount = st.st_size;
103    b->ruleCount = st.st_size / sizeof( struct tr_ip_range );
104    b->fd = fd;
105
106    {
107        char * base = tr_basename( b->filename );
108        tr_inf( _( "Blocklist \"%s\" contains %'zu entries" ), base, b->ruleCount );
109        tr_free( base );
110    }
111}
112
113static void
114blocklistEnsureLoaded( tr_blocklist * b )
115{
116    if( !b->rules )
117        blocklistLoad( b );
118}
119
120static int
121compareAddressToRange( const void * va,
122                       const void * vb )
123{
124    const uint32_t *           a = va;
125    const struct tr_ip_range * b = vb;
126
127    if( *a < b->begin ) return -1;
128    if( *a > b->end ) return 1;
129    return 0;
130}
131
132static void
133blocklistDelete( tr_blocklist * b )
134{
135    blocklistClose( b );
136    unlink( b->filename );
137}
138
139/***
140****  PACKAGE-VISIBLE
141***/
142
143tr_blocklist *
144_tr_blocklistNew( const char * filename,
145                  int          isEnabled )
146{
147    tr_blocklist * b;
148
149    b = tr_new0( tr_blocklist, 1 );
150    b->fd = -1;
151    b->filename = tr_strdup( filename );
152    b->isEnabled = isEnabled;
153
154    return b;
155}
156
157const char*
158_tr_blocklistGetFilename( const tr_blocklist * b )
159{
160    return b->filename;
161}
162
163void
164_tr_blocklistFree( tr_blocklist * b )
165{
166    blocklistClose( b );
167    tr_free( b->filename );
168    tr_free( b );
169}
170
171int
172_tr_blocklistExists( const tr_blocklist * b )
173{
174    struct stat st;
175
176    return !stat( b->filename, &st );
177}
178
179int
180_tr_blocklistGetRuleCount( const tr_blocklist * b )
181{
182    blocklistEnsureLoaded( (tr_blocklist*)b );
183
184    return b->ruleCount;
185}
186
187int
188_tr_blocklistIsEnabled( tr_blocklist * b )
189{
190    return b->isEnabled;
191}
192
193void
194_tr_blocklistSetEnabled( tr_blocklist * b,
195                         int            isEnabled )
196{
197    b->isEnabled = isEnabled ? 1 : 0;
198}
199
200int
201_tr_blocklistHasAddress( tr_blocklist         * b,
202                         const struct in_addr * addr )
203{
204    uint32_t                   needle;
205    const struct tr_ip_range * range;
206
207    if( !b->isEnabled )
208        return 0;
209
210    blocklistEnsureLoaded( b );
211    if( !b->rules )
212        return 0;
213
214    needle = ntohl( addr->s_addr );
215
216    range = bsearch( &needle,
217                     b->rules,
218                     b->ruleCount,
219                     sizeof( struct tr_ip_range ),
220                     compareAddressToRange );
221
222    return range != NULL;
223}
224
225int
226_tr_blocklistSetContent( tr_blocklist * b,
227                         const char *   filename )
228{
229    FILE *       in;
230    FILE *       out;
231    char *       line;
232    int          lineCount = 0;
233    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
234
235    if( !filename )
236    {
237        blocklistDelete( b );
238        return 0;
239    }
240
241    in = fopen( filename, "r" );
242    if( !in )
243    {
244        tr_err( err_fmt, filename, tr_strerror( errno ) );
245        return 0;
246    }
247
248    blocklistClose( b );
249
250    out = fopen( b->filename, "wb+" );
251    if( !out )
252    {
253        tr_err( err_fmt, b->filename, tr_strerror( errno ) );
254        fclose( in );
255        return 0;
256    }
257
258    while( !fggets( &line, in ) )
259    {
260        char *  rangeBegin;
261        char *  rangeEnd;
262        char *  crpos;
263        struct in_addr in_addr;
264        struct tr_ip_range range;
265
266        rangeBegin = strrchr( line, ':' );
267        if( !rangeBegin ){ free( line ); continue; }
268        ++rangeBegin;
269
270        rangeEnd = strchr( rangeBegin, '-' );
271        if( !rangeEnd ){ free( line ); continue; }
272        *rangeEnd++ = '\0';
273
274        if(( crpos = strchr( rangeEnd, '\r' )))
275            *crpos = '\0';
276
277        if( tr_netResolve( rangeBegin, &in_addr ) )
278            tr_err( "blocklist skipped invalid address [%s]\n", rangeBegin );
279        range.begin = ntohl( in_addr.s_addr );
280
281        if( tr_netResolve( rangeEnd, &in_addr ) )
282            tr_err( "blocklist skipped invalid address [%s]\n", rangeEnd );
283        range.end = ntohl( in_addr.s_addr );
284
285        free( line );
286
287        if( fwrite( &range, sizeof( struct tr_ip_range ), 1, out ) != 1 )
288        {
289            tr_err( _(
290                       "Couldn't save file \"%1$s\": %2$s" ), b->filename,
291                   tr_strerror( errno ) );
292            break;
293        }
294
295        ++lineCount;
296    }
297
298    {
299        char * base = tr_basename( b->filename );
300        tr_inf( _( "Blocklist \"%1$s\" updated with %2$'d entries" ), base, lineCount );
301        tr_free( base );
302    }
303
304
305    fclose( out );
306    fclose( in );
307
308    blocklistLoad( b );
309
310    return lineCount;
311}
312
Note: See TracBrowser for help on using the repository browser.