I have the following setup:
- Printer #1 on LAN
- Printer #2 on LAN
- Internet facing Debian Apache 2.2 web server at
server-external-ip
that I want to use as an IPP gateway to the two printers
The two printers are reachable (from LAN and from the Apache server) at the following IPP URLs:
http://printer-1-local-ip/printer
http://printer-2-local-ip/printer
(The printers are not physically attached to the web server.)
I want them to be reachable from the Internet at the following URLs:
http://server-external-ip/prn1
http://server-external-ip/prn2
IPP works exclusively through HTTP requests to the printer address (i.e., the whole printing process happens through POST requests at the http://printer-X-local-ip/printer URLs), so I only need to redirect (i.e., reverse proxy with Apache) URLs 1 and 2 above.
Apache is serving other content, so I cannot replace it with a custom program (e.g., netcat or netsed). Also, I cannot run a custom program on a different port since the printer clients will only be able to reach the server at port 80.
Then I tried the following Apache configuration:
RewriteRule ^/prn1$ http://printer-1-local-ip:80/printer [P]
ProxyPassReverse /prn1 http://printer-1-local-ip
Connecting a Windows client to the http://server-external-ip/prn1 URL, the reverse proxy works. But the IPP protocol also sends to the printer (inside the POST-ed data) the full device URL.
This means that the printer receives an explicit IPP request for a http://server-external-ip/prn1 printer, and not for its correct address (http://printer-1-local-ip/printer). So it refuses the connection.
I added this entry into the HOST file at the Windows client:
server-external-ip printer-dns-name
But it still doesn't work since the printer receives an IPP request for http://printer-dns-name/prn1 which still has the wrong service name (i.e., prn1 instead of printer).
I cannot change the reverse proxy url from http://server-external-ip/prn1 to http://server‑external‑ip/printer since I have to provide access to both printers (and I can't change the printer service name in the printer configuration).
What I want to do is to mangle the IPP data HTTP POST-ed to the printer to substitute http://server‑external‑ip/prnX with http://printer-X-local-ip/printer (there are no checksums in the IPP protocol and from the packets I captured this should work).
The problem is that all the Apache modules I can google for won't help you in mangling HTTP request bodies sent to the reverse-proxied printer. mod_rewrite
works only on headers, mod_substitute
works on response bodies, mod_headers
works on request and response headers, mod_replace
works on everything but request bodies, etc.
With mod_substitute
I tried with the following:
<Location />
AddOutputFilterByType SUBSTITUTE application/ipp
Substitute "s|server-external-ip/prn1|printer-1-local-ip/printer|"
</Location>
But, as expected, it works perfectly on response bodies but not on proxied requests (I checked proxying to another server). Also note that IPP requests are of the application/ipp MIME type, so the filtering won't (significantly) impact normal traffic.
Any idea on how to solve this mess? I feel like there should be an easy solution and I'm not looking at things the right way. That's why I'm asking this always-awesome community (I have no posts here yet, but I'm a longtime fan).
I'd like to stay on this "redirection approach", so workarounds will be useful only if no direct solution exists. And yes, I could modify an Apache module for the purpose, but I don't really feel like it... :-)
In the meantime I'll try some netsed magic... :-)