atharvawarade9807 commited on
Commit
c6e6f10
·
verified ·
1 Parent(s): 11b6a2c

Upload 18 files

Browse files
Version_4/New Text Document.txt ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import csv
2
+ import json
3
+ import socket
4
+ import random
5
+ from urllib.parse import urlparse
6
+
7
+ # ==========================================
8
+ # DEFENDER V5 - BALANCED CSV TO JSON PIPELINE
9
+ # ==========================================
10
+
11
+ def extract_domain(raw_url):
12
+ """Safely extracts the domain name from a raw URL string."""
13
+ url = raw_url.strip()
14
+ if not url.startswith('http'):
15
+ url = 'http://' + url
16
+ try:
17
+ parsed = urlparse(url)
18
+ domain = parsed.netloc.split(':')[0]
19
+ return domain if domain else None
20
+ except:
21
+ return None
22
+
23
+ def resolve_domain(domain):
24
+ """Attempts to resolve domain to an active IP address."""
25
+ try:
26
+ return socket.gethostbyname(domain)
27
+ except socket.gaierror:
28
+ return None
29
+
30
+ def build_dataset_from_csv():
31
+ csv_filename = "malicious_urls.csv" # <-- Change this if your file name is different
32
+ output_file = "network_telemetry.json"
33
+
34
+ print(f"[*] Scanning {csv_filename} to extract 2500 'good' and 2500 'bad' URLs...")
35
+
36
+ telemetry_data = []
37
+ bad_count = 0
38
+ good_count = 0
39
+
40
+ try:
41
+ with open(csv_filename, mode='r', encoding='utf-8') as file:
42
+ reader = csv.DictReader(file)
43
+
44
+ for row in reader:
45
+ # Stop parsing immediately if both limits are reached
46
+ if bad_count >= 2500 and good_count >= 2500:
47
+ break
48
+
49
+ raw_url = row.get('URL', '')
50
+ label_str = row.get('Label', '').strip().lower()
51
+
52
+ if not raw_url:
53
+ continue
54
+
55
+ # Check label and verify if we still need more samples for that category
56
+ if label_str == 'bad' and bad_count < 2500:
57
+ is_malicious = 1.0
58
+ elif label_str == 'good' and good_count < 2500:
59
+ is_malicious = 0.0
60
+ else:
61
+ continue # Skip row if label doesn't match or target is already full
62
+
63
+ domain = extract_domain(raw_url)
64
+ if not domain:
65
+ continue
66
+
67
+ # DNS Lookup (ensures high quality topological edges for the Graph)
68
+ ip = resolve_domain(domain)
69
+
70
+ if ip:
71
+ telemetry_data.append({
72
+ "ip": ip,
73
+ "domain": domain,
74
+ "asn": random.randint(40000, 60000) if is_malicious == 1.0 else 15169, # Placeholder ASNs
75
+ "is_malicious": is_malicious
76
+ })
77
+
78
+ if is_malicious == 1.0:
79
+ bad_count += 1
80
+ else:
81
+ good_count += 1
82
+
83
+ # Progress counter (DNS resolution takes a moment)
84
+ total_processed = bad_count + good_count
85
+ if total_processed % 100 == 0:
86
+ print(f" -> Processed {total_processed} active rows... (Good: {good_count}/2500 | Bad: {bad_count}/2500)")
87
+
88
+ print(f"\n[+] Extraction Complete!")
89
+ print(f" - Legitimate (Good) URLs mapped: {good_count}")
90
+ print(f" - Malicious (Bad) URLs mapped: {bad_count}")
91
+
92
+ # Shuffle the list so the model doesn't process all bad URLs first, then all good URLs
93
+ random.shuffle(telemetry_data)
94
+
95
+ with open(output_file, "w") as f:
96
+ json.dump(telemetry_data, f, indent=4)
97
+
98
+ print(f"[+] Balanced dataset successfully saved to: {output_file}")
99
+ print("[*] Ready to train! Run: python train.py")
100
+
101
+ except FileNotFoundError:
102
+ print(f"[-] Error: Could not find '{csv_filename}' in this directory.")
103
+
104
+ if __name__ == "__main__":
105
+ build_dataset_from_csv()
Version_4/__pycache__/config.cpython-313.pyc ADDED
Binary file (916 Bytes). View file
 
Version_4/app.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ import torch
4
+ import os
5
+ import socket
6
+ from urllib.parse import urlparse
7
+ from models.gnn import PhishingGNN_Model
8
+ from pipeline.graph_engine import TopologicalGraphEngine
9
+ from config import *
10
+ import uvicorn
11
+
12
+ app = FastAPI(title="Defender V5 Sovereign Threat Analysis API")
13
+
14
+ # Define node dimension configurations
15
+ in_channels_dict = {
16
+ 'ip': 16,
17
+ 'domain': 32,
18
+ 'asn': 8,
19
+ 'cert': 16
20
+ }
21
+
22
+ # Load model directly into state memory matching training dimension maps
23
+ model = PhishingGNN_Model(
24
+ metadata=GRAPH_METADATA,
25
+ in_channels_dict=in_channels_dict,
26
+ hidden_channels=HIDDEN_CHANNELS,
27
+ num_heads=NUM_HEADS,
28
+ num_layers=NUM_LAYERS,
29
+ dropout_rate=0.0
30
+ )
31
+
32
+ if os.path.exists(MODEL_SAVE_PATH):
33
+ model.load_state_dict(torch.load(MODEL_SAVE_PATH, map_location='cpu', weights_only=True))
34
+ model.eval()
35
+
36
+ # Payload model expects a URL
37
+ class URLPayload(BaseModel):
38
+ url: str
39
+
40
+ @app.post("/analyze")
41
+ async def analyze_url(payload: URLPayload):
42
+ try:
43
+ # 1. Parse the URL to extract the domain
44
+ parsed_url = urlparse(payload.url)
45
+ domain = parsed_url.netloc or parsed_url.path.split('/')[0]
46
+
47
+ if ':' in domain:
48
+ domain = domain.split(':')[0]
49
+
50
+ if not domain:
51
+ raise HTTPException(status_code=400, detail="Invalid URL format.")
52
+
53
+ # 2. Resolve the domain to an IP address
54
+ try:
55
+ ip = socket.gethostbyname(domain)
56
+ except socket.gaierror:
57
+ raise HTTPException(status_code=400, detail=f"DNS Resolution failed for domain: {domain}")
58
+
59
+ # 3. Build telemetry dictionary
60
+ telemetry_log = {
61
+ "ip": ip,
62
+ "domain": domain,
63
+ "asn": None
64
+ }
65
+
66
+ # 4. Pass through Graph Engine
67
+ engine = TopologicalGraphEngine()
68
+ x_dict, edge_index_dict = engine.extract_and_build([telemetry_log])
69
+
70
+ with torch.no_grad():
71
+ raw_scores = model(x_dict, edge_index_dict)
72
+ threat_probability = float(raw_scores.max().item())
73
+
74
+ return {
75
+ "input_url": payload.url,
76
+ "resolved_domain": domain,
77
+ "resolved_ip": ip,
78
+ "structural_anomaly_score": round(threat_probability, 5),
79
+ "remediation_verdict": "ISOLATE_ROUTING" if threat_probability > 0.70 else "ALLOW"
80
+ }
81
+
82
+ except HTTPException:
83
+ raise
84
+ except Exception as e:
85
+ raise HTTPException(status_code=500, detail=f"Graph Engine Exception: {str(e)}")
86
+
87
+ if __name__ == "__main__":
88
+ uvicorn.run(app, host="127.0.0.1", port=8005)
Version_4/build_dataset.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import csv
2
+ import json
3
+ import socket
4
+ import random
5
+ from urllib.parse import urlparse
6
+
7
+ # ==========================================
8
+ # DEFENDER V5 - CSV TO JSON PIPELINE (BUGFIXED)
9
+ # ==========================================
10
+
11
+ def extract_domain(raw_url):
12
+ """Safely extracts the domain name from a raw URL string."""
13
+ url = raw_url.strip()
14
+ if not url.startswith('http'):
15
+ url = 'http://' + url
16
+ try:
17
+ parsed = urlparse(url)
18
+ domain = parsed.netloc.split(':')[0]
19
+ return domain if domain else None
20
+ except:
21
+ return None
22
+
23
+ def resolve_domain(domain):
24
+ """Attempts to resolve domain to an active IP address. Fails gracefully if offline or corrupted."""
25
+ try:
26
+ return socket.gethostbyname(domain)
27
+ except (socket.gaierror, UnicodeEncodeError):
28
+ # BUGFIX: Added UnicodeEncodeError to prevent crashes from hidden junk characters like \x87
29
+ return None
30
+
31
+ def build_dataset_from_csv():
32
+ csv_filename = "malicious_urls.csv"
33
+ output_file = "network_telemetry.json"
34
+
35
+ print(f"[*] Scanning {csv_filename} to extract 2500 'good' and 2500 'bad' URLs...")
36
+
37
+ telemetry_data = []
38
+ bad_count = 0
39
+ good_count = 0
40
+
41
+ try:
42
+ with open(csv_filename, mode='r', encoding='utf-8', errors='ignore') as file:
43
+ # Added errors='ignore' above to strip out any raw structural file encoding issues
44
+ reader = csv.DictReader(file)
45
+
46
+ for row in reader:
47
+ # Stop parsing immediately if both limits are reached
48
+ if bad_count >= 2500 and good_count >= 2500:
49
+ break
50
+
51
+ raw_url = row.get('URL', '')
52
+ label_str = row.get('Label', '').strip().lower()
53
+
54
+ if not raw_url:
55
+ continue
56
+
57
+ # Check label and verify if we still need more samples for that category
58
+ if label_str == 'bad' and bad_count < 2500:
59
+ is_malicious = 1.0
60
+ elif label_str == 'good' and good_count < 2500:
61
+ is_malicious = 0.0
62
+ else:
63
+ continue # Skip row if label doesn't match or target category is already full
64
+
65
+ domain = extract_domain(raw_url)
66
+ if not domain:
67
+ continue
68
+
69
+ # DNS Lookup
70
+ ip = resolve_domain(domain)
71
+
72
+ if ip:
73
+ telemetry_data.append({
74
+ "ip": ip,
75
+ "domain": domain,
76
+ "asn": random.randint(40000, 60000) if is_malicious == 1.0 else 15169,
77
+ "is_malicious": is_malicious
78
+ })
79
+
80
+ if is_malicious == 1.0:
81
+ bad_count += 1
82
+ else:
83
+ good_count += 1
84
+
85
+ # Progress counter
86
+ total_processed = bad_count + good_count
87
+ if total_processed % 100 == 0 or (bad_count == 2500 and total_processed % 10 == 0):
88
+ print(f" -> Processed {total_processed} active rows... (Good: {good_count}/2500 | Bad: {bad_count}/2500)")
89
+
90
+ print(f"\n[+] Extraction Complete!")
91
+ print(f" - Legitimate (Good) URLs mapped: {good_count}")
92
+ print(f" - Malicious (Bad) URLs mapped: {bad_count}")
93
+
94
+ if len(telemetry_data) == 0:
95
+ print("[-] Error: No active domains were resolved. Check internet connection or CSV headers.")
96
+ return
97
+
98
+ # Shuffle the list so the model mixes good and bad data
99
+ random.shuffle(telemetry_data)
100
+
101
+ with open(output_file, "w") as f:
102
+ json.dump(telemetry_data, f, indent=4)
103
+
104
+ print(f"[+] Balanced dataset successfully saved to: {output_file}")
105
+ print("[*] Ready to train! Run: python train.py")
106
+
107
+ except FileNotFoundError:
108
+ print(f"[-] Error: Could not find '{csv_filename}' in this directory.")
109
+
110
+ if __name__ == "__main__":
111
+ build_dataset_from_csv()
Version_4/checkpoints/phishing_gnn_master.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9d89a611d4655e4d430f60432caa2b7d600587dbf385dd14fdfa992412d11cb
3
+ size 4696055
Version_4/config.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ # ==========================================
4
+ # DEFENDER V5 - GLOBAL CONFIGURATION
5
+ # ==========================================
6
+
7
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
8
+ CHECKPOINT_DIR = os.path.join(BASE_DIR, "checkpoints")
9
+ MODEL_SAVE_PATH = os.path.join(CHECKPOINT_DIR, "phishing_gnn_master.pt")
10
+
11
+ # Topology Definition
12
+ NODE_TYPES = ['ip', 'domain', 'asn', 'cert']
13
+ EDGE_TYPES = [
14
+ ('domain', 'resolves_to', 'ip'),
15
+ ('ip', 'hosted_on', 'asn'),
16
+ ('domain', 'secured_by', 'cert'),
17
+ ('cert', 'issued_to', 'ip'),
18
+ ('domain', 'redirects_to', 'domain')
19
+ ]
20
+ GRAPH_METADATA = (NODE_TYPES, EDGE_TYPES)
21
+
22
+ # Model Deep-Stack Hyperparameters
23
+ HIDDEN_CHANNELS = 128
24
+ NUM_HEADS = 8
25
+ NUM_LAYERS = 4
26
+ DROPOUT_RATE = 0.15
Version_4/models/__init__.py ADDED
File without changes
Version_4/models/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (144 Bytes). View file
 
Version_4/models/__pycache__/gnn.cpython-313.pyc ADDED
Binary file (4.74 kB). View file
 
Version_4/models/gnn.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from torch.nn import ModuleDict, ModuleList, Linear, LayerNorm, Dropout
5
+ from torch_geometric.nn import HGTConv
6
+ from typing import Dict, Tuple, List
7
+
8
+ class PhishingGNN_Model(torch.nn.Module):
9
+ """
10
+ Standalone Heterogeneous Graph Transformer (HGT) for pure topological threat analysis.
11
+ Processes multi-relational network metadata independently of lexical features.
12
+ """
13
+ def __init__(
14
+ self,
15
+ metadata: Tuple[List[str], List[Tuple[str, str, str]]],
16
+ in_channels_dict: Dict[str, int], # Maps node types to their specific input sizes
17
+ hidden_channels: int,
18
+ num_heads: int,
19
+ num_layers: int,
20
+ dropout_rate: float
21
+ ):
22
+ super().__init__()
23
+ self.node_types, self.edge_types = metadata
24
+ self.num_layers = num_layers
25
+
26
+ # Multi-type input embedding alignment using explicit feature dimensions
27
+ self.inputs_proj = ModuleDict({
28
+ node_type: Linear(in_channels_dict[node_type], hidden_channels)
29
+ for node_type in self.node_types
30
+ })
31
+
32
+ self.convs = ModuleList()
33
+ self.layer_norms = ModuleList()
34
+ self.dropouts = ModuleList()
35
+
36
+ for _ in range(num_layers):
37
+ # No 'group' parameter here to ensure PyG compatibility
38
+ self.convs.append(HGTConv(hidden_channels, hidden_channels, metadata, num_heads))
39
+ self.layer_norms.append(ModuleDict({
40
+ node_type: LayerNorm(hidden_channels) for node_type in self.node_types
41
+ }))
42
+ self.dropouts.append(Dropout(p=dropout_rate))
43
+
44
+ # Advanced classification projection head for targeting IP anomalies
45
+ self.classifier = torch.nn.Sequential(
46
+ Linear(hidden_channels, hidden_channels // 2),
47
+ torch.nn.GELU(),
48
+ Dropout(p=dropout_rate),
49
+ Linear(hidden_channels // 2, 1)
50
+ )
51
+
52
+ def forward(self, x_dict: Dict[str, torch.Tensor], edge_index_dict: Dict[Tuple[str, str, str], torch.Tensor]) -> torch.Tensor:
53
+ # Align input spaces
54
+ h_dict = {node_type: F.gelu(self.inputs_proj[node_type](x)) for node_type, x in x_dict.items()}
55
+
56
+ # Deep graph convolutions with normalization and skip connections
57
+ for i in range(self.num_layers):
58
+ h_residual_dict = {node_type: h.clone() for node_type, h in h_dict.items()}
59
+ h_dict = self.convs[i](h_dict, edge_index_dict)
60
+
61
+ for node_type in self.node_types:
62
+ h = self.dropouts[i](h_dict[node_type])
63
+ h = h + h_residual_dict[node_type]
64
+ h_dict[node_type] = self.layer_norms[i][node_type](h)
65
+
66
+ # Isolate the 'ip' node matrix for final threat probability generation
67
+ return torch.sigmoid(self.classifier(h_dict['ip']))
68
+
69
+ def safe_save(self, path: str):
70
+ """Ensures parent directories exist before execution to prevent saving crashes."""
71
+ os.makedirs(os.path.dirname(path), exist_ok=True)
72
+ torch.save(self.state_dict(), path)
Version_4/network_telemetry.json ADDED
The diff for this file is too large to render. See raw diff
 
Version_4/pipeline/__init__.py ADDED
File without changes
Version_4/pipeline/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (146 Bytes). View file
 
Version_4/pipeline/__pycache__/graph_engine.cpython-313.pyc ADDED
Binary file (3.85 kB). View file
 
Version_4/pipeline/graph_engine.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from typing import Dict, List, Tuple
3
+
4
+ class TopologicalGraphEngine:
5
+ """Translates incoming raw telemetry logs into PyTorch Geometric HeteroData formats."""
6
+ def __init__(self):
7
+ self.ip_map, self.domain_map, self.asn_map = {}, {}, {}
8
+
9
+ def extract_and_build(self, telemetries: List[dict]) -> Tuple[Dict[str, torch.Tensor], Dict[Tuple, torch.Tensor]]:
10
+ # Map dynamic components to index pointers
11
+ for log in telemetries:
12
+ if log.get('ip') and log['ip'] not in self.ip_map:
13
+ self.ip_map[log['ip']] = len(self.ip_map)
14
+ if log.get('domain') and log['domain'] not in self.domain_map:
15
+ self.domain_map[log['domain']] = len(self.domain_map)
16
+ if log.get('asn') and log['asn'] not in self.asn_map:
17
+ self.asn_map[log['asn']] = len(self.asn_map)
18
+
19
+ # High-dimensional hidden state initializers (using structural placeholders)
20
+ # Note: These sizes must match in_channels_dict in app.py and train.py
21
+ x_dict = {
22
+ 'ip': torch.randn((max(1, len(self.ip_map)), 16)),
23
+ 'domain': torch.randn((max(1, len(self.domain_map)), 32)),
24
+ 'asn': torch.randn((max(1, len(self.asn_map)), 8)),
25
+ 'cert': torch.randn((1, 16))
26
+ }
27
+
28
+ domain_to_ip = [[], []]
29
+ ip_to_asn = [[], []]
30
+
31
+ for log in telemetries:
32
+ if log.get('domain') and log.get('ip'):
33
+ domain_to_ip[0].append(self.domain_map[log['domain']])
34
+ domain_to_ip[1].append(self.ip_map[log['ip']])
35
+ if log.get('ip') and log.get('asn'):
36
+ ip_to_asn[0].append(self.ip_map[log['ip']])
37
+ ip_to_asn[1].append(self.asn_map[log['asn']])
38
+
39
+ edge_index_dict = {
40
+ ('domain', 'resolves_to', 'ip'): torch.tensor(domain_to_ip, dtype=torch.long),
41
+ ('ip', 'hosted_on', 'asn'): torch.tensor(ip_to_asn, dtype=torch.long),
42
+ ('domain', 'secured_by', 'cert'): torch.empty((2, 0), dtype=torch.long),
43
+ ('cert', 'issued_to', 'ip'): torch.empty((2, 0), dtype=torch.long),
44
+ ('domain', 'redirects_to', 'domain'): torch.empty((2, 0), dtype=torch.long)
45
+ }
46
+
47
+ return x_dict, edge_index_dict
Version_4/requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi
2
+ pydantic
3
+ uvicorn
4
+ torch
5
+ torch-geometric
Version_4/simulate_warfare.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.optim as optim
4
+ import random
5
+ from models.gnn import PhishingGNN_Model
6
+ from pipeline.graph_engine import TopologicalGraphEngine
7
+ from config import *
8
+
9
+ def generate_synthetic_warfare(batch_size=100):
10
+ """Generates synthetic network logs simulating both normal traffic and advanced attacks."""
11
+ logs = []
12
+ labels = []
13
+
14
+ for _ in range(batch_size):
15
+ is_attack = random.random() > 0.5
16
+
17
+ if is_attack:
18
+ logs.append({
19
+ 'ip': f"{random.randint(1, 255)}.{random.randint(1,255)}.0.0",
20
+ 'domain': None,
21
+ 'asn': random.choice([666, 9999, 5555])
22
+ })
23
+ labels.append([1.0])
24
+ else:
25
+ logs.append({
26
+ 'ip': f"104.21.{random.randint(1,100)}.{random.randint(1,255)}",
27
+ 'domain': f"safe-service-{random.randint(1,100)}.com",
28
+ 'asn': 13335
29
+ })
30
+ labels.append([0.0])
31
+
32
+ return logs, torch.tensor(labels, dtype=torch.float32)
33
+
34
+ def run_war_games():
35
+ print("[*] Initiating Autonomous Threat War Games...")
36
+
37
+ in_channels_dict = {'ip': 16, 'domain': 32, 'asn': 8, 'cert': 16}
38
+ model = PhishingGNN_Model(
39
+ metadata=GRAPH_METADATA,
40
+ in_channels_dict=in_channels_dict,
41
+ hidden_channels=HIDDEN_CHANNELS,
42
+ num_heads=NUM_HEADS,
43
+ num_layers=NUM_LAYERS,
44
+ dropout_rate=DROPOUT_RATE
45
+ )
46
+
47
+ optimizer = optim.AdamW(model.parameters(), lr=0.001)
48
+ criterion = nn.BCELoss()
49
+ engine = TopologicalGraphEngine()
50
+
51
+ for wave in range(50):
52
+ logs, labels = generate_synthetic_warfare(batch_size=200)
53
+ x_dict, edge_index_dict = engine.extract_and_build(logs)
54
+
55
+ optimizer.zero_grad()
56
+ predictions = model(x_dict, edge_index_dict)
57
+ valid_preds = predictions[:len(labels)]
58
+
59
+ loss = criterion(valid_preds, labels)
60
+ loss.backward()
61
+ optimizer.step()
62
+
63
+ if (wave + 1) % 10 == 0:
64
+ print(f"Attack Wave {wave+1:02d}/50 Defeated | Model Penetration Loss: {loss.item():.4f}")
65
+
66
+ model.safe_save(MODEL_SAVE_PATH)
67
+ print(f"[+] War games complete. Apex model hardened and saved to: {MODEL_SAVE_PATH}")
68
+
69
+ if __name__ == "__main__":
70
+ run_war_games()
Version_4/train.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.optim as optim
5
+ from models.gnn import PhishingGNN_Model
6
+ from pipeline.graph_engine import TopologicalGraphEngine
7
+ from config import *
8
+
9
+ def run_training_pipeline():
10
+ print("[*] Launching Production Defender V5 Training Run...")
11
+
12
+ # 1. Try to load real data, fallback to mock if missing
13
+ try:
14
+ with open("network_telemetry.json", "r") as f:
15
+ dataset = json.load(f)
16
+ print(f"[+] Loaded {len(dataset)} real telemetry logs.")
17
+ except FileNotFoundError:
18
+ print("[-] network_telemetry.json not found. Falling back to simulated context.")
19
+ dataset = [
20
+ {'ip': '185.220.101.5', 'domain': 'shadow-dns-bypass.net', 'asn': 44050, 'is_malicious': 1.0},
21
+ {'ip': '193.56.28.14', 'asn': 57099, 'is_malicious': 1.0},
22
+ {'ip': '8.8.8.8', 'domain': 'dns.google', 'asn': 15169, 'is_malicious': 0.0}
23
+ ]
24
+
25
+ # 2. Extract logs and structure target threat labels
26
+ engine = TopologicalGraphEngine()
27
+ x_dict, edge_index_dict = engine.extract_and_build(dataset)
28
+
29
+ labels_list = []
30
+ for ip_str in engine.ip_map.keys():
31
+ matching_logs = [log for log in dataset if log.get('ip') == ip_str]
32
+ label = matching_logs[0].get('is_malicious', 0.0) if matching_logs else 0.0
33
+ labels_list.append([label])
34
+
35
+ labels = torch.tensor(labels_list, dtype=torch.float32)
36
+
37
+ # 3. Model setup
38
+ in_channels_dict = {'ip': 16, 'domain': 32, 'asn': 8, 'cert': 16}
39
+ model = PhishingGNN_Model(
40
+ metadata=GRAPH_METADATA,
41
+ in_channels_dict=in_channels_dict,
42
+ hidden_channels=HIDDEN_CHANNELS,
43
+ num_heads=NUM_HEADS,
44
+ num_layers=NUM_LAYERS,
45
+ dropout_rate=DROPOUT_RATE
46
+ )
47
+
48
+ optimizer = optim.AdamW(model.parameters(), lr=0.0005, weight_decay=1e-3)
49
+ criterion = nn.BCELoss()
50
+
51
+ # 4. Optimization Loop
52
+ model.train()
53
+ for epoch in range(100):
54
+ optimizer.zero_grad()
55
+ predictions = model(x_dict, edge_index_dict)
56
+
57
+ # Only calculate loss on the nodes we have labels for
58
+ valid_preds = predictions[:len(labels)]
59
+ loss = criterion(valid_preds, labels)
60
+
61
+ loss.backward()
62
+ optimizer.step()
63
+
64
+ if (epoch + 1) % 20 == 0:
65
+ print(f"Epoch {epoch+1:03d}/100 | Topological Loss: {loss.item():.5f}")
66
+
67
+ model.safe_save(MODEL_SAVE_PATH)
68
+ print(f"[+] Operational weights successfully frozen at: {MODEL_SAVE_PATH}")
69
+
70
+ if __name__ == "__main__":
71
+ run_training_pipeline()