Skip to content

Commit fe2f58e

Browse files
BornToBeRootclaude
andcommitted
Fix: IP Scanner: Read web pages tried http on https ports (R16)
After https failed, http was tried on the same port, also on 443 / 8443: for a device whose TLS handshake fails (e.g. TLS 1.0 only), the Web column showed the error page for plain http on an https port (e.g. nginx "400 The plain HTTP request was sent to HTTPS port") without a certificate. 443 / 8443 are only requested with https now, 80 / 8080 with http, other ports with https and then http as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 3ce934c commit fe2f58e

4 files changed

Lines changed: 14 additions & 6 deletions

File tree

‎Source/NETworkManager.Models/Network/WebPageResolver.cs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,21 @@ public static int GetTimeout(int port, string scheme, int timeout)
123123
}
124124

125125
/// <summary>
126-
/// Gets the schemes to try for a port: http for 80 / 8080, https and then http for any other port (a TLS
127-
/// handshake with a plain http server fails right away).
126+
/// Gets the schemes to try for a port: https for 443 / 8443 (if the TLS handshake fails, e.g. a device that
127+
/// only supports TLS 1.0, http would only return the error page of the server for plain http on an https port),
128+
/// http for 80 / 8080, https and then http for any other port (a TLS handshake with a plain http server fails
129+
/// right away).
128130
/// </summary>
129131
/// <param name="port">Port number.</param>
130132
/// <returns>Schemes in the order to try them.</returns>
131133
public static string[] GetSchemes(int port)
132134
{
133-
return port is 80 or 8080 ? ["http"] : ["https", "http"];
135+
return port switch
136+
{
137+
443 or 8443 => ["https"],
138+
80 or 8080 => ["http"],
139+
_ => ["https", "http"]
140+
};
134141
}
135142

136143
/// <summary>

‎Source/NETworkManager.Tests/Network/WebPageResolverTests.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public void GetTimeout(int port, string scheme, int timeout, int expected)
6969
[Theory]
7070
[InlineData(80, new[] { "http" })]
7171
[InlineData(8080, new[] { "http" })]
72-
[InlineData(443, new[] { "https", "http" })]
72+
[InlineData(443, new[] { "https" })]
73+
[InlineData(8443, new[] { "https" })]
7374
[InlineData(9000, new[] { "https", "http" })]
7475
public void GetSchemes(int port, string[] expected)
7576
{

‎Website/docs/application/ip-scanner.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ Timeout in milliseconds after which an mDNS request is considered lost.
420420

421421
### Read web pages
422422

423-
Read the web page (`GET /`) of every reachable host with an open port of the [Ports](#ports-1) below: status code, title, the `Server` and `X-Powered-By` headers, the realm of a login prompt (`WWW-Authenticate` header of a `401` response, e.g. `RT-AC68U` - routers, cameras and printers often name their model there) the target of a redirect to another host (e.g. `https://unifi.local:8443/`) and, for https, the TLS certificate: subject, issuer (`Self-signed` for a self-signed certificate) and the end of the validity (`(expired)` if it is expired). The title is shown in the **Web** column (the URL in the tooltip), all values in the **Web** section of the row details. The ports are tried in the order of the list, the first one that answers is used: http on `80` and `8080`, https and then http on any other port. On ports other than `443` / `8443`, the https attempt waits at most 1 second (also with a higher timeout), so a plain http device that doesn't answer the TLS handshake doesn't cost the whole timeout before http is tried. Redirects on the same host (e.g. http to https, `/` to `/login.html`) are followed. If the page has no title, the column shows the realm, the `Server` header (e.g. `nginx`) or the redirect target. The values are in the search and the export (`WebStatusCode`, `WebServer`, `WebPoweredBy`, `WebRealm`, `WebRedirectURL`, `WebCertificateSubject`, `WebCertificateIssuer`, `WebCertificateNotAfter`, `WebCertificateSelfSigned`). **Web Console** in the context menu opens the port (and scheme) that answered.
423+
Read the web page (`GET /`) of every reachable host with an open port of the [Ports](#ports-1) below: status code, title, the `Server` and `X-Powered-By` headers, the realm of a login prompt (`WWW-Authenticate` header of a `401` response, e.g. `RT-AC68U` - routers, cameras and printers often name their model there) the target of a redirect to another host (e.g. `https://unifi.local:8443/`) and, for https, the TLS certificate: subject, issuer (`Self-signed` for a self-signed certificate) and the end of the validity (`(expired)` if it is expired). The title is shown in the **Web** column (the URL in the tooltip), all values in the **Web** section of the row details. The ports are tried in the order of the list, the first one that answers is used: https on `443` and `8443`, http on `80` and `8080`, https and then http on any other port. On ports other than `443` / `8443`, the https attempt waits at most 1 second (also with a higher timeout), so a plain http device that doesn't answer the TLS handshake doesn't cost the whole timeout before http is tried. Redirects on the same host (e.g. http to https, `/` to `/login.html`) are followed. If the page has no title, the column shows the realm, the `Server` header (e.g. `nginx`) or the redirect target. The values are in the search and the export (`WebStatusCode`, `WebServer`, `WebPoweredBy`, `WebRealm`, `WebRedirectURL`, `WebCertificateSubject`, `WebCertificateIssuer`, `WebCertificateNotAfter`, `WebCertificateSelfSigned`). **Web Console** in the context menu opens the port (and scheme) that answered.
424424

425425
**Type:** `Boolean`
426426

‎Website/docs/changelog/next-release.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Release date: **xx.xx.2026**
9393
- New **OS (guess)** column with the operating system guessed from the TTL of the ping reply (icon and text: `Linux / Unix`, `Windows` or `Network device`, the tooltip shows the number of hops), can be disabled with the new setting **Guess the operating system from the TTL** (default on). No additional packets are sent; IPv4 only. Also in the search, **Copy** and the export (`OSGuess`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
9494
- An icon in the result marks this computer, the default gateway and the DNS and DHCP servers of the connected network interfaces (all roles in the tooltip), e.g. to find the router in a `/24`. Also in the search and the export (`Role`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
9595
- New **Resolve mDNS hostname** setting (default off, with **Timeout**): the mDNS hostname (e.g. `macbook.local`) of reachable hosts is resolved with a reverse lookup sent to UDP port `5353` of the host (Apple devices, Linux with Avahi, Android, printers, IoT devices). Shown in the row details (new **Hostnames** section with the DNS, mDNS and NetBIOS name) and used as **Hostname** if there is no DNS hostname (before the NetBIOS name). Also in the search, **Copy** and the export (`MDNSHostname`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
96-
- New **Read web pages** setting (default off, with **Timeout**): the web page (`GET /`) of reachable hosts with an open web port is read - the title is shown in the new **Web** column (URL in the tooltip, `Server` header if the page has no title), e.g. to identify routers, printers and NAS. The row details (new **Web** section) show the URL, the HTTP status code, the title, the `Server` and `X-Powered-By` headers, the realm of a login prompt (`WWW-Authenticate`, often the model of a router or camera) the target of a redirect to another host and, for https, the TLS certificate (subject, issuer or `Self-signed`, valid until, `(expired)`). The ports are configurable (**Ports**, default `443; 80; 8443; 8080`, tried in this order, with a button to restore the default); only ports that are open in the port scan are requested, http on `80` / `8080`, https and then http on other ports. Redirects on the same host are followed, certificate errors are accepted, no cookies or credentials are sent. **Web Console** in the context menu opens the port that answered. Also in the search, **Copy** > **Web** (title, URL, server) and the export (`WebTitle`, `WebURL`, `WebStatusCode`, `WebServer`, `WebPoweredBy`, `WebRealm`, `WebRedirectURL`, `WebCertificateSubject`, `WebCertificateIssuer`, `WebCertificateNotAfter`, `WebCertificateSelfSigned`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
96+
- New **Read web pages** setting (default off, with **Timeout**): the web page (`GET /`) of reachable hosts with an open web port is read - the title is shown in the new **Web** column (URL in the tooltip, `Server` header if the page has no title), e.g. to identify routers, printers and NAS. The row details (new **Web** section) show the URL, the HTTP status code, the title, the `Server` and `X-Powered-By` headers, the realm of a login prompt (`WWW-Authenticate`, often the model of a router or camera) the target of a redirect to another host and, for https, the TLS certificate (subject, issuer or `Self-signed`, valid until, `(expired)`). The ports are configurable (**Ports**, default `443; 80; 8443; 8080`, tried in this order, with a button to restore the default); only ports that are open in the port scan are requested, https on `443` / `8443`, http on `80` / `8080`, https and then http on other ports. Redirects on the same host are followed, certificate errors are accepted, no cookies or credentials are sent. **Web Console** in the context menu opens the port that answered. Also in the search, **Copy** > **Web** (title, URL, server) and the export (`WebTitle`, `WebURL`, `WebStatusCode`, `WebServer`, `WebPoweredBy`, `WebRealm`, `WebRedirectURL`, `WebCertificateSubject`, `WebCertificateIssuer`, `WebCertificateNotAfter`, `WebCertificateSelfSigned`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
9797
- New **Read the SNMP system information** setting (default off, with **Version** `v1` / `v2c`, **Community** and **Timeout**): name, description and location (`sysName`, `sysDescr`, `sysLocation`) are read with the other probes from every IP address - a host that answers is shown as up (**Detected by** `SNMP`), also if it blocks the ping and all ports - and shown in the row details (new **SNMP** section), the name also in the new **SNMP name** column, e.g. to identify switches and printers. The community is saved as plain text in the settings (warning icon next to the field, use a read-only community). Also in the search, **Copy** > **SNMP** and the export (`SNMPName`, `SNMPDescription`, `SNMPLocation`). [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
9898
- The **Hostname** and **MAC address** / **Vendor** columns (and the new **Web** and **SNMP name** columns and the new row details) show `...` while the lookup / request is running instead of `-/-`, like the ping, port and NetBIOS columns, so a missing value can be told apart from one that is still resolved. **Hostname** and **MAC address** / **Vendor** show `...` until all their sources are finished (DNS, mDNS and NetBIOS name / neighbor table and NetBIOS). **Copy** > **Hostname** / **MAC address** / **Vendor** is disabled until the value arrived. [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)
9999
- The **Ping status**, **Port status** and **NetBIOS reachable** columns show a status icon (green check / red cross, like the action of a rule in the **Firewall**) instead of the text (e.g. `Success` / `Timed out`, `Open` / `Closed`, `Yes` / `No`); the tooltip shows the details: ping status with time and TTL, the open ports with their service and the NetBIOS computer name and workgroup / domain. [#PR](https://github.com/BornToBeRoot/NETworkManager/pull/PR)

0 commit comments

Comments
 (0)