Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advertising services on the local machine #125

Open
lathiat opened this issue May 20, 2017 · 15 comments

Comments

Projects
None yet
3 participants
@lathiat
Copy link
Owner

commented May 20, 2017

It is desirable to support advertising services but only to the local machine, and not to advertise them to the network.

The specific use case is the IPPUSBXD project (https://github.com/tillkamppeter/ippusbxd/)

Currently we disable the loopback interface unless no other interfaces are activated. We should consider just enabling it at all times - there also seems to be a problem with the lo.IPv6 interface at least in avahi-discover it does not appear which is surprising.

Review the usage of loopback and figure out how to handle this nicely. One drawback to always advertising it is that local services will always appear 'twice' from 2 interfaces even on single interface machines. We could potentially not advertise services on loopback unless specifically requested, or not worry about it since we need to improve duplicate names on multiple interfaces anyway since we enabled IPv6 by default.

@lathiat lathiat added this to the v0.6.33 milestone May 20, 2017

@tillkamppeter

This comment has been minimized.

Copy link

commented May 20, 2017

Duplicate appearing of services I have already without "lo" support. My laptop runs the Virtual Machine Manager (libvirt-based) and this creates a bridge network interface ("virbr") to provide network for the VMs by a kind of virtual NAT router. This makes all local CUPS queues (and other services from my laptop) already appearing under two interfaces. The same happens if you connect wired and wireless network simultaneously.
So for me it looks common having a service appearing in avahi-discover more than once. So I assume that clients must be able to handle it.

@tillkamppeter

This comment has been minimized.

Copy link

commented May 20, 2017

Attaching the patch which makes entries on the "lo" interface being advertised, as suggested in the documentation of ippusbxd. Note that more work on Avahi is needed.

list-lo-entries.diff.txt

@tillkamppeter

This comment has been minimized.

Copy link

commented May 21, 2017

My problem is that if I apply my patch, the IPP-over-USB printer gets advertised (on the "lo" interface) and one can see it in the output of avahi-discover. The record shows its address with the correct IP, 127.0.0.1, but not with the hostname "localhost". Instead, the network host name of my laptop is shown, something like "XXX.local". So CUPS or cups-browsed (when not configured to use only IP addresses and no host names) try to access the printer via the URI "ipp://XXX.local:60000/ipp/print" (Note that ippusbxd uses port 60000 here as the standard IPP port 631 is already occupied by CUPS) and fail, as XXX.local is resolved to the laptop's network IP address and not to 127.0.0.1. Configuring cups-browsed to use only IP addresses makes it successfully using the URI "ipp://127.0.0.1:60000/ipp/print".
This needs to get solved in Avahi, as especially CUPS wants to be as standard-conforming as possible and not make exceptions for services on localhost. In addition, I also want to stop using the IP-address workaround with cups-browsed.

@tillkamppeter

This comment has been minimized.

Copy link

commented May 21, 2017

By the way, when applying my patch, avahi-discover shows only the "lo"-interface entries for IPv4 and not for IPv6. ippusbxd supports both IPv4 and IPv6 and CUPS and cups-browsed, too.

@lathiat lathiat modified the milestones: v0.7, v0.8 Jul 13, 2017

@tillkamppeter

This comment has been minimized.

Copy link

commented Dec 6, 2017

@rithvikp1998 has found a solution for the problem described here by adding a single-line change to my patch. With this, services from "lo" get advertised with "localhost" as server host name. This way said IPP-over-USB printers get correctly set up by CUPS and cups-browsed.
Patch attached:
local-only-services-support.patch.txt

tillkamppeter added a commit to tillkamppeter/avahi that referenced this issue Dec 15, 2017

Add support to advertise local services ("localhost") on the local ma…
…chine only

This is the patch attached to Issue lathiat#125 (on Dec 6, 2017) and also
shown in the readme.md of ippusbxd
(https://github.com/OpenPrinting/ippusbxd).

It makes also services on the loopback ("lo") interface being
advertised and these records use "localhost" instead of the network
host name of the machine as server host name. This way clients, like
for example CUPS or cups-browsed will find these local services and be
able to work with them as they were network services.
@tillkamppeter

This comment has been minimized.

Copy link

commented Dec 15, 2017

Created pull request #161 applying my current patch.

@tillkamppeter

This comment has been minimized.

Copy link

commented Dec 13, 2018

@lathiat, we urgently need this patch being adopted upstream in Avahi to implement standard-conforming printing. It is not only needed for IPP-over-USB using ippusbxd (https://github.com/OpenPrinting/ippusbxd) but also for the future format of printer and scanner drivers, the Printer Applications, which are daemons emulating a driverless IPP printer (and/or scanner) on localhost and communicate with the printer hardware. These applications will also advertise themselves via DNS-SD and, like ippusbxd, they have to do it local-machine-only on localhost, which is supported by Avahi if this patch is applied.
In Ubuntu we carry the patch as a distro patch for more than a year now and we did not get any complaints about it, neither bug reports nor security advisories.
Debian is not adopting the patch with the reasoning that it is not upstream in Avahi (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=909564), so standard-conforming printing is not possible with Debian currently.
See also following slides in OpenPrinting Summit/PWG Meeting presentations:

@msekletar

This comment has been minimized.

Copy link
Contributor

commented Feb 14, 2019

@tillkamppeter I'd be happy to pull down the patch to Fedora too if upstream doesn't move forward on this.

@tillkamppeter

This comment has been minimized.

Copy link

commented Feb 14, 2019

@msekletar, please go ahead using it as a distro patch for now to make also Fedora/Red Hat supporting the current IPP printing standards and to get a larger user base for the patch.

@tillkamppeter

This comment has been minimized.

Copy link

commented Feb 25, 2019

@lathiat, you promised to apply this (pull request #161) in Malta. Could you soon do it? Thanks.

@lathiat

This comment has been minimized.

Copy link
Owner Author

commented Mar 28, 2019

The blocker for me to accept this patch, is that I don't think it is acceptable to hack the hostname of services on loopback to be "localhost". I am potentially fine with the half of the patch that enables the loopback interface. On Mac OS X, though, they don't enable the loopback interface unless all other interfaces are down. And that's nicer behaviour because it means that local services don't appear twice on two interfaces on systems with a basic single interface configuration.

My problem is that if I apply my patch, the IPP-over-USB printer gets advertised (on the "lo" interface) and one can see it in the output of avahi-discover. The record shows its address with the correct IP, 127.0.0.1, but not with the hostname "localhost". Instead, the network host name of my laptop is shown, something like "XXX.local". So CUPS or cups-browsed (when not configured to use only IP addresses and no host names) try to access the printer via the URI "ipp://XXX.local:60000/ipp/print" (Note that ippusbxd uses port 60000 here as the standard IPP port 631 is already occupied by CUPS) and fail, as XXX.local is resolved to the laptop's network IP address and not to 127.0.0.1. Configuring cups-browsed to use only IP addresses makes it successfully using the URI "ipp://127.0.0.1:60000/ipp/print".
This needs to get solved in Avahi, as especially CUPS wants to be as standard-conforming as possible and not make exceptions for services on localhost. In addition, I also want to stop using the IP-address workaround with cups-browsed.

In the same way that CUPS does not necessarily want to make exceptions for localhost only services in order to be standards conforming, we have the same problem in Avahi. You want to add the same localhost-exception to avahi that you don't want to add to CUPS. So hopefully you can understand from that point of view why from the outset it doesn't seem right.

Given that you are implementing this IPP behaviour which is using localhost (and one of the few cases where mDNS services are used from localhost) I would argue it makes more sense to put such logic in CUPS, if it was to be put anywhere.

The entire call path within avahi for browsing service types and resolving a specific service returns the interface index ('scope') for that specific service. If a service exists on multiple interfaces, when you resolve it, you get multiple callbacks for each interface with the interface ID. And then when you query for the IP address for the hostname, whether through the avahi resolver or the glibc gethostbyname interface - you should send that same scope ID to ensure you get the IP of the relevant interface. This is actually important for link-local IPv6 services, if you don't set that scope ID, you won't be able connect.

Technically, these are actually unique services, because Avahi/mDNS has no way of knowing if "Brother Printer" on 1 interface is the same "Brother Printer" as on another interface. It's possible to be on 2 distinct networks, with two devices with the same name. In reality that doesn't happen most of the time, but it is possible. Ideally a selection UI for services would let users select between interfaces and technically any UI that allows users to select a service, should let the user choose between the two interfaces. It should then keep and re-use that scope ID for future queries, which will ensure it gets an IP that is actually listening on that port.

Hence, ideally, cups should be remembering the interface scope and using that to query the IP. Of course, for normal network printers and the majority of network scenarios where the same service name doesn't exists on 2 separate networks that is actually 2 different devices, that may not be totally desirable since if you moved for example from wired to wireless, you might want to find the printer on either interface. So if you just used the hostname, that would work. Though arguably, you should/could have instead not re-used the "same" printer for both interfaces, but setup 2 different printers for each interface. On MacOSX you can actually encode the interface name/index in the hostname/URL, e.g. brother-printer.local%lo - unfortunately that does not currently work on Linux when passed direct to gethostbyname() - though that is something I have wanted to fix.

Another alternative would be to have cups enumerate all of the IP addresses for a host and try to connect to all of this. This also is something I would normally expect CUPS to do, particularly for example to correctly handle IPv4+IPv6 when perhaps that host only has connectivity to one of them.

The last alternative I can think of is that IPPUSBXD could not bind to localhost but instead bind to all interfaces but filter the connections to only accept connections from the local host.

I'll setup a reproducer with CUPS to observe it's behaviour with regards to name resolution, trying multiple IPs, etc.. and see if I can come up with a more concerete suggestion on fixing this from the CUPS side.

@lathiat

This comment has been minimized.

Copy link
Owner Author

commented Mar 28, 2019

To bring some clarity to the general situation, a device being on localhost is not the only place situations like this occur.

If a device has multiple IP addresses and a given service only listens on one of them, you also have this same kind of problem. That can be two IP addresses in different subnets but on the same network/interface, it can be having both an IPv4 and IPv6 address, or it could be that both the advertising and browsing device are both on two separate networks (but the service only listens on one of them). In all of these cases unless you use the extra information that Avahi gives you during service browse time (e.g. to then specify the interface and protocol to resolve the address on), you will get back multiple IPs and you need to try them all in order to find one that works.

So really the most straight forward solution would be to ensure that CUPS enumerates the hostname for multiple IP addresses and tries all of them. That is easily done even with the glibc resolving API directly looking up the hostname.local. That's part of what I'll check into with CUPS.

@lathiat

This comment has been minimized.

Copy link
Owner Author

commented Apr 4, 2019

I found this old bug which illustrates my point perfecty:
https://bugs.launchpad.net/ubuntu/+source/avahi/+bug/1099184
apple/cups#4305

The complaint is that when CUPS discovers a printer, it sometimes resolves the IPv6 address of the hostname - but the printer does not respond on IPv6 so the print fails.

This is why CUPS should be keeping track of the scope ID and address family firstly, or worst case, why it should fall back and try all of the IP addresses. As mentioned by the person that closed the bug - though - that person failed to understand that Avahi does provide this information, CUPS is currently not using it.

We can solve both that problem, and this one, with the same fix.

@tillkamppeter

This comment has been minimized.

Copy link

commented Apr 4, 2019

Trent, could you check whether cups-browsed does it right?

The resolve_callback() function in utils/cups-browsed.c of cups-filters contains the readout of interface name, host name, IP address, and address family from the Avahi message when a new printer appears. It actually works with ippusbxd also when the initial Avahi patch (without renaming the host name to "localhost"), IPv6 also works, but mentioned Launchpad bug not tested.

@tillkamppeter

This comment has been minimized.

Copy link

commented Apr 18, 2019

Trent, could you create a new Issue on CUPS upstream describing which changes are needed on CUPS in order to handle DNS-SD messages from services on the local machine (via "lo" interface) correctly? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.