Skip to content

Commit 5f9f5ae

Browse files
Take every out-of-band directive out of the connect screen, not just MCP
TelnetNegotiationCore's framing now follows the specification rather than a stricter reading of it: a line-initial #$# that cannot be acted on is dropped rather than passed through, in a session or outside one. MCP says so plainly -- an unrecognised message on that prefix is silently dropped, not shown to a reader. For the crawler that means the other three lines go too. All 57 line-initial #$# lines in the catalogue now come out of the screen, not just the 54 MCP offers: also two "#$# SDWC-*-NOWRAP" and one "#$#LOGIN_TRIGGER", which are somebody's client directives sent on the prefix reserved for exactly that, and which no reader should have been shown either. Line-initial is still what keeps ASCII art safe, and the catalogue is the evidence: of the 59 screens matching #$# anywhere, the 3 that match only mid-line are all art. Both cases have a test. 555 tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent ef5bbca commit 5f9f5ae

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

src/MUI.Crawl/Telnet/TelnetProbe.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,10 +1102,13 @@ private TelnetInterpreterBuilder Build(Observations seen, List<byte[]> lines, Pr
11021102
//
11031103
// Deliberately WITHOUT answering. The crawler has no use for an MCP session, and answering
11041104
// would put text on a stranger's login prompt for one it will never open -- the objection
1105-
// MSSPPlaintextProtocol makes to sending MSSP-REQUEST unbidden. The offer is consumed
1106-
// either way; only the reply is suppressed. Nothing after the offer is stripped, because
1107-
// no session opens and the library treats a #$# line outside a session as ordinary output
1108-
// -- which is the conservative reading, and the one that keeps ASCII art safe.
1105+
// MSSPPlaintextProtocol makes to sending MSSP-REQUEST unbidden. Only the reply is
1106+
// suppressed: the framing is not conditional on a session, so every line-initial #$# comes
1107+
// out, which takes the other three with it -- two "#$# SDWC-*-NOWRAP" and one
1108+
// "#$#LOGIN_TRIGGER", somebody's client directives on the prefix reserved for exactly that.
1109+
//
1110+
// Line-initial is what keeps ASCII art safe, and the catalogue is the evidence: of the 59
1111+
// screens matching #$# anywhere, the 3 that match only mid-line are all art.
11091112
//
11101113
// Noted on the offer rather than on negotiation, because there is no negotiation: the
11111114
// offer arriving is the whole of the evidence that this server speaks MCP.

tests/MUI.Crawl.Tests/Telnet/ProbeSessionTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,33 @@ public async Task TheCrawlerDoesNotAnswerAnMcpOffer()
17131713
await Assert.That(game.Received.Any(line => line.StartsWith("#$#"))).IsFalse();
17141714
}
17151715

1716+
/// <summary>
1717+
/// The other line-initial <c>#$#</c> lines in the catalogue go too, not just the MCP offer.
1718+
/// </summary>
1719+
/// <remarks>
1720+
/// <c>#$#</c> is the out-of-band prefix, and MCP says an unrecognised message on it is dropped
1721+
/// rather than shown. The three remaining line-initial matches in the catalogue -- two
1722+
/// <c>#$# SDWC-*-NOWRAP</c> and one <c>#$#LOGIN_TRIGGER</c> -- are somebody's client directives,
1723+
/// which is exactly what that prefix is for and exactly what a reader should not be shown.
1724+
/// </remarks>
1725+
[Test]
1726+
public async Task OtherOutOfBandDirectivesGoToo()
1727+
{
1728+
await using var game = new FakeGame
1729+
{
1730+
Banner = "#$# SDWC-START-NOWRAP\r\n"
1731+
+ "Welcome to the game.\r\n"
1732+
+ "#$#LOGIN_TRIGGER\r\n"
1733+
+ "#$# SDWC-END-NOWRAP\r\n",
1734+
WhoReply = "0 Players logged in.\r\n",
1735+
};
1736+
1737+
var result = await new TelnetProbe(Fast()).ProbeAsync(game.Target);
1738+
1739+
await Assert.That(result.Banner).DoesNotContain("#$#");
1740+
await Assert.That(result.Banner).Contains("Welcome to the game.");
1741+
}
1742+
17161743
/// <summary>
17171744
/// <c>#$#</c> inside ASCII art is art, not protocol. Three of the 59 screens that match
17181745
/// <c>#$#</c> anywhere match only in the middle of a line -- <c>d######## #$#</c>,

0 commit comments

Comments
 (0)