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...
- ...all AirPrint devices will announce themselves as
_ipp._tcp
(not_airprint._tcp
). Also, it looks like... - ...you can identify AirPrint devices by looking for the
TXT
record ofurf="$anything"
andpdl="$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?"
- First, list all IPP printers.
- 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:
- The fake device will still appear as an IPP printer in the DNS-SD/Bonjour browse lists.
- 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.