Changeset 13823
- Timestamp:
- Jan 21, 2013, 5:39:20 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/blocklist.c
r13631 r13823 50 50 struct tr_ipv4_range 51 51 { 52 uint32_tbegin;53 uint32_tend;52 uint32_t begin; 53 uint32_t end; 54 54 }; 55 55 56 56 struct tr_blocklist 57 57 { 58 59 60 61 62 63 58 bool isEnabled; 59 int fd; 60 size_t ruleCount; 61 size_t byteCount; 62 char * filename; 63 struct tr_ipv4_range * rules; 64 64 }; 65 65 … … 67 67 blocklistClose (tr_blocklist * b) 68 68 { 69 if (b->rules)70 { 71 72 73 74 75 76 69 if (b->rules != NULL) 70 { 71 munmap (b->rules, b->byteCount); 72 close (b->fd); 73 b->rules = NULL; 74 b->ruleCount = 0; 75 b->byteCount = 0; 76 b->fd = -1; 77 77 } 78 78 } … … 81 81 blocklistLoad (tr_blocklist * b) 82 82 { 83 int fd; 84 size_t byteCount; 85 struct stat st; 86 const char * err_fmt = _("Couldn't read \"%1$s\": %2$s"); 87 88 blocklistClose (b); 89 90 if (stat (b->filename, &st) == -1) 91 return; 92 93 fd = open (b->filename, O_RDONLY | O_BINARY); 94 if (fd == -1) 95 { 96 tr_err (err_fmt, b->filename, tr_strerror (errno)); 97 return; 98 } 99 100 byteCount = (size_t) st.st_size; 101 b->rules = mmap (NULL, byteCount, PROT_READ, MAP_PRIVATE, fd, 0); 102 if (!b->rules) 103 { 104 tr_err (err_fmt, b->filename, tr_strerror (errno)); 105 close (fd); 106 return; 107 } 108 109 b->fd = fd; 110 b->byteCount = byteCount; 111 b->ruleCount = byteCount / sizeof (struct tr_ipv4_range); 112 113 { 114 char * base = tr_basename (b->filename); 115 tr_inf (_("Blocklist \"%s\" contains %zu entries"), base, b->ruleCount); 116 tr_free (base); 117 } 83 int fd; 84 size_t byteCount; 85 struct stat st; 86 char * base; 87 const char * err_fmt = _("Couldn't read \"%1$s\": %2$s"); 88 89 blocklistClose (b); 90 91 if (stat (b->filename, &st) == -1) 92 return; 93 94 fd = open (b->filename, O_RDONLY | O_BINARY); 95 if (fd == -1) 96 { 97 tr_err (err_fmt, b->filename, tr_strerror (errno)); 98 return; 99 } 100 101 byteCount = (size_t) st.st_size; 102 b->rules = mmap (NULL, byteCount, PROT_READ, MAP_PRIVATE, fd, 0); 103 if (!b->rules) 104 { 105 tr_err (err_fmt, b->filename, tr_strerror (errno)); 106 close (fd); 107 return; 108 } 109 110 b->fd = fd; 111 b->byteCount = byteCount; 112 b->ruleCount = byteCount / sizeof (struct tr_ipv4_range); 113 114 base = tr_basename (b->filename); 115 tr_inf (_("Blocklist \"%s\" contains %zu entries"), base, b->ruleCount); 116 tr_free (base); 118 117 } 119 118 … … 121 120 blocklistEnsureLoaded (tr_blocklist * b) 122 121 { 123 if (!b->rules)124 122 if (b->rules == NULL) 123 blocklistLoad (b); 125 124 } 126 125 127 126 static int 128 compareAddressToRange (const void * va, 129 const void * vb) 130 { 131 const uint32_t * a = va; 132 const struct tr_ipv4_range * b = vb; 133 134 if (*a < b->begin) return -1; 135 if (*a > b->end) return 1; 136 return 0; 127 compareAddressToRange (const void * va, const void * vb) 128 { 129 const uint32_t * a = va; 130 const struct tr_ipv4_range * b = vb; 131 132 if (*a < b->begin) return -1; 133 if (*a > b->end) return 1; 134 return 0; 137 135 } 138 136 … … 140 138 blocklistDelete (tr_blocklist * b) 141 139 { 142 143 140 blocklistClose (b); 141 unlink (b->filename); 144 142 } 145 143 … … 151 149 _tr_blocklistNew (const char * filename, bool isEnabled) 152 150 { 153 154 155 156 157 158 159 160 151 tr_blocklist * b; 152 153 b = tr_new0 (tr_blocklist, 1); 154 b->fd = -1; 155 b->filename = tr_strdup (filename); 156 b->isEnabled = isEnabled; 157 158 return b; 161 159 } 162 160 … … 164 162 _tr_blocklistGetFilename (const tr_blocklist * b) 165 163 { 166 164 return b->filename; 167 165 } 168 166 … … 170 168 _tr_blocklistFree (tr_blocklist * b) 171 169 { 172 173 174 170 blocklistClose (b); 171 tr_free (b->filename); 172 tr_free (b); 175 173 } 176 174 … … 178 176 _tr_blocklistExists (const tr_blocklist * b) 179 177 { 180 181 182 178 struct stat st; 179 180 return !stat (b->filename, &st); 183 181 } 184 182 … … 186 184 _tr_blocklistGetRuleCount (const tr_blocklist * b) 187 185 { 188 189 190 186 blocklistEnsureLoaded ((tr_blocklist*)b); 187 188 return b->ruleCount; 191 189 } 192 190 … … 194 192 _tr_blocklistIsEnabled (tr_blocklist * b) 195 193 { 196 194 return b->isEnabled; 197 195 } 198 196 … … 200 198 _tr_blocklistSetEnabled (tr_blocklist * b, bool isEnabled) 201 199 { 202 200 b->isEnabled = isEnabled ? 1 : 0; 203 201 } 204 202 … … 206 204 _tr_blocklistHasAddress (tr_blocklist * b, const tr_address * addr) 207 205 { 208 uint32_tneedle;209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 206 uint32_t needle; 207 const struct tr_ipv4_range * range; 208 209 assert (tr_address_is_valid (addr)); 210 211 if (!b->isEnabled || addr->type == TR_AF_INET6) 212 return 0; 213 214 blocklistEnsureLoaded (b); 215 216 if (!b->rules || !b->ruleCount) 217 return 0; 218 219 needle = ntohl (addr->addr.addr4.s_addr); 220 221 range = bsearch (&needle, 222 b->rules, 223 b->ruleCount, 224 sizeof (struct tr_ipv4_range), 225 compareAddressToRange); 226 227 return range != NULL; 230 228 } 231 229 … … 238 236 parseLine1 (const char * line, struct tr_ipv4_range * range) 239 237 { 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 238 char * walk; 239 int b[4]; 240 int e[4]; 241 char str[64]; 242 tr_address addr; 243 244 walk = strrchr (line, ':'); 245 if (!walk) 246 return false; 247 ++walk; /* walk past the colon */ 248 249 if (sscanf (walk, "%d.%d.%d.%d-%d.%d.%d.%d", 250 &b[0], &b[1], &b[2], &b[3], 251 &e[0], &e[1], &e[2], &e[3]) != 8) 252 return false; 253 254 tr_snprintf (str, sizeof (str), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]); 255 if (!tr_address_from_string (&addr, str)) 256 return false; 257 range->begin = ntohl (addr.addr.addr4.s_addr); 258 259 tr_snprintf (str, sizeof (str), "%d.%d.%d.%d", e[0], e[1], e[2], e[3]); 260 if (!tr_address_from_string (&addr, str)) 261 return false; 262 range->end = ntohl (addr.addr.addr4.s_addr); 263 264 return true; 267 265 } 268 266 … … 274 272 parseLine2 (const char * line, struct tr_ipv4_range * range) 275 273 { 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 274 int unk; 275 int a[4]; 276 int b[4]; 277 char str[32]; 278 tr_address addr; 279 280 if (sscanf (line, "%3d.%3d.%3d.%3d - %3d.%3d.%3d.%3d , %3d , ", 281 &a[0], &a[1], &a[2], &a[3], 282 &b[0], &b[1], &b[2], &b[3], 283 &unk) != 9) 284 return false; 285 286 tr_snprintf (str, sizeof (str), "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); 287 if (!tr_address_from_string (&addr, str)) 288 return false; 289 range->begin = ntohl (addr.addr.addr4.s_addr); 290 291 tr_snprintf (str, sizeof (str), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]); 292 if (!tr_address_from_string (&addr, str)) 293 return false; 294 range->end = ntohl (addr.addr.addr4.s_addr); 295 296 return true; 299 297 } 300 298 … … 302 300 parseLine (const char * line, struct tr_ipv4_range * range) 303 301 { 304 305 302 return parseLine1 (line, range) 303 || parseLine2 (line, range); 306 304 } 307 305 … … 309 307 compareAddressRangesByFirstAddress (const void * va, const void * vb) 310 308 { 311 312 313 314 315 309 const struct tr_ipv4_range * a = va; 310 const struct tr_ipv4_range * b = vb; 311 if (a->begin != b->begin) 312 return a->begin < b->begin ? -1 : 1; 313 return 0; 316 314 } 317 315 … … 319 317 _tr_blocklistSetContent (tr_blocklist * b, const char * filename) 320 318 { 321 322 323 324 325 326 327 328 329 330 331 { 332 333 334 } 335 336 337 if (!in)338 { 339 340 341 } 342 343 344 345 346 if (!out)347 { 348 349 350 351 } 352 353 354 355 { 356 357 358 359 360 361 362 363 364 365 319 FILE * in; 320 FILE * out; 321 int inCount = 0; 322 char line[2048]; 323 const char * err_fmt = _("Couldn't read \"%1$s\": %2$s"); 324 struct tr_ipv4_range * ranges = NULL; 325 size_t ranges_alloc = 0; 326 size_t ranges_count = 0; 327 328 if (!filename) 329 { 330 blocklistDelete (b); 331 return 0; 332 } 333 334 in = fopen (filename, "rb"); 335 if (in == NULL) 336 { 337 tr_err (err_fmt, filename, tr_strerror (errno)); 338 return 0; 339 } 340 341 blocklistClose (b); 342 343 out = fopen (b->filename, "wb+"); 344 if (out == NULL) 345 { 346 tr_err (err_fmt, b->filename, tr_strerror (errno)); 347 fclose (in); 348 return 0; 349 } 350 351 /* load the rules into memory */ 352 while (fgets (line, sizeof (line), in) != NULL) 353 { 354 char * walk; 355 struct tr_ipv4_range range; 356 357 ++inCount; 358 359 /* zap the linefeed */ 360 if ((walk = strchr (line, '\r'))) *walk = '\0'; 361 if ((walk = strchr (line, '\n'))) *walk = '\0'; 362 363 if (!parseLine (line, &range)) 366 364 { 367 368 369 365 /* don't try to display the actual lines - it causes issues */ 366 tr_err (_("blocklist skipped invalid address at line %d"), inCount); 367 continue; 370 368 } 371 369 372 370 if (ranges_alloc == ranges_count) 373 371 { 374 375 372 ranges_alloc += 4096; /* arbitrary */ 373 ranges = tr_renew (struct tr_ipv4_range, ranges, ranges_alloc); 376 374 } 377 375 378 379 } 380 381 382 { 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 376 ranges[ranges_count++] = range; 377 } 378 379 if (ranges_count > 0) /* sort and merge */ 380 { 381 struct tr_ipv4_range * r; 382 struct tr_ipv4_range * keep = ranges; 383 const struct tr_ipv4_range * end; 384 385 /* sort */ 386 qsort (ranges, ranges_count, sizeof (struct tr_ipv4_range), 387 compareAddressRangesByFirstAddress); 388 389 /* merge */ 390 for (r=ranges+1, end=ranges+ranges_count; r!=end; ++r) { 391 if (keep->end < r->begin) 392 *++keep = *r; 393 else if (keep->end < r->end) 394 keep->end = r->end; 395 } 396 397 ranges_count = keep + 1 - ranges; 400 398 401 399 #ifndef NDEBUG 402 403 404 405 406 407 408 409 410 411 412 400 /* sanity checks: make sure the rules are sorted 401 * in ascending order and don't overlap */ 402 { 403 size_t i; 404 405 for (i=0; i<ranges_count; ++i) 406 assert (ranges[i].begin <= ranges[i].end); 407 408 for (i=1; i<ranges_count; ++i) 409 assert (ranges[i-1].end < ranges[i].begin); 410 } 413 411 #endif 414 412 } 415 413 416 if (fwrite (ranges, sizeof (struct tr_ipv4_range), ranges_count, out) != ranges_count) 417 tr_err (_("Couldn't save file \"%1$s\": %2$s"), b->filename, tr_strerror (errno)); 418 else { 419 char * base = tr_basename (b->filename); 420 tr_inf (_("Blocklist \"%s\" updated with %zu entries"), base, ranges_count); 421 tr_free (base); 422 } 423 424 tr_free (ranges); 425 fclose (out); 426 fclose (in); 427 428 blocklistLoad (b); 429 430 return ranges_count; 431 } 414 if (fwrite (ranges, sizeof (struct tr_ipv4_range), ranges_count, out) != ranges_count) 415 { 416 tr_err (_("Couldn't save file \"%1$s\": %2$s"), b->filename, tr_strerror (errno)); 417 } 418 else 419 { 420 char * base = tr_basename (b->filename); 421 tr_inf (_("Blocklist \"%s\" updated with %zu entries"), base, ranges_count); 422 tr_free (base); 423 } 424 425 tr_free (ranges); 426 fclose (out); 427 fclose (in); 428 429 blocklistLoad (b); 430 431 return ranges_count; 432 }
Note: See TracChangeset
for help on using the changeset viewer.