我有以下设置:
- 局域网上的打印机 #1
- LAN 上的打印机 #2
- 面向互联网的 Debian Apache 2.2 Web 服务器
server-external-ip
,我想将其用作两台打印机的 IPP 网关
可以通过以下 IPP URL 访问这两台打印机(从 LAN 和 Apache 服务器):
http://printer-1-local-ip/printer
http://printer-2-local-ip/printer
(打印机并未物理连接到 Web 服务器。)
我希望可以通过以下 URL 从 Internet 访问它们:
http://server-external-ip/prn1
http://server-external-ip/prn2
IPP 仅通过对打印机地址的 HTTP 请求进行工作(即,整个打印过程通过 POST 请求在http://打印机-X-本地-ip/打印机URL),所以我只需要重定向(即,反向代理使用 Apache) 上面的 URL 1 和 2。
Apache 正在提供其他内容,因此我无法用自定义程序(例如 netcat 或 netsed)替换它。此外,我无法在其他端口上运行自定义程序,因为打印机客户端只能通过端口 80 访问服务器。
然后我尝试了以下 Apache 配置:
RewriteRule ^/prn1$ http://printer-1-local-ip:80/printer [P]
ProxyPassReverse /prn1 http://printer-1-local-ip
将 Windows 客户端连接到http://服务器外部ip/prn1URL,反向代理可以工作。但 IPP 协议还会向打印机(在 POST 数据内)发送完整的设备 URL。
这意味着打印机收到一个明确的 IPP 请求http://服务器外部ip/prn1打印机,而不是其正确的地址(http://printer-1-local-ip/printer)所以它拒绝连接。
我将此条目添加到 Windows 客户端的 HOST 文件中:
server-external-ip printer-dns-name
但它仍然不起作用,因为打印机收到 IPP 请求http://打印机的 DNS 名称/prn1服务名称仍然错误(例如prn1代替打印机)。
我无法更改反向代理网址http://服务器外部ip/prn1到http://服务器外部 IP/打印机因为我必须提供对两台打印机的访问权限(并且我无法更改打印机打印机配置中的服务名称)。
我想要做的是破坏通过 HTTP POST 发送到打印机的 IPP 数据以替换http://服务器外部ip/prnX和http://打印机-X-本地-ip/打印机(IPP 协议中没有校验和,从我捕获的数据包来看,这应该可以工作)。
问题是,我用 Google 搜索到的所有 Apache 模块都无法帮助你处理 HTTP请求体发送到反向代理打印机。mod_rewrite
仅适用于标题、mod_substitute
适用于响应主体、mod_headers
适用于请求和响应标题、mod_replace
适用于除请求主体之外的所有内容等。
我mod_substitute
尝试了以下方法:
<Location />
AddOutputFilterByType SUBSTITUTE application/ipp
Substitute "s|server-external-ip/prn1|printer-1-local-ip/printer|"
</Location>
但是,正如预期的那样,它在响应主体上工作得很好,但在代理请求上却不行(我检查了代理到另一台服务器)。还要注意的是,IPP 请求属于应用程序/ippMIME 类型,因此过滤不会(显著)影响正常流量。
有没有什么办法可以解决这个问题?我觉得应该有一个简单的解决方案,但我没有用正确的方式看待问题。这就是为什么我要向这个一直很棒的社区询问(我还没有在这里发帖,但我是这里的长期粉丝)。
我希望继续使用这种“重定向方法”,因此只有在没有直接解决方案的情况下,变通方法才有用。是的,我可以为此修改 Apache 模块,但我真的不想这样做... :-)
与此同时,我会尝试一些网状魔法... :-)
答案1
为什么不这样做:为您的外部打印机定义两个 DNS 名称,例如。
printer-1-external.mydomain.com CNAME external-server.mydomain.com
printer-2-external.mydomain.com CNAME external-server.mydomain.com
您甚至可以使用与内部相同的名称。让内部 DNS 将打印机名称直接解析为打印机,让外部 DNS 解析为外部 IP...
在您的服务器上添加两个基于名称的虚拟主机:
<VirtualHost *:80>
ServerName printer-1-external.mydomain.com
ProxyPass / http://printer-1-local-ip/
</VirtualHost>
<VirtualHost *:80>
ServerName printer-2-external.mydomain.com
ProxyPass / http://printer-2-local-ip/
</VirtualHost>
这样,您的 IPP 请求http://printer-2-external.mydomain.com/printer将在其发布参数中具有正确的服务名称。
答案2
抱歉,我无法添加评论,但是,如果您还没有添加评论,请检查是否:
ProxyPreserveHost On
在您的conf文件中设置。
重写的方法对于上下文根来说很好,但是对于主机名问题,听起来您可能需要检查 ProxyPreserveHost。