Skip to content

Instantly share code, notes, and snippets.

@ftk
Last active July 1, 2024 04:38
Show Gist options
  • Save ftk/253347b2c9a53bbd6087f086970106b6 to your computer and use it in GitHub Desktop.
Save ftk/253347b2c9a53bbd6087f086970106b6 to your computer and use it in GitHub Desktop.
http mitm proxy. Simple http proxy to modify Range: http headers. Can be used to speed up youtube in mpv
#!/bin/sh
# installation script for the lazy
# this script assumes rust toolchain (https://rustup.rs/) and openssl are installed
# should also work in windows assuming you edit ~/.config/mpv to your mpv dir
set -eux
git clone https://gist.github.com/253347b2c9a53bbd6087f086970106b6.git ytrangefix
cd ytrangefix
mkdir src
cp main.rs src/
cargo build --release
# install lua script to mpv dir
scriptdir=~/.config/mpv/scripts/ytrangefix
mkdir -p $scriptdir
cp target/release/http-ytproxy $scriptdir/
cp ytproxy.lua $scriptdir/main.lua
cd $scriptdir
# generate private keys for mitm proxy (they don't matter)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -passout pass:"third-wheel" -subj "/C=US/ST=private/L=province/O=city/CN=hostname.example.com"
echo done!
# To generate mitm cert and key:
# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -passout pass:"third-wheel" -subj "/C=US/ST=private/L=province/O=city/CN=hostname.example.com"
# see: https://github.com/campbellC/third-wheel
[package]
name = "http-ytproxy"
version = "0.1.0"
edition = "2021"
[dependencies]
third-wheel = "0.6"
argh = "0.1"
[dependencies.tokio]
version = "1"
use argh::FromArgs;
use third_wheel::hyper::{Request, Body};
use third_wheel::hyper::http::HeaderValue;
use third_wheel::hyper::service::Service;
use third_wheel::*;
/// Run a TLS mitm proxy that modifies Range header to be http_chunk_size bytes.
#[derive(FromArgs)]
struct StartMitm {
/// port to bind proxy to
#[argh(option, short = 'p', default = "8080")]
port: u16,
/// pem file for self-signed certificate authority certificate
#[argh(option, short = 'c', default = "\"cert.pem\".to_string()")]
cert_file: String,
/// pem file for private signing key for the certificate authority
#[argh(option, short = 'k', default = "\"key.pem\".to_string()")]
key_file: String,
/// range header chunk
#[argh(option, short = 'r', default = "10485760")]
http_chunk_size: u64,
}
fn mitm(mut req: Request<Body>, mut third_wheel: ThirdWheel, http_chunk_size:u64) -> <ThirdWheel as Service<Request<Body>>>::Future {
//println!("req: {}", req.uri());
let hdr = req.headers_mut();
if let Some(val) = hdr.get("Range") {
let range = val.to_str().unwrap();
//println!("Range: {}", range);
if range.starts_with("bytes=") {
if let Some((p1, _p2)) = range[6..].split_once('-') {
if let Ok(start) = p1.parse::<u64>() {
let newrange = format!("bytes={}-{}", start, start + http_chunk_size);
//println!("-> {}",newrange);
hdr.insert("Range", HeaderValue::from_str(&newrange).unwrap());
}
}
}
}
third_wheel.call(req)
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let args: StartMitm = argh::from_env();
let ca = CertificateAuthority::load_from_pem_files_with_passphrase_on_key(
&args.cert_file,
&args.key_file,
"third-wheel",
)?;
let trivial_mitm =
mitm_layer(move |req, tw| mitm(req,tw, args.http_chunk_size) );
let mitm_proxy = MitmProxy::builder(trivial_mitm, ca).build();
let (_, mitm_proxy_fut) = mitm_proxy.bind(format!("127.0.0.1:{}", args.port).parse().unwrap());
mitm_proxy_fut.await.unwrap();
Ok(())
}
local function init()
local url = mp.get_property("stream-open-filename")
-- check for youtube link
if url:find("^https:") == nil or url:find("youtu") == nil then
return
end
local proxy = mp.get_property("http-proxy")
if proxy and proxy ~= "" and proxy ~= "http://127.0.0.1:12081" then
return
end
-- launch mitm proxy
local args = {
mp.get_script_directory() .. "/http-ytproxy",
"-c", mp.get_script_directory() .. "/cert.pem",
"-k", mp.get_script_directory() .. "/key.pem",
"-r", "10485760", -- range modification
"-p", "12081" -- proxy port
}
mp.command_native_async({
name = "subprocess",
capture_stdout = false,
playback_only = false,
args = args,
});
mp.set_property("http-proxy", "http://127.0.0.1:12081")
mp.set_property("tls-verify", "no")
-- this is not really needed
--mp.set_property("tls-verify", "yes")
--mp.set_property("tls-ca-file", mp.get_script_directory() .. "/cert.pem")
end
mp.register_event("start-file", init)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment