Compare commits

...

2 Commits

Author SHA1 Message Date
Xavier Roche
04bbb489cf Drop the per-request pre-resolve that slowed crawls on non-default ports (#181) (#518)
back_solve() resolved the raw "host:port" authority once per backing
request through check_hostname_dns() — an uncached getaddrinfo whose
result was only logged (host_wait() is always synchronous now). The
connect path already strips the port and resolves through the DNS cache,
so this lookup was pure overhead. On resolvers that don't fail fast on
the malformed "host:port" name (search-domain expansion, DNS timeouts)
it added a per-request stall: the reported slowness. Mirrors on port 80,
or with the port omitted, avoided the bad name and stayed fast.

Remove back_solve() and its debug-only lookup; keep the synchronous
host_wait() gate. Add a DNS self-test pinning that the cache/connect
path resolves "host:port" as the bare host.

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 00:13:40 +02:00
Xavier Roche
a24b1d3c9f Release 3.49.12 (#517)
Roll up 25 commits since 3.49.11 (July 5): security fixes in the
network-facing parsers (remote stack overflow and uninitialized read in
Content-Type/-Encoding handling, fuzzer-found over-reads in the filter,
URL and IDNA parsers, cache-index bounds, filter-pattern backtracking,
world-readable cookies.txt), crawl-correctness fixes (double-encoded UTF-8
links, gzip-mislabeled bodies, cache reconcile/corruption handling,
orphaned .delayed placeholders), the new --why filter diagnostic, and
build hardening (_FORTIFY_SOURCE, -fstack-protector-strong).

VERSION_INFO 3:3:0 -> 3:4:0: httrackp tail-appends why_url, no layout or
exported-signature break, so soname stays libhttrack.so.3 (revision bump).

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 21:28:23 +02:00
7 changed files with 60 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
AC_PREREQ([2.71])
AC_INIT([httrack], [3.49.11], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
AC_INIT([httrack], [3.49.12], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
AC_COPYRIGHT([
HTTrack Website Copier, Offline Browser for Windows and Unix
Copyright (C) 1998-2015 Xavier Roche and other contributors
@@ -29,11 +29,11 @@ AC_CONFIG_SRCDIR(src/httrack.c)
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE([subdir-objects])
# 3:3:0: 3.49.11 only adds enum values, macros and inline helpers to the
# installed headers (no struct layout or exported signature changed vs
# 3.49.10), so it stays soname .so.3; bump revision.
# 3:4:0: 3.49.12 tail-appends one field (why_url) to httrackp and otherwise only
# deletes dead comments; no struct layout or exported signature broke vs 3.49.11,
# so it stays soname .so.3; bump revision.
# (3:0:0 was the htsblk mime-buffer widening, the ABI break that moved .so.2 -> .so.3.)
VERSION_INFO="3:3:0"
VERSION_INFO="3:4:0"
AM_MAINTAINER_MODE
AC_USE_SYSTEM_EXTENSIONS

10
debian/changelog vendored
View File

@@ -1,3 +1,13 @@
httrack (3.49.12-1) unstable; urgency=medium
* New upstream release: security and crawl-correctness fixes (remote stack
overflow in Content-Type/-Encoding parsing, fuzzer-found parser over-reads,
world-readable cookies.txt, filter-pattern denial of service) plus a new
--why filter diagnostic; full list in history.txt.
* Build with _FORTIFY_SOURCE and -fstack-protector-strong.
-- Xavier Roche <xavier@debian.org> Fri, 10 Jul 2026 21:11:09 +0200
httrack (3.49.11-1) unstable; urgency=medium
* New upstream release: crawl correctness and security fixes (network-facing

View File

@@ -4,6 +4,23 @@ HTTrack Website Copier release history:
This file lists all changes and fixes that have been made for HTTrack
3.49-12
+ New: --why explains which filter rule accepts or rejects a given URL, then exits (#505)
+ Fixed: links carrying raw UTF-8 bytes were fetched double-encoded and 404'd (#516)
+ Fixed: an uncompressed body mislabeled as gzip no longer loses the page (#515)
+ Fixed: remote stack overflow and uninitialized read in Content-Type/-Encoding parsing (#506)
+ Fixed: several over-reads and a leak in the filter, URL and IDNA parsers (#499)
+ Fixed: bound the cache-index (.ndx) parser to its buffer (#507)
+ Fixed: catastrophic backtracking on '*'-heavy filter patterns (#513)
+ Fixed: cookies.txt was created world-readable (#511)
+ Fixed: a single corrupt cache entry no longer aborts the whole mirror (#494)
+ Fixed: cache-reconcile policy was broken for zip caches (#491, #493, #495)
+ Fixed: cancelling a crawl mid type-check no longer orphans .delayed placeholders (#496)
+ Fixed: detect URLs after the first inline script and in mid-tag attributes (#497)
+ Changed: build with _FORTIFY_SOURCE and -fstack-protector-strong (#504)
+ Changed: removed the pre-3.31 (.dat/.ndx) cache import (#512)
+ Changed: multiple internal hardening and build improvements (libFuzzer harnesses, CodeQL, dead-code removal)
3.49-11
+ New: parse robots.txt Allow rules and path wildcards per RFC 9309 (#452)
+ New: advertise deflate in Accept-Encoding and decode deflate responses (#450)

View File

@@ -2050,13 +2050,9 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
if (!back_trylive(opt, cache, sback, p)) {
#if HTS_XGETHOST
#if HDEBUG
printf("back_solve..\n");
#endif
back[p].status = STATUS_WAIT_DNS; // tentative de résolution du nom de host
soc = INVALID_SOCKET; // pas encore ouverte
back_solve(opt, &back[p]); // préparer
if (host_wait(opt, &back[p])) { // prêt, par ex fichier ou dispo dans dns
back[p].status = STATUS_WAIT_DNS; // host name resolution attempt
soc = INVALID_SOCKET; // not opened yet
if (host_wait(opt, &back[p])) { // ready (file, or cached dns)
#if HDEBUG
printf("ok, dns cache ready..\n");
#endif
@@ -2199,37 +2195,9 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
}
#if HTS_XGETHOST
// attendre que le host (ou celui du proxy) ait été résolu
// si c'est un fichier, la résolution est immédiate
// idem pour ftp://
void back_solve(httrackp * opt, lien_back * back) {
assertf(opt != NULL);
assertf(back != NULL);
if ((!strfield(back->url_adr, "file://"))
&& !strfield(back->url_adr, "ftp://")
) {
const char *a;
if (!(back->r.req.proxy.active))
a = back->url_adr;
else
a = back->r.req.proxy.name;
assertf(a != NULL);
a = jump_protocol_const(a);
if (check_hostname_dns(a)) {
hts_log_print(opt, LOG_DEBUG, "resolved: %s", a);
} else {
hts_log_print(opt, LOG_DEBUG, "failed to resolve: %s", a);
}
}
}
// détermine si le host a pu être résolu
int host_wait(httrackp * opt, lien_back * back) {
// Always synchronous. No more background DNS resolution
// (does not really improve performances)
return 1;
}
// Resolution is synchronous inside the connect path; no pre-resolve step, so
// the host is always immediately ready.
int host_wait(httrackp *opt, lien_back *back) { return 1; }
#endif
// élimine les fichiers non html en backing (anticipation)

View File

@@ -138,7 +138,6 @@ LLint back_transferred(LLint add, struct_back * sback);
// hostback
#if HTS_XGETHOST
void back_solve(httrackp * opt, lien_back * sback);
int host_wait(httrackp * opt, lien_back * sback);
#endif
int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize);

View File

@@ -297,6 +297,26 @@ int dns_selftests(httrackp *opt) {
IPV6_resolver = 0;
}
/* "host:port" resolves as the bare host: the cache/connect path strips
":port" before both the backend and the cache key (#181). */
mock_reset_calls();
{
SOCaddr a;
char ip[64];
const char *err = NULL;
/* cache miss: the backend is hit with the stripped host, not "host:port" */
CHECK(hts_dns_resolve2(opt, "v6only.test:8080", &a, &err) != NULL);
CHECK(mock_find("v6only.test")->calls == 1);
/* the bare host shares that one cache entry (stripped key) */
CHECK(hts_dns_resolve2(opt, "v6only.test", &a, &err) != NULL);
CHECK(mock_find("v6only.test")->calls == 1);
/* a port variant of an already-cached host also hits, right address */
CHECK(hts_dns_resolve2(opt, "v4only.test:1234", &a, &err) != NULL);
SOCaddr_inetntoa(ip, sizeof(ip), a);
CHECK(strcmp(ip, "1.2.3.4") == 0);
}
/* newhttp_addr() must connect to the addr_index-th address, not always the
first: this is what back_connect_next relies on to reach the fallback. */
{

View File

@@ -43,8 +43,8 @@ Please visit our Website: http://www.httrack.com
configure.ac, decoupled from these). VERSION is the display form, VERSIONID
the dotted numeric form, AFF_VERSION the short form shown in footers,
LIB_VERSION the data/cache format generation. */
#define HTTRACK_VERSION "3.49-11"
#define HTTRACK_VERSIONID "3.49.11"
#define HTTRACK_VERSION "3.49-12"
#define HTTRACK_VERSIONID "3.49.12"
#define HTTRACK_AFF_VERSION "3.x"
#define HTTRACK_LIB_VERSION "2.0"