Charteris Community Server

Welcome to the Charteris plc Community
Welcome to Charteris Community Server Sign in | Join | Help
in Search

Chris Dickson's Blog

Talking to WCF over named pipes – (1) The Framing Protocol

This is the first in a short series of posts looking into the detail of how message exchanges occur over a WCF channel using the named pipe binding. Although I first introduced this question in the context of a security vulnerability of this binding in .NET 3.5, it is of more general interest, judging by the number of questions I have seen in newsgroups and the blogosphere wondering about interoperability with WCF over a named pipe transport. In particular, anyone who aspires to:

  • implementing a non-.NET client to communicate with a WCF service over named pipes; or
  • implementing a non-.NET named pipe server which WCF clients can interoperate with using the named pipe binding;

will have to grapple with each of the issues I will discuss in this series.

By way of introduction, let’s develop the pipe listener code I showed in my previous post, to look at the data which arrives from the client immediately after the connection is established. This time we’ll read and display on the console the data sent by the client:

using (NamedPipeServerStream pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, -1)) // Calls CreateNamedPipe
{
    pipeServer.WaitForConnection();  // Calls ConnectNamedPipe
   
    byte
[] buffer = new byte[0x1000];
    int readThisTime = pipeServer.Read(buffer, 0, 0x1000);
    Console.WriteLine("{0} bytes received:\n", readThisTime); 
    OutputBufferFormatted(buffer, readThisTime);

}

OutputBufferFormatted is a formatting function I wrote to dump both the hex and character representation of the bytes received. I won’t bore you with the gory details.

This is the output I saw when my WCF client first connected to this listener:

image

So, what’s going on here?… eight bytes in I recognise the URL as being the service URL which my client was expecting to communicate with, but why has the client sent that in this way, and what are those other bytes all about?

The answer is to be found in the .NET Message Framing Protocol. This is a protocol designed by Microsoft for framing a messaging interaction so as to provide support for a variety of message encoding formats and transport stream semantics, delimit message boundaries, and enable malformed messages to be skipped. It is used by three of the standard WCF bindings NetTcpBinding, NetMsmqBinding and the binding we are currently interested in, the NetNamedPipeBinding (or rather, more accurately, their respective transport binding elements NetTcpBindingElement, etc).

The protocol is published in MSDN. From it we can readily interpret the data sent by our client as follows:

0x0, 0x1, 0x0

Version record: Version 1.0 of the Message Framing Protocol is being used by the client
0x1, 0x2 Mode record: The client is using the protocol in its Duplex mode. This initiates the protocol for multiple bidirectional messages.
0x2, 0x2e, net.pipe://lo… Via record: The byte value 0x2e specifies the length of the URL. The URL specifies the destination of the subsequent messages which will be framed in the protocol.
0x3, 0x8 Known Encoding record: The byte value 0x8 indicates that the client will be using “Binary encoding with in-band dictionary”. We’ll touch on what that means later.

Taken together, these comprise the first four, mandatory, records of the client’s protocol Preamble Message. The Preamble Message is not complete, however, as we do not yet see a Preamble End record (a single byte with value 0xc). We need to read from the pipe again to get the rest of the Preamble Message: this is because the WCF client is writing to the pipe in Message mode, in which each write is treated by the system as a separate message. In this mode, each call we make to NamedPipeServerStream.Read() will not read beyond the end of a client message unit. If we change the listener code to call Read twice, we see more data:

image

Interpreting this according to the framing protocol:  

0x9

Indicates the start of an Upgrade Request record
0x15 Length prefix for the upgrade protocol which follows (21 bytes)
application/negotiate The name of the upgrade protocol requested by the client

By sending this record the client is requesting that a protocol identified by the string “application/negotiate” should now be executed in order to upgrade the communication stream. This protocol is the Negotiate mechanism (often known as SPNEGO) defined by RFC4178, by which a mutually agreed security context can be negotiated between the client and server, to provide Privacy and Integrity for the data being sent over the pipe. The client is requesting this because the WCF NetNamedPipeBinding by default sets the SecurityMode to “Transport”.

Note that we still haven’t received the Preamble End record - at this stage, the ball is in our court to continue the protocol: our listener must send an Upgrade Response record back to the client before the process can proceed. Once we do that, the client will initiate the SPNEGO protocol, and we will have to fulfill the service side of that protocol, before the framing protocol exchange continues. I don’t want to go into any details on this now, so we will step over this part by using the .NET implementation of the protocol, System.Net.Security.NegotiateStream, to wrap our pipe data stream, as shown below.

Console.WriteLine("End of initial data stream.\nClient is waiting for our Upgrade Response\n");
// Send Upgrade Response record
pipeServer.WriteByte(0xa);
pipeServer.WaitForPipeDrain();
Console.WriteLine("Upgrade Response sent\n");
Console.WriteLine("Wrapping pipe in a NegotiateStream\n");
NegotiateStream negoStream = new NegotiateStream(pipeServer, true);
negoStream.AuthenticateAsServer();

// now we use the negoStream in future IO rather than the pipeServer

The AuthenticateAsServer method call encompasses the entire series of token exchanges between the listener and the client, to establish the security context. Subsequently, every time we read from or write to the NegotiateStream instance everything needed to encrypt/decrypt etc will be happening transparently within the implementation of the framework class.

Here’s the full output we get after we have wrapped the stream and called Read on it:

image

We see at last the single byte Preamble End record (byte 0xc) sent by the client. The protocol requires our listener to send back the single byte Preamble Ack record, completing the preliminary handshake. The protocol then moves to the stage where the actual messages can be sent and received. Let’s see this happening, when we send the Preamble Ack record (byte 0xb) and read from the pipe again:

image

Well, this looks as though the client may be sending us a message of sorts, but it doesn’t look at first sight like the kind of SOAP message we would expect from a WCF client. There are two reasons:

  • first, the Framing Protocol itself has a thin envelope which heads the payload message. That is: the first byte (0x06) indicating a Sized Envelope Record; followed by two bytes 0x93 0x02 which specify the size of the payload message. Refer to the Protocol for details of how the size is encoded – it can be up to five bytes in length.
  • secondly, remember that Known Encoding record in the PreAmble the client sent… that told us the client was going to use a binary encoding scheme. What we see here, following the framing protocol header, is actually a representation of a SOAP message, but the encoding scheme used makes parts of it pretty hard if not impossible to interpet manually. That’s another layer of complexity which needs to be grappled with before we can work with the messages.

In summary, pulling apart a single service call by a WCF client using the NetNamedPipeBinding, demonstrates that there are at least three layers of protocol implementation which have to be addressed, in addition to the named pipe transport IO itself, if one were to contemplate implementing one side of the interchange without using WCF:

  • the Framing Protocol, which we have covered a good deal of above. As you can see this is not particularly complex and might not be too daunting a task;
  • The .NET Negotiate Stream and SPNEGO protocols by which stream upgrade occurs to secure the conversation.
  • The message encoding scheme which the framing protocol calls “Binary encoding with in-band dictionary”.

I will have more to say about these latter two in subsequent posts. 

Published Nov 04 2010, 06:55 PM by chrisdi
Filed under: , ,

Comments

 

Chris Dickson's Blog said:

This is the second in a series of posts looking at the detail of how message exchanges occur over a WCF

November 18, 2010 4:45 PM
 

Chris Dickson's Blog said:

This is the third in a series of posts looking at the detail of how message exchanges occur over a WCF

November 24, 2010 1:44 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Commercial Edition), by Telligent Systems