Skip to content

Commit

Permalink
feat: 🎸 all events are supported
Browse files Browse the repository at this point in the history
  • Loading branch information
monlor committed Aug 6, 2024
1 parent 46c8f0c commit c39255c
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 34 deletions.
10 changes: 7 additions & 3 deletions mitmproxy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ FROM mitmproxy/mitmproxy
LABEL MAINTAINER [email protected]
LABEL VERSION 1.0.0

RUN apt-get update && apt-get install -y curl && \
RUN apt-get update && apt-get install -y curl nginx && \
pip install requests

COPY mitmproxy.py /mitmproxy.py

EXPOSE 8080 8081
COPY nginx.conf /etc/nginx/nginx.conf

ENTRYPOINT ["mitmweb", "--web-host", "0.0.0.0", "--web-port", "8081", "--listen-port", "8080", "-s", "/mitmproxy.py"]
COPY --chmod=755 entrypoint.sh /

EXPOSE 80 8080 8081

ENTRYPOINT [ "/entrypoint.sh" ]
4 changes: 3 additions & 1 deletion mitmproxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export SCRIPT_UPDATE_INTERVAL=300 # 可选,默认为300秒

## Port

8080,8081
ui: 80,8080

proxy: 8081

## Rmote script

Expand Down
18 changes: 18 additions & 0 deletions mitmproxy/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

# 设置环境变量
export MITMPROXY_USER=${MITMPROXY_USER:-""}
export MITMPROXY_PASS=${MITMPROXY_PASS:-""}

# 构建 mitmweb 命令
MITMWEB_CMD="mitmweb --web-host 0.0.0.0 --web-port 8081 --listen-port 8080 -s /mitmproxy.py $@"

# 如果设置了用户名和密码,添加代理认证
if [ -n "$MITMPROXY_USER" ] && [ -n "$MITMPROXY_PASS" ]; then
MITMWEB_CMD="$MITMWEB_CMD --proxyauth $MITMPROXY_USER:$MITMPROXY_PASS"
fi

nginx -g 'daemon off;' &

# 执行 mitmweb 命令
exec $MITMWEB_CMD
102 changes: 74 additions & 28 deletions mitmproxy/mitmproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,109 @@
import os
import time
import threading
import base64
from mitmproxy import ctx

class CustomMitmProxy:
def __init__(self):
self.username = os.environ.get('MITMPROXY_USER', '')
self.password = os.environ.get('MITMPROXY_PASS', '')
self.auth_enabled = bool(self.username)
self.remote_script_url = os.environ.get('REMOTE_SCRIPT_URL', '')
self.remote_script = None
self.update_interval = int(os.environ.get('SCRIPT_UPDATE_INTERVAL', 300)) # 默认5分钟
self.last_update_time = 0
self.timeout = int(os.environ.get('SCRIPT_REQUEST_TIMEOUT', 10)) # 默认10秒

if self.remote_script_url:
self.load_remote_script() # 启动时立即更新远程脚本
self.start_update_thread()

def request(self, flow: http.HTTPFlow) -> None:
if self.auth_enabled:
if not self.authenticate(flow):
flow.response = http.Response.make(
407, b"Authentication required", {"Proxy-Authenticate": "Basic"}
)
return
self.handle_event(flow, 'request')

if self.remote_script_url and self.remote_script:
self.execute_remote_script(flow)
def response(self, flow: http.HTTPFlow) -> None:
self.handle_event(flow, 'response')

def authenticate(self, flow: http.HTTPFlow) -> bool:
auth_header = flow.request.headers.get("Proxy-Authorization")
if auth_header:
try:
scheme, user_pass = auth_header.split()
username, password = base64.b64decode(user_pass.encode()).decode().split(":")
if username == self.username and password == self.password:
return True
except Exception as e:
ctx.log.error(f"Authentication error: {e}")
return False
def client_connected(self, client):
self.handle_event(client, 'client_connected')

def client_disconnected(self, client):
self.handle_event(client, 'client_disconnected')

def server_connect(self, data):
self.handle_event(data, 'server_connect')

def server_connected(self, data):
self.handle_event(data, 'server_connected')

def server_disconnected(self, data):
self.handle_event(data, 'server_disconnected')

def tcp_start(self, flow):
self.handle_event(flow, 'tcp_start')

def tcp_message(self, flow):
self.handle_event(flow, 'tcp_message')

def tcp_error(self, flow):
self.handle_event(flow, 'tcp_error')

def tcp_end(self, flow):
self.handle_event(flow, 'tcp_end')

def http_connect(self, flow):
self.handle_event(flow, 'http_connect')

def websocket_handshake(self, flow):
self.handle_event(flow, 'websocket_handshake')

def websocket_start(self, flow):
self.handle_event(flow, 'websocket_start')

def websocket_message(self, flow):
self.handle_event(flow, 'websocket_message')

def websocket_error(self, flow):
self.handle_event(flow, 'websocket_error')

def websocket_end(self, flow):
self.handle_event(flow, 'websocket_end')

def next_layer(self, layer):
self.handle_event(layer, 'next_layer')

def configure(self, updated):
self.handle_event(updated, 'configure')

def done(self):
self.handle_event(None, 'done')

def load(self, loader):
self.handle_event(loader, 'load')

def running(self):
self.handle_event(None, 'running')

def handle_event(self, flow, event_type):
if self.remote_script_url and self.remote_script:
self.execute_remote_script(flow, event_type)

def load_remote_script(self):
if self.remote_script_url:
try:
response = requests.get(self.remote_script_url)
response = requests.get(self.remote_script_url, timeout=self.timeout)
if response.status_code == 200:
self.remote_script = response.text
ctx.log.info("Remote script updated successfully.")
else:
ctx.log.error(f"Failed to load remote script. Status code: {response.status_code}")
except Exception as e:
except requests.exceptions.Timeout:
ctx.log.error(f"Request to {self.remote_script_url} timed out.")
except requests.exceptions.RequestException as e:
ctx.log.error(f"Failed to load remote script: {e}")

def execute_remote_script(self, flow):
def execute_remote_script(self, flow, event_type):
try:
exec(self.remote_script, {'flow': flow})
exec(self.remote_script, {'flow': flow, 'event_type': event_type})
except Exception as e:
ctx.log.error(f"Error executing remote script: {e}")
ctx.log.error(f"Error executing remote script for {event_type}: {e}")

def update_script_periodically(self):
while True:
Expand Down
28 changes: 28 additions & 0 deletions mitmproxy/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name localhost;

location / {
proxy_pass http://localhost:8081;
proxy_set_header Host localhost:8081;
proxy_set_header Origin http://localhost:8081;

expires off;
proxy_http_version 1.1;
proxy_redirect http://$http_host:8081 http://$http_host;
proxy_buffering off;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
102 changes: 100 additions & 2 deletions mitmproxy/test.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,100 @@
def request(flow):
flow.request.headers["Custom-Header"] = "Custom-Value"
def handle_event(flow, event_type):
print(f"Event: {event_type}")

if event_type == 'request':
# 处理请求
# 可以修改请求头、URL、方法等
flow.request.headers["X-Custom-Request-Header"] = "CustomRequestValue"
print(f"Request URL: {flow.request.url}")

elif event_type == 'response':
# 处理响应
# 可以修改响应头、内容、状态码等
flow.response.headers["X-Custom-Response-Header"] = "CustomResponseValue"
print(f"Response status code: {flow.response.status_code}")

elif event_type == 'client_connected':
# 客户端连接时触发
print(f"Client connected: {flow}")

elif event_type == 'client_disconnected':
# 客户端断开连接时触发
print(f"Client disconnected: {flow}")

elif event_type == 'server_connect':
# 服务器连接开始时触发
print(f"Server connecting: {flow}")

elif event_type == 'server_connected':
# 服务器连接建立时触发
print(f"Server connected: {flow}")

elif event_type == 'server_disconnected':
# 服务器断开连接时触发
print(f"Server disconnected: {flow}")

elif event_type == 'tcp_start':
# TCP连接开始时触发
print(f"TCP connection started: {flow}")

elif event_type == 'tcp_message':
# 收到TCP消息时触发
print(f"TCP message: {flow}")

elif event_type == 'tcp_error':
# TCP连接出错时触发
print(f"TCP error: {flow}")

elif event_type == 'tcp_end':
# TCP连接结束时触发
print(f"TCP connection ended: {flow}")

elif event_type == 'http_connect':
# 处理HTTP CONNECT请求
print(f"HTTP CONNECT: {flow}")

elif event_type == 'websocket_handshake':
# WebSocket握手完成时触发
print(f"WebSocket handshake: {flow}")

elif event_type == 'websocket_start':
# WebSocket连接开始时触发
print(f"WebSocket started: {flow}")

elif event_type == 'websocket_message':
# 收到WebSocket消息时触发
print(f"WebSocket message: {flow.websocket.messages[-1].content}")

elif event_type == 'websocket_error':
# WebSocket连接出错时触发
print(f"WebSocket error: {flow}")

elif event_type == 'websocket_end':
# WebSocket连接结束时触发
print(f"WebSocket ended: {flow}")

elif event_type == 'next_layer':
# 用于协议嗅探和动态协议切换
print(f"Next layer: {flow}")

elif event_type == 'configure':
# 配置发生变化时触发
print(f"Configuration changed: {flow}")

elif event_type == 'done':
# addon关闭时触发
print("Addon is shutting down")

elif event_type == 'load':
# addon首次加载时触发
print(f"Addon loaded: {flow}")

elif event_type == 'running':
# 代理完全启动并运行时触发
print("Proxy is running")

# 可以根据需要添加更多的事件处理逻辑
# 例如,可以在这里添加日志记录、数据分析或其他自定义操作

# 主执行点
handle_event(flow, event_type)

0 comments on commit c39255c

Please sign in to comment.