Bye CUPS: Printing with Netcat
retrohacker.substack.com
retrohacker.substack.com
The problem is that few printers support _all_ of these standards. Postscript, for example, is surprisingly complex to implement in practice, which leads to a lot of inexpensive network printers actually lacking postscript support. Further, printers are very slow at rasterizing, and so while support for PDF rasterization is very common you probably don't want to use it. You can easily see a minute per page for printing modest PDFs. In-printer PDF rasterization is also of very uneven quality, and I have seen issues like completely broken kerning in documents due to the printer's poor handling of embedded fonts.
One of the key functions of something like CUPS is to address this problem: CUPS standardizes the format of all printed documents to something that is well-supported by the printer, and performs much of the rasterization ahead of time on the much faster print server. This saves time and improves reliability since you don't need to figure out if a given document is supported by the printer. For most printers these days some variant of PCL is the preferred language for jobs, as it's simpler and easier to implement than Postscript. It also presents fewer security concerns.
Of course the other major problem CUPS solves is the management of the queue, including across multiple users. That's an important feature but not one that matters in a lot of home situations. That said, if you don't use a printing system you can and will run into annoying situations where you cannot print a document because you are waiting for the previous one to complete sending, which often gets blocked on the printer's memory space or rasterization.
That's interesting. Back in the day (of HP LaserJet 4L and similar), I learned that rasterizing on the PC and sending to the printer was very slow because printers had slow connections and little memory. The resolution was also limited and it looked blocky. The rule was to never print "as bitmap" if you could avoid it. OTOH printing "flat" postscript was very fast and yielded much better quality. I think the printers allowed loadable fonts and often had some of the standards (Times, Arial) pre-loaded.
But the nature of printing has changed! People now want to print things in all kinds of arbitrary fonts, which requires either rasterizing to print resolution (which is a lot, 300-600dpi) or sending the printer all the outlines as vector instructions. Postscript and PCL take different approaches to this and sometimes different print stacks do as well. And then add graphics, and 99% of documents you encounter these days provide all graphics in raster format in the first place. The result is that something, either the host or the printer, needs to take a raster graphic (which can even just be little icons) and interpolate them to whatever dot pitch the printer is using. That tends to be the real killer... that interpolation can take a printer a very long time. Usually there's some way in the PCL (exposed via the printer driver) that you can tell the printer to interpolate to a lower DPI which will speed things up, but make your images look worse.
Unfortunately sending 600dpi graphics over the network can still be kind of slow and does contribute to the "Receiving Data..." and time to first page even with modern printers and drivers. Most laser printers have a pretty poor TTFP anyway, though, so it's not too big of a deal.
netcat is also a secret weapon around the house. My girlfriend runs macOS, but it's way more reliable to just nc files to each other over wifi than deal with all the cloud and airdropping bullshit.
Warning, headphone users: may hurt your ears. Trust me on the volume lowering.
With 16 bit samples and (default) two channels, you can recognizeably hear small integer values in your left ear. :)
It's for you.
It has never occurred to me to do that but it is actually quite an obvious thing to do when you "know" that everything is a file.
Any idea what the visual equivalent would be?
Perhaps:
head -c800 /dev/urandom > /dev/tty
Or:
mplayer -demuxer rawvideo -rawvideo w=80:h=60 /dev/urandom
Change that to w=720 h=576 (for pal countries) and you can relive the glory days of analog TV static. Except not - mey memory seems to tell me it's more colourful. I guess it's to do with the limited chroma resolution in pal?
Analog color television color information is sent "out of band" from the point of view of black-and-white television (as a sideband frequency, with neat analog trickery to cancel out its effect on main signal). Color TV is backwards compatible. It's unlikely that random input happens to look like meaningful properly encoded color information, so television static is largely black and white.
mplayer -vf eq2=1:1:0:0.6 -demuxer rawvideo -rawvideo pal /dev/urandom
Consider lowly embedded linux. You COULD dig down deep into the documentation of which register, which interrupt, which special memory address needs to be written to interact with the right ports on a embedded linux board. All while adding a bunch of safeguards and checks to make sure "Only you are doing this".
Or, as if often the case, you can simply find the right /dev/xxxx device and read from it or write to it.
9 times out of 10, you'd not suffer any negative consequences from using the /dev/xxx system as intended and you get the bonus ability of being able to interact with the outside world using programming languages other than C.
Audio files are (for me) the canonical example. A text file has no inherent bit-rate. An audio file being handled without knowledge of (even just) its sample rate has its semantics distorted or destroyed.
There's an awful lot of things you can do with the file approach, and I love it. Cross into the time domain and try to retain the same approach, and I say you're making a serious mistake.
What's worse is when the actual programming APIs (as opposed to just redirecting stdout to /dev/dsp) also fail to model the time aspect, and encourage programmers to think that you can just shovel data at a device without any consequences for your software's properties (like latency).
The irony, of course, is that the proprietary version of OSS failed, and it ended up going open source again.
IMO, /dev/dsp was the right approach and should have been extended instead of being replaced with entirely different interfaces.
Meanwhile, OSS on FreeBSD just worked.
I still roll my eyes and I don’t get surprised every couple of years when somebody releases a yet another Linux audio daemon.
Maybe it’s some kind of Linux tradition.
At least PipeWire is saner compared to PulseAudio.
You seem to be stuck in, oh, maybe 2008.
There hasn't been "yet another Linux audio daemon" in more than a decade. JACK came along in the early 2000's (I wrote it), and PulseAudio in 2004 or thereabouts. All that nonsense with esd, artsd etc. was over because the aughts were over.
While it supports the same APIs as Pulseaudio, it's still a new audio (and video) daemon.
Even though i don't do audio on Linux.
I don't get why this was never fixed at the kernel level. You have onions of layers.
It is the audio solution for Linux.
PipeWire does video too, and when combined with a compatible Wayland compositor, serves as a replacement for remote X11.
Don't worry, THIS time we got right FOR SURE.
FWIW, I have recently switched from PulseAudio to PipeWire. I remembered how rough the switch from plain ALSA to PulseAudio was, and thus was utterly baffled how smooth the transition to PipeWire is. I just uninstalled PulseAudio, installed PipeWire, rebooted, and everything just worked, down to the Bluetooth headset that I never quite got to work well with PulseAudio.
It is really important to run a sound daemon with realtime privileges. This is the only way to ensure no cracks.
In what way?
There were (and are) many problems with the OSS API, a number of which continue to exist in the ALSA API too.
All serious audio APIs (plugins, or native audio I/O) use a pull model at the bottom of the stack, so that i/o is driven by the hardware. You can layer a push model (where software does blocking read/write calls whenever it wants) on top of that, but not the other way around.
And yes, OSS and ALSA both implement select/poll etc. for audio devices, but do not enforce the use of this model, resulting in the 2000s being filled with Linux (and *BSD) apps that couldn't function correctly without oodles of buffering.
I used a script to toggle the SPDIF output stream of my Soundblaster Live to get track marks on the Mini Disc player recording the output.
I'd never though of that, so simple!
# On the receiver
nc -l 9000 > output.file
# On the sender
nc 172.17.0.7 9000 < input.file
My only issue is that it seems to hang after it's done. What am I missing?Netcat has plenty of (confusing) options, but there's usually a solution.
# on sender
ncat --send-only --listen 12345 < file.zip
# then, on receiver
ncat --recv-only 1.2.3.4 12345 > file.zipI also setup a horrible video chat in bash using just vlc and netcat. Audio works better like this
I never bothered with a printing system.. I'd just cat a ps file to /dev/lp0
Being able to just send wave data to the audio device "file" is pretty common on most systems that smell like Unix.
The netcat trickery from the article works on any platforms where netcat is available, what file formats are specifically supported varies by printer. Most will take text and Postscript (though some famous printers like the LaserJet 4 still had PS as an optional addon), anything more complicated is implementation-specific.
After a particularly rubbish time trying to get HPLIP working again after a pacman -Syu I did a literature search: Mr CUPS had deprecated everything apart from IPP Everywhere. So, I tried it out.
Me and the missus send docs to print and they get printed. I cannot remember the last failure (apart from running out of paper.) I also have toner levels monitored via Home Assistant.
I also have an office with several MFPs and inkjets, accessed via Windows (Server 2019) print queues. They are not so reliable. I often have to restart the Print Spooler service on our print server. To be fair, it is generally one queue that is at fault.
Printer drivers run in process as well as the port monitor (for older printers). You might find the situation improves if you use an inbox driver (one that comes with Windows) and/or the standard port monitor.
Now printers integrate the IPP functionality.
There is no need to suffer if that will do the job.
Pragmatism is not the enemy of perfection.
Even when it works, there might be downsides, as some other comments are alluding to. The long print time one mentioned is likely because while you're lucky that your printer understands how to transcode pdf to ps in order to print a pdf, the onboard processor on the printer is much weaker than whatever you have on your computer. Also beware that if you're doing this on a radio network, I don't think netcat can encrypt the traffic. So don't be printing your credit card statements this way.
https://patrick.wagstrom.net/weblog/2003/05/23/lpdforfunandm...
Printers are fine with accepting jobs from multiple clients and have been for a long time. After all this is pretty much standard practice for any small office without a server.
Of course netcat does not encrypt anything. But if your printer accepts encrypted traffic you can send that over netcat. The question is what encryptions do the printers support? What protocol (stack) CUPS uses in the end? I have never heard that a printer certificate has expired, so my first guess would be it's all in cleartext.
Avoid jetdirect (9100) port like the plague. Partial files? Errors parsing the postscript? Outputting to the jetdirect port will result in printing every bit of that trash out, no questions asked. Walked up to a printer and found Nearly blank pages with one PCL or Postscript line telling you there's an error? That's jetdirect printing for you, and there's no good reason for it. LPD and IPP have actual protocols signaling start and end of jobs, so nothing comes out if something in the process fails, saving paper, toner and frustration. Yeah, you can't just use netcat, but you can easily use lp: lp -h 192.168.0.30 file.ps
Printing raw to a printer without drivers is also a terrible idea, it happens to work some of the time, but leaves you at the mercy of printer defaults. Printing a US Letter page on a printer which defaults to A4 (or vise versa)? Say goodbye to part of your print job. Now, yeah, you could program the correct command sequences into your postscript document, but why would you want to? Plenty of other things used in documents will cause errors if sent to a printer without being sanitized by CUPS (or filters to lpng, or whatnot).
CUPS isn't great. It makes printing so much harder than it needs to be. I absolutely hate having to remember the exact syntax to select B&W on my color printer: lp -o ColorMode=Monochrome It's very difficult to track down how it's mangling your print jobs, when there's a problem and you need to do so. Having to do an old apache style allow,deny reverse polish notation logic to configure who you want to access the printer and admin interface is user-hostile to be sure. And more. But it certainly has made it much easier to go from nothing to up and printing quickly, it's certainly got every feature you could need, and it's certainly reliable. I've done it in the old days, and I certainly don't want to go back to configuring printcaps manually with inscrutable invocation of ghostscript and many other print filters.
I'd try to find these printers used then I'd upgrade them: more RAM, more fonts, adding a network card inside the printer etc.
I still have several of these printers in a garage, some of them have printed more than 300 000 pages. They probably still work: some things were that good back then.
And, yup, there's something feeling magical when netcat'ing a .ps file (or another format) directly to the printer.
I was only half disappointed.
That is what a form feed character is for (ASCII 0x0C).
[0] https://community.spiceworks.com/how_to/2077-how-to-bake-an-...
The value of CUPS is that it enables the CUPS-serving computer to run as a print server. This means not only print drivers (document format support --- typically plain text, Postscript, and one or more PDL (printer definition languages) & PCL (Printer Control Language), but status on the printer, queue management, job control, and access control. Note that if your printer is generally available on your local WiFi network, you might want to give more thought to that last element.
If those are overkill for you and your printer Just Works with generated output, then yes, you can get by without the complexity.
Note that you can also often telnet directly to the printer port.
Be aware of what you're trading off, though, and whether or not you actually need what CUPS, or direct network access, offers.
If you still need a print server, it can be well worth the extra $100 or so to buy a business-class printer with an IPP server in it, so that CUPS runs on a chip inside the printer instead of on a separate computer. (Generally anything that supports "Airprint" will do this, and also at the mid range you avoid the "printers whose ink cartridges are more expensive than the printer" zone.)
Apple never really maintained CUPS. They hired the author, Michael Sweet, and he pretty much served as the printing team. He left Apple a couple years ago, and basically stalled their printing department.
He’s recently become head of the Printer Working Group, and they’re all pushing IPP Everywhere towards greater adoption. It’s a laudable effort.
1. https://github.com/apple/cups/graphs/contributors 2. https://github.com/OpenPrinting/cups/graphs/contributors
Google shut down Google Cloud Print in 2020 and moved to IPP.
Microsoft announced that they were moving to IPP (branded as Universal Print) in 2020 as well.
CUPS still exists because legacy printers don't have built in IPP support.
I was in grad school in a wetlab, so I had to label a ton of microcentrifuge tubes. Having a quick web interface e to generate the ZPL files that would be FTP’d to the printer let me avoid writing all of that out by hand.
It was such a simple system. And the FTP server was basically a queue, so you could print a bunch of labels at a time.
Unix printing was designed in an era when most printers were dumb serial or parallel devices chained directly to a computer. Or if they had an ethernet jack, had some bizarro proprietary system that was very minimal and included no memory, queueing, or ability to interpret complex formats like PDF. That is the environment CUPS was designed for. And it was a huge improvement over the old lp system. The "l" in "lp" literally means "line".
Like everything else in the computer world printers have gotten a lot more capable. They may literally be running CUPS. That's why you don't need another complex print spooler and format convertor on your client machine.
http://danieru.com/2013/06/06/what-is-port-9100-how-to-print...
While you're at it you may as well try out the printer exploit kit https://github.com/RUB-NDS/PRET
Only recently, by buying a Brother laser printer at home, and setting all my machines to use NixOS, I haven't been needing to think about printer problems anymore. All I need is this piece of config, and the printer will Just Work with the new computer:
https://github.com/pimeys/nixos/blob/main/modules/home-servi...
Thank you for sharing.
Aaand this is how I made my printer spit out dozens of garbage pages with just one to two lines of gibberish on each (the PDF source code, admirably giving up the page at each occurrence of the corresponding char)...
My printer is a Brother HL-2270DW... seems to be quite a dumb one...
Magic in printing is still an arcanum. PPD files. Windows 10 as a print server. (some print devices are not networked)
Prelude files. in-printing logic like line reversal, density adjustments for photos. Double sided printing meta-signalling, n-up..
"oh, I don't need that stuff" fine, fine, nc is going to work for you, at the end of a bumpy road to a printer which supports it. And, right up until its 2am, you want to colour print that late birthday card for your favourite aunt, and the printer is stuck on nc...
I can send stuff to it over FTP, too.
$90!
I will never use CUPS again. I'll need a printer driver, yes, but I'll never need CUPS.
GET / HTTP/1.1https://www.freedomit.co.nz/kb-centos/76-using-port-9100-to-...
Edit: It took about 5 mins to print a 3-page document, with long pauses between each page.
The problems were to do with handling problems like printer jams, out of paper etc which require, in essence, a partial resend and was tricky. Print spoolers on all platforms managed some of this complexity.
The greater memory on printers and the ability to locally retry a page make it simpler today, but only in the most casual settings. If you want to print anything substantial, treating a printer as a file is not really a good idea.
The only system I'm aware of that managed that was AFP on IBM mainframes. Certainly the Windows print spooler doesn't. It assumes the printer handles a paper jam and just waits until it is ready to accept more data.
* That's not encrypted.
* (More importantly) You might look at the printer firmware's complexity, excessive IoT/cloud-friendliness, and hints from the printer brand about their current engineering standards... and become uneasy about plugging that into your LAN, even if you firewall it to heck.
Partial solution: for my modern laser printer, I've left its NIC unconnected, and put my own print server in front of it, on a VLAN, and connected via USB. And I still strongly suspect at least a couple classes of vulnerability still present, but no time to look into it or mitigate.
Variation for the article's needs: you can make a one-line script TLS/SSL tunnel from a local port on your workstation host(s), to a thin isolating host (old RasPi?) in front of the printer. So content is encrypted over the LAN, and the printer is more isolated than it would be normally.
Another variation: plug the printer directly into a single host that needs it (such as via USB or a dedicated Ethernet NIC), and then decide what to do about any other hosts that want to use the printer.
Sorry to be cheeky, but welcome to 1977. ;)
If I want to print multiple pages per sheet: Open PDF in Firefox, CTRL+P -> Save to PDF and configure the document. You can also pipe through `gs` to do this.
For _huge_ documents (100s of pages), I'll pipe through `gs` first to do the pdf->ps conversion on my laptops CPU. The printer can do it, it just takes a lot longer.
There is nothing magic about netcat. You are just dumping Postscript/PDF data on a TCP port the printer is listening on.
I can put `nc [printer_ip] 9100` there and it will just print. I just printed your comment this way.
That's cool! Thank you for teaching me something!
1: https://git.cloudef.pw/escpos2raster.git/tree/ 2: https://git.cloudef.pw/escpos2raster.git/tree/src/bin/starpb...
They also don’t turn into junk, after the next OS update, when the manufacture decided not to provide driver updates anymore.
I did not realize this was an exotic thing to do?
Edit: Now that im testing it, i see that firefox has recently dropped support for printing to postscript. Classic firefox. Can someone recommend me an alternative browser?
Nice to see that .pdf pretty much just works.
Untested, but code reviewed with one eye.
With Plan9/9front everything involving TLS could me made a script and an Acme frontend, except for video.
Also, check this for gopher:
https://github.com/hb9kns/nago
Now you can browse HN, play IF, read news, and so on over Gopher with just Busybox (sh, grep, tail and netcat requiredin the busybox build) and an internet connection:
gopher://hngopher.com
gopher://mozz.us
Altough with just less, echo and nc:
echo / | nc mozz.us 70 | less
echo /long/selector/to/a/text/file.txt | ncmozz.us 70 | less
Crazy but it could work on heavily tiny restricted devices
such as a RetroBSD with nc, echo and less in a tiny
microcontroller. dict(){ echo "define * $1\\n\\q" | nc dict.org 2628 | less ; }
dict unixEqually cool and terrifying. I can dig up my notes if someone is interested.
It actually blew my mind after doing Linux for 10 years. "Everything is a file" isn't a lie.
My wife (not technical) figured this out one day and I didn't believe her at first that this would all "just work".
I've printed from my phone to my pi CUPS server. Even Windows 10 understands IPP.
Is Linux printing really such a problem?
It seems far more friendly to mention that netcat is an option to the average home linux user.
(Very few printers in the world seem to be setup to use secure connections unfortunately)