The scenario: You have a card printer that you need to configure
with a new computer in order to print loyalty cards. The
printer, a
Sigma DS3, uses a protocol in which plan text is sent to it on 9100 in a
special format called the
opencard specification. It takes this text and instructions, and uses them to fill
out an svg based template stored on the printer. For your end,
the template is already made so it doesn't seem hard. Just add a
text only printer and configure software to use it right? But
every morning when you come in, rougly 6-12 cards will have been
printed that just have the text ?xml version
, just
like the featured image. The printer has no useful logs, and
provides no hints as to where these jobs came from or why they
exist.
Identifying the Cause
This network was very old, not entirely mapped and had many "ghosts" so to speak. At first, I figured it was probably some old computer, long forgotten that was just sending data to the ip of the printer by happenstance. Often I find IP leases had been remapped from old things as this network had been operational since 2002. It would be a pain to reconfigure the printer just right in windows (we have software with hardcoded printer configs), so I just tried turning it off to see if the requests would eventually stop. A month later, I revisit it, and the requests persist. At this point, I spit some lazy python code out to basically accept most traffic on most ports and dump it to a file, logging the source of the connections. I then run it on a computer that gets swapped in, granting that system the original IP the printer had.
First, there was the sanity check, I tried printing something to the python server to see what gets sent. Sure enough, we see the following:
<
153851 ^MREWARD TEST
";002050020800150585?>
This seemed reasonably expected, so where was the strange xml data coming from? I left the monitor running overnight and sure enough I found what I wanted to see:
POST /WebServices/Printer HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="http://schemas.microsoft.com/windows/2006/08/wdp/print/GetPrinterElements"
User-Agent: Windows-WSD-Print/1.0
Host: 192.168.0.124:9100
Content-Length: 725
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsdp="http://schemas.microsoft.com/windows/2006/08/wdp/print">
<soap:Header>
<wsa:To>http://192.168.0.124:9100/WebServices/Printer</wsa:To>
<wsa:Action>http://schemas.microsoft.com/windows/2006/08/wdp/print/GetPrinterElements</wsa:Action>
<wsa:MessageID>urn:uuid:4d8b8a4e-7e1f-4e9b-8a2c-987654321abc</wsa:MessageID>
</soap:Header>
<soap:Body>
<wsdp:GetPrinterElements>
<wsdp:RequestedElements>
<wsdp:Name>wsdp:PrinterStatus</wsdp:Name>
<wsdp:Name>wsdp:PrinterDescription</wsdp:Name>
<wsdp:Name>wsdp:PrintSchemaCapabilities</wsdp:Name>
</wsdp:RequestedElements>
</wsdp:GetPrinterElements>
</soap:Body>
</soap:Envelope>
Despite being a "Generic / Text Only Printer", Windows was sending WSD soap requests to the printer to check its status. I finally understood where the mystery text came from. Its a long read, but you can find most the info about WSD here.
The Solution
To get windows to finally behave, I used a bait and switch approach to trick it into thinking it was using an offline printer.
The steps were as follows:
- You will want to add the device using "The printer that I want isn't listed" > "Add manually"
-
Next, you will use "Add a local printer or network printer
with manual settings".
-
You then select "Create a new port" > "Local Port". This step
is important for tricking windows so it stops sending SOAP
requests. Name the port whatever.
- As with normal setup, you want the Make and Model to be "Generic" > "Generic / Text Only"
- Use the driver that is currently installed.
- Name the printer what you want, for my example, I called it "DATACARD".
- I didn't chose the share the printer, but this should have no bearing on the process
- After finishing the setup, we find the newly created printer in the settings and open "Printer Properties" > "Ports"
-
Now is the part where we trick it. We hit "Add Port..." >
"Standard TCP/IP Port" > "New Port..."
-
We then enter the printer IP the way would would normally have
done for a text only network printer. This includes selecting
custom in the additional port information screen and setting
the port to raw 9100.
-
We now select our newly created port and hit "Apply".
Congrats! The bait and switch is now complete and Windows
won't try to discover information about a text only
printer.
Conclusions
Windows has lots of random surprises, old legacy code, and undocumented subsystems. While WSD in general is documented, the exact mechanism which decides when windows checks printers for status information is completely undocumented for end users. This type of bait and switch logic isn't one of a kind, and although I can't remember a specific example, I have defintiely had to do this type of thing to Windows before. This one just happens to be particularly pesky because each printed output costs money and labor. In the grand scheme of things, its one of the tamer issues that Windows presents. Perhaps in the future, Microsoft will fix this unintuitive behavior. My goal here is that if they don't, there will be some place somewhere that the answer might be googled for the next guy as I could not find an answer to this online.