From b6f2ffd6adacc55a52c471b761bd7dba84acf8b9 Mon Sep 17 00:00:00 2001
From: Andrevich <47223721+1andrevich@users.noreply.github.com>
Date: Sun, 8 Dec 2024 12:43:20 +0400
Subject: [PATCH] Updated build files
---
src/{step 5 ooni list => }/bird2_converter.py | 0
src/step 5 ooni list/.idea/.gitignore | 3 +
src/step 5 ooni list/.idea/.name | 1 +
.../inspectionProfiles/profiles_settings.xml | 6 +
src/step 5 ooni list/.idea/misc.xml | 7 +
src/step 5 ooni list/.idea/modules.xml | 8 +
.../.idea/step 5 ooni list.iml | 8 +
src/step 5 ooni list/.idea/vcs.xml | 6 +
src/step 5 ooni list/domain_sum.py | 2 +-
src/step 5 ooni list/ip_4files_sum.py | 2 +-
src/step 5 ooni list/ipsum_bgp.py | 198 -
src/step 5 ooni list/resolver_community.py | 10 +-
src/step 5 ooni list/resolver_ooni.py | 6 +-
...ep 6 temp - summarization and ASN CIDRs.py | 124 +-
src/xray-geoip/config.json | 27 +
src/xray-geoip/go.mod | 34 +
src/xray-geoip/go.sum | 248 +
src/xray-geoip/init.go | 8 +
src/xray-geoip/lib/config.go | 128 +
src/xray-geoip/lib/error.go | 13 +
src/xray-geoip/lib/func.go | 43 +
src/xray-geoip/lib/instance.go | 65 +
src/xray-geoip/lib/lib.go | 458 +
src/xray-geoip/main.go | 41 +
src/xray-geoip/output/dat/geoip.dat | Bin 0 -> 227594 bytes
src/xray-geoip/output/dat/nord.dat | 10417 ++++
src/xray-geoip/plugin/maxmind/country_csv.go | 214 +
src/xray-geoip/plugin/maxmind/mmdb_in.go | 227 +
src/xray-geoip/plugin/plaintext/text_in.go | 227 +
src/xray-geoip/plugin/plaintext/text_out.go | 166 +
src/xray-geoip/plugin/special/cutter.go | 96 +
src/xray-geoip/plugin/special/private.go | 94 +
src/xray-geoip/plugin/special/test.go | 74 +
src/xray-geoip/plugin/v2ray/dat_in.go | 204 +
src/xray-geoip/plugin/v2ray/dat_out.go | 227 +
src/xray-geosite/data/refilter | 42752 ++++++++++++++++
src/xray-geosite/go.mod | 16 +
src/xray-geosite/go.sum | 20 +
src/xray-geosite/main.go | 391 +
39 files changed, 56317 insertions(+), 254 deletions(-)
rename src/{step 5 ooni list => }/bird2_converter.py (100%)
create mode 100644 src/step 5 ooni list/.idea/.gitignore
create mode 100644 src/step 5 ooni list/.idea/.name
create mode 100644 src/step 5 ooni list/.idea/inspectionProfiles/profiles_settings.xml
create mode 100644 src/step 5 ooni list/.idea/misc.xml
create mode 100644 src/step 5 ooni list/.idea/modules.xml
create mode 100644 src/step 5 ooni list/.idea/step 5 ooni list.iml
create mode 100644 src/step 5 ooni list/.idea/vcs.xml
delete mode 100644 src/step 5 ooni list/ipsum_bgp.py
create mode 100644 src/xray-geoip/config.json
create mode 100644 src/xray-geoip/go.mod
create mode 100644 src/xray-geoip/go.sum
create mode 100644 src/xray-geoip/init.go
create mode 100644 src/xray-geoip/lib/config.go
create mode 100644 src/xray-geoip/lib/error.go
create mode 100644 src/xray-geoip/lib/func.go
create mode 100644 src/xray-geoip/lib/instance.go
create mode 100644 src/xray-geoip/lib/lib.go
create mode 100644 src/xray-geoip/main.go
create mode 100644 src/xray-geoip/output/dat/geoip.dat
create mode 100644 src/xray-geoip/output/dat/nord.dat
create mode 100644 src/xray-geoip/plugin/maxmind/country_csv.go
create mode 100644 src/xray-geoip/plugin/maxmind/mmdb_in.go
create mode 100644 src/xray-geoip/plugin/plaintext/text_in.go
create mode 100644 src/xray-geoip/plugin/plaintext/text_out.go
create mode 100644 src/xray-geoip/plugin/special/cutter.go
create mode 100644 src/xray-geoip/plugin/special/private.go
create mode 100644 src/xray-geoip/plugin/special/test.go
create mode 100644 src/xray-geoip/plugin/v2ray/dat_in.go
create mode 100644 src/xray-geoip/plugin/v2ray/dat_out.go
create mode 100644 src/xray-geosite/data/refilter
create mode 100644 src/xray-geosite/go.mod
create mode 100644 src/xray-geosite/go.sum
create mode 100644 src/xray-geosite/main.go
diff --git a/src/step 5 ooni list/bird2_converter.py b/src/bird2_converter.py
similarity index 100%
rename from src/step 5 ooni list/bird2_converter.py
rename to src/bird2_converter.py
diff --git a/src/step 5 ooni list/.idea/.gitignore b/src/step 5 ooni list/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/src/step 5 ooni list/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/src/step 5 ooni list/.idea/.name b/src/step 5 ooni list/.idea/.name
new file mode 100644
index 0000000..0b8725e
--- /dev/null
+++ b/src/step 5 ooni list/.idea/.name
@@ -0,0 +1 @@
+domain_sum.py
\ No newline at end of file
diff --git a/src/step 5 ooni list/.idea/inspectionProfiles/profiles_settings.xml b/src/step 5 ooni list/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/src/step 5 ooni list/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/step 5 ooni list/.idea/misc.xml b/src/step 5 ooni list/.idea/misc.xml
new file mode 100644
index 0000000..f17f7d1
--- /dev/null
+++ b/src/step 5 ooni list/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/step 5 ooni list/.idea/modules.xml b/src/step 5 ooni list/.idea/modules.xml
new file mode 100644
index 0000000..e53d105
--- /dev/null
+++ b/src/step 5 ooni list/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/step 5 ooni list/.idea/step 5 ooni list.iml b/src/step 5 ooni list/.idea/step 5 ooni list.iml
new file mode 100644
index 0000000..ba390fe
--- /dev/null
+++ b/src/step 5 ooni list/.idea/step 5 ooni list.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/step 5 ooni list/.idea/vcs.xml b/src/step 5 ooni list/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/src/step 5 ooni list/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/step 5 ooni list/domain_sum.py b/src/step 5 ooni list/domain_sum.py
index f45dc45..ff02bd1 100644
--- a/src/step 5 ooni list/domain_sum.py
+++ b/src/step 5 ooni list/domain_sum.py
@@ -25,7 +25,7 @@ def main():
# Read domains from the three files
domains1 = read_domains_from_file("sum/input/domains.lst")
domains2 = read_domains_from_file("sum/input/ooni_domains.lst")
- domains3 = read_domains_from_file("sum/input/community.lst")
+ domains3 = read_domains_from_file("community.lst")
# Combine all domains
all_domains = set(domains1 + domains2 + domains3)
diff --git a/src/step 5 ooni list/ip_4files_sum.py b/src/step 5 ooni list/ip_4files_sum.py
index 4fa5052..fc82c17 100644
--- a/src/step 5 ooni list/ip_4files_sum.py
+++ b/src/step 5 ooni list/ip_4files_sum.py
@@ -13,7 +13,7 @@ def main():
ips1 = read_ips_from_file("sum/input/ip.lst")
ips2 = read_ips_from_file("sum/input/ooni_ips.lst")
ips3 = read_ips_from_file("sum/input/ip_community.lst")
- ips4 = read_ips_from_file("sum/input/discord_ips.lst")
+ ips4 = read_ips_from_file("discord_ips.lst")
# Combine all IPs and remove duplicates
unique_ips = set(ips1 + ips2 + ips3 + ips4)
diff --git a/src/step 5 ooni list/ipsum_bgp.py b/src/step 5 ooni list/ipsum_bgp.py
deleted file mode 100644
index 560fe7e..0000000
--- a/src/step 5 ooni list/ipsum_bgp.py
+++ /dev/null
@@ -1,198 +0,0 @@
-import socket
-import geoip2.database
-import logging
-import requests
-import ipaddress
-import time
-import os
-import subprocess
-import json
-from collections import defaultdict
-from idna import encode as idna_encode
-
-# Paths to input files
-IP_LST_PATH = 'sum/input/ips_all.lst'
-DOMAINS_LST_PATH = 'sum/output/domains_all.lst'
-OUTPUT_FILE = 'sum/output/ipsum.lst'
-
-# Path to the GeoLite2 ASN database
-GEOIP_DB_PATH = 'sum/GeoLite2-ASN.mmdb'
-GEOIP_DB_URL = 'https://git.io/GeoLite2-ASN.mmdb'
-
-# Function to download the GeoLite2 ASN database
-def download_geolite2_asn_db():
- if not os.path.exists(GEOIP_DB_PATH):
- try:
- response = requests.get(GEOIP_DB_URL)
- response.raise_for_status()
- with open(GEOIP_DB_PATH, 'wb') as f:
- f.write(response.content)
- logging.info(f'Downloaded GeoLite2 ASN database to {GEOIP_DB_PATH}')
- except requests.RequestException as e:
- logging.error(f'Failed to download GeoLite2 ASN database: {e}')
- raise
-
-# Initialize the GeoIP2 reader
-def initialize_geoip_reader():
- download_geolite2_asn_db()
- return geoip2.database.Reader(GEOIP_DB_PATH)
-
-# Set up logging
-logging.basicConfig(level=logging.DEBUG,
- format='%(asctime)s - %(levelname)s - %(message)s',
- handlers=[
- logging.FileHandler('summary.log', mode='a'),
- logging.StreamHandler()
- ])
-
-# Trusted ASNs for company domains
-COMPANY_DOMAINS = {
- 'google.com': [15169],
- 'youtube.com': [15169],
- 'ggpht.com': [15169],
- 'facebook.com': [32934],
- 'instagram.com': [32934],
- 'whatsapp.com': [32934],
- 'microsoft.com': [8075],
- 'linkedin.com': [14492],
- 'netflix.com': [2906],
- 'akamai.com': [20940],
- 'twitter.com': [13414],
- 'x.com': [13414],
- 'dropbox.com': [19679],
- 'tesla.com': [394161]
-}
-
-# Local IP CIDRs to exclude
-LOCAL_IP_CIDRS = [
- ipaddress.ip_network('127.0.0.0/8'),
- ipaddress.ip_network('10.0.0.0/8'),
- ipaddress.ip_network('172.16.0.0/12'),
- ipaddress.ip_network('192.168.0.0/16'),
- ipaddress.ip_network('169.254.0.0/16'),
- ipaddress.ip_network('::1/128'),
- ipaddress.ip_network('fc00::/7'),
- ipaddress.ip_network('fe80::/10')
-]
-
-# Function to summarize IPs into /28 subnets at most
-def summarize_ips(ips):
- try:
- # Remove duplicates and sort IPs, treating them as networks (e.g., x.x.x.x/32)
- networks = [ipaddress.ip_network(ip, strict=False) for ip in set(ips)]
- collapsed_networks = ipaddress.collapse_addresses(networks)
- summarized_networks = []
-
- for network in collapsed_networks:
- if network.prefixlen < 28: # If network is bigger than /28, split into /28
- for subnet in network.subnets(new_prefix=28):
- summarized_networks.append(subnet)
- else:
- summarized_networks.append(network)
-
- logging.info(f'Summarized networks: {summarized_networks}')
- return summarized_networks
- except ValueError as e:
- logging.error(f'Error summarizing IPs: {e}')
- return []
-
-# Function to handle rate-limiting errors (429) and retry after waiting
-def handle_rate_limit():
- wait_time = 60 # Wait time of 60 seconds
- logging.warning(f'Rate limit hit. Waiting for {wait_time} seconds.')
- time.sleep(wait_time)
-
-# Function to get CIDRs for a domain from ASN using ip.guide
-def get_cidr_for_asn(asn):
- try:
- command = f'curl -sL https://ip.guide/as{asn}'
- result = subprocess.run(command, shell=True, capture_output=True, text=True)
- if result.returncode == 0:
- data = json.loads(result.stdout)
- return data.get('routes', {}).get('v4', [])
- else:
- logging.error(f'Error executing curl command: {result.stderr}')
- return []
- except Exception as e:
- logging.error(f'Error retrieving CIDRs for ASN {asn}: {e}')
- return []
-
-# Function to resolve a domain with retries and punycode support
-def resolve_domain(domain):
- try:
- domain_punycode = idna_encode(domain).decode('utf-8')
- return socket.gethostbyname_ex(domain_punycode)[2]
- except Exception as e:
- logging.error(f'Could not resolve domain {domain}: {e}')
- return []
-
-# Function to check if a domain matches COMPANY_DOMAINS and fetch CIDRs
-def process_domain_for_asn(domain, processed_asns):
- asns = COMPANY_DOMAINS.get(domain, [])
- cidrs = set()
- for asn in asns:
- if asn not in processed_asns:
- processed_asns.add(asn)
- cidrs.update(get_cidr_for_asn(asn))
- return cidrs
-
-# Function to read IPs from ip.lst
-def read_ips_from_file(file_path):
- try:
- with open(file_path, 'r') as f:
- return [line.strip() for line in f.readlines() if line.strip()]
- except FileNotFoundError:
- logging.error(f'File not found: {file_path}')
- return []
-
-# Function to check if an IP is local
-def is_local_ip(ip):
- try:
- ip_obj = ipaddress.ip_network(ip, strict=False)
- for cidr in LOCAL_IP_CIDRS:
- if ip_obj.version == cidr.version and ip_obj.subnet_of(cidr):
- return True
- except ValueError as e:
- logging.error(f'Invalid IP or CIDR: {ip}: {e}')
- return False
-
-# Function to write summarized CIDRs to ipsum.lst
-def write_summarized_ips(ips, filename):
- try:
- with open(filename, 'w') as f:
- for cidr in ips:
- f.write(f'{cidr}\n')
- logging.info(f'Written summarized IPs to {filename}')
- except Exception as e:
- logging.error(f'Error writing summarized IPs to file: {e}')
-
-# Main function to process ip.lst, summarize, and add CIDRs for company domains
-def main():
- # Initialize the GeoIP2 reader
- reader = initialize_geoip_reader()
-
- # Read IPs from ip.lst
- ips = read_ips_from_file(IP_LST_PATH)
-
- # Filter out local IPs
- ips = [ip for ip in ips if not is_local_ip(ip)]
-
- # Summarize the IPs into /28 networks
- summarized_ips = summarize_ips(ips)
-
- # Check domains.lst for COMPANY_DOMAINS matches and get corresponding CIDRs
- domains = read_ips_from_file(DOMAINS_LST_PATH)
- company_cidrs = set()
- processed_asns = set()
-
- for domain in domains:
- company_cidrs.update(process_domain_for_asn(domain, processed_asns))
-
- # Combine summarized IPs and company CIDRs
- final_cidrs = set(summarized_ips) | company_cidrs
-
- # Write the final output to ipsum.lst
- write_summarized_ips(final_cidrs, OUTPUT_FILE)
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/src/step 5 ooni list/resolver_community.py b/src/step 5 ooni list/resolver_community.py
index 2910981..269802c 100644
--- a/src/step 5 ooni list/resolver_community.py
+++ b/src/step 5 ooni list/resolver_community.py
@@ -2,8 +2,8 @@ import socket
import concurrent.futures
import threading
import gc
-import time # For introducing delay
-import requests # For making API calls to get ASN details
+#import time # For introducing delay
+#import requests # For making API calls to get ASN details
import ipaddress
from idna import encode as idna_encode
from queue import Queue
@@ -55,7 +55,7 @@ def process_domain(domain, existing_cidrs):
return set()
# Function to read domains from domains.lst file
-def read_domains_from_file(file_path="sum/input/community.lst"):
+def read_domains_from_file(file_path="community.lst"):
try:
with open(file_path, 'r', encoding='utf-8') as f:
domains = [line.strip() for line in f.readlines() if line.strip()]
@@ -81,7 +81,7 @@ def main():
gc.enable()
# Read the domains from domains.lst file
- domains = read_domains_from_file("sum/input/community.lst")
+ domains = read_domains_from_file("community.lst")
if not domains:
return
@@ -92,7 +92,7 @@ def main():
writer_thread.start()
# Use ThreadPoolExecutor to use more threads (set to 16 threads for better utilization)
- with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
+ with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
future_to_domain = {executor.submit(process_domain, domain, existing_cidrs): domain for domain in domains}
for future in concurrent.futures.as_completed(future_to_domain):
diff --git a/src/step 5 ooni list/resolver_ooni.py b/src/step 5 ooni list/resolver_ooni.py
index 2662396..8ced875 100644
--- a/src/step 5 ooni list/resolver_ooni.py
+++ b/src/step 5 ooni list/resolver_ooni.py
@@ -2,8 +2,8 @@ import socket
import concurrent.futures
import threading
import gc
-import time # For introducing delay
-import requests # For making API calls to get ASN details
+#import time
+#import requests
import ipaddress
from idna import encode as idna_encode
from queue import Queue
@@ -92,7 +92,7 @@ def main():
writer_thread.start()
# Use ThreadPoolExecutor to use more threads (set to 16 threads for better utilization)
- with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
+ with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
future_to_domain = {executor.submit(process_domain, domain, existing_cidrs): domain for domain in domains}
for future in concurrent.futures.as_completed(future_to_domain):
diff --git a/src/step 6 temp - summarization and ASN CIDRs.py b/src/step 6 temp - summarization and ASN CIDRs.py
index d3dd811..560fe7e 100644
--- a/src/step 6 temp - summarization and ASN CIDRs.py
+++ b/src/step 6 temp - summarization and ASN CIDRs.py
@@ -4,25 +4,44 @@ import logging
import requests
import ipaddress
import time
+import os
+import subprocess
+import json
from collections import defaultdict
from idna import encode as idna_encode
# Paths to input files
-IP_LST_PATH = "ip.lst"
-DOMAINS_LST_PATH = "domains.lst"
-OUTPUT_FILE = "ipsum.lst"
+IP_LST_PATH = 'sum/input/ips_all.lst'
+DOMAINS_LST_PATH = 'sum/output/domains_all.lst'
+OUTPUT_FILE = 'sum/output/ipsum.lst'
# Path to the GeoLite2 ASN database
-GEOIP_DB_PATH = "GeoLite2-ASN.mmdb"
+GEOIP_DB_PATH = 'sum/GeoLite2-ASN.mmdb'
+GEOIP_DB_URL = 'https://git.io/GeoLite2-ASN.mmdb'
+
+# Function to download the GeoLite2 ASN database
+def download_geolite2_asn_db():
+ if not os.path.exists(GEOIP_DB_PATH):
+ try:
+ response = requests.get(GEOIP_DB_URL)
+ response.raise_for_status()
+ with open(GEOIP_DB_PATH, 'wb') as f:
+ f.write(response.content)
+ logging.info(f'Downloaded GeoLite2 ASN database to {GEOIP_DB_PATH}')
+ except requests.RequestException as e:
+ logging.error(f'Failed to download GeoLite2 ASN database: {e}')
+ raise
# Initialize the GeoIP2 reader
-reader = geoip2.database.Reader(GEOIP_DB_PATH)
+def initialize_geoip_reader():
+ download_geolite2_asn_db()
+ return geoip2.database.Reader(GEOIP_DB_PATH)
# Set up logging
logging.basicConfig(level=logging.DEBUG,
- format="%(asctime)s - %(levelname)s - %(message)s",
+ format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
- logging.FileHandler("summary.log", mode='a'),
+ logging.FileHandler('summary.log', mode='a'),
logging.StreamHandler()
])
@@ -34,7 +53,6 @@ COMPANY_DOMAINS = {
'facebook.com': [32934],
'instagram.com': [32934],
'whatsapp.com': [32934],
- 'fbcdn.net': [32934],
'microsoft.com': [8075],
'linkedin.com': [14492],
'netflix.com': [2906],
@@ -45,6 +63,17 @@ COMPANY_DOMAINS = {
'tesla.com': [394161]
}
+# Local IP CIDRs to exclude
+LOCAL_IP_CIDRS = [
+ ipaddress.ip_network('127.0.0.0/8'),
+ ipaddress.ip_network('10.0.0.0/8'),
+ ipaddress.ip_network('172.16.0.0/12'),
+ ipaddress.ip_network('192.168.0.0/16'),
+ ipaddress.ip_network('169.254.0.0/16'),
+ ipaddress.ip_network('::1/128'),
+ ipaddress.ip_network('fc00::/7'),
+ ipaddress.ip_network('fe80::/10')
+]
# Function to summarize IPs into /28 subnets at most
def summarize_ips(ips):
@@ -61,99 +90,103 @@ def summarize_ips(ips):
else:
summarized_networks.append(network)
- logging.info(f"Summarized networks: {summarized_networks}")
+ logging.info(f'Summarized networks: {summarized_networks}')
return summarized_networks
except ValueError as e:
- logging.error(f"Error summarizing IPs: {e}")
+ logging.error(f'Error summarizing IPs: {e}')
return []
-
# Function to handle rate-limiting errors (429) and retry after waiting
def handle_rate_limit():
wait_time = 60 # Wait time of 60 seconds
- logging.warning(f"Rate limit hit. Waiting for {wait_time} seconds.")
+ logging.warning(f'Rate limit hit. Waiting for {wait_time} seconds.')
time.sleep(wait_time)
-
-# Function to get CIDRs for a domain from ASN using GeoLite2
+# Function to get CIDRs for a domain from ASN using ip.guide
def get_cidr_for_asn(asn):
try:
- url = f"https://api.bgpview.io/asn/{asn}/prefixes"
- response = requests.get(url)
-
- if response.status_code == 200:
- data = response.json()
- return [prefix['prefix'] for prefix in data['data']['ipv4_prefixes']]
-
- elif response.status_code == 429:
- handle_rate_limit()
- return get_cidr_for_asn(asn) # Retry after waiting
-
- elif response.status_code == 403:
- logging.error(f"Access forbidden for ASN {asn}, skipping.")
+ command = f'curl -sL https://ip.guide/as{asn}'
+ result = subprocess.run(command, shell=True, capture_output=True, text=True)
+ if result.returncode == 0:
+ data = json.loads(result.stdout)
+ return data.get('routes', {}).get('v4', [])
+ else:
+ logging.error(f'Error executing curl command: {result.stderr}')
return []
-
- return []
except Exception as e:
- logging.error(f"Error retrieving CIDRs for ASN {asn}: {e}")
+ logging.error(f'Error retrieving CIDRs for ASN {asn}: {e}')
return []
-
# Function to resolve a domain with retries and punycode support
def resolve_domain(domain):
try:
domain_punycode = idna_encode(domain).decode('utf-8')
return socket.gethostbyname_ex(domain_punycode)[2]
except Exception as e:
- logging.error(f"Could not resolve domain {domain}: {e}")
+ logging.error(f'Could not resolve domain {domain}: {e}')
return []
-
# Function to check if a domain matches COMPANY_DOMAINS and fetch CIDRs
-def process_domain_for_asn(domain):
+def process_domain_for_asn(domain, processed_asns):
asns = COMPANY_DOMAINS.get(domain, [])
cidrs = set()
- if asns:
- for asn in asns:
+ for asn in asns:
+ if asn not in processed_asns:
+ processed_asns.add(asn)
cidrs.update(get_cidr_for_asn(asn))
return cidrs
-
# Function to read IPs from ip.lst
def read_ips_from_file(file_path):
try:
with open(file_path, 'r') as f:
return [line.strip() for line in f.readlines() if line.strip()]
except FileNotFoundError:
- logging.error(f"File not found: {file_path}")
+ logging.error(f'File not found: {file_path}')
return []
+# Function to check if an IP is local
+def is_local_ip(ip):
+ try:
+ ip_obj = ipaddress.ip_network(ip, strict=False)
+ for cidr in LOCAL_IP_CIDRS:
+ if ip_obj.version == cidr.version and ip_obj.subnet_of(cidr):
+ return True
+ except ValueError as e:
+ logging.error(f'Invalid IP or CIDR: {ip}: {e}')
+ return False
# Function to write summarized CIDRs to ipsum.lst
def write_summarized_ips(ips, filename):
try:
with open(filename, 'w') as f:
for cidr in ips:
- f.write(f"{cidr}\n")
- logging.info(f"Written summarized IPs to {filename}")
+ f.write(f'{cidr}\n')
+ logging.info(f'Written summarized IPs to {filename}')
except Exception as e:
- logging.error(f"Error writing summarized IPs to file: {e}")
-
+ logging.error(f'Error writing summarized IPs to file: {e}')
# Main function to process ip.lst, summarize, and add CIDRs for company domains
def main():
+ # Initialize the GeoIP2 reader
+ reader = initialize_geoip_reader()
+
# Read IPs from ip.lst
ips = read_ips_from_file(IP_LST_PATH)
+ # Filter out local IPs
+ ips = [ip for ip in ips if not is_local_ip(ip)]
+
# Summarize the IPs into /28 networks
summarized_ips = summarize_ips(ips)
# Check domains.lst for COMPANY_DOMAINS matches and get corresponding CIDRs
domains = read_ips_from_file(DOMAINS_LST_PATH)
company_cidrs = set()
+ processed_asns = set()
for domain in domains:
- company_cidrs.update(process_domain_for_asn(domain))
+ company_cidrs.update(process_domain_for_asn(domain, processed_asns))
# Combine summarized IPs and company CIDRs
final_cidrs = set(summarized_ips) | company_cidrs
@@ -161,6 +194,5 @@ def main():
# Write the final output to ipsum.lst
write_summarized_ips(final_cidrs, OUTPUT_FILE)
-
-if __name__ == "__main__":
- main()
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/src/xray-geoip/config.json b/src/xray-geoip/config.json
new file mode 100644
index 0000000..ed9e8c9
--- /dev/null
+++ b/src/xray-geoip/config.json
@@ -0,0 +1,27 @@
+{
+ "input": [
+ {
+ "type": "text",
+ "action": "add",
+ "args": {
+ "name": "refilter",
+ "uri": "./ipsum.lst",
+ "onlyIPType": "ipv4"
+ }
+ },
+ {
+ "type": "private",
+ "action": "add"
+ }
+ ],
+ "output": [
+ {
+ "type": "v2rayGeoIPDat",
+ "action": "output",
+ "args": {
+ "outputName": "geoip.dat",
+ "wantedList": ["refilter", "private"]
+ }
+ }
+ ]
+}
diff --git a/src/xray-geoip/go.mod b/src/xray-geoip/go.mod
new file mode 100644
index 0000000..61c4a0e
--- /dev/null
+++ b/src/xray-geoip/go.mod
@@ -0,0 +1,34 @@
+module github.com/v2fly/geoip
+
+go 1.22.0
+
+toolchain go1.23.1
+
+require (
+ github.com/oschwald/maxminddb-golang v1.13.1
+ github.com/v2fly/v2ray-core/v5 v5.19.0
+ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
+ google.golang.org/protobuf v1.34.2
+)
+
+require (
+ github.com/adrg/xdg v0.5.0 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/pprof v0.0.0-20240927233043-f3f46ee36851 // indirect
+ github.com/onsi/ginkgo/v2 v2.20.2 // indirect
+ github.com/onsi/gomega v1.34.1 // indirect
+ github.com/pelletier/go-toml v1.9.5 // indirect
+ github.com/pires/go-proxyproto v0.7.0 // indirect
+ github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
+ github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
+ github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
+ github.com/quic-go/quic-go v0.47.0 // indirect
+ github.com/stretchr/testify v1.9.0 // indirect
+ go.starlark.net v0.0.0-20240925182052-1207426daebd // indirect
+ golang.org/x/crypto v0.27.0 // indirect
+ golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
+ golang.org/x/net v0.29.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
+ golang.org/x/text v0.18.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/src/xray-geoip/go.sum b/src/xray-geoip/go.sum
new file mode 100644
index 0000000..12ea96c
--- /dev/null
+++ b/src/xray-geoip/go.sum
@@ -0,0 +1,248 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
+github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
+github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
+github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
+github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY=
+github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg=
+github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
+github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d h1:zsO4lp+bjv5XvPTF58Vq+qgmZEYZttJK+CWtSZhKenI=
+github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d/go.mod h1:f1iKL6ZhUWvbk7PdWVmOaak10o86cqMUYEmn1CZNGEI=
+github.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f h1:IXSA5gow10s7zIOJfPOpXDtNBWCTA0715BDAhoJBXEs=
+github.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f/go.mod h1:tleDrpPTlLUVmgnEoN6qBliKWqJaZFJXqZdFjTd+ocU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
+github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
+github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a h1:YtdtTUN1iH97s+6PUjLnaiKSQj4oG1/EZ3N9bx6g4kU=
+github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a/go.mod h1:/CZpbhAusDOobpcb9yubw46kdYjq0zRC0Wpg9a9zFQM=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
+github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
+github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
+github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
+github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
+github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
+github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/pprof v0.0.0-20240927233043-f3f46ee36851 h1:vVVnLmuArD0iybzYyh+YQ98ZQNx6yeqBqYouyJ36hcE=
+github.com/google/pprof v0.0.0-20240927233043-f3f46ee36851/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/jhump/protoreflect v1.15.0 h1:U5T5/2LF0AZQFP9T4W5GfBjBaTruomrKobiR4E+oA/Q=
+github.com/jhump/protoreflect v1.15.0/go.mod h1:qww51KYjD2hoCl/ohxw5cK2LSssFczrbO1t8Ld2TENs=
+github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
+github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
+github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
+github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/reedsolomon v1.9.3 h1:N/VzgeMfHmLc+KHMD1UL/tNkfXAt8FnUqlgXGIduwAY=
+github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
+github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
+github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
+github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
+github.com/mustafaturan/bus v1.0.2 h1:2x3ErwZ0uUPwwZ5ZZoknEQprdaxr68Yl3mY8jDye1Ws=
+github.com/mustafaturan/bus v1.0.2/go.mod h1:h7gfehm8TThv4Dcaa+wDQG7r7j6p74v+7ftr0Rq9i1Q=
+github.com/mustafaturan/monoton v1.0.0 h1:8SCej+JiNn0lyps7V+Jzc1CRAkDR4EZPWrTupQ61YCQ=
+github.com/mustafaturan/monoton v1.0.0/go.mod h1:FOnE7NV3s3EWPXb8/7+/OSdiMBbdlkV0Lz8p1dc+vy8=
+github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
+github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
+github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
+github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
+github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
+github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
+github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
+github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pion/dtls/v2 v2.2.4 h1:YSfYwDQgrxMYXLBc/m7PFY5BVtWlNm/DN4qoU2CbcWg=
+github.com/pion/dtls/v2 v2.2.4/go.mod h1:WGKfxqhrddne4Kg3p11FUMJrynkOY4lb25zHNO49wuw=
+github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
+github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
+github.com/pion/sctp v1.7.6 h1:8qZTdJtbKfAns/Hv5L0PAj8FyXcsKhMH1pKUCGisQg4=
+github.com/pion/sctp v1.7.6/go.mod h1:ichkYQ5tlgCQwEwvgfdcAolqx1nHbYCxo4D7zK/K0X8=
+github.com/pion/transport/v2 v2.0.0 h1:bsMYyqHCbkvHwj+eNCFBuxtlKndKfyGI2vaQmM3fIE4=
+github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
+github.com/pion/udp v0.1.4 h1:OowsTmu1Od3sD6i3fQUJxJn2fEvJO6L1TidgadtbTI8=
+github.com/pion/udp v0.1.4/go.mod h1:G8LDo56HsFwC24LIcnT4YIDU5qcB6NepqqjP0keL2us=
+github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
+github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
+github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
+github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
+github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
+github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
+github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE=
+github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
+github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
+github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
+github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
+github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
+github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
+github.com/refraction-networking/utls v1.3.1 h1:3zVomUqx7nCmyGuU/6kYA/jp5NcqX8KQSGko8pY5Ch4=
+github.com/refraction-networking/utls v1.3.1/go.mod h1:kHXvVB66a4BzVRYC4Em7e1HAfp7uwOCCw0+2CZ3sMY8=
+github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
+github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
+github.com/secure-io/siv-go v0.0.0-20180922214919-5ff40651e2c4 h1:zOjq+1/uLzn/Xo40stbvjIY/yehG0+mfmlsiEmc0xmQ=
+github.com/secure-io/siv-go v0.0.0-20180922214919-5ff40651e2c4/go.mod h1:aI+8yClBW+1uovkHw6HM01YXnYB8vohtB9C83wzx34E=
+github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
+github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/v2fly/BrowserBridge v0.0.0-20210430233438-0570fc1d7d08 h1:4Yh46CVE3k/lPq6hUbEdbB1u1anRBXLewm3k+L0iOMc=
+github.com/v2fly/BrowserBridge v0.0.0-20210430233438-0570fc1d7d08/go.mod h1:KAuQNm+LWQCOFqdBcUgihPzRpVXRKzGbTNhfEfRZ4wY=
+github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848 h1:p1UzXK6VAutXFFQMnre66h7g1BjRKUnLv0HfmmRoz7w=
+github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848/go.mod h1:p80Bv154ZtrGpXMN15slDCqc9UGmfBuUzheDFBYaW/M=
+github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
+github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
+github.com/v2fly/v2ray-core/v5 v5.4.1 h1:1l3KIFKoOlZkUp6D9MUlN/gz6aOEx09YfRVmnwnoGIQ=
+github.com/v2fly/v2ray-core/v5 v5.4.1/go.mod h1:8JUFMS/1biOF9rWV7V5IU3NKU8GhCd442MqW3DgdFKw=
+github.com/v2fly/v2ray-core/v5 v5.19.0 h1:TF2noX1c1npgSg98TASHLdYDWDRhi97gBLpid1cwMUY=
+github.com/v2fly/v2ray-core/v5 v5.19.0/go.mod h1:iRydCoQWwE8mhaf/VOWe5jKB8r7LkZfHsbOvwRfJWUo=
+github.com/xiaokangwang/VLite v0.0.0-20220418190619-cff95160a432 h1:I/ATawgO2RerCq9ACwL0wBB8xNXZdE3J+93MCEHReRs=
+github.com/xiaokangwang/VLite v0.0.0-20220418190619-cff95160a432/go.mod h1:QN7Go2ftTVfx0aCTh9RXHV8pkpi0FtmbwQw40dy61wQ=
+github.com/xtaci/smux v1.5.15 h1:6hMiXswcleXj5oNfcJc+DXS8Vj36XX2LaX98udog6Kc=
+github.com/xtaci/smux v1.5.15/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
+go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g=
+go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk=
+go.starlark.net v0.0.0-20240925182052-1207426daebd h1:S+EMisJOHklQxnS3kqsY8jl2y5aF0FDEdcLnOw3q22E=
+go.starlark.net v0.0.0-20240925182052-1207426daebd/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
+go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
+go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
+go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 h1:nJAwRlGWZZDOD+6wni9KVUNHMpHko/OnRwsrCYeAzPo=
+go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y=
+go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
+go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
+golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
+google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/src/xray-geoip/init.go b/src/xray-geoip/init.go
new file mode 100644
index 0000000..c137de8
--- /dev/null
+++ b/src/xray-geoip/init.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "github.com/v2fly/geoip/plugin/maxmind"
+ _ "github.com/v2fly/geoip/plugin/plaintext"
+ _ "github.com/v2fly/geoip/plugin/special"
+ _ "github.com/v2fly/geoip/plugin/v2ray"
+)
diff --git a/src/xray-geoip/lib/config.go b/src/xray-geoip/lib/config.go
new file mode 100644
index 0000000..20e5137
--- /dev/null
+++ b/src/xray-geoip/lib/config.go
@@ -0,0 +1,128 @@
+package lib
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strings"
+)
+
+var (
+ inputConfigCreatorCache = make(map[string]inputConfigCreator)
+ outputConfigCreatorCache = make(map[string]outputConfigCreator)
+)
+
+type inputConfigCreator func(Action, json.RawMessage) (InputConverter, error)
+
+type outputConfigCreator func(Action, json.RawMessage) (OutputConverter, error)
+
+func RegisterInputConfigCreator(id string, fn inputConfigCreator) error {
+ id = strings.ToLower(id)
+ if _, found := inputConfigCreatorCache[id]; found {
+ return errors.New("config creator has already been registered")
+ }
+ inputConfigCreatorCache[id] = fn
+ return nil
+}
+
+func createInputConfig(id string, action Action, data json.RawMessage) (InputConverter, error) {
+ id = strings.ToLower(id)
+ fn, found := inputConfigCreatorCache[id]
+ if !found {
+ return nil, errors.New("unknown config type")
+ }
+ return fn(action, data)
+}
+
+func RegisterOutputConfigCreator(id string, fn outputConfigCreator) error {
+ id = strings.ToLower(id)
+ if _, found := outputConfigCreatorCache[id]; found {
+ return errors.New("config creator has already been registered")
+ }
+ outputConfigCreatorCache[id] = fn
+ return nil
+}
+
+func createOutputConfig(id string, action Action, data json.RawMessage) (OutputConverter, error) {
+ id = strings.ToLower(id)
+ fn, found := outputConfigCreatorCache[id]
+ if !found {
+ return nil, errors.New("unknown config type")
+ }
+ return fn(action, data)
+}
+
+type config struct {
+ Input []*inputConvConfig `json:"input"`
+ Output []*outputConvConfig `json:"output"`
+}
+
+type inputConvConfig struct {
+ iType string
+ action Action
+ converter InputConverter
+}
+
+func (i *inputConvConfig) UnmarshalJSON(data []byte) error {
+ var temp struct {
+ Type string `json:"type"`
+ Action Action `json:"action"`
+ Args json.RawMessage `json:"args"`
+ }
+
+ if err := json.Unmarshal(data, &temp); err != nil {
+ return err
+ }
+
+ if !ActionsRegistry[temp.Action] {
+ return fmt.Errorf("invalid action %s in type %s", temp.Action, temp.Type)
+ }
+
+ config, err := createInputConfig(temp.Type, temp.Action, temp.Args)
+ if err != nil {
+ return err
+ }
+
+ i.iType = config.GetType()
+ i.action = config.GetAction()
+ i.converter = config
+
+ return nil
+}
+
+type outputConvConfig struct {
+ iType string
+ action Action
+ converter OutputConverter
+}
+
+func (i *outputConvConfig) UnmarshalJSON(data []byte) error {
+ var temp struct {
+ Type string `json:"type"`
+ Action Action `json:"action"`
+ Args json.RawMessage `json:"args"`
+ }
+
+ if err := json.Unmarshal(data, &temp); err != nil {
+ return err
+ }
+
+ if temp.Action == "" {
+ temp.Action = ActionOutput
+ }
+
+ if !ActionsRegistry[temp.Action] {
+ return fmt.Errorf("invalid action %s in type %s", temp.Action, temp.Type)
+ }
+
+ config, err := createOutputConfig(temp.Type, temp.Action, temp.Args)
+ if err != nil {
+ return err
+ }
+
+ i.iType = config.GetType()
+ i.action = config.GetAction()
+ i.converter = config
+
+ return nil
+}
diff --git a/src/xray-geoip/lib/error.go b/src/xray-geoip/lib/error.go
new file mode 100644
index 0000000..5778e96
--- /dev/null
+++ b/src/xray-geoip/lib/error.go
@@ -0,0 +1,13 @@
+package lib
+
+import "errors"
+
+var (
+ ErrDuplicatedConverter = errors.New("duplicated converter")
+ ErrUnknownAction = errors.New("unknown action")
+ ErrInvalidIPType = errors.New("invalid IP type")
+ ErrInvalidIP = errors.New("invalid IP address")
+ ErrInvalidIPLength = errors.New("invalid IP address length")
+ ErrInvalidIPNet = errors.New("invalid IPNet address")
+ ErrInvalidPrefixType = errors.New("invalid prefix type")
+)
diff --git a/src/xray-geoip/lib/func.go b/src/xray-geoip/lib/func.go
new file mode 100644
index 0000000..8cef3ce
--- /dev/null
+++ b/src/xray-geoip/lib/func.go
@@ -0,0 +1,43 @@
+package lib
+
+import (
+ "fmt"
+ "strings"
+)
+
+var (
+ inputConverterMap = make(map[string]InputConverter)
+ outputConverterMap = make(map[string]OutputConverter)
+)
+
+func ListInputConverter() {
+ fmt.Println("All available input formats:")
+ for name, ic := range inputConverterMap {
+ fmt.Printf(" - %s (%s)\n", name, ic.GetDescription())
+ }
+}
+
+func RegisterInputConverter(name string, c InputConverter) error {
+ name = strings.TrimSpace(name)
+ if _, ok := inputConverterMap[name]; ok {
+ return ErrDuplicatedConverter
+ }
+ inputConverterMap[name] = c
+ return nil
+}
+
+func ListOutputConverter() {
+ fmt.Println("All available output formats:")
+ for name, oc := range outputConverterMap {
+ fmt.Printf(" - %s (%s)\n", name, oc.GetDescription())
+ }
+}
+
+func RegisterOutputConverter(name string, c OutputConverter) error {
+ name = strings.TrimSpace(name)
+ if _, ok := outputConverterMap[name]; ok {
+ return ErrDuplicatedConverter
+ }
+ outputConverterMap[name] = c
+ return nil
+}
diff --git a/src/xray-geoip/lib/instance.go b/src/xray-geoip/lib/instance.go
new file mode 100644
index 0000000..5631766
--- /dev/null
+++ b/src/xray-geoip/lib/instance.go
@@ -0,0 +1,65 @@
+package lib
+
+import (
+ "encoding/json"
+ "errors"
+ "os"
+)
+
+type Instance struct {
+ config *config
+ input []InputConverter
+ output []OutputConverter
+}
+
+func NewInstance() (*Instance, error) {
+ return &Instance{
+ config: new(config),
+ input: make([]InputConverter, 0),
+ output: make([]OutputConverter, 0),
+ }, nil
+}
+
+func (i *Instance) Init(configFile string) error {
+ content, err := os.ReadFile(configFile)
+ if err != nil {
+ return err
+ }
+
+ if err := json.Unmarshal(content, &i.config); err != nil {
+ return err
+ }
+
+ for _, input := range i.config.Input {
+ i.input = append(i.input, input.converter)
+ }
+
+ for _, output := range i.config.Output {
+ i.output = append(i.output, output.converter)
+ }
+
+ return nil
+}
+
+func (i *Instance) Run() error {
+ if len(i.input) == 0 || len(i.output) == 0 {
+ return errors.New("input type and output type must be specified")
+ }
+
+ var err error
+ container := NewContainer()
+ for _, ic := range i.input {
+ container, err = ic.Input(container)
+ if err != nil {
+ return err
+ }
+ }
+
+ for _, oc := range i.output {
+ if err := oc.Output(container); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/src/xray-geoip/lib/lib.go b/src/xray-geoip/lib/lib.go
new file mode 100644
index 0000000..d1d23ab
--- /dev/null
+++ b/src/xray-geoip/lib/lib.go
@@ -0,0 +1,458 @@
+package lib
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "net/netip"
+ "strings"
+ "sync"
+
+ "go4.org/netipx"
+)
+
+const (
+ ActionAdd Action = "add"
+ ActionRemove Action = "remove"
+ ActionOutput Action = "output"
+
+ IPv4 IPType = "ipv4"
+ IPv6 IPType = "ipv6"
+)
+
+var ActionsRegistry = map[Action]bool{
+ ActionAdd: true,
+ ActionRemove: true,
+ ActionOutput: true,
+}
+
+type Action string
+
+type IPType string
+
+type Typer interface {
+ GetType() string
+}
+
+type Actioner interface {
+ GetAction() Action
+}
+
+type Descriptioner interface {
+ GetDescription() string
+}
+
+type InputConverter interface {
+ Typer
+ Actioner
+ Descriptioner
+ Input(Container) (Container, error)
+}
+
+type OutputConverter interface {
+ Typer
+ Actioner
+ Descriptioner
+ Output(Container) error
+}
+
+type Entry struct {
+ name string
+ mu *sync.Mutex
+ ipv4Builder *netipx.IPSetBuilder
+ ipv6Builder *netipx.IPSetBuilder
+}
+
+func NewEntry(name string) *Entry {
+ return &Entry{
+ name: strings.ToUpper(strings.TrimSpace(name)),
+ mu: new(sync.Mutex),
+ ipv4Builder: new(netipx.IPSetBuilder),
+ ipv6Builder: new(netipx.IPSetBuilder),
+ }
+}
+
+func (e *Entry) GetName() string {
+ return e.name
+}
+
+func (e *Entry) hasIPv4Builder() bool {
+ return e.ipv4Builder != nil
+}
+
+func (e *Entry) hasIPv6Builder() bool {
+ return e.ipv6Builder != nil
+}
+
+func (e *Entry) processPrefix(src any) (*netip.Prefix, IPType, error) {
+ switch src := src.(type) {
+ case net.IP:
+ ip, ok := netipx.FromStdIP(src)
+ if !ok {
+ return nil, "", ErrInvalidIP
+ }
+ switch {
+ case ip.Is4():
+ prefix := netip.PrefixFrom(ip, 32)
+ return &prefix, IPv4, nil
+ case ip.Is6():
+ prefix := netip.PrefixFrom(ip, 128)
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case *net.IPNet:
+ prefix, ok := netipx.FromStdIPNet(src)
+ if !ok {
+ return nil, "", ErrInvalidIPNet
+ }
+ ip := prefix.Addr()
+ switch {
+ case ip.Is4():
+ return &prefix, IPv4, nil
+ case ip.Is6():
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case netip.Addr:
+ switch {
+ case src.Is4():
+ prefix := netip.PrefixFrom(src, 32)
+ return &prefix, IPv4, nil
+ case src.Is6():
+ prefix := netip.PrefixFrom(src, 128)
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case *netip.Addr:
+ switch {
+ case src.Is4():
+ prefix := netip.PrefixFrom(*src, 32)
+ return &prefix, IPv4, nil
+ case src.Is6():
+ prefix := netip.PrefixFrom(*src, 128)
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case netip.Prefix:
+ ip := src.Addr()
+ switch {
+ case ip.Is4():
+ return &src, IPv4, nil
+ case ip.Is6():
+ return &src, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case *netip.Prefix:
+ ip := src.Addr()
+ switch {
+ case ip.Is4():
+ return src, IPv4, nil
+ case ip.Is6():
+ return src, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ case string:
+ _, network, err := net.ParseCIDR(src)
+ switch err {
+ case nil:
+ prefix, ok := netipx.FromStdIPNet(network)
+ if !ok {
+ return nil, "", ErrInvalidIPNet
+ }
+ ip := prefix.Addr()
+ switch {
+ case ip.Is4():
+ return &prefix, IPv4, nil
+ case ip.Is6():
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+
+ default:
+ ip, err := netip.ParseAddr(src)
+ if err != nil {
+ return nil, "", err
+ }
+ switch {
+ case ip.Is4():
+ prefix := netip.PrefixFrom(ip, 32)
+ return &prefix, IPv4, nil
+ case ip.Is6():
+ prefix := netip.PrefixFrom(ip, 128)
+ return &prefix, IPv6, nil
+ default:
+ return nil, "", ErrInvalidIPLength
+ }
+ }
+ }
+
+ return nil, "", ErrInvalidPrefixType
+}
+
+func (e *Entry) add(prefix *netip.Prefix, ipType IPType) error {
+ e.mu.Lock()
+ defer e.mu.Unlock()
+
+ switch ipType {
+ case IPv4:
+ if !e.hasIPv4Builder() {
+ e.ipv4Builder = new(netipx.IPSetBuilder)
+ }
+ e.ipv4Builder.AddPrefix(*prefix)
+ case IPv6:
+ if !e.hasIPv6Builder() {
+ e.ipv6Builder = new(netipx.IPSetBuilder)
+ }
+ e.ipv6Builder.AddPrefix(*prefix)
+ default:
+ return ErrInvalidIPType
+ }
+
+ return nil
+}
+
+func (e *Entry) remove(prefix *netip.Prefix, ipType IPType) error {
+ e.mu.Lock()
+ defer e.mu.Unlock()
+
+ switch ipType {
+ case IPv4:
+ if e.hasIPv4Builder() {
+ e.ipv4Builder.RemovePrefix(*prefix)
+ }
+ case IPv6:
+ if e.hasIPv6Builder() {
+ e.ipv6Builder.RemovePrefix(*prefix)
+ }
+ default:
+ return ErrInvalidIPType
+ }
+
+ return nil
+}
+
+func (e *Entry) AddPrefix(cidr any) error {
+ prefix, ipType, err := e.processPrefix(cidr)
+ if err != nil {
+ return err
+ }
+ if err := e.add(prefix, ipType); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (e *Entry) RemovePrefix(cidr string) error {
+ prefix, ipType, err := e.processPrefix(cidr)
+ if err != nil {
+ return err
+ }
+ if err := e.remove(prefix, ipType); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (e *Entry) MarshalText(opts ...IgnoreIPOption) ([]string, error) {
+ var ignoreIPType IPType
+ for _, opt := range opts {
+ if opt != nil {
+ ignoreIPType = opt()
+ }
+ }
+ disableIPv4, disableIPv6 := false, false
+ switch ignoreIPType {
+ case IPv4:
+ disableIPv4 = true
+ case IPv6:
+ disableIPv6 = true
+ }
+
+ prefixSet := make([]string, 0, 1024)
+
+ if !disableIPv4 && e.hasIPv4Builder() {
+ ipv4set, err := e.ipv4Builder.IPSet()
+ if err != nil {
+ return nil, err
+ }
+ prefixes := ipv4set.Prefixes()
+ for _, prefix := range prefixes {
+ prefixSet = append(prefixSet, prefix.String())
+ }
+ }
+
+ if !disableIPv6 && e.hasIPv6Builder() {
+ ipv6set, err := e.ipv6Builder.IPSet()
+ if err != nil {
+ return nil, err
+ }
+ prefixes := ipv6set.Prefixes()
+ for _, prefix := range prefixes {
+ prefixSet = append(prefixSet, prefix.String())
+ }
+ }
+
+ if len(prefixSet) > 0 {
+ return prefixSet, nil
+ }
+
+ return nil, fmt.Errorf("entry %s has no prefix", e.GetName())
+}
+
+type IgnoreIPOption func() IPType
+
+func IgnoreIPv4() IPType {
+ return IPv4
+}
+
+func IgnoreIPv6() IPType {
+ return IPv6
+}
+
+type Container interface {
+ GetEntry(name string) (*Entry, bool)
+ Add(entry *Entry, opts ...IgnoreIPOption) error
+ Remove(name string, opts ...IgnoreIPOption)
+ Loop() <-chan *Entry
+}
+
+type container struct {
+ entries *sync.Map // map[name]*Entry
+}
+
+func NewContainer() Container {
+ return &container{
+ entries: new(sync.Map),
+ }
+}
+
+func (c *container) isValid() bool {
+ if c == nil || c.entries == nil {
+ return false
+ }
+ return true
+}
+
+func (c *container) GetEntry(name string) (*Entry, bool) {
+ if !c.isValid() {
+ return nil, false
+ }
+ val, ok := c.entries.Load(strings.ToUpper(strings.TrimSpace(name)))
+ if !ok {
+ return nil, false
+ }
+ return val.(*Entry), true
+}
+
+func (c *container) Loop() <-chan *Entry {
+ ch := make(chan *Entry, 300)
+ go func() {
+ c.entries.Range(func(key, value any) bool {
+ ch <- value.(*Entry)
+ return true
+ })
+ close(ch)
+ }()
+ return ch
+}
+
+func (c *container) Add(entry *Entry, opts ...IgnoreIPOption) error {
+ var ignoreIPType IPType
+ for _, opt := range opts {
+ if opt != nil {
+ ignoreIPType = opt()
+ }
+ }
+
+ name := entry.GetName()
+ val, found := c.GetEntry(name)
+ switch found {
+ case true:
+ var ipv4set, ipv6set *netipx.IPSet
+ var err4, err6 error
+ if entry.hasIPv4Builder() {
+ ipv4set, err4 = entry.ipv4Builder.IPSet()
+ if err4 != nil {
+ return err4
+ }
+ }
+ if entry.hasIPv6Builder() {
+ ipv6set, err6 = entry.ipv6Builder.IPSet()
+ if err6 != nil {
+ return err6
+ }
+ }
+ switch ignoreIPType {
+ case IPv4:
+ if !val.hasIPv6Builder() {
+ val.ipv6Builder = new(netipx.IPSetBuilder)
+ }
+ val.ipv6Builder.AddSet(ipv6set)
+ case IPv6:
+ if !val.hasIPv4Builder() {
+ val.ipv4Builder = new(netipx.IPSetBuilder)
+ }
+ val.ipv4Builder.AddSet(ipv4set)
+ default:
+ if !val.hasIPv4Builder() {
+ val.ipv4Builder = new(netipx.IPSetBuilder)
+ }
+ if !val.hasIPv6Builder() {
+ val.ipv6Builder = new(netipx.IPSetBuilder)
+ }
+ val.ipv4Builder.AddSet(ipv4set)
+ val.ipv6Builder.AddSet(ipv6set)
+ }
+ c.entries.Store(name, val)
+
+ case false:
+ switch ignoreIPType {
+ case IPv4:
+ entry.ipv4Builder = nil
+ case IPv6:
+ entry.ipv6Builder = nil
+ }
+ c.entries.Store(name, entry)
+ }
+
+ return nil
+}
+
+func (c *container) Remove(name string, opts ...IgnoreIPOption) {
+ val, found := c.GetEntry(name)
+ if !found {
+ log.Printf("failed to remove non-existent entry %s", name)
+ return
+ }
+
+ var ignoreIPType IPType
+ for _, opt := range opts {
+ if opt != nil {
+ ignoreIPType = opt()
+ }
+ }
+
+ switch ignoreIPType {
+ case IPv4:
+ val.ipv6Builder = nil
+ c.entries.Store(name, val)
+ case IPv6:
+ val.ipv4Builder = nil
+ c.entries.Store(name, val)
+ default:
+ c.entries.Delete(name)
+ }
+}
diff --git a/src/xray-geoip/main.go b/src/xray-geoip/main.go
new file mode 100644
index 0000000..c35696b
--- /dev/null
+++ b/src/xray-geoip/main.go
@@ -0,0 +1,41 @@
+// GeoIP generator
+//
+// Before running this file, the GeoIP database must be downloaded and present.
+// To download GeoIP database: https://dev.maxmind.com/geoip/geoip2/geolite2/
+// Inside you will find block files for IPv4 and IPv6 and country code mapping.
+package main
+
+import (
+ "flag"
+ "log"
+
+ "github.com/v2fly/geoip/lib"
+)
+
+var (
+ list = flag.Bool("l", false, "List all available input and output formats")
+ configFile = flag.String("c", "config.json", "Path to the config file")
+)
+
+func main() {
+ flag.Parse()
+
+ if *list {
+ lib.ListInputConverter()
+ lib.ListOutputConverter()
+ return
+ }
+
+ instance, err := lib.NewInstance()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := instance.Init(*configFile); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := instance.Run(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/xray-geoip/output/dat/geoip.dat b/src/xray-geoip/output/dat/geoip.dat
new file mode 100644
index 0000000000000000000000000000000000000000..6aa74652fccc332df6ea4bcbe01838cbe6219134
GIT binary patch
literal 227594
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