如何反向代理原始TCP数据包

我正在devise一个系统,远程设备将状态更新安全地发送到中央日志logging服务器进行聚合。 在服务器上,我使用了Redis + Logstash + Elasticsearch解决scheme。 发送到服务器的数据是敏感的,必须encryption。 我正在努力寻找一种有效和安全的方法来将日志“加载”到Redis列表中。

这些设备目前能够将以下Redis命令直接发送到端口6379。

"*3\r\n$5\r\nLPUSH\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"

正确的密钥和列表条目是在服务器上的Redis中创build的。

下一步是将redis放在防火墙后面并对数据包进行encryption。 我目前的尝试是使用Apache作为反向代理。 设备将与Apachebuild立双向SSL连接,然后使用回送接口将已消耗的信息反向代理到端口6379。 双向SSL连接没有问题,并且将消息转发给Redis。 不幸的是,这不是设备发送的消息。 tcpdump告诉我以下…

tcpdump -nnXvv -i lo host localhost and port 6379

 127.0.0.1.48916 > 127.0.0.1.6379: Flags [P.], cksum 0xfeab (incorrect -> 0x9415), seq 1:132, ack 1, win 1025, options [nop,nop,TS val 299310518 ecr 299310518], length 131 0x0000: 4500 00b7 12b7 4000 4006 2988 7f00 0001 E.....@.@.)..... 0x0010: 7f00 0001 bf14 18eb ce9c 0f04 e920 abec ................ 0x0020: 8018 0401 feab 0000 xxxx xxxx xxxx xxxx ................ 0x0030: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx ....*3./.HTTP/1. 0x0040: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1..Host:.localho 0x0050: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx st:6379..X-Forwa 0x0060: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx rded-For:.xx.xxx 0x0070: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx .xxx.xxx..X-Forw 0x0080: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx arded-Server:.xx 0x0090: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx .xxx.xxx.xx..Con 0x00a0: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx nection:.Keep-Al 0x00b0: xxxx xxxx xxxx xx ive.... 

从ASCII转换中可以看出,Apache在* 3之后的第一个CRLF处截断了消息,并附加了用于转发的HTTP标头信息,正如所假设的那样。 当然,由于Redis不再使用Redis序列化协议(RESP)格式化消息,所以Redis正在回复一个错误。

1)有没有办法configurationApache来盲目转发原始的TCP数据包?

2)如果没有,这个问题是否有标准的开源解决scheme?

感谢您的时间!

如果一切正常,除了从Apache到头文件的附录,那么你可以通过mod_headersclosures这些: http ://httpd.apache.org/docs/2.2/mod/mod_headers.html

虽然我的直觉告诉我,Apache + PHP不是一个最佳的解决scheme,但这是一个快速而令人满意的解决scheme。 Apache将HTTP消息发送到提取post的PHP脚本,并使用回送接口将其转发到redis。 对于“后代”,我已经在这里粘贴了脚本的骨架版本。

 <?php $file = fopen("/some/logging.txt","a"); $entityBody = file_get_contents('php://input'); $redisSocket = fsockopen("localhost", 6379, $errno, $errstr, 30); if (!$redisSocket) { fwrite($file, "Error: $errstr ($errno)\n"); } else { fwrite($redisSocket, "$entityBody"); $redisResponse = fgets($redisSocket); if (!$redisResponse) { fwrite($file, "No response from Redis"); } else { fwrite($file, "Redis Response: $redisResponse"); } } ?> 

我尽量避免用脚本粘在一起,但是到目前为止,它还提供了额外的好处,允许我检查input数据的完整性,并创build自定义日志和响应。