How can I list the IP addresses of all the AirPrint printers on a network?

Solution 1:

I do not have an AirPrint printer on my network. And never played with one either...


I cannot test with a real AirPrint device in my proximity right now.

But here is how I can list all the IPP-enabled printers (in this case they are all connected via CUPS):

First, browse for DNS-SD discoverable services (all types):

kp@zdv-wireless-43-219:> dns-sd  -B  _services._dns-sd._udp  local.

  Browsing for _services._dns-sd._udp.local.
  DATE: ---Fri 20 May 2016---
  23:54:37.797  ...STARTING...
  Timestamp     A/R Flags  if Domain  Service Type         Instance Name
  23:54:37.798  Add     3   4 .       _tcp.local.          _ssh
  23:54:37.798  Add     3   4 .       _tcp.local.          _sftp-ssh
  23:54:37.798  Add     3   4 .       _tcp.local.          _airplay
  23:54:37.798  Add     3   4 .       _tcp.local.          _raop
  23:54:37.798  Add     3   4 .       _tcp.local.          _googlecast
  23:54:37.798  Add     3   4 .       _tcp.local.          _nomachine
  23:54:37.798  Add     3   4 local.  _apple-mobdev2._tcp. _sub
  23:54:37.798  Add     3   4 .       _tcp.local.          _apple-mobdev2
  23:54:37.798  Add     3   4 .       _tcp.local.          _ipps
  23:54:37.798  Add     3   4 .       _tcp.local.          _ipp
  23:54:37.798  Add     3   4 .       _tcp.local.          _workstation
  23:54:37.798  Add     3   4 .       _tcp.local.          _http
  23:54:37.798  Add     3   4 .       _tcp.local.          _amzn-wplay
  23:54:37.798  Add     3   4 .       _tcp.local.          _rfb
  23:54:37.798  Add     3   4 .       _tcp.local.          _afpovertcp
  23:54:37.798  Add     3   4 .       _tcp.local.          _smb
  23:54:37.798  Add     3   4 .       _udp.local.          _net-assistant
  23:54:37.798  Add     2   4 .       _tcp.local.          _eppc
  ^C

So yes, there is indeed an IPP print service (but no AirPrint one, which would be marked by stand out being tagged as Service Type of _airprint._tcp in the list).

Second, browse for all present services of type "IPP":

kp@zdv-wireless-43-219:> dns-sd  -B  _ipp._tcp  local.

  Browsing for _ipp._tcp.local.
  DATE: ---Fri 20 May 2016---
  23:54:47.782  ...STARTING...
  Timestamp     A/R  Flags  if Domain  Service Type   Instance Name
  23:54:47.783  Add      3   4 local.  _ipp._tcp.     Officejet6500donna @ mbp
  23:54:47.783  Add      3   4 local.  _ipp._tcp.     raw2dir @ mbp
  23:54:47.783  Add      2   4 local.  _ipp._tcp.     Officejet 6600 @ mbp
  ^C

Ok, one of the instance names is "Officejet 6600 @ mbp".

Third, lookup specific info about the printer named "Officejet 6600 @ mbp":

kp@zdv-wireless-43-219:> dns-sd  -L  "Officejet 6600 @ mbp"  _ipp._tcp  local.

  Lookup Officejet 6600 @ mbp._ipp._tcp.local.
  DATE: ---Fri 20 May 2016---
  23:54:55.252  ...STARTING...
  23:54:55.253  Officejet\0326600\032@\032mbp._ipp._tcp.local. can be reached at mbp2-2.local.:631 (interface 4)
   txtvers=1 qtotal=1 rp=printers/Officejet_6600 ty=Unknown \
    adminurl=https://mbp2-2.local.:631/printers/Officejet_6600 \
     note=Büro\ im\ Keller priority=0 product=\(Officejet\ 6600\ e-All-in-One\) \
      pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster \
       UUID=e7d11337-a440-3f2d-7168-b53de4325791 TLS=1.2 Color=T Scan=T \
        printer-state=3 printer-type=0x480900E
  ^C

Half of the info you are looking for (hostname of the printer) is covered by the sentence "Officejet\0326600\032@\032mbp._ipp._tcp.local. can be reached at mbp2-2.local.:631"

This gives the current (Bonjour-)hostname of node offering the looked-up print service.

Fourth, look up the IPv4 and IPv6 addresses for a given hostname:

kp@zdv-wireless-43-219:> dns-sd -Gv4v6 mbp2-2.local

  DATE: ---Sat 21 May 2016---
  0:12:41.025  ...STARTING...
  Timestamp     A/R Flags if Hostname    Address                                      TTL
  0:12:41.025  Add  3  4 mbp2-2.local.   FE80:0000:0000:0000:AEBC:32FF:FEAE:CAEB%en0  120
  0:12:41.025  Add  3  4 mbp2-2.local.   FD00:0000:0000:0000:AEBC:32FF:FEAE:CAEB%  120
  0:12:41.025  Add  2  4 mbp2-2.local.   192.168.177.20                               120
  ^C

Summary

Assuming my first command had returned some _airprint service available in my network, then my guess is that one of the returned lines would read:

00:00:00.000  Add     3   4 .       _tcp.local.          _airprint

Thus, my second command would have to be:

kp@zdv-wireless-43-219:> dns-sd  -B  _airprint._tcp  local.

I assume this could return something like

200:00:00.000  Add    3   4 local.  _airprint._tcp.  Some AirPrinter @ somehost

Then my third command should read:

kp@zdv-wireless-43-219:> dns-sd  -L  "Some AirPrinter @ somehost"  local.

Which would return a line telling you "... can be reached at somewhere.local.:1234". From which to derive the fourth command:

kp@zdv-wireless-43-219:> dns-sd  -Gv4v6  somewhere.local.  

Caveats: The last part, about AirPrint service discovery may be wrong. It could be the case that AirPrint services announce themselves just as standard IPP services do. You have to find out yourself. If you do, please report back.


Update

I've googled a bit for "_airprint._tcp".

I didn't find a single instance of anybody who reported in some forum their output from dns-sd -B listing this particular string.

However, there were lots + lots of _airplay._tcp and _ipp._tcp results. This means that "_airprint._tcp" does not seem to exist, and AirPrint printers must be using a different signature to make themselves known to potential clients. However, we already know that all AirPrint services use IPP for communication with their clients, so they also MUST be making the _ipp._tcp service type announcements.

Hence it is safe to conclude that...

  1. ...all AirPrint devices will announce themselves as _ipp._tcp (not _airprint._tcp). Also, it looks like...
  2. ...you can identify AirPrint devices by looking for the TXT record of urf="$anything" and pdl="$anything,image/urf".

To verify this, I checked with what the (fake) announcement from dns-sd.org tells about its AirPrint (warning, it is not permanently on the Internet, sometimes it goes away for hours...). It does return this:

kp@zdv-wireless-43-219:>  dns-sd -Z _ipp._tcp,_universal dns-sd.org.

  Browsing for _ipp._tcp,_universal.dns-sd.org.
  DATE: ---Sat 21 May 2016---
   1:40:45.688  ...STARTING...

  ; To direct clients to browse a different domain, substitute that domain in place of '@'
  lb._dns-sd._udp                                 PTR     @

  ; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.
  ; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local
  ; names with the correct fully-qualified (unicast) domain name of the target host offering the service.

  _ipp._tcp                                       PTR     Stuart's\032Home\032AirPrint\032Printer._ipp._tcp
  Stuart's\032Home\032AirPrint\032Printer._ipp._tcp SRV     0 0 631 airprint.dns-sd.org. ; Replace with unicast FQDN of target host
  Stuart's\032Home\032AirPrint\032Printer._ipp._tcp TXT     "txtvers=1" "qtotal=1" "rp=ipp/printer" \
    "pdl=application/postscript,application/vnd.hp-PCL,application/vnd.hp-PCLXL,application/pdf,image/urf" \
    "URF=CP99,W8,OB10,PQ3-4-5,ADOBERGB24,DEVRGB24,DEVW8,SRGB24,IS1-2-4,MT1-2-3-5-12,MT1-2-3-5-12,RS600" \
    "ty=HP LaserJet 400 color M451nw" "product=(HP LaserJet 400 color M451nw)" \
    "priority=10" "adminurl=http://www.dns-sd.org/ServerStaticSetup.html" \
    "note=At Stuart's house" "Color=T" "Duplex=F" "Scan=F"
^C

Indeed, "Stuart's Home AirPrint Printer" mentions "URF" in its TXT records.

So, to summarize the answer to your question "How can I get the IP addresses of all AirPrint printers?"

  1. First, list all IPP printers.
  2. Second, exclude these IPP printers which do NOT enumerate the two above mentioned urf-entries in their TXT records.

Verify my statements

The following (minimal) command will announce a fake AirPrint device in your LAN (until you cancel the command with ^C):

dns-sd                                                                   \                                                                            
    -R "Minimal AirPrint Demo (dummy+fake printer fooling iPad clients)" \               
    _ipp._tcp.,_universal                                                \                                                              
    .                                                                    \                                                                                  
    631                                                                  \                                                                                
    pdl="image/urf"                                                      \                                                                    
    URF=""

Your iOS devices will now enumerate this printer amongst its auto-discovered AirPrint devices.

(BTW, you can announce the port as something different from 631 too -- the iOS clients will still identify it as an AirPrint device...)

Now repeat this little experiment, just leave one of the two image/urf or URF="" statements off your command:

  1. The fake device will still appear as an IPP printer in the DNS-SD/Bonjour browse lists.
  2. But iOS clients will only list as AirPrint-capable these (fake or real) devices with the "URF"-related entries.

Solution 2:

Before you dive into the following answer:
Please make sure you've understood the comprehensive AirPrint explanations for the [AirPrint] tag info I've recently written.


There is another tool which can identify AirPrint devices. It is the little known ippfind utility, that ships as part of CUPS (on Debian: as part of the cups-client package).

There is an ippfind.exe utility available for Windows as well. It ships as part of the IPP Everywhere Selfcertification Software Package which is available for download from the Printer Working Group (PWG) website here:

  • http://ftp.pwg.org/pub/pwg/tools/sw-ippeveselfcert10-20151110-windows.msi. For it to actually work on Windows, you also need the following:

  • Bonjour Print Services for Windows

So the following method works on Linux as well as on Mac OS X and Windows.

I'll show now step by step, how to work with it...

Most simple command finds all IPP printer URIs

The most simple way to execute the utility is this:

ippfind

On my current system, it returns:

  ipp://mbp2-2.local.:632/printers/DummyAirPrint
  ipp://mbp2-3.local.:631/printers/Officejet6500eric
  ipp://mbp2-4.local.:631/printers/Officejet_6500
  ipp://mbp2-5.local.:631/printers/Officejet_6500_E709n
  ipp://mbp2-1.local.:631/printers/Officejet_6600
  ipp://mbp2-7.local.:633/printers/Officejet6500donna
  ipp://mbp2-8.local.:631/printers/raw2dir

This is a list of all IPP print services (including the AirPrint ones). Note how some of these do not use the default IPP port 631, but they are still discovered.

Because ippfind didn't see any command line parameters, it silently used its default ones, and in reality this command did run:

ippfind _ipp._tcp --print

Filter out the AirPrint devices

To narrow down from all IPP printers to only those which support AirPrint, we have to add the subtype _universal to our query:

 ippfind _ipp._tcp,_universal --print

This leaves me with the following subset of the full list from above:

  ipp://mbp2-2.local.:632/printers/DummyAirPrint
  ipp://mbp2-3.local.:631/printers/Officejet6500eric
  ipp://mbp2-7.local.:633/printers/Officejet6500donna

Get the host names for the IPP URIs

ippfind works similar as the classical find utility which searches for files, directories and other objects in the file system hierarchy, and therefor has a --exec parameter, which can be used to run a command against each found item:

 ippfind _ipp._tcp,_universal --exec echo '{service_hostname}' \;

The command returns the host names for all the AirPrinters. It does not list the other, non-AirPrint IPP printers:

  mbp2-2.local.
  mbp2-3.local.
  mbp2-7.local.

Find the IP addresses of all AirPrint devices

Since from previous answers we already know that dns-sd -G will return the IP addresses, we can execute this instead of the simple echo command from above:

ippfind _ipp._tcp,_universal --exec dns-sd -G v4 '{service_hostname}' \;

    DATE: ---Tue 24 May 2016---
     3:39:18.024  ...STARTING...
    Timestamp     A/R Flags if Hostname         Address          TTL
     3:39:18.028  Add     2  4 mbp2-2.local.    192.168.177.20   120
     3:39:18.028  Add     2  4 mbp2-3.local.    192.168.177.28   120
     3:39:18.028  Add     2  4 mbp2-7.local.    192.168.177.31   120
^C

Voila!, a list of IP addresses alongside the fully qualified (Bonjour) host names....

You could of course also run something like:

ippfind _ipp._tcp,_universal --exec echo  '{service_hostname}' \;  \
    | while read line; do ping -c 1 "$line" ; done                 \
    | grep PING

PING mbp2-2.local (192.168.177.20): 56 data bytes
PING mbp2-3.local (192.168.177.28): 56 data bytes
PING mbp2-7.local (192.168.177.31): 56 data bytes

(for example, if dns-sd is not readily available, like on Windows), and it will also report the IP addresses (simply because ping needed and resolved them and also reports them).


(I admit: I did not test this with real AirPrint devices -- I simply have none available. I did it with simulated ones. But I would be surprised if this didn't work as well in the environment the OP works with...)

Solution 3:

Here is another answer. It's shorter, and more direct to the point. However, I'll let the first answer stand on its own, since it may be useful for people who are exploring this topic.


Currently, I only know an answer for Linux.... If I find a command for Mac + dns-sd, I'll extend this answer.

On Linux, run this command:

kp@zdv-linux-003:>  avahi-browse -rt _universal._sub._ipp._tcp

  +  wlan1 IPv4 AirPrint Demo (Dummy Drucker)                 Internet Printer     local
  =  wlan1 IPv4 AirPrint Demo (Dummy Drucker)                 Internet Printer     local
     hostname = [zdv-linux-003]
     address = [192.168.177.20]
     port = [632]
     txt = ["URF=V1.2,DM3,OF1-2-3-4,CP99,W8,OB10,PQ3-4-5,ADOBERGB24,DEVRGB24,DEVW8,SRGB24,IS1-2-4,MT1-2-3-5-12,RS600" \
            "pdl=application/pdf,image/urf,image/jpeg,image/pwg-raster" \
            "usb_CMD=" "usb_MDL=" "usb_MFG=" "Transparent=T" "TBCP=T" \
            "Product=" "Staple=T" "Sort=T" "Punch=2" "PaperCustom=T" \
            "PaperMax=isoC-A2" "Duplex=T" "Copies=T" "Color=T" \
            "Collate=T" "Bind=T" "Fax=F" "Binary=T" "Transparent=T" \
            "DUUID=12345678-9ABC-DEF0-1234-56789ABCDEF0" \
            "UUID=533f7ac6-1c37-11e6-ac21-ffa8e4bdcbf9" "TLS=1.2" \
            "printer-type=0x0480FFFC" "printer-state=3" \
            "product=Generic PDF PPD" "priority=1" \
            "adminurl=mailto:[email protected]" \
            "kind=disc,label,large-format,postcard,receipt,roll,document,envelope,photo" \
            "air=none" "air=username,password" "note3=" \
            "note2=(totally dummy and fake device)" \
            "note=Virtueller Drucker für Demos von IPP-Everywhere in Room 3a/3b" \
            "ty=Kurt Pfeifle Handmade Model" "rp=printers/DummyAirPrint" \
            "qtotal=1" "txtvers=1"]

As you can see, the service type _universal._sub._ipp._tcp will display AirPrint devices, and the -r parameter will resolve it and reveal the IP address 192.168.177.20.


Solution 4:

There's a fairly painless way of doing this with the perl module Net::Bonjour:

#!/usr/bin/perl

use Net::Bonjour;
use warnings;
use strict;

my $res = Net::Bonjour->new('printer');

print "Name\t\t\tAddress\tPort\n";
foreach my $entry ( $res->entries) {
    print join ("\t", $entry->name , $entry->address , $entry->port) , "\n";
}

This will list the names, ip addresses and ports of all the Bonjour enabled printers on the network, not just the AirPrint ones. It works on Mac, Windows and Linux.