├── HTTP ├── README.md └── src │ ├── .idea │ ├── .gitignore │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── src.iml │ └── vcs.xml │ ├── __pycache__ │ └── client.cpython-39.pyc │ ├── client.py │ ├── ip_num_test.py │ └── server.py └── README.md /HTTP/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Proxy 2 | ## 安装 3 | 需 Python >= 3.8 4 | ```bash 5 | python3 -m venv .venv 6 | source .venv/bin/activate 7 | pip3 install -r requirements.txt 8 | ``` 9 | 10 | ## 项目配置 11 | ### 函数配置 12 | 开通阿里云函数 FC, 在你想要的地区创建 HTTP 触发器触发的云函数, 将 server.py 的内容复制到 index.py 中, 点击部署. 13 | 14 | 记录下函数的公网访问地址, 填写进 client.py 中. (建议同时修改 Token.) 15 | 16 | 可以在多个地区部署多个云函数, 同时使用多个地址. 17 | 18 | 19 | ## 客户端配置 20 | 本项目基于 mitmproxy 提供本地代理,为代理 HTTPS 流量需安装证书。 21 | 运行 `mitmdump` 命令,证书目录自动生成在在 ~/.mitmproxy 中,安装并信任。 22 | 23 | 开启代理开始运行: 24 | ```bash 25 | mitmdump -s client.py -p 8081 --no-http2 26 | ``` 27 | 28 | 如在 VPS 上运行需将 `block_global` 参数设为 false 29 | ```bash 30 | mitmdump -s client.py -p 8081 --no-http2 --set block_global=false 31 | ``` 32 | 33 | ### ip 数量 34 | 经测试,单个地区服务器 200 个请求分配 ip 数量在 50 左右。 35 | 36 | ## 限制 37 | 1. 请求与响应流量包不能大于 6M 38 | 2. 可在云函数环境配置中修改执行超时时间 39 | 3. 因云函数限制不能进行长连接,仅支持代理 HTTP 流量 40 | 41 | ## 免责声明 42 | 此工具仅供测试和教育使用,请勿用于非法目的。 43 | -------------------------------------------------------------------------------- /HTTP/src/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /HTTP/src/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /HTTP/src/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /HTTP/src/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /HTTP/src/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HTTP/src/.idea/src.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HTTP/src/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /HTTP/src/__pycache__/client.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyc8503/fc-proxy/c4fb915e564166e99017bbad8ab574ab81fca81e/HTTP/src/__pycache__/client.cpython-39.pyc -------------------------------------------------------------------------------- /HTTP/src/client.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pickle 3 | from typing import List 4 | from random import choice 5 | from urllib.parse import urlparse 6 | from base64 import b64encode, b64decode 7 | 8 | import mitmproxy 9 | from mitmproxy.version import VERSION 10 | 11 | 12 | if int(VERSION[0]) > 6: 13 | from mitmproxy.http import Headers 14 | else: 15 | from mitmproxy.net.http import Headers 16 | 17 | 18 | scf_servers: List[str] = ["https://proxy-fc-proxhangzhou-qxdlrwmkbb.cn-hangzhou.fcapp.run"] 19 | SCF_TOKEN = "Token" 20 | 21 | 22 | def request(flow: mitmproxy.http.HTTPFlow): 23 | scf_server = choice(scf_servers) 24 | r = flow.request 25 | data = { 26 | "method": r.method, 27 | "url": r.pretty_url, 28 | "headers": dict(r.headers), 29 | "cookies": dict(r.cookies), 30 | "params": dict(r.query), 31 | "data": b64encode(r.raw_content).decode("ascii"), 32 | } 33 | 34 | flow.request = flow.request.make( 35 | "POST", 36 | url=scf_server, 37 | content=json.dumps(data), 38 | headers={ 39 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 40 | "Accept-Encoding": "gzip, deflate, compress", 41 | "Accept-Language": "en-us;q=0.8", 42 | "Cache-Control": "max-age=0", 43 | "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", 44 | "Connection": "close", 45 | "Host": urlparse(scf_server).netloc, 46 | "SCF-Token": SCF_TOKEN, 47 | }, 48 | ) 49 | 50 | 51 | def response(flow: mitmproxy.http.HTTPFlow): 52 | if flow.response.status_code != 200: 53 | mitmproxy.ctx.log.warn("Error") 54 | 55 | if flow.response.status_code == 401: 56 | flow.response.headers = Headers(content_type="text/html;charset=utf-8") 57 | return 58 | 59 | if flow.response.status_code == 433: 60 | flow.response.headers = Headers(content_type="text/html;charset=utf-8") 61 | flow.response.text = "操作已超过云函数服务最大时间限制,可在函数配置中修改执行超时时间" 62 | return 63 | 64 | if flow.response.status_code == 200: 65 | body = flow.response.content.decode("utf-8") 66 | resp = pickle.loads(b64decode(body)) 67 | 68 | r = flow.response.make( 69 | status_code=resp.status_code, 70 | headers=dict(resp.headers), 71 | content=resp.content, 72 | ) 73 | if resp.headers.get('Content-Encoding'): 74 | r.headers.insert(-1,"Content-Encoding",resp.headers['Content-Encoding']) 75 | 76 | flow.response = r 77 | -------------------------------------------------------------------------------- /HTTP/src/ip_num_test.py: -------------------------------------------------------------------------------- 1 | import concurrent 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | import requests 5 | 6 | ips = set() 7 | 8 | 9 | def ac_ip(i): 10 | print(i) 11 | r = requests.get("http://myip.ipip.net", proxies={"http": "http://127.0.0.1:8081"}) 12 | ips.add(r.text) 13 | 14 | 15 | with ThreadPoolExecutor(max_workers=5) as executor: 16 | executor.map(ac_ip, list(range(200))) 17 | 18 | print("".join(ips)) 19 | print(len(ips)) 20 | -------------------------------------------------------------------------------- /HTTP/src/server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | import json 3 | import pickle 4 | from base64 import b64decode, b64encode 5 | 6 | import requests 7 | 8 | 9 | SCF_TOKEN = "Token" 10 | 11 | 12 | def handler(environ: dict, start_response): 13 | try: 14 | token = environ["HTTP_SCF_TOKEN"] 15 | assert token == SCF_TOKEN, "Invalid token." 16 | except: 17 | status = '403 Forbidden' 18 | response_headers = [('Content-type', 'text/json')] 19 | start_response(status, response_headers) 20 | return [] 21 | 22 | try: 23 | request_body_size = int(environ.get('CONTENT_LENGTH', 0)) 24 | except (ValueError): 25 | request_body_size = 0 26 | request_body = environ['wsgi.input'].read(request_body_size) 27 | 28 | kwargs = json.loads(request_body.decode("utf-8")) 29 | kwargs['data'] = b64decode(kwargs['data']) 30 | # Prohibit automatic redirect to avoid network errors such as connection reset 31 | r = requests.request(**kwargs, verify=False, allow_redirects=False) 32 | 33 | # TODO: REFACTOR NEEDED. Return response headers and body directly. 34 | # There are many errors occured when setting headers to r.headers with some aujustments(https://cloud.tencent.com/document/product/583/12513). 35 | # and the response `r.content`/`r.raw.read()` to body.(like gzip error) 36 | serialized_resp = pickle.dumps(r) 37 | 38 | status = '200 OK' 39 | response_headers = [('Content-type', 'text/json')] 40 | start_response(status, response_headers) 41 | return [b64encode(serialized_resp)] 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fc-proxy 2 | 将阿里云函数的机器集群作为代理池. 3 | 4 | 本项目灵感和部分代码来自 https://github.com/shimmeris/SCFProxy, 主要将项目从腾讯云平台迁移到阿里云函数. 5 | 6 | ## 原理 7 | 详细原理参见文章[浅谈云函数的利用面](https://xz.aliyun.com/t/9502) 8 | 9 | 我的博客[相关链接](https://blog.lyc8503.net/post/sfc-proxy-pool/) 10 | --------------------------------------------------------------------------------