AirPrint and Linux

I've been trying the iPhone OS[1] 4.2 GM, and decided to play with the AirPrint functionality. However, Apple has removed the ability to print to locally attached PC/Mac printers with the final versions of iTunes 10.1 and OS X 10.6.5. Using a beta version of iTunes 10.1 for Windows, Wireshark, avahi-discover and a few other tools, I managed to get an understanding of how AirPrint works. What I've found is:

  • AirPrint uses IPP for print management.
  • AirPrint listens to mDNS (Bonjour/Avahi) for printer discovery.
  • AirPrint requires a _universal subtype to be present in the _ipp announcement before it will consider listing the printer.
  • AirPrint requires an additional TXT record, "URF", to be present and non-empty before it will consider listing the printer.
  • While this URF format (see below) appears to be a future option for Apple, all current AirPrint-enabled apps seem to send print data as PDF.
  • When a printer is protected by a username/password, the iTunes/AirPrint daemon will send a TXT record "air=username,password".

The original announcement as sent by iTunes 10.1 Beta 2 for Windows looked mostly like a normal IPP announcement, except for the _universal subtype (which standard CUPS does not seem to send), and the following TXT records:

pdl=application/pdf,image/jpeg,image/urf
URF=W8,DM1,CP255,RS600-300
air=username,password

(The last record is a literal string "username,password", not an obfuscated user/pass.)

I haven't been able to find much info about what "URF" is. I'm guessing a raster format of some kind. The CUPS implementation in the iTunes beta is accepting it though. What I found is that the image/urf type is not required to be in the pdl record. Currently, all AirPrint enabled apps seem to be fine with sending PDFs, so as long as your CUPS daemon has a PDF filter, you're good. What IS required is the URF record. It has to exist, and cannot be empty, or the printer does not show up in the AirPrint list. The "air" record seems to exist to provide a hint to AirPrint that the target requires a login. If your printer target is not protected by a login, this record can be omitted.

So, with this known, how do we set up a Linux (or presumably *BSD) server as an AirPrint server? We're going to have to manually set up an Avahi service. CUPS can publish to Avahi, but as this requires an extra record and subtype that CUPS does not provide, we'll have to duplicate the printer record manually.

Note that most of this is Debian-centric. If you are not running Debian, you'll probably have to adjust things here and there.

1. Install CUPS and make sure it's actually working. Configuring CUPS correctly is outside the scope of this guide. You will need to have a PDF filter working correctly. Debian seems to provide this out of the box with a CUPS install; your mileage may vary.

2. Go into the CUPS interface and make sure "Share published printers connected to this system" is enabled.

3. Install avahi-daemon and make sure it is running. Restart CUPS to get it to publish printer services. (AirPrint will not be using the CUPS-published services, but we will need them to recreate a manual service.)

4. On another Linux box, install avahi-discover and run it from a terminal. Click the printer you wish to duplicate. Now switch back to the console and a set of debugging lines should be printed similar to this (I've added some linebreaks for readability):

Service data for service 'HP LaserJet 1200 @ nibbler.xn--n3h' of type '_ipp._tcp' in domain 'local' on 3.0:
    Host nibbler.local (10.9.8.1), port 631, TXT data: [
        'pdl=application/pdf,application/postscript,application/vnd.cups-raster,application/octet-stream,image/png',
        'Copies=T',
        'Duplex=T',
        'Binary=T',
        'Transparent=T',
        'printer-type=0x3056',
        'printer-state=3',
        'product=(GPL Ghostscript)',
        'note=Home',
        'ty=HP LaserJet Series PCL 4/5, 1.3',
        'rp=printers/hp1200',
        'qtotal=1',
        'txtvers=1'
    ]

5. Back on the server, create /etc/avahi/services/name.service. name can be anything; I named it /etc/avahi/services/hp1200.service in this case.

6. Create an XML file similar to the example below, using the data above as the values. Note that the data is in the opposite order of what avahi-discover gave it to you.

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">AirPrint hp1200 @ %h</name>
<service>
       <type>_ipp._tcp</type>
       <subtype>_universal._sub._ipp._tcp</subtype>
       <port>631</port>
       <txt-record>txtvers=1</txt-record>
       <txt-record>qtotal=1</txt-record>
       <txt-record>rp=printers/hp1200</txt-record>
       <txt-record>ty=HP LaserJet Series PCL 4/5, 1.3</txt-record>
       <txt-record>note=Home</txt-record>
       <txt-record>product=(GPL Ghostscript)</txt-record>
       <txt-record>printer-state=3</txt-record>
       <txt-record>printer-type=0x3056</txt-record>
       <txt-record>Transparent=T</txt-record>
       <txt-record>Binary=T</txt-record>
       <txt-record>Duplex=T</txt-record>
       <txt-record>Copies=T</txt-record>
       <txt-record>pdl=application/pdf,application/postscript,application/vnd.cups-raster,application/octet-stream,image/png</txt-record>
       <txt-record>URF=none</txt-record>
</service>
</service-group>

The only differences are 1) I named the service "AirPrint hp1200" to not interfere with the "hp1200" service that CUPS publishes, and 2) the added "URF=none" record. And be sure to double check that "application/pdf" is included in the pdl record. If it's not there, don't simply try to add it, that won't work. You'll need to figure out why your CUPS installation doesn't have a PDF filter.

7. Save the file. avahi-daemon should notice the new file and load it without a needed restart.

8. On your iPhone/iPad, go into an application (Safari, for example), print, and search for printers. Your new printer definition should be in there.

9. Print!

10. (Optional) Wonder why you're still printing things in 2010, let alone from a mobile device. For me, this was mostly an exercise in figuring out how AirPrint worked. The example printer used here, an HP LaserJet 1200, was bought used as a demo/display model from an office supply store in 2002. I print maybe 10 pages per year on it. 8 years later, and the original demo toner cartridge is still working fine.

--

[1] I've been working with Cisco IOS for over 10 years now, and flat out refuse to call this "iOS". Live with it.

49 Comments

  1. Taking the clues provided in your excellent description, I wrote a simple one-off to generate the service files http://www.atxconsulting.com/blog/tjfontaine/2010/11/21/automatically-generate-airprint-avahi-service-files-cups-printers

  2. Hey, so... this is almost working for me, except that the print center is just looping between starting the job and trying to send it, and nothing is getting printed. I set this up on my Ubuntu box, and its trying to point to a Brother Printer which is actually hooked up to a Windows computer through a MacBook.. i think that complexity could have something to do with the failure though.

    AirPrint Brother HL-5140 @ %h

    _ipp._tcp
    _universal._sub._ipp._tcp
    631
    txtvers=1
    qtotal=1
    rp=printers/BrotherHL_5140
    ty=Brother HL-5140 series CUPS
    note=Main Room
    product=(HL-5140 series)
    printer-state=3
    printer-type=0xB046
    Transparent=T
    Binary=T
    Duplex=F
    Copies=T
    pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png
    URF=none

  3. It might be because the printer is on another computer (different than the one you're advertising). You will have to add / edit the "host-name" in your new service to point to the printer or computer.

  4. Alright, I'll see what happens. I wish Apple would just add back this feature they promised!

  5. Nope, I set up a local PDF virtual printer and tried sharing it with no luck (using cups-pdf) the iPad just flicks between "status | Waiting" and "status | Printing 1 of 2..." with no effect. It looks to me like its having trouble connecting to my ubuntu desktop.. but i've got printer sharing turned on so far as i can tell.

  6. I had to add ServerAlias * into the cupsd.conf file.

  7. "I've been working with Cisco IOS for over 10 years now, and flat out refuse to call this "iOS". Live with it."

    God bless you! :-D

  8. Using the script at http://www.atxconsulting.com/blog/tjfontaine/2010/11/21/automatically-generate-airprint-avahi-service-files-cups-printers, I created the service file. I can now "print" from my phone, nothing actually prints. I'm on the right track, but it's not quite there yet.

  9. Thanks. Very useful. Your file also worked without changes for my LaserJet 1020.

  10. Wonderful! Works perfectly on Gentoo for my Samsung CLP-325 networked via a Sitecom print server. Thank you.

  11. @steven, make sure you've actually gone and configured your cupsd.conf file. The vanilla copy won't work for this. You definitely need ServerAlias * to be in there and then some other stuff might be needed

  12. Didn't work for me, running ubuntu 10.4. Looks like it works from the iPhone side, but nothing ever gets into the print queue. CUPS access log shows a Get-Printer-Attributes call with a 200 success, but just one line (from an ipv6 origin). When I print from a windows machine (to the same cups printer) I see many more lines in the access log with an ipv4 origin. lpr sample.pdf works fine. tj's script worked fine. What else can I check, look into?

  13. Magnifique,

    Cela fonctionne très bien avec une Gentoo.

    Attention :
    - au bug de pdftops avec net-print/cups-1.3.11-r1 (http://bugs.gentoo.org/show_bug.cgi?id=309901) sur la gentoo.
    - aux droits d'accès à Cups dans le cupsd.conf (en particulier les allow/deny)

    Sinon, la manip est bien décrite et documentée => encore Merci Ryan.

    Christian

  14. Works great(iPad-> Debian and MacBook -> Debian) , but the print job sure takes a long time to start. As far as I can tell the delay is on the client side (tcpdump shows no traffic on the Debian side). Anyone else having the same issue?

  15. Canot run python script :(

    "Failed to find python libxml or elementtree"

    Can someone help - or maybe if you have the service file for Canon Pixma iP5300?

  16. Does AirPrint only use multicast mDNS or also Unicast DNS-SD? We're trying to make it work on an enterprise network without allowing broadcasts across subnets.

  17. Thanks very much for the article and to the people who suggested adding the ServerAlias * to cups.conf. Did that and I could print!

  18. How Conserns

    Manually adding DNS-SD printer service discovery records for AirPrint to an existing name server.

    See: http://www.dns-sd.org/ServerStaticSetup.html

    _universal._sub._ipp._tcp PTR prn._ipp._tcp
    _ipp._tcp PTR prn._ipp._tcp
    prn._ipp._tcp SRV 0 0 631 cups..tld.
    TXT "URF=none" "txtvers=1" "qtotl=1" \
    "rp=printers/" \
    "ty=Fiery X3eTY 35C-KM PS Color Server v2.01 eu" \
    "product=(Fiery X3eTY 35C-KM PS v2.01 eu)" \
    "transparent=t" "copies=t" "duplex=t" "color=f"\
    "pdl=application/pdf,application/postscript" \
    "note=Campus, Building, Floor, Hall"

    Regards Peter

  19. Hi,

    thanks a lot very usefull tutorial, i have my debian with cups 1.3.8 and avahi now printing on my samsung ML-2010 from the iphone. I don't understand how to protect the printer with login and password the txt record "air=username,password" when used put a lock icon on the printer when listed in the iphone but no credentials are asked when printing. Anyone used this record with succes?

    Thanks

    k.

  20. I am guessing that URF stands for "Universal Raster Format". Doing a web search on that shows that it could well be that. See the following article:

    http://www.mail-archive.com/lprng@lprng.com/msg06114.html

  21. @kelo: I would check on the CUPS site to see what is documented: http://www.cups.org/

  22. Does this still work on 4.3? I've tried this (and airprint for windows) and both come up with "No Printers Found" even though i see MDNS standard query coming from iphone/ipad and MDNS Standard query Response.

    No idea why it won't work (linux cups or windows airprint.exe).

    Thx.

  23. FYI.. those responses are in Wireshark (sniffer). Phone is asking, and servers are responding. I never tried this with 4.2.x but 4.3 isn't working right now for me.

  24. Thanks, this blog and tjfontaine's python script made it a breeze to print to my network attached Dell 1700n from my iPad WiFi (1st Gen) w/ iPhone OS 4.3.1 by way of my Ubuntu 10.04.2 LTS box.

  25. Does not work for me either with ios 4.3.2. Worked with ios 4.2.x. Anyone got an idea what is wrong with ios 4.3

  26. I just found out that you need to enable and disable flight mode to reset the WLAN connection. Then the iphone was able to find the printer. It seems that the bonjour service of the device does a complete rescan only if the wlan is freshly activated. Saw some reports of that in different boards.

  27. The only thing I had to change because of my LAN setup is to add the line:
    ServerAlias *
    somewhere in /etc/cups/cupsd.conf Otherwise I got bad request errors bevause the iPad used a server name that cups refused to validate. Certainly due to my LAN setup. Hope this could help some of you.

    -Swift

    • I had the same problem. Once I added "ServerAlias *" to the top of my /etc/cups/cupsd.conf file, it started to work.

      I also used the script provided in the first comment to generate my service file. It wouldn't work initially. In case anybody else gets stuck, I had to install python-cups before running the script.

  28. Thank you very much for these instructions. They helped me to patch the CUPS packages in Ubuntu Natty (11.04, will come with next update) and Oneiric (11.10) to automatically advertize printers via DNS-SD in a way to be found and accepted by AirPrint clients, without any additional service definition file. You only need to share your printers. See https://bugs.launchpad.net/bugs/711779.

    Till

  29. Hey everybody,

    first of all: thank you very much, it's such a great tutorial, everything works fine with my Epson printer. But I plan to share a Virtual PDF Printer working with cups-pdf for my iPad, too.

    My question: I just modified my skript for the Epson and I changed the same fields I did for the Epson with you suggestion above, but my devices still don't find it! I make a new service-file. Is the Problem that avahi only can handle with one file?

    Here is my script for the Virtual PDF-Printer, maybe there a some mistakes, I'm a real Newbie on text-based Linux, sorry ;)

    PDF Printer

    _ipp._tcp
    _universal._sub._ipp._tcp
    631
    txtver=1
    qtotal=1
    rp=printers/PDF_Printer
    ty=>PDF Printer
    adminurl=http://192.168.2.82:631/printers/PDF_Printer</txt-reco
    note=>>
    priority=0
    product=PDF Printer
    printer-state=3
    printer-type=0x801046
    Transparent=T
    Binary=T
    Fax=F
    Color=T
    Duplex=F
    Staple=F
    Copies=F
    Collate=F
    Punch=F
    Bind=F
    Sort=F
    Scan=F
    pdl=application/octet-stream,application/pdf,application/postsc
    URF=W8,SRGB24,CP1,RS600

  30. THANK YOU!!! This walk through is awesome, worked right off the bat using an iPod touch, iOS 5 Beta 2, CentOS 5.6 Server & Ricoh Aficio CL3500N Printer!

  31. Ok this is an awesome guide you have here, thank you. One stumbling block I found was that I have firestarter (Ubuntu firewall for dummies) and it was preventing my ipad from seeing the printers. After a lot of messing about I discovered reference to multicast being blocked by firestarter by default. Through trial and error I found this solution:
    1. Edit /etc/firestarter/firewall
    2. Comment out these lines:
    $IPT -A INPUT -s 224.0.0.0/8 -d 0/0 -j DROP
    $IPT -A INPUT -s 0/0 -d 224.0.0.0/8 -j DROP
    $IPT -A OUTPUT -s 224.0.0.0/8 -d 0/0 -j DROP
    $IPT -A OUTPUT -s 0/0 -d 224.0.0.0/8 -j DROP

    After restarting firestarted I found I could still print, even though the firewall was active. Anyway, thought this tidbit might be helpful to your readers.

  32. Dude, you rock! As a Linux noob, this was easy enough. Now, here it is 2011. Why are we printing?

    1) Kids reports - yes, schools should allow electronic submissions - will probably happen by the time my great grandchildren get to school
    2) Coupons stores need - yes, they should allow e-coupons and scan at the checkout, but most don't
    3) Mailing labels
    4) Recipes - yes I do want a recipe service to submit directly to MasterCook on the PC, but until then...

    Any others?

  33. Can you confirm if this still works on iOS 5? Lots of people are doing the Windows equivalent of this with the utility at http://jaxov.com/2010/11/download-airprint-installer-for-windows-7-xp-vista. They are reporting iOS 5 incompatibility. Some are even saying that AirPrint doesn't work with certain canon and hp printers natively after the ios5 update.

    Since it looks like you have dug further into tracing the protocol, can you tell if Apple changed something for iOS 5? Perhaps something new in the URF header?

    Thanks.

  34. Hello ! Thanks for the Great Description . It worked very well since i updated my iPhone to iOS 5.

    Are there any known solutions ?

    Greetings,
    Matze

  35. On IOS5 using Ubuntu 10.04 LTS this works but only if I setup a cron job to touch the appropriate .services file every minute. As soon as the file is touched the printer shows up again. Otherwise it says no airprint printers found. Seems like there might be something with avahi that isn't quite right. Anyone have any ideas?

  36. I just tried this with Ubuntu 11.10 and found that I don't need to create the service file. I'm using IOS5 on my iPod Touch and once I have cups setup to publish, it all just works.

  37. Thanks for this awesome tutorial. I was able to set up my Ubuntu 11.10 server/desktop at home as an AirPrint printer. For the problem where you are seeing the AirPrint printer but cannot print to it, make sure to enable "Share printers connected to this system" in the CUPS administrative screen. The easiest way is to browse to http://localhost:631/admin in the Server/Server Settings section. The option shows up under the "Advanced" link but doesn't require you to go to the advanced settings.

    FYI, my printer is an old-school Brother HL1870N (networked) with BR-Script3. So this is to confirm that the tutorial should work for any attached or non-attached printer.

  38. Thanks for this, managed to debug why one of my printers was not working for iOS through avahi ...

  39. Hey Ryan, thanx for your work!
    used tjfontaine's script to provide from now on the airprint service from my debian squeeze linux box for ipad and other devices

  40. Hi,

    today I've installed IOS6 update, and the printer are no more discoverable.

    Anyone have this issue?

    Thanks

  41. Airprint and IOS 6 problem

    This link solved the problem for me http://ubuntuforums.org/showthread.php?p=12252252#post12252252

    Again thank to all

    Re: iOS 6 doesn't recognize CUPS print shares
    I've made a little bit of progress on this at work, where we're running Debian 6 with CUPS and Avahi-daemon.

    1) Apple changed the format of their airprint printing from PDF to URF with iOS 6.
    2) URF is a unirast format file. This appears to be an apple-specific format
    3) Printers that natively support Airprint have support for URF, so they continue working
    4) CUPS does not natively support unirast, and so the avahi configuration files I generated do not mention that they support URF. Therefore, the Airprint printers do not show up in iOS 6.
    5) Some guy wrote a very basic URF to PDF converter and published it in 2010 when iOS 4.2 came out, because apparently it was necessary then as well. https://github.com/superna9999/urftopdf
    6) I've installed this on airprintstaff following these instuctions https://github.com/superna9999/urfto...tall-and-Usage and re-ran airprint-generate.py which now mentions URF support
    7) The printers show up under iOS 6 now. The URF format decoding is not complete, though, so the print job must be set to "duplex off" when airprinting. This preference is ignored when the file is converted to PDF anyway (duplex is turned on).

    It looks like URFtoPDF isn't fully developed at this point, but there's definitely a starting point.

    Edit: thanks to previous posters in this thread for assistance in getting this far!
    Last edited by kloostec; 9 Hours Ago at 08:10 PM..

  42. I have a strange behaviour after updating my new ipad to iOS6.
    After the update the new iPad is no more showing any AirPrint printer.
    Another old iPad 1 running iOS 5 (It can't be updated to iOS6... Good bless Apple!!!) it's instead able to show the AirPrintprinter and to print.
    Any idea how to solve the iOS6 problem?
    Thanks

  43. Just FYI, the image/urf type now has to be in the pdl. If not, the printer will not be detected in iOS 6

  44. I've setup a CUPS-PDF virtual printer on cups 1.3.11 and printing from Desktop and IPad 1 (iOS 5.1.1) works. But from iPhone 3G (iOS 6.0) getting errors in the cups error log:
    IPP Read Error !
    code=400 (Bad Request)

    Anyone have any ideas ?

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2014 Ryan Finnie

Theme by Anders NorenUp ↑