Files
tianxuan/scripts/gen_complex_test.py
T

87 lines
4.1 KiB
Python

"""生成复杂 TLS 合成测试数据(含经纬度、MAC地址、大量空值)"""
import polars as pl
import numpy as np
from pathlib import Path
RNG = np.random.RandomState(42)
CLIENTS = [f'192.168.{RNG.randint(1,255)}.{RNG.randint(1,255)}' for _ in range(80)]
SERVERS = (
[f'10.0.{RNG.randint(1,255)}.{RNG.randint(1,255)}' for _ in range(80)]
+ [f'203.0.113.{RNG.randint(1,255)}' for _ in range(30)]
)
DOMAINS = ['mail.example.com', 'api.example.org', 'cdn.example.net', 'login.example.org',
'storage.example.net', 'video.example.com', 'auth.example.com', 'pay.example.org']
TLS_VERSIONS = ['TLSv1.2', 'TLSv1.3', 'TLSv1.2', 'TLSv1.3', 'TLSv1.1', None]
CIPHERS = ['TLS_AES_128_GCM_SHA256', 'TLS_AES_256_GCM_SHA384',
'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', None]
CERT_STATUS = ['valid', 'valid', 'valid', 'expired', 'self_signed', None]
def gen_mac():
return ':'.join(f'{RNG.randint(0,255):02x}' for _ in range(6))
CITIES = [
('Beijing', 39.9, 116.4), ('Shanghai', 31.2, 121.5), ('Tokyo', 35.7, 139.7),
('Singapore', 1.35, 103.8), ('London', 51.5, -0.13), ('Frankfurt', 50.1, 8.68),
('NewYork', 40.7, -74.0), ('SanFrancisco', 37.8, -122.4),
('Sydney', -33.9, 151.2), ('Mumbai', 19.1, 72.9),
]
def gen_flows(n_rows=5000):
from datetime import datetime, timedelta
base_ts = datetime(2025, 1, 1)
rows = []
for _ in range(n_rows):
src_ip = RNG.choice(CLIENTS)
dst_ip = RNG.choice(SERVERS)
si = RNG.randint(0, len(CITIES))
di = RNG.randint(0, len(CITIES))
src_city, src_lat, src_lon = CITIES[si]
dst_city, dst_lat, dst_lon = CITIES[di]
same_city = src_city == dst_city
bs = int(max(0, RNG.lognormal(8, 2))) if RNG.random() > 0.05 else None
br = int(max(0, bs * RNG.uniform(0.1, 2))) if bs and RNG.random() > 0.05 else None
dur = round(RNG.exponential(20), 2) if RNG.random() > 0.08 else None
hok = RNG.choice([True, True, True, False, None])
trusted = hok and RNG.choice([True, True, False, None]) if hok else None
tmo = int(RNG.exponential(500)) + 100 if hok else RNG.choice([None, RNG.randint(5000, 30000)])
rows.append({
'timestamp': (base_ts + timedelta(seconds=RNG.randint(0, 31536000))).strftime('%Y-%m-%d %H:%M:%S'),
'src_ip': src_ip, 'dst_ip': dst_ip,
'src_mac': gen_mac(), 'dst_mac': gen_mac(),
'src_url': f'https://{RNG.choice(DOMAINS)}{RNG.choice(["/","/login","/api/v1/users","/api/v1/data","/favicon.ico"])}',
'dst_url': f'https://{RNG.choice(DOMAINS)}{RNG.choice(["/","/login","/api/v1/users","/api/v1/data"])}',
'sni': RNG.choice(DOMAINS + [None, None]),
'src_city': src_city, 'src_latitude': src_lat, 'src_longitude': src_lon,
'dst_city': dst_city if not same_city else None,
'dst_latitude': dst_lat if not same_city else None,
'dst_longitude': dst_lon if not same_city else None,
'bytes_sent': bs, 'bytes_rev': br, 'duration': dur,
'tls_version': RNG.choice(TLS_VERSIONS),
'cipher': RNG.choice(CIPHERS),
'dst_port': RNG.choice([80, 443, 8080, 8443, 53, 993, 5223, None]),
'cert_status': RNG.choice(CERT_STATUS),
'handshake_ok': hok, 'trusted': trusted, 'timeout_ms': tmo,
})
df = pl.DataFrame(rows)
nulls = df.null_count()
for col in df.columns:
n = int(nulls[col].item())
if n > 0:
print(f' {col}: {n}/{len(df)} 缺失 ({n*100//len(df)}%)')
print(f'总行数: {len(df)}, 列数: {len(df.columns)}')
return df
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--rows', type=int, default=5000)
parser.add_argument('--output', type=str, default='data/complex_test.csv')
args = parser.parse_args()
df = gen_flows(args.rows)
Path(args.output).parent.mkdir(parents=True, exist_ok=True)
df.write_csv(args.output, null_value='')
print(f'已生成: {args.output} ({Path(args.output).stat().st_size/1024/1024:.1f} MB)')