2013年10月22日 星期二

[Python] 使用 PyICAP 淺玩 ICAP 與 Squid (以 Response Modification / RESPMOD 為例) @ Ubuntu 12.04

最近在研究 Internet Content Adaptation Protocol (ICAP),這東西好玩之處是可以跟 Proxy server 整再一起,當 proxy 幫 client 去要資料前後,可以透過 ICAP 來將資料加工處理一下。此協定主要可分成兩種資料流:Request Modification 和 Response Modification,直接看圖最清楚:

Request Modification:

Request Modification

Response Modification:

Response Modification

在 Ubuntu 中,可以用 apt-cache search icap 可以看到少少的套件可以把玩(用病毒掃描、限制網址瀏覽等),舉例來說,當使用者要瀏覽一個惡意網站前,可以先阻擋下來;當使用者下載完一個檔案時,可以幫忙掃描,若是病毒則可以擋下。至於我想把玩的主因之一是跟人閒聊一些免費 AP 時,很好奇它是怎樣做到幫網頁加料的,也就是用了他們家的 AP 後,瀏覽的網頁都會多個廣告,以此為目標加以進行下,此為 Response Modification 例子。

首先感謝 pyicap 這小又不簡單的 framework (ICAP 說難不難,說簡單也不簡單,詳請請看 RFC 3507),再次感謝作者佛心分享,依照著內附的 example/respmod_copy.py 小改一下,實作方向此:

  • 告訴 ICAP-client (Squid) 不要對 HTML, HTM 做 preview
  • 挑出 content-type 是 HTML 出來
  • 處理 HTTP 資料,將 gzip 的解開
  • 更新 <body> 資料
  • 將資料在壓成 gzip 後丟出去

片段程式碼(完整版):

#!/bin/env python
# -*- coding: utf8 -*-

import random
import SocketServer

from pyicap import *

import StringIO
import gzip
import re

#...

class ICAPHandler(BaseICAPRequestHandler):

def example_OPTIONS(self):
# ...
self.set_icap_header('Transfer-Complete', 'html,htm')
# ...

def example_RESPMOD(self):
# ...
if self.preview:
# ...
elif analysis_flag:
# ...
try:
orig_data = ''
if content_encoding in ('gzip', 'x-gzip', 'deflate'):
if content_encoding == 'deflate':
data = StringIO.StringIO(zlib.decompress(raw))
else:
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(raw))
orig_data = data.read()

#formated_out = orig_data.replace( "<body>", """
formated_out = re.sub(r"(<body[^>]*>)", """
<body>
<!-- src from: http://zh-yue.wikipedia.org/wiki/%E4%B8%96%E7%95%8C%E4%B8%89%E5%A4%A7%E5%A4%9C%E6%99%AF -->
<center><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Victoria_Harbour_around_Chinese_New_Year_Night_with_Fireworks_and_Laser_Show.jpg/1024px-Victoria_Harbour_around_Chinese_New_Year_Night_with_Fireworks_and_Laser_Show.jpg" /></center>
""", orig_data )

data = StringIO.StringIO()
f = gzip.GzipFile(fileobj=data, mode='w')
f.write(formated_out)
f.close()

self.write_chunk( data.getvalue() )

need_output = False

except Exception, e:
print e

if need_output:
self.write_chunk(raw)

# ...


Squid 設定(/etc/squid3/squid.conf):

icap_enable on
icap_send_client_ip on
icap_send_client_username on
icap_client_username_encode off
icap_client_username_header X-Authenticated-User
icap_preview_enable on
icap_preview_size 1024
#icap_service service_req reqmod_precache bypass=1 icap://127.0.0.1:13440/squidclamav
#adaptation_access service_req allow all
icap_service service_resp respmod_precache bypass=1 icap://127.0.0.1:13440/example
adaptation_access service_resp allow all


成果,瀏覽一則 Yahoo 新聞時,最上頭被植入一個張圖檔(紅色框框):

Response Modification example

沒有留言:

張貼留言