-
Notifications
You must be signed in to change notification settings - Fork 330
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
Comments
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. |
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. |
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". |
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. |
@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. |
…chine only This is the patch attached to Issue avahi#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.
Created pull request #161 applying my current patch. |
@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. |
@tillkamppeter I'd be happy to pull down the patch to Fedora too if upstream doesn't move forward on this. |
@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. |
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.
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. |
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. |
I found this old bug which illustrates my point perfecty: 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. |
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. |
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. |
Concerning ippusbxd to not use "lo" but all the other interfaces instead, this would be really awkward as ippusbxd had to watch all the interfaces appearing and disappearing and to bing itself all the time to the available interfaces. Such an awkward technique I do not want to make the standard for ippusbxd and all IPP Printer/Scanner Applications. |
Trent, now it is already August and I am still waiting for your checks on CUPS you have promised and also the resulting Issue report on CUPS upstream. |
It is theoretically possible that ippusbxd would advertise its service on all interfaces (
Therefore the current architecture of ippusbxd represents best what one expects from a USB printer. The IPP-over-USB is not intended for automatic printer sharing but for driverless USB printing (CUPS sets up the printer automatically querying all needed information from the printer) and for configuring the printer hardware from the client through its web admin interface. |
For me it looks more consistent if the DNS-SD record produced by Avahi for the loopback ("lo") interface reports "localhost" as host name and not the host's network host name. You say in your first comment from March 28 you tell that a service which exists on multiple interfaces is reported independently for each interface and each of these DNS-SD reports are absolutely independent, it is even possible that different services can have the same service name and report on different interfaces.
gethostbyname only finds the non-loopback IP addresses when querying the network host name and not the loopback IPs 127.0.0.1 and ::1 whereas querying "localhost" only finds the 127.0.0.1 and ::1 IPs, so "till-x1yoga.local", "lo", and 127.0.0,1 / ::1 are not belonging together but "till-x1yoga.local" is the correct host name for any other interface's DNS-SD report. |
If a printer (device) advertises itself via DNS-SD on both IPv4 and IPv6 but only listens on IPv4 or generally advertises itself on network interface/network protocol/service type combos on which it is not listening this is a bug in the printer's (device's) firmware. In Avahi one cannot do much about it as Avahi is not checking each DNS-SD record for its validity (is communication accepted this way?). CUPS (or any other client) can only overcome such bugs by trying through the advertised combos until finding a working one, as already said here. |
If Avahi returns 127.0.0.1 as one of the addresses for a .local lookup, that will cause some serious security problems when machine A (a.local.) looks up machine B ("b.local.") and gets its own loopback address. By returning localhost ("localhost.") that security issue is avoided. Keep in mind as well that when CUPS tries to connect to a printer/server, it tries all of the addresses returned by a lookup in parallel until one of the connections succeeds. Since CUPS also validates the Host: header in requests (and block any attempt to communicate with cupsd over the loopback interface if the hostname is not "localhost" or "localhost."), this will result in a successful connection but a failed request, breaking printing. So you really do need to return "localhost" for services registered on the loopback interface. |
j
ср, 7 авг. 2019 г., 16:32 Michael R Sweet <notifications@github.com>:
… If Avahi returns 127.0.0.1 as one of the addresses for a .local lookup,
that will cause some serious security problems when machine A (a.local.)
looks up machine B ("b.local.") and gets its own loopback address. By
returning localhost ("localhost.") that security issue is avoided.
Keep in mind as well that when CUPS tries to connect to a printer/server,
it tries all of the addresses returned by a lookup in parallel until one of
the connections succeeds. Since CUPS also validates the Host: header in
requests (and block any attempt to communicate with cupsd over the loopback
interface if the hostname is not "localhost" or "localhost."), this will
result in a successful connection but a failed request, breaking printing.
So you really *do* need to return "localhost" for services registered on
the loopback interface.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#125>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AL5DSES5EBRDKIP6PBA7QKLQDLFINANCNFSM4DMEZCMA>
.
|
New findings -- I purchased a Deskjet 3700 which has IPP everywhere and did some further experimentation. For whatever reason when CUPS discovers an _ipp._tcp printer via mDNS (regardless of if it's IPPUSBXD based or not), it generates an ipp:// URL having resolved the hostname, e.g. ipp://optane.local:60000/ipp/print|HP DeskJet 3700 series This then means that when it later connects, it has lost the information about which interface index to resolve the hostname over. It tries to connect to one of the public IPs (or really, some IP at random) and fails. It would be possible in theory to add the interface index as optane.local%lo but there is so much manual URL handling I think this would be difficult and linux nss-mdns doesn't currently support this (though I plan to add it). However if you instead use a dnssd:// URL which CUPS already supports, then it will actually do the lookup using mDNS/Avahi at the time of printing already, and then correctly resolves the hostname using the interface index and prints successfully (tested with a real setup) without the localhost hack patch: If you have another kind of mDNS service such as _pdl-datastream._tcp CUPS already uses a URL in this form (e.g. when doing "add new printer"). But for whatever reason if it's an _ipp._tcp service it overrides to the ipp://hostname form instead. So I need to understand why CUPS is generating an ipp:// URL instead of a dnssd:// URL and if this is intentional for some reason - or otherwise I suspect it's probably an oversight but it would be great to know if there is some actual intentional reason for this from @michaelrsweet and @tillkamppeter as really this behaviour doesn't make sense to me - in all cases I think we should be doing the reference via dnssd and then letting CUPS make the IPP connection from there. I tried to trace what area of the CUPS code is doing this and failed - I couldn't logically follow it and then I tried tracing in gdb to understand the call flow and failed there I think largely because I could not figure out how to get gdb to reliably attach to the cups-deviced process that is forked from cupsd dynamically and that seems (at least I think) to be the one calling the functions that generate the URLs.. does anyone have a recipe for this? I tried setting "set follow-fork-mode child" and "set detach-on-fork off" but it seemed to just follow some fork early on and then lose the parent cupsd process. If we can make this work then all I need to do is merge the patch to actually allow publishing on the loopback interface which I am 100% happy to do - I am just not happy with monkeying the URL to localhost. As a side note for this testing largely I disabled cups-browsed and used the built-in cups code for dnssd browsing which appears to do the same thing more or less - should this functionality should be deprecated from cups-browsed or is it somehow a superset of the built-in functionality? In any case the fix applies whichever discovery path you are using. I think cups-browsed is using cups to generate the ipp:// URL so if we changed that it would fix both cases. So if I could get some input from here that'd be great otherwise perhaps we could open this as a bug over at CUPS now to discuss it?
|
@lathiat, I assume you are making pure CUPS observations, not running cups-browsed. Make sure you make all observations with cups-browsed NOT running for now.
I get
So the CUPS which I have installed (2.2.12-2ubuntu1 on Eoan/18.10) generates URIs with ipp: (or ipps:) and the DNS-SD service name, no resolved host name. Seems that the ipp CUPS backend resolves the host names/IPs/ports whenever they send off a job. |
I’m on Focal latest now, but I was getting the same hostname behaviour on Eoan. Curious that yours uses the dns-sd service name with ipp://. I was using ippusbxd from git when testing today though I’ll re-test with the Ubuntu version again when I’m at a machine next (which I had done before in the past) since it’s possible some flag it’s setting is changing what cups is doing. I’ll also share my cups config and a dump of what ippusbxd is doing. Using Ubuntu avahi (from focal) except I rebuilt and changed the patch not to switch out the hostname. And for what it’s worth when I was using cups-browsed with the implicitclass URL it sets up during printing it would get switched out for the same ipp://optane.local URL Curious would be good to know what drives CUPS to choose between the two. |
The version of ippusbxd, whether GIT or the Ubuntu package, has probably no influence. The changes are small. |
Here is my |
@lathiat, Michael Sweet is on an extended vacation, so we cannot wait for an answer from him. |
The driverless utility of cups-filters I have switched over to DNS-SD-service-name-based URIs now (commit in cups-filters). cups-browsed will follow soon. |
Also note that cups-browsed has a workaround for Avahi with the loopback device support but without the host name switch to "localhost", as the former is done by me several months earlier than the latter, done by one of my students. In the meantime I had made cups-browsed working only with the first part by switching the host name in the URIs by itself. |
@tillkamppeter Temporary queues use the resolved service name since the expectation is that the queue will go away. But queues created manually use the DNS-SD name. (the dnssd scheme is an artifact of the original macOS implementation, but we support DNS-SD service names for ipp:/ipps: URIs as well...) |
Also note that the IPP standard still defines the |
Big advantage of DNS-SD-service-name-based URIs is also that they are independent of the port, so that one does not need to take so much care that the Printer Applications take always the same port on each start. |
@michaelrsweet, when I have no cups-browsed running, ippusbxd running for a local IPP-over-USB printer,
CUPS version is 2.2.12 on Eoan. |
@michaelrsweet, does the resource of a DNS-SD-service-name-based URI has any meaning, or does one get to the same destination also without it?
and
mean the same? |
@tillkamppeter Yes, they are treated the same. |
cups-browsed is also switched over to DNS-SD-service-name-based URIs now (commit in cups-filters). |
Thanks, @michaelrsweet, in cups-browsed I let the URIs of remote CUPS queues have a |
Preparing to commit the patch to publish localhost service but just need to fix this issue first. |
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.
The text was updated successfully, but these errors were encountered: