source: trunk/libtransmission/blocklist.c @ 6323

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

Update NEWS file to say the Clutch rewrite's been folded into Transmission.

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