请求host不匹配时重新生成证书
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@ tokio = { version = "1.47.5", features = ["full"] }
|
|||||||
tokio-rustls = "0.26"
|
tokio-rustls = "0.26"
|
||||||
rustls-pemfile = "2"
|
rustls-pemfile = "2"
|
||||||
jni = "0.22.4"
|
jni = "0.22.4"
|
||||||
rcgen = "0.14"
|
rcgen = { version = "0.14", features = ["x509-parser"] }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
tokio-util = "0.7.20"
|
tokio-util = "0.7.20"
|
||||||
|
|||||||
+4
-147
@@ -1,156 +1,13 @@
|
|||||||
use rcgen::{
|
|
||||||
CertificateParams, DistinguishedName, DnType, ExtendedKeyUsagePurpose, IsCa, KeyPair,
|
|
||||||
KeyUsagePurpose, SanType,
|
|
||||||
};
|
|
||||||
use std::{env, fs, path::PathBuf};
|
use std::{env, fs, path::PathBuf};
|
||||||
|
#[path = "src/cert.rs"]
|
||||||
const CA_KEY: &str = "-----BEGIN PRIVATE KEY-----
|
mod cert;
|
||||||
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA
|
use cert::*;
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShZANiAAQTglHNUqyS
|
|
||||||
mMHIqtl3Mh3rl+cJvQtMoKylXcitUdz8nRWJoVl+OlEg4e/WMcY+GDXKyuKYaaYu
|
|
||||||
FjHoooGBq1ZhbcRdkYq8CfOrDmPPeSqk3O1zh743u6VpVJ8cArJw7Wc=
|
|
||||||
-----END PRIVATE KEY-----";
|
|
||||||
|
|
||||||
const CA_CHAIN: &str = "-----BEGIN PRIVATE KEY-----
|
|
||||||
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA
|
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShZANiAAQTglHNUqyS
|
|
||||||
mMHIqtl3Mh3rl+cJvQtMoKylXcitUdz8nRWJoVl+OlEg4e/WMcY+GDXKyuKYaaYu
|
|
||||||
FjHoooGBq1ZhbcRdkYq8CfOrDmPPeSqk3O1zh743u6VpVJ8cArJw7Wc=
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDaDCCAu6gAwIBAgIPKWkmwiejoVJjkrGUgqUEMAoGCCqGSM49BAMDMFYxCzAJ
|
|
||||||
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
|
||||||
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM3
|
|
||||||
NDFaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
|
||||||
aHJhIEluYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
|
||||||
AQYFK4EEACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZ
|
|
||||||
fjpRIOHv1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+
|
|
||||||
N7ulaVSfHAKycO1no4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
|
||||||
WUIgkFQwHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMB0GA1UdJQQWMBQG
|
|
||||||
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
|
||||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
|
||||||
BAGDjiEBAm4wCAYGZ4EMAQICMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
|
||||||
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
|
||||||
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNT1ZUTFNDQUczQy5wN2MwNwYDVR0f
|
|
||||||
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
|
||||||
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
|
||||||
AwMDaAAwZQIxAMSZt2xsPeumRdeSMSQ3CbzIZeQ/q7GDCWfeE1Pq+mhgA6gRM44c
|
|
||||||
NVF3xJ+wsxJk+wIwFJbaDMokD8Ei6eNOiA8yUMYvfzQyngmrhZQMdPCK1SewrR79
|
|
||||||
4rSb9vGqxZzelQth
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
|
||||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
|
||||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
|
||||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
|
||||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
|
||||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
|
||||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
|
||||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
|
||||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
|
||||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
|
||||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
|
||||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
|
||||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
|
||||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
|
||||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
|
||||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
|
||||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
|
||||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
|
||||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDzzCCAregAwIBAgIRAI1aSBGTnvRH13ERzdmEmukwDQYJKoZIhvcNAQELBQAw
|
|
||||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
|
||||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
|
||||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
|
||||||
ODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu
|
|
||||||
YzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE
|
|
||||||
ACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZfjpRIOHv
|
|
||||||
1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+N7ulaVSf
|
|
||||||
HAKycO1no4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw
|
|
||||||
HQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMA4GA1UdDwEB/wQEAwIBBjAS
|
|
||||||
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
|
||||||
AjAxBgNVHSAEKjAoMAgGBmeBDAECAjANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO
|
|
||||||
IQECbjBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B
|
|
||||||
QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB
|
|
||||||
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC
|
|
||||||
AQEAHlbhZpjhkPEAQVhPHRtBDaHqiisVD20pQ1TUeSx3l62Qe7NQ0b7vWQy7DN0i
|
|
||||||
KOu7BGpP5EnIjvXbz9FhpfPJ4FhKEt3tQ51rqXz2oD8vRaryvExWPobDUz3j7HN6
|
|
||||||
OzBsVMIe3PD7AAkpky0x8zMSi/ep5R9OMzybmNptbtppyuB5ytgq+h7lQdRIP+CQ
|
|
||||||
TaJX3qTgfMqzntYre5GljmEB5hU2/rSn8zoSU2APkJidlZFpghtgbD4I2VRHZvCw
|
|
||||||
FFr/SrFM9pwrgbJNZ1MtyTSVgI5NlNb0aMfLR+/r6jJt3ROeY2yh2QQ2dx+Yqgdb
|
|
||||||
uL5ChFWOQU+ErSDnUq7yr+pjBQ==
|
|
||||||
-----END CERTIFICATE-----";
|
|
||||||
|
|
||||||
/// 证书里要覆盖的域名。抓包目标 host 必须在这里面,否则 App 会报证书不受信任。
|
|
||||||
const SAN: &[&str] = &[
|
|
||||||
// 国服
|
|
||||||
"*.dailygn.com",
|
|
||||||
// 日服
|
|
||||||
"production-game-api.sekai.colorfulpalette.org",
|
|
||||||
"*.sekai.colorfulpalette.org",
|
|
||||||
// 国际服
|
|
||||||
"n-production-game-api.sekai-en.com",
|
|
||||||
"*.sekai-en.com",
|
|
||||||
// 台服 / 韩服(cdn 和 https 两个域都会出现)
|
|
||||||
"*.bytedgame.com",
|
|
||||||
"mk-zian-obt-cdn.bytedgame.com",
|
|
||||||
"mk-zian-obt-https.bytedgame.com",
|
|
||||||
"mkkorea-obt-prod01-cdn.bytedgame.com",
|
|
||||||
"mkkorea-obt-prod01-https.bytedgame.com",
|
|
||||||
];
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
|
||||||
let ca_key = KeyPair::from_pem(CA_KEY).expect("parse CA key failed");
|
let (fullchain_pem, leaf_key_pem) = sign(SAN.iter());
|
||||||
let first_ca_pem = first_pem_certificate(CA_CHAIN);
|
|
||||||
let issuer = rcgen::Issuer::from_ca_cert_pem(&first_ca_pem, ca_key)
|
|
||||||
.expect("build Issuer from CA cert + key failed");
|
|
||||||
|
|
||||||
let mut leaf_params = CertificateParams::default();
|
|
||||||
let mut dn = DistinguishedName::new();
|
|
||||||
dn.push(DnType::CommonName, SAN[0]);
|
|
||||||
leaf_params.distinguished_name = dn;
|
|
||||||
|
|
||||||
leaf_params.subject_alt_names = SAN
|
|
||||||
.iter()
|
|
||||||
.map(|d| SanType::DnsName((*d).try_into().unwrap()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
leaf_params.key_usages = vec![
|
|
||||||
KeyUsagePurpose::DigitalSignature,
|
|
||||||
KeyUsagePurpose::KeyEncipherment,
|
|
||||||
];
|
|
||||||
leaf_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
|
|
||||||
leaf_params.is_ca = IsCa::NoCa;
|
|
||||||
// AKI 必须和签发者证书里的 SKI 一致,rcgen 的 Issuer 会自动从 CA 证书里取
|
|
||||||
leaf_params.use_authority_key_identifier_extension = true;
|
|
||||||
// 有效期落在 CA 的有效期内(2025-04-30 ~ 2040-04-28)
|
|
||||||
leaf_params.not_before = rcgen::date_time_ymd(2025, 5, 1);
|
|
||||||
leaf_params.not_after = rcgen::date_time_ymd(2038, 1, 1);
|
|
||||||
|
|
||||||
let leaf_key = KeyPair::generate().expect("generate leaf key failed");
|
|
||||||
let leaf_cert = leaf_params
|
|
||||||
.signed_by(&leaf_key, &issuer)
|
|
||||||
.expect("sign leaf cert failed");
|
|
||||||
|
|
||||||
// leaf + 完整 CA 链(两个 G3C 交叉签名都带上,让验证器自己选路径)
|
|
||||||
let fullchain_pem = format!("{}{}", leaf_cert.pem(), CA_CHAIN);
|
|
||||||
fs::write(out_dir.join("fullchain.pem"), fullchain_pem).unwrap();
|
fs::write(out_dir.join("fullchain.pem"), fullchain_pem).unwrap();
|
||||||
|
|
||||||
let leaf_key_pem = leaf_key.serialize_pem();
|
|
||||||
fs::write(out_dir.join("leaf.key"), leaf_key_pem).unwrap();
|
fs::write(out_dir.join("leaf.key"), leaf_key_pem).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_pem_certificate(pem: &str) -> String {
|
|
||||||
let begin = "-----BEGIN CERTIFICATE-----";
|
|
||||||
let end = "-----END CERTIFICATE-----";
|
|
||||||
if let (Some(s), Some(e)) = (pem.find(begin), pem.find(end)) {
|
|
||||||
pem[s..e + end.len()].to_string()
|
|
||||||
} else {
|
|
||||||
panic!("no certificate found in CA chain PEM");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
use crate::cert::{check_cert_included, sign};
|
||||||
|
use crate::info;
|
||||||
|
use rustls_pemfile::{certs, private_key};
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn build_tls_acceptor(target_hosts: Vec<String>) -> Arc<rustls::ServerConfig> {
|
||||||
|
let is_included_built_in = check_cert_included(target_hosts.iter().map(|s| s.as_str()));
|
||||||
|
let (cert_chain, key) = if is_included_built_in {
|
||||||
|
let fullchain = include_bytes!(concat!(env!("OUT_DIR"), "/fullchain.pem"));
|
||||||
|
let leaf_key = include_bytes!(concat!(env!("OUT_DIR"), "/leaf.key"));
|
||||||
|
let cert_chain = certs(&mut BufReader::new(&fullchain[..]))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.unwrap();
|
||||||
|
let key = private_key(&mut BufReader::new(&leaf_key[..]))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
(cert_chain, key)
|
||||||
|
} else {
|
||||||
|
info!("Target hosts not match built-in cert, generating new cert");
|
||||||
|
let target = target_hosts.iter().map(|s| s.as_str()).collect::<Vec<_>>();
|
||||||
|
let (fullchain, leaf_key) = sign(target.iter());
|
||||||
|
let cert_chain = certs(&mut BufReader::new(fullchain.as_bytes()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.unwrap();
|
||||||
|
let key = private_key(&mut BufReader::new(leaf_key.as_bytes()))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
(cert_chain, key)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut config = rustls::ServerConfig::builder()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_single_cert(cert_chain, key)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
config.alpn_protocols = vec![b"http/1.1".to_vec()];
|
||||||
|
|
||||||
|
Arc::new(config)
|
||||||
|
}
|
||||||
+171
-19
@@ -1,24 +1,176 @@
|
|||||||
use rustls_pemfile::{certs, private_key};
|
use rcgen::{
|
||||||
use std::io::BufReader;
|
CertificateParams, DistinguishedName, DnType, ExtendedKeyUsagePurpose, IsCa, KeyPair,
|
||||||
use std::sync::Arc;
|
KeyUsagePurpose, SanType,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn build_tls_acceptor() -> Arc<rustls::ServerConfig> {
|
const CA_KEY: &str = "-----BEGIN PRIVATE KEY-----
|
||||||
let fullchain = include_bytes!(concat!(env!("OUT_DIR"), "/fullchain.pem"));
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA
|
||||||
let leaf_key = include_bytes!(concat!(env!("OUT_DIR"), "/leaf.key"));
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShZANiAAQTglHNUqyS
|
||||||
|
mMHIqtl3Mh3rl+cJvQtMoKylXcitUdz8nRWJoVl+OlEg4e/WMcY+GDXKyuKYaaYu
|
||||||
|
FjHoooGBq1ZhbcRdkYq8CfOrDmPPeSqk3O1zh743u6VpVJ8cArJw7Wc=
|
||||||
|
-----END PRIVATE KEY-----";
|
||||||
|
|
||||||
let cert_chain = certs(&mut BufReader::new(&fullchain[..]))
|
const CA_CHAIN: &str = "-----BEGIN PRIVATE KEY-----
|
||||||
.collect::<Result<Vec<_>, _>>()
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA
|
||||||
.unwrap();
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShZANiAAQTglHNUqyS
|
||||||
let key = private_key(&mut BufReader::new(&leaf_key[..]))
|
mMHIqtl3Mh3rl+cJvQtMoKylXcitUdz8nRWJoVl+OlEg4e/WMcY+GDXKyuKYaaYu
|
||||||
.unwrap()
|
FjHoooGBq1ZhbcRdkYq8CfOrDmPPeSqk3O1zh743u6VpVJ8cArJw7Wc=
|
||||||
.unwrap();
|
-----END PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDaDCCAu6gAwIBAgIPKWkmwiejoVJjkrGUgqUEMAoGCCqGSM49BAMDMFYxCzAJ
|
||||||
|
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
||||||
|
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM3
|
||||||
|
NDFaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
||||||
|
aHJhIEluYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
||||||
|
AQYFK4EEACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZ
|
||||||
|
fjpRIOHv1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+
|
||||||
|
N7ulaVSfHAKycO1no4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
||||||
|
WUIgkFQwHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMB0GA1UdJQQWMBQG
|
||||||
|
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
||||||
|
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
||||||
|
BAGDjiEBAm4wCAYGZ4EMAQICMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
||||||
|
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
||||||
|
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNT1ZUTFNDQUczQy5wN2MwNwYDVR0f
|
||||||
|
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
||||||
|
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
||||||
|
AwMDaAAwZQIxAMSZt2xsPeumRdeSMSQ3CbzIZeQ/q7GDCWfeE1Pq+mhgA6gRM44c
|
||||||
|
NVF3xJ+wsxJk+wIwFJbaDMokD8Ei6eNOiA8yUMYvfzQyngmrhZQMdPCK1SewrR79
|
||||||
|
4rSb9vGqxZzelQth
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||||
|
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||||
|
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||||
|
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||||
|
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||||
|
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||||
|
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||||
|
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||||
|
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||||
|
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||||
|
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||||
|
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||||
|
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||||
|
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||||
|
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||||
|
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||||
|
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||||
|
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||||
|
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDzzCCAregAwIBAgIRAI1aSBGTnvRH13ERzdmEmukwDQYJKoZIhvcNAQELBQAw
|
||||||
|
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||||
|
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||||
|
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||||
|
ODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu
|
||||||
|
YzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE
|
||||||
|
ACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZfjpRIOHv
|
||||||
|
1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+N7ulaVSf
|
||||||
|
HAKycO1no4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw
|
||||||
|
HQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMA4GA1UdDwEB/wQEAwIBBjAS
|
||||||
|
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||||
|
AjAxBgNVHSAEKjAoMAgGBmeBDAECAjANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO
|
||||||
|
IQECbjBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B
|
||||||
|
QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB
|
||||||
|
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC
|
||||||
|
AQEAHlbhZpjhkPEAQVhPHRtBDaHqiisVD20pQ1TUeSx3l62Qe7NQ0b7vWQy7DN0i
|
||||||
|
KOu7BGpP5EnIjvXbz9FhpfPJ4FhKEt3tQ51rqXz2oD8vRaryvExWPobDUz3j7HN6
|
||||||
|
OzBsVMIe3PD7AAkpky0x8zMSi/ep5R9OMzybmNptbtppyuB5ytgq+h7lQdRIP+CQ
|
||||||
|
TaJX3qTgfMqzntYre5GljmEB5hU2/rSn8zoSU2APkJidlZFpghtgbD4I2VRHZvCw
|
||||||
|
FFr/SrFM9pwrgbJNZ1MtyTSVgI5NlNb0aMfLR+/r6jJt3ROeY2yh2QQ2dx+Yqgdb
|
||||||
|
uL5ChFWOQU+ErSDnUq7yr+pjBQ==
|
||||||
|
-----END CERTIFICATE-----";
|
||||||
|
|
||||||
let mut config = rustls::ServerConfig::builder()
|
pub const SAN: &[&str] = &[
|
||||||
.with_no_client_auth()
|
// 国服
|
||||||
.with_single_cert(cert_chain, key)
|
"*.dailygn.com",
|
||||||
.unwrap();
|
// 日服
|
||||||
|
"production-game-api.sekai.colorfulpalette.org",
|
||||||
|
"*.sekai.colorfulpalette.org",
|
||||||
|
// 国际服
|
||||||
|
"n-production-game-api.sekai-en.com",
|
||||||
|
"*.sekai-en.com",
|
||||||
|
// 台服 / 韩服(cdn 和 https 两个域都会出现)
|
||||||
|
"*.bytedgame.com",
|
||||||
|
"mk-zian-obt-cdn.bytedgame.com",
|
||||||
|
"mk-zian-obt-https.bytedgame.com",
|
||||||
|
"mkkorea-obt-prod01-cdn.bytedgame.com",
|
||||||
|
"mkkorea-obt-prod01-https.bytedgame.com",
|
||||||
|
];
|
||||||
|
|
||||||
config.alpn_protocols = vec![b"http/1.1".to_vec()];
|
#[allow(unused)] // caused in re-build in build.rs
|
||||||
|
pub fn check_cert_included<'a>(target_hosts: impl Iterator<Item = &'a str>) -> bool {
|
||||||
Arc::new(config)
|
for host in target_hosts {
|
||||||
|
if SAN.contains(&host) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut found = false;
|
||||||
|
for included_host in SAN {
|
||||||
|
if !included_host.starts_with("*.") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let without_star = &included_host[2..];
|
||||||
|
let host_without_first = host.split_once(".");
|
||||||
|
if let Some(parts) = host_without_first
|
||||||
|
&& parts.1 == without_star
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign<'a>(target_hosts: impl Iterator<Item = &'a &'a str>) -> (String, String) {
|
||||||
|
let mut target_hosts = target_hosts.peekable();
|
||||||
|
|
||||||
|
let ca_key = KeyPair::from_pem(CA_KEY).expect("parse CA key failed");
|
||||||
|
let first_ca_pem = first_pem_certificate(CA_CHAIN);
|
||||||
|
let issuer = rcgen::Issuer::from_ca_cert_pem(&first_ca_pem, ca_key)
|
||||||
|
.expect("build Issuer from CA cert + key failed");
|
||||||
|
|
||||||
|
let mut leaf_params = CertificateParams::default();
|
||||||
|
let mut dn = DistinguishedName::new();
|
||||||
|
dn.push(DnType::CommonName, target_hosts.peek().unwrap().to_string());
|
||||||
|
leaf_params.distinguished_name = dn;
|
||||||
|
|
||||||
|
leaf_params.subject_alt_names = target_hosts
|
||||||
|
.map(|d| SanType::DnsName((*d).try_into().unwrap()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
leaf_params.key_usages = vec![
|
||||||
|
KeyUsagePurpose::DigitalSignature,
|
||||||
|
KeyUsagePurpose::KeyEncipherment,
|
||||||
|
];
|
||||||
|
leaf_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
|
||||||
|
leaf_params.is_ca = IsCa::NoCa;
|
||||||
|
// AKI 必须和签发者证书里的 SKI 一致,rcgen 的 Issuer 会自动从 CA 证书里取
|
||||||
|
leaf_params.use_authority_key_identifier_extension = true;
|
||||||
|
// 有效期落在 CA 的有效期内(2025-04-30 ~ 2040-04-28)
|
||||||
|
leaf_params.not_before = rcgen::date_time_ymd(2025, 5, 1);
|
||||||
|
leaf_params.not_after = rcgen::date_time_ymd(2038, 1, 1);
|
||||||
|
|
||||||
|
let leaf_key = KeyPair::generate().expect("generate leaf key failed");
|
||||||
|
let leaf_cert = leaf_params
|
||||||
|
.signed_by(&leaf_key, &issuer)
|
||||||
|
.expect("sign leaf cert failed");
|
||||||
|
|
||||||
|
let fullchain_pem = format!("{}{}", leaf_cert.pem(), CA_CHAIN);
|
||||||
|
let leaf_key_pem = leaf_key.serialize_pem();
|
||||||
|
(fullchain_pem, leaf_key_pem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_pem_certificate(pem: &str) -> String {
|
||||||
|
let begin = "-----BEGIN CERTIFICATE-----";
|
||||||
|
let end = "-----END CERTIFICATE-----";
|
||||||
|
if let (Some(s), Some(e)) = (pem.find(begin), pem.find(end)) {
|
||||||
|
pem[s..e + end.len()].to_string()
|
||||||
|
} else {
|
||||||
|
panic!("no certificate found in CA chain PEM");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ mod cert;
|
|||||||
mod mitm;
|
mod mitm;
|
||||||
mod mut_qstring;
|
mod mut_qstring;
|
||||||
mod tun;
|
mod tun;
|
||||||
|
mod acceptor;
|
||||||
|
|
||||||
use crate::mitm::{ProxyConfig, StepSpec, Waiter, Waiters, run_session};
|
use crate::mitm::{ProxyConfig, StepSpec, Waiter, Waiters, run_session};
|
||||||
use jni::objects::{Global, JClass, JObject, JString};
|
use jni::objects::{Global, JClass, JObject, JString};
|
||||||
|
|||||||
+18
-11
@@ -1,8 +1,8 @@
|
|||||||
use crate::cert::build_tls_acceptor;
|
|
||||||
use crate::mut_qstring::MutQString;
|
use crate::mut_qstring::MutQString;
|
||||||
use crate::tun::{BorrowedTunIo, RewindStream};
|
use crate::tun::{BorrowedTunIo, RewindStream};
|
||||||
use crate::{error, info, warn};
|
use crate::{error, info, warn};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
use http::Uri;
|
||||||
use http_body_util::{BodyExt, Full};
|
use http_body_util::{BodyExt, Full};
|
||||||
use hyper::body::Incoming;
|
use hyper::body::Incoming;
|
||||||
use hyper_util::rt::TokioIo;
|
use hyper_util::rt::TokioIo;
|
||||||
@@ -14,13 +14,13 @@ use std::net::SocketAddr;
|
|||||||
use std::os::fd::RawFd;
|
use std::os::fd::RawFd;
|
||||||
use std::sync::{Arc, Mutex as StdMutex, OnceLock};
|
use std::sync::{Arc, Mutex as StdMutex, OnceLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use http::Uri;
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
use tokio_rustls::StartHandshake;
|
use tokio_rustls::StartHandshake;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
use tun_rs::BorrowedAsyncDevice;
|
use tun_rs::BorrowedAsyncDevice;
|
||||||
|
use crate::acceptor::build_tls_acceptor;
|
||||||
|
|
||||||
static ROOT_STORE: OnceLock<Arc<RootCertStore>> = OnceLock::new();
|
static ROOT_STORE: OnceLock<Arc<RootCertStore>> = OnceLock::new();
|
||||||
|
|
||||||
@@ -145,13 +145,12 @@ where
|
|||||||
return passthrough_cancel_wrapped(io, dst, None, upstream, &cancel).await;
|
return passthrough_cancel_wrapped(io, dst, None, upstream, &cancel).await;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 崩溃上报之类的域名直接拒绝,不建立上游连接
|
if let Some(host) = sni.as_deref()
|
||||||
if let Some(host) = sni.as_deref() {
|
&& is_blocked_host(host)
|
||||||
if is_blocked_host(host) {
|
{
|
||||||
warn!("blocked host {host} ({dst:?}), connection rejected");
|
warn!("blocked host {host} ({dst:?}), connection rejected");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let host_matched = sni
|
let host_matched = sni
|
||||||
.as_deref()
|
.as_deref()
|
||||||
@@ -382,7 +381,6 @@ fn force_full_mysekai(uri: &Uri) -> Option<Uri> {
|
|||||||
Uri::try_from(format!("{}?{}", uri.path(), query).as_str()).ok()
|
Uri::try_from(format!("{}?{}", uri.path(), query).as_str()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Deserialize, Debug, Clone)]
|
||||||
pub struct StepSpec {
|
pub struct StepSpec {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@@ -450,9 +448,16 @@ impl ProxyConfig {
|
|||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let pass = url.password().unwrap_or("");
|
let pass = url.password().unwrap_or("");
|
||||||
Some(base64_encode(format!("{}:{}", url.username(), pass).as_bytes()))
|
Some(base64_encode(
|
||||||
|
format!("{}:{}", url.username(), pass).as_bytes(),
|
||||||
|
))
|
||||||
};
|
};
|
||||||
Ok(Some(Self { tls, host, port, auth }))
|
Ok(Some(Self {
|
||||||
|
tls,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
auth,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +478,9 @@ struct Upstream {
|
|||||||
|
|
||||||
impl Upstream {
|
impl Upstream {
|
||||||
fn new(proxy: Option<ProxyConfig>) -> Self {
|
fn new(proxy: Option<ProxyConfig>) -> Self {
|
||||||
Self { proxy: proxy.map(Arc::new) }
|
Self {
|
||||||
|
proxy: proxy.map(Arc::new),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect(&self, dst: SocketAddr, host: Option<&str>) -> anyhow::Result<UpstreamIo> {
|
async fn connect(&self, dst: SocketAddr, host: Option<&str>) -> anyhow::Result<UpstreamIo> {
|
||||||
@@ -571,7 +578,7 @@ pub async fn run_session(
|
|||||||
let mut ip_stack = ipstack::IpStack::new(ipstack_config, tun_io);
|
let mut ip_stack = ipstack::IpStack::new(ipstack_config, tun_io);
|
||||||
let mut bridge_tasks = JoinSet::new();
|
let mut bridge_tasks = JoinSet::new();
|
||||||
|
|
||||||
let tls_acceptor = build_tls_acceptor();
|
let tls_acceptor = build_tls_acceptor(target_hosts.clone());
|
||||||
let upstream = Upstream::new(proxy);
|
let upstream = Upstream::new(proxy);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
Reference in New Issue
Block a user