天天看點

雲函數實作代理

部落格貌似有很久很久沒有更新了。但是其實并沒有停止學習(筆記大部分寫到了語雀上,有空閑時間同步到部落格)。今天看了公衆号裡的一篇文章,自己實際操作了一下發現有一些坑,是以來做個記錄

雲函數實作代理

文章參考:https://mp.weixin.qq.com/s/HT6liYdsaKW34OMQGu3XAw

雲函數實作HTTP代理

用戶端挂上代理發送資料包,HTTP 代理伺服器攔截資料包,提取 HTTP 封包相關資訊,然後将封包以某種形式 POST 到雲函數進行解析,雲函數根據解析到的資訊對目标發起請求,最終将結果一層一層傳回。

雲函數基礎配置

選擇自定義建立,地域自選,部署模式,代碼部署,運作環境Python3.6,其餘預設即可。

雲函數實作代理

函數代碼配置

然後配置函數代碼,服務端代碼server.py:

# -*- coding: utf8 -*-
import json
import pickle
from base64 import b64decode, b64encode

import requests

SCF_TOKEN = "TOKEN" #需要自定義随機值,用于鑒權

def authorization():
    return {
        "isBase64Encoded": False,
        "statusCode": 401,
        "headers": {},
        "body": "Please provide correct SCF-Token",
    }

def main_handler(event: dict, context: dict):
    try:
        token = event["headers"]["scf-token"]
    except KeyError:
        return authorization()

    if token != SCF_TOKEN:
        return authorization()

    data = event["body"]
    kwargs = json.loads(data)
    kwargs['data'] = b64decode(kwargs['data'])
    r = requests.request(**kwargs, verify=False, allow_redirects=False)

    serialized_resp = pickle.dumps(r)

    return {
        "isBase64Encoded": False,
        "statusCode": 200,
        "headers": {},
        "body": b64encode(serialized_resp).decode("utf-8"),
    }           

複制

修改 server.py 中的 SCF_TOKEN 為随機值,該值将用于鑒權, client.py 中的 SCF_TOKEN需要與server.py中的SCF_TOKEN保持一緻。

雲函數實作代理

進階配置

雲函數操作最大逾時限制預設為 3 秒,可以将雲函數環境配置中的執行逾時時間拉滿,其餘預設即可

雲函數實作代理

建立觸發器

配置完上面的所有内容後,建立觸發器,自定義觸發器,

觸發方式選擇 API 網關觸發,其他預設就好。

雲函數實作代理

建立好觸發器之後,基本配置就完成了,點選完成,等待函數配置完成,就會跳轉到管理頁面,我們找到觸發管理,其中通路路徑就是我們的雲函數通路位址。

雲函數實作代理

服務端就基本配置好了,下面還需要配置一下用戶端。

用戶端配置

本地代理這裡使用的是mitmproxy,可以直接pip安裝。

安裝mitmproxy 注意這個版本和本機python的版本是挂鈎的。我這邊是

Python3.7

4.0.1版本的

mitmproxy

才能正常使用。(這裡嘗試了很久,之前沒指定版本的時候會報錯原因就是Python版本太低而mitmproxy版本太高。具體mitmproxy的版本對應Python哪個版本,大家自己去嘗試下。)

python3 -m pip install mitmproxy==4.0.1           

複制

如果需要代理 HTTPS流量需安裝證書。首次運作 mitmdump指令,證書目錄自動生成在 ~/.mitmproxy中,安裝并信任。

雲函數實作代理

輕按兩下

mitmproxy-ca-cert.pem

檔案,設為始終信任。

雲函數實作代理

下面需要配置用戶端client.py代碼,需要将觸發器中的通路路徑添加至 client.py 中 scf_servers變量中,以逗号 , 分隔。scf_servers 參數可以添加多個API接口,這樣就可以擷取更多的IP池。

import json
import pickle
from typing import List
from random import choice
from urllib.parse import urlparse
from base64 import b64encode, b64decode

import mitmproxy
from mitmproxy.net.http import Headers

#API通路位址,可以添加多個,以逗号分隔
scf_servers: List[str] = [""]

#授權Token,與雲函數中的token配置一緻
SCF_TOKEN = "token"


def request(flow: mitmproxy.http.HTTPFlow):
    scf_server = choice(scf_servers)
    r = flow.request
    data = {
        "method": r.method,
        "url": r.pretty_url,
        "headers": dict(r.headers),
        "cookies": dict(r.cookies),
        "params": dict(r.query),
        "data": b64encode(r.raw_content).decode("ascii"),
    }

    flow.request = flow.request.make(
        "POST",
        url=scf_server,
        content=json.dumps(data),
        headers={
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, compress",
            "Accept-Language": "en-us;q=0.8",
            "Cache-Control": "max-age=0",
            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
            "Connection": "close",
            "Host": urlparse(scf_server).netloc,
            "SCF-Token": SCF_TOKEN,
        },
    )


def response(flow: mitmproxy.http.HTTPFlow):
    if flow.response.status_code != 200:
        mitmproxy.ctx.log.warn("Error")

    if flow.response.status_code == 401:
        flow.response.headers = Headers(content_type="text/html;charset=utf-8")
        return

    if flow.response.status_code == 433:
        flow.response.headers = Headers(content_type="text/html;charset=utf-8")
        flow.response.text = "<html><body>操作已超過雲函數服務最大時間限制,可在函數配置中修改執行逾時時間</body></html>"
        return

    if flow.response.status_code == 200:
        body = flow.response.content.decode("utf-8")
        resp = pickle.loads(b64decode(body))

        r = flow.response.make(
            status_code=resp.status_code,
            headers=dict(resp.headers),
            content=resp.content,
        )
        flow.response = r           

複制

配置好之後就可以開啟代理

mitmdump -s client.py -p 8081 --no-http2           

複制

雲函數實作代理

在浏覽器下配置http代理

雲函數實作代理

我們檢視一下ip

雲函數實作代理

可見已經是 騰訊雲的位址了。

但是https的站點這裡還是會報出ssl錯誤

雲函數實作代理

一些https的站還是會出問題的。這裡找了很久解決辦法,還是沒搞定。如果大佬們看出有什麼問題,請聯系下小弟。

雲函數實作SOCKS5代理

雲函數基礎配置

雲函數實作代理

函數代碼

# -*- coding: utf8 -*-
# server.py
import json
import socket
import select

bridge_ip = "ip"
bridge_port = port

def main_handler(event, context):
    data = json.loads(event["body"])
    out = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    out.connect((data["host"], data["port"]))

    bridge = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    bridge.connect((bridge_ip, bridge_port))
    bridge.send(data["uid"].encode("ascii"))

    while True:
        readable, _, _ = select.select([out, bridge], [], [])
        if out in readable:
            data = out.recv(4096)
            bridge.send(data)
        if bridge in readable:
            data = bridge.recv(4096)
            out.send(data)           

複制

修改 server.py中的 bridge_ip與 bridge_port為自己 VPS的 ip及開啟監聽的端口

雲函數實作代理

進階配置

與上面http一樣。

修改雲函數逾時時間為 900s,這樣一個 SOCKS5 連接配接最多元持 15m

雲函數實作代理

建立觸發器

同樣與上面http一樣 觸發方式為API網關觸發

雲函數實作代理

用戶端配置

下載下傳 https://github.com/culprits/SCFProxy.git 到我們的vps上

雲函數實作代理

執行

Pip3 install -r requirements.txt 安裝所需要的庫,最後直接執行

python3 socks5.py -u "https://service-q3vrbamf-1257145077.bj.apigw.tencentcs.com/release/socks5" -bp 9001 -sp 9002 --user Sch0lar --passwd Sch0lar           

複制

  • -u 參數需要填寫 API 網關提供的位址,必填
  • -l 表示本機監聽的 ip,預設為 0.0.0.0
  • -sp 表示 SOCKS5 代理監聽的端口,必填
  • -bp 表示用于監聽來自雲函數連接配接的端口,與 server.py 中的 bridge_port 相同,必填
  • –user 和 –passwd 用于 SOCKS5 伺服器對連接配接進行身份驗證,用戶端需配置相應的使用者名和密碼

背景運作

screen python3 socks5.py -u "https://service-q3vrbamf-1257145077.bj.apigw.tencentcs.com/release/socks5" -bp 9001 -sp 9002           

複制

配置好socks5代理

雲函數實作代理
雲函數實作代理
雲函數實作代理