nickgammon / mushclient

Open Source Windows MUD game client
www.mushclient.com
182 stars 76 forks source link

Wrong role in telnet CHARSET negotiation #47

Closed amotzkau closed 5 years ago

amotzkau commented 5 years ago

MUSHClient sends IAC WILL CHARSET and expects the MUD to start the IAC SB CHARSET subnegotiation. But according to RFC 2066 (https://tools.ietf.org/html/rfc2066) about the IAC SB CHARSET REQUEST message:

This message initiates a new CHARSET subnegotiation. It can only be sent by a side that has received a DO CHARSET message and sent a WILL CHARSET message (in either order).

So either MUSHClient should send a IAC DO CHARSET and wait for the server to send the SB or send the IAC WILL CHARSET and start itself the SB.

Best Regards, Alex

nickgammon commented 5 years ago

if you refer to https://tools.ietf.org/html/rfc854 :

In summary, WILL XXX is sent, by either party, to indicate that party's desire (offer) to begin performing option XXX, DO XXX and DON'T XXX being its positive and negative acknowledgments; similarly, DO XXX is sent to indicate a desire (request) that the other party (i.e., the recipient of the DO) begin performing option XXX, WILL XXX and WON'T XXX being the positive and negative acknowledgments. Since the NVT is what is left when no options are enabled, the DON'T and WON'T responses are guaranteed to leave the connection in a state which both ends can handle. Thus, all hosts may implement their TELNET processes to be totally unaware of options that are not supported, simply returning a rejection to (i.e., refusing) any option request that cannot be understood.

So, DO CHARSET is sent by the server "to indicate a desire (request) that the other party (i.e., the recipient of the DO) begin performing option CHARSET".

Since the client responds WILL CHARSET then the server can now go ahead and perform the option, namely:

IAC SB CHARSET REQUEST DELIM NAME IAC SE

So either MUSHClient should send a IAC DO CHARSET and wait for the server to send the SB or send the IAC WILL CHARSET and start itself the SB.

MUSHclient does not want the server to use a particular character set, it is the other way around.

nickgammon commented 5 years ago

The comments in the source describe the sequence:

Server sends:  IAC DO CHARSET
Client sends:  IAC WILL CHARSET
Server sends:  IAC SB CHARSET REQUEST DELIM NAME IAC SE
Client sends:  IAC SB CHARSET ACCEPTED NAME IAC SE
or
Client sends:  IAC SB CHARSET REJECTED IAC SE

where:

  CHARSET: 0x2A
  REQUEST: 0x01
  ACCEPTED:0x02
  REJECTED:0x03
  DELIM:   some character that does not appear in the charset name, other than IAC, eg. comma, space
  NAME:    the character string "UTF-8" (or some other name like "S-JIS")
amotzkau commented 5 years ago

You quoted it:

In summary, WILL XXX is sent, by either party, to indicate that party's desire (offer) to begin performing option XXX

So if the Client sends WILL CHARSET (as mushclient does) it indicates that the client is willing to perform the CHARSET option (by sending the subnegotiation).

If MushClient doesn't want that it should wait for a WILL CHARSET by the server and respond with a DO CHARSET and then wait for the subnegotiation.

You wrote:

So, DO CHARSET is sent by the server "to indicate a desire (request) that the other party (i.e., the recipient of the DO) begin performing option CHARSET".

That's correct. So the other party is MushClient und shall begin performing. But it doesn't.

Since the client responds WILL CHARSET then the server can now go ahead and perform the option, namely.

No, the other party, MushClient, shall perform, you wrote it in the line above. Do you see the difference between those two sentences? They are exactly the opposite of each other...

amotzkau commented 5 years ago

Just for context where I'm coming from: I added the negotiation to a mudlib. We send DO CHARSET first (giving the client the option to send all possible encodings, we can handle them all) and if we get a WONT CHARSET, we will try a WILL CHARSET and send our favourite encodings back if we get a DO CHARSET.

It does work with TinyFugue Rebirth, but MushClient does it exactly in the opposite way, and reading the RFCs that's the wrong way.

fiendish commented 5 years ago

The description looks like a real bug to me.

Server sends: IAC DO CHARSET Client sends: IAC WILL CHARSET

I think WILL and DO are swapped here, and it should be instead:

Server sends:  IAC WILL CHARSET            (requesting permission to set charset)
Client sends:  IAC DO CHARSET                (granting permission to set charset)
nickgammon commented 5 years ago

There doesn't seem to be a problem with supporting both, and the fix to do so is fairly trivial.

See https://github.com/nickgammon/mushclient/commit/662585f

amotzkau commented 5 years ago

Hmm, I still have a problem with that solution. As I said we send a DO CHARSET first, to see if the client wants to give us their encoding and therefore responds with a WILL CHARSET. Only If that doesn't work (we get a WONT CHARSET) then we'll try WILL CHARSET and wait for a DO CHARSET. So we have the following communication:

or

This is RFC compliant, but MushClient acknowledges the first variant and never sends the SB CHARSET, so the server waits forever.

nickgammon commented 5 years ago

Server sends: DO CHARSET Client: sends: WILL CHARSET Client shall send SB CHARSET

You have misinterpreted how this is supposed to work. The word "shall" does not appear in RFC 2066. The initial negotiation (DO/WILL or WILL/DO) is for establishing if the parties are prepared to do this particular subnet negotiation. There is no obligation to do it. The server should not wait forever for the subnegotiation. If it receives it, well and good.

You wanted me to change it so that the client would recognize DO CHARSET. From the RFC:

IAC WILL CHARSET The sender REQUESTS permission to, or AGREES to, use CHARSET option subnegotiation to choose a character set.

OK, the client has agreed to use CHARSET subnegotiation. That is, it acknowledges that it will recognize future queries along the lines of:

IAC SB CHARSET REQUEST DELIM NAME IAC SE

And it does indeed support that.

From the RFC:

IAC DO CHARSET The sender REQUESTS that, or AGREES to have, the other side use CHARSET option subnegotiation to choose a character set.

That is exactly what the client has done. It agreed to let the other side (your server) use CHARSET subnegotiation.


Let me put it this way, if we had negotiated that the client supports MCCP, does the client expect the very next packet to be compressed? No. It waits for the subnegotiation message, which it has acknowledged that it supports.

All that the DO/WILL stuff does is establish a capability. It doesn't demand that the client use that capability. I think it is a serious coding error for the server to sit there doing nothing under these circumstances (or indeed, any circumstances).

amotzkau commented 5 years ago

Okay, I see where you're coming from.

So to cope with that I need to send both:

This is what I wanted to avoid, but I see there's no way around it:

Okay, I'll try that. Thank you for adding the DO CHARSET response.