Changeset 12024


Ignore:
Timestamp:
Feb 24, 2011, 3:01:26 PM (12 years ago)
Author:
jordan
Message:

(2.2x) backport r11882, r11888 for #4016 "blocklists don't handle overlapping/unsorted rules"

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2x/libtransmission/blocklist.c

    r11709 r12024  
    1212
    1313#include <stdio.h>
    14 #include <stdlib.h> /* free() */
     14#include <stdlib.h> /* qsort(), free() */
    1515#include <string.h>
    1616
     
    4747***/
    4848
    49 struct tr_ip_range
     49struct tr_ipv4_range
    5050{
    5151    uint32_t    begin;
     
    5555struct tr_blocklist
    5656{
    57     tr_bool               isEnabled;
    58     int                   fd;
    59     size_t                ruleCount;
    60     size_t                byteCount;
    61     char *                filename;
    62     struct tr_ip_range * rules;
     57    tr_bool                isEnabled;
     58    int                    fd;
     59    size_t                 ruleCount;
     60    size_t                 byteCount;
     61    char *                 filename;
     62    struct tr_ipv4_range * rules;
    6363};
    6464
     
    108108    b->fd = fd;
    109109    b->byteCount = byteCount;
    110     b->ruleCount = byteCount / sizeof( struct tr_ip_range );
     110    b->ruleCount = byteCount / sizeof( struct tr_ipv4_range );
    111111
    112112    {
     
    128128                       const void * vb )
    129129{
    130     const uint32_t *           a = va;
    131     const struct tr_ip_range * b = vb;
     130    const uint32_t *             a = va;
     131    const struct tr_ipv4_range * b = vb;
    132132
    133133    if( *a < b->begin ) return -1;
     
    207207                         const tr_address * addr )
    208208{
    209     uint32_t                   needle;
    210     const struct tr_ip_range * range;
     209    uint32_t                     needle;
     210    const struct tr_ipv4_range * range;
    211211
    212212    assert( tr_isAddress( addr ) );
     
    225225                     b->rules,
    226226                     b->ruleCount,
    227                      sizeof( struct tr_ip_range ),
     227                     sizeof( struct tr_ipv4_range ),
    228228                     compareAddressToRange );
    229229
     
    237237 */
    238238static tr_bool
    239 parseLine1( const char * line, struct tr_ip_range * range )
     239parseLine1( const char * line, struct tr_ipv4_range * range )
    240240{
    241241    char * walk;
     
    273273 */
    274274static tr_bool
    275 parseLine2( const char * line, struct tr_ip_range * range )
     275parseLine2( const char * line, struct tr_ipv4_range * range )
    276276{
    277277    int unk;
     
    301301
    302302static int
    303 parseLine( const char * line, struct tr_ip_range * range )
     303parseLine( const char * line, struct tr_ipv4_range * range )
    304304{
    305305    return parseLine1( line, range )
     
    307307}
    308308
     309static int
     310compareAddressRangesByFirstAddress( const void * va, const void * vb )
     311{
     312    const struct tr_ipv4_range * a = va;
     313    const struct tr_ipv4_range * b = vb;
     314    if( a->begin != b->begin )
     315        return a->begin < b->begin ? -1 : 1;
     316    return 0;
     317}
     318
    309319int
    310 _tr_blocklistSetContent( tr_blocklist * b,
    311                          const char *   filename )
     320_tr_blocklistSetContent( tr_blocklist * b, const char * filename )
    312321{
    313322    FILE * in;
    314323    FILE * out;
    315324    int inCount = 0;
    316     int outCount = 0;
    317325    char line[2048];
    318326    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
     327    struct tr_ipv4_range * ranges = NULL;
     328    size_t ranges_alloc = 0;
     329    size_t ranges_count = 0;
    319330
    320331    if( !filename )
     
    341352    }
    342353
     354    /* load the rules into memory */
    343355    while( fgets( line, sizeof( line ), in ) != NULL )
    344356    {
    345357        char * walk;
    346         struct tr_ip_range range;
     358        struct tr_ipv4_range range;
    347359
    348360        ++inCount;
     
    359371        }
    360372
    361         if( fwrite( &range, sizeof( struct tr_ip_range ), 1, out ) != 1 )
     373        if( ranges_alloc == ranges_count )
    362374        {
    363             tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename,
    364                    tr_strerror( errno ) );
    365             break;
     375            ranges_alloc += 4096; /* arbitrary */
     376            ranges = tr_renew( struct tr_ipv4_range, ranges, ranges_alloc );
    366377        }
    367378
    368         ++outCount;
    369     }
    370 
    371     {
     379        ranges[ranges_count++] = range;
     380    }
     381
     382    if( ranges_count > 0 ) /* sort and merge */
     383    {
     384        struct tr_ipv4_range * r;
     385        struct tr_ipv4_range * keep = ranges;
     386        const struct tr_ipv4_range * end;
     387
     388        /* sort */
     389        qsort( ranges, ranges_count, sizeof( struct tr_ipv4_range ),
     390               compareAddressRangesByFirstAddress );
     391
     392        /* merge */
     393        for( r=ranges+1, end=ranges+ranges_count; r!=end; ++r ) {
     394            if( keep->end < r->begin )
     395                *++keep = *r;
     396            else if( keep->end < r->end )
     397                keep->end = r->end;
     398        }
     399
     400        ranges_count = keep + 1 - ranges;
     401
     402#ifndef NDEBUG
     403        /* sanity checks: make sure the rules are sorted
     404         * in ascending order and don't overlap */
     405        {
     406            size_t i;
     407
     408            for( i=0; i<ranges_count; ++i )
     409                assert( ranges[i].begin <= ranges[i].end );
     410
     411            for( i=1; i<ranges_count; ++i )
     412                assert( ranges[i-1].end < ranges[i].begin );
     413        }
     414#endif
     415    }
     416
     417    if( fwrite( ranges, sizeof( struct tr_ipv4_range ), ranges_count, out ) != ranges_count )
     418        tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename, tr_strerror( errno ) );
     419    else {
    372420        char * base = tr_basename( b->filename );
    373         tr_inf( _( "Blocklist \"%s\" updated with %d entries" ), base, outCount );
     421        tr_inf( _( "Blocklist \"%s\" updated with %zu entries" ), base, ranges_count );
    374422        tr_free( base );
    375423    }
    376424
     425    tr_free( ranges );
    377426    fclose( out );
    378427    fclose( in );
     
    380429    blocklistLoad( b );
    381430
    382     return outCount;
    383 }
    384 
     431    return ranges_count;
     432}
Note: See TracChangeset for help on using the changeset viewer.