(trunk libT) #4016 "blocklists don't handle overlapping/unsorted rules" -- fixed.

This commit is contained in:
Jordan Lee 2011-02-13 16:14:31 +00:00
parent 5c14353398
commit e187ae58a9
1 changed files with 60 additions and 12 deletions

View File

@ -11,7 +11,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> /* free() */ #include <stdlib.h> /* qsort(), free() */
#include <string.h> #include <string.h>
#ifdef WIN32 #ifdef WIN32
@ -306,16 +306,27 @@ parseLine( const char * line, struct tr_ipv4_range * range )
|| parseLine2( line, range ); || parseLine2( line, range );
} }
static int
compareAddressRangesByFirstAddress( const void * va, const void * vb )
{
const struct tr_ipv4_range * a = va;
const struct tr_ipv4_range * b = vb;
if( a->begin != b->begin )
return a->begin < b->begin ? -1 : 1;
return 0;
}
int int
_tr_blocklistSetContent( tr_blocklist * b, _tr_blocklistSetContent( tr_blocklist * b, const char * filename )
const char * filename )
{ {
FILE * in; FILE * in;
FILE * out; FILE * out;
int inCount = 0; int inCount = 0;
int outCount = 0;
char line[2048]; char line[2048];
const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" ); const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
struct tr_ipv4_range * ranges = NULL;
size_t ranges_alloc = 0;
size_t ranges_count = 0;
if( !filename ) if( !filename )
{ {
@ -340,6 +351,7 @@ _tr_blocklistSetContent( tr_blocklist * b,
return 0; return 0;
} }
/* load the rules into memory */
while( fgets( line, sizeof( line ), in ) != NULL ) while( fgets( line, sizeof( line ), in ) != NULL )
{ {
char * walk; char * walk;
@ -358,27 +370,63 @@ _tr_blocklistSetContent( tr_blocklist * b,
continue; continue;
} }
if( fwrite( &range, sizeof( struct tr_ipv4_range ), 1, out ) != 1 ) if( ranges_alloc == ranges_count )
{ {
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename, ranges_alloc += 4096; /* arbitrary */
tr_strerror( errno ) ); ranges = tr_renew( struct tr_ipv4_range, ranges, ranges_alloc );
break;
} }
++outCount; ranges[ranges_count++] = range;
} }
if( ranges_count > 0 ) /* sort and merge */
{ {
struct tr_ipv4_range * r;
struct tr_ipv4_range * keep = ranges;
const struct tr_ipv4_range * end;
/* sort */
qsort( ranges, ranges_count, sizeof( struct tr_ipv4_range ),
compareAddressRangesByFirstAddress );
/* merge */
for( r=ranges+1, end=ranges+ranges_count; r!=end; ++r ) {
if( keep->end < r->begin )
*++keep = *r;
else if( keep->end < r->end )
keep->end = r->end;
}
ranges_count = keep + 1 - ranges;
#ifndef NDEBUG
/* sanity checks: make sure the rules are sorted
* in ascending order and don't overlap */
{
size_t i;
for( i=0; i<ranges_count; ++i )
assert( ranges[i].begin <= ranges[i].end );
for( i=1; i<ranges_count; ++i )
assert( ranges[i-1].end < ranges[i].begin );
}
#endif
}
if( fwrite( ranges, sizeof( struct tr_ipv4_range ), ranges_count, out ) != ranges_count )
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename, tr_strerror( errno ) );
else {
char * base = tr_basename( b->filename ); char * base = tr_basename( b->filename );
tr_inf( _( "Blocklist \"%s\" updated with %d entries" ), base, outCount ); tr_inf( _( "Blocklist \"%s\" updated with %zu entries" ), base, ranges_count );
tr_free( base ); tr_free( base );
} }
tr_free( ranges );
fclose( out ); fclose( out );
fclose( in ); fclose( in );
blocklistLoad( b ); blocklistLoad( b );
return outCount; return ranges_count;
} }