Winsock LSP (Layered Service Provider) Guide
Winsock LSP (Layered Service Provider) Guide
Site: http://www.komodia.com/
Email : [email protected]
1. What is LSP?
LSP (Layered Service Provider) is a component that intercepts winsock2
calls, has the ability to manipulate them, and then has the option to pass
them to the winsock2 provider.
Each “service” has a different LSP chain (i.e., LSP for TCP, UDP, raw
sockets, netbios, etc.) These LSPs are called base providers because they
call the actual winsock2 functions.
The LSPs in the chain that aren’t base providers are called layered
providers. (These implement only higher-level calls)
3. LSP – Name space provider (NSP)
This article focuses on transport provider LSPs. This section is a brief
overview of name space provider LSPs.
NSPs are mostly used to extend domains on the web. For example, you
can sell domains that end in “.lsp”. These are not official, of course, but if
the resolving computer has NSP installed, you will be able to resolve the
.lsp extension. (I am assuming that the NSP is made by the seller of the
.lsp domain and acts to resolve the domain.)
Microsoft’s default LSP samples have matured and are quite good.
However, without proper guidance they can look pretty scary!
Part of this document uses my own LSP sample: I took Microsoft’s LSP
sample, and wrapped it in a VC6 project (I just hate makefiles.)
When the DLL is unloaded, the LSP will deallocate all of its resources.
The LSP is loaded in each process with winsock2 calls that use the base
provider the LSP has layered (thus you may have many running instances
of your LSP.)
This function is called when the user calls WSAStartup. Essentially, the
LSP loads all the layered protocols beneath it in the chain, and initializes
its own calling table (a dynamic table for calling its WSP functions.)
7. Installing the LSP
Every LSP has a unique GUID. Make sure you change the default GUID,
found in provider.CPP, using the GUID variable, ProviderGuid. You can
use GuidGen, supplied with the Visual Studio, to generate a new GUID.
The latest Microsoft LSP Installer sample can take the LSP file as a
parameter and retrieve the GUID from an exported method called
“GetLspGuid” – unlike the old LSP Installer, in which the GUID was
embedded in the installer.
This guide shows how to use the default installer. However, for a 100%
successful installation you’d need to write an extra 10,000 line of code.
The good news is that we already did it for you. Check out Komodia’s
advanced LSP installer page at:
http://www.komodia.com/index.php?page=rlsp.html
The number on the left is the LSP’s ID, and the string on the right is the
LSP’s description.
Now that you have the list, you can layer your LSP on top of the base
providers. The base provider’s ID for TCP in this example is 1001, for
UDP 1002, and for raw sockets 1003. However, this may vary from
machine to machine, because on most laptops there is an IrDA (infrared)
base provider installed with the ID 1001, which makes the ID for TCP
1002, and so on.
For most implementations you would normally want to install your LSP
on top of the TCP, as follows: RegisterLSP –i –o 1001 –d LSPFilename
Now that you’ve installed your LSP, you can view it with: RegisterLSP –
p, or with: RegisterLSP –l, which displays layered protocols only.
To install your LSP over all base providers and all 3rd-party LSPs, use:
RegisterLSP –a – d LSPFilename
For removing LSPs, I would simply restore the registry backup you made
earlier, but it can also be done with: RegisterLSP –r
9. Installation issues
All versions of Internet Explorer have a nice “feature” (not bug, of
course...): they use the UDP protocol for internal communication, and
send UDP sockets into the TCP functions (and vice versa). This is
undesirable design, but apparently we are to blame. To fix this, whenever
you layer over TCP, make sure to layer over UDP as well.
10. Modifying the LSP
We have a compiling and working LSP, and now we want to add some
features to it.
Every Winsock call prefixed by WSA has a WSP call in the LSP.
WSARecv is mapped to WSPRecv, so if we want to log all the data that
enters the system we can use:
In the beginning of every WSP function that receives the socket handle as
a parameter, there is a function for resolving the socket context (a
structure that contains information about the socket.) If you wish to keep
additional information about each socket, you must put it in this socket
context structure.
After the socket context is found, the LSP checks if the operation is
overlapped. If it is, the LSP function saves the overlapped data inside the
overlap structure within the socket context, and queues this data for the
function that handles the overlapped operation.
OverlappedManagerThread dispatches the overlap and
IntermediateCompletionRoutine performs the overlap operation itself.
If the operation is not overlapped, the LSP calls the next LSP after it in
the chain.
Let’s say you wish to get the data that will end up inside the buffer after
the lower-layered function finishes. For example, you wish to search a
specific string in order to implement context checking for an IDS.
To do this, you need to intercept in two places. First, in the
IntermediateCompletionRoutine, in case the receive call is overlapped,
and second, after the call to the next LSP, if the call is overlapped.
Don’t forget to check the error flag for errors: if there is an error, the
buffer contains random data.
You can find the peer address trying to connect by inspecting the variable
addr.
If you decide not to allow this connection, simply return the value
INVALID_SOCKET.
Let’s say we wish to add a running number to each socket. We will add
an int variable, and the structure will look like this:
CRITICAL_SECTION SockCritSec;
A variable to look for is Inherit, which specifies if the data is taken from
another SOCK_INFO structure (as when a socket is accepted.)
//Original code
NewInfo->ProviderSocket = ProviderSocket;
NewInfo->bClosing = FALSE;
NewInfo->dwOutstandingAsync = 0;
NewInfo->BytesRecv = 0;
NewInfo->BytesSent = 0;
NewInfo->Provider = Provider;
NewInfo->hWnd = (Inherit ? Inherit-
>hWnd : 0;(
NewInfo->uMsg = (Inherit ? Inherit-
>uMsg : 0;(
static iID=1;
NewInfo->iRunningNumber=iID++;
So that in each call, the context info will contain this data for our later
use.
13. Communicating with the LSP
Since LSP is a DLL that doesn’t run in our process, we must use IPC
(Inter Process Communication) to communicate with it.
There are many ways to do this: mail slots, COM, named pipes, and
more.
Every programmer has his or her own preference, but we’ll save that
topic for another article.