Apache mod_substitute 对反向代理主机的 HTTP 请求

Apache mod_substitute 对反向代理主机的 HTTP 请求

我有以下设置:

  • 局域网上的打印机 #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 访问它们:

  1. http://server-external-ip/prn1
  2. 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/prn1http://服务器外部 IP/打印机因为我必须提供对两台打印机的访问权限(并且我无法更改打印机打印机配置中的服务名称)。

我想要做的是破坏通过 HTTP POST 发送到打印机的 IPP 数据以替换http://服务器外部ip/prnXhttp://打印机-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。

http://httpd.apache.org/docs/2.2/vhosts/examples.html

相关内容