Skip to content

Instantly share code, notes, and snippets.

@ssrlive
Last active March 8, 2024 04:35
Show Gist options
  • Save ssrlive/0f3aa03cebed77b4a9a70c7afa4ecdad to your computer and use it in GitHub Desktop.
Save ssrlive/0f3aa03cebed77b4a9a70c7afa4ecdad to your computer and use it in GitHub Desktop.
Generate ACL file
use log::{info, LevelFilter};
use reqwest;
use serde_json::Value;
use std::fs::File;
use std::io::prelude::*;
use std::time::SystemTime;
use tokio;
// https://github.com/shadowsocks/shadowsocks-rust/blob/master/acl/genacl_proxy_gfw_bypass_china_ip.py
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
const GFW_TRANSLATED_URL: &str =
"https://raw.githubusercontent.com/NateScarlet/gfwlist.acl/master/gfwlist.acl.json";
const CHINA_IP_LIST_URL: &str =
"https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt";
const CUSTOM_BYPASS: [&str; 5] = [
"127.0.0.1",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"fd00::/8",
];
const CUSTOM_PROXY: [&str; 0] = [];
#[tokio::main]
async fn main() -> Result<(), BoxError> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init();
log::set_max_level(LevelFilter::Trace);
let output_file_path = "shadowsocks.acl";
info!("WRITING {}", output_file_path);
let mut file = File::create(output_file_path)?;
let now = SystemTime::now();
file.write_all(b"# Generated by genacl.py\n")?;
file.write_all(format!("# Time: {:?}\n", now).as_bytes())?;
file.write_all(b"\n")?;
file.write_all(b"[proxy_all]\n")?;
file.write_all(b"\n[proxy_list]\n")?;
write_gfw_list(&mut file).await?;
file.write_all(b"\n[bypass_list]\n")?;
write_china_ip(&mut file).await?;
if !CUSTOM_BYPASS.is_empty() {
info!("CUSTOM_BYPASS {} lines", CUSTOM_BYPASS.len());
file.write_all(b"\n[bypass_list]\n")?;
for a in &CUSTOM_BYPASS {
file.write_all(a.as_bytes())?;
file.write_all(b"\n")?;
}
}
if !CUSTOM_PROXY.is_empty() {
info!("CUSTOM_PROXY {} lines", CUSTOM_PROXY.len());
file.write_all(b"\n[proxy_list]\n")?;
for a in &CUSTOM_PROXY {
file.write_all(a.as_bytes())?;
file.write_all(b"\n")?;
}
}
info!("DONE");
Ok(())
}
async fn fetch_url_content(url: &str) -> Result<String, BoxError> {
info!("FETCHING {}", url);
let resp = reqwest::get(url).await?;
let body = resp.text().await?;
Ok(body)
}
async fn write_gfw_list(file: &mut File) -> Result<(), BoxError> {
let gfw_json = fetch_url_content(GFW_TRANSLATED_URL).await?;
let gfw_obj: Value = serde_json::from_str(&gfw_json)?;
if let Some(blacklist) = gfw_obj.get("blacklist") {
if let Some(blacklist) = blacklist.as_array() {
for line in blacklist {
if let Some(line) = line.as_str() {
file.write_all(line.as_bytes())?;
file.write_all(b"\n")?;
}
}
}
}
Ok(())
}
async fn write_china_ip(file: &mut File) -> Result<(), BoxError> {
let china_ip_list = fetch_url_content(CHINA_IP_LIST_URL).await?;
file.write_all(china_ip_list.as_bytes())?;
file.write_all(b"\n")?;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment