1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
package config
import (
"net/netip"
"vpnem/internal/models"
)
// BYPASS_PROCESSES — processes that go direct, bypassing TUN.
// Ported 1:1 from vpn.py.
var BypassProcesses = []string{
"QTranslate.exe",
"aspia_host.exe",
"aspia_host_service.exe",
"aspia_desktop_agent.exe",
"Performer Application v5.x.exe",
"chromium.exe",
"Яндекс Музыка.exe",
}
// PreferDirectProcesses should stay outside global bypass, but still avoid the proxy
// unless a stronger blocked/refilter/forced rule matches first.
var PreferDirectProcesses = []string{
"obs64.exe",
}
// ProxyableBrowserProcesses intentionally stay OUT of the default direct bypass list.
// Their traffic should follow routing mode rules, otherwise Full/Re-filter modes
// cannot proxy IP-check and blocked domains correctly.
var ProxyableBrowserProcesses = []string{
"chrome.exe",
"firefox.exe",
"msedgewebview2.exe",
}
// LovenseProcessRegex — force Lovense through proxy regardless of mode.
var LovenseProcessRegex = []string{"(?i).*lovense.*"}
// BYPASS_IPS — VPN server IPs + service IPs, always direct.
// NL servers, RU servers, misc.
var StaticBypassIPs = []string{
// NL servers
"5.180.97.200/32", "5.180.97.199/32", "5.180.97.198/32",
"5.180.97.197/32", "5.180.97.181/32",
// RU servers
"84.252.100.166/32", "84.252.100.165/32", "84.252.100.161/32",
"84.252.100.117/32", "84.252.100.103/32",
// Misc
"109.107.175.41/32", "146.103.104.48/32", "77.105.138.163/32",
"91.84.113.225/32", "146.103.98.171/32", "94.103.88.252/32",
"178.20.44.93/32", "89.124.70.47/32",
}
// ReservedCIDRs — ranges not covered by ip_is_private.
var ReservedCIDRs = []string{
"100.64.0.0/10", // CGNAT / Tailscale
"192.0.0.0/24", // IETF protocol assignments
"192.0.2.0/24", // TEST-NET-1
"198.51.100.0/24", // TEST-NET-2
"203.0.113.0/24", // TEST-NET-3
"240.0.0.0/4", // Reserved (Class E)
"255.255.255.255/32", // Broadcast
}
// LocalDomainSuffixes — local/mDNS domains, always direct.
var LocalDomainSuffixes = []string{
"local", "localhost", "lan", "internal", "home.arpa",
"corp", "intranet", "test", "invalid", "example",
"home", "localdomain",
}
// WindowsNCSIDomains — Windows Network Connectivity Status Indicator.
// Without these going direct, Windows shows "No Internet" warnings.
var WindowsNCSIDomains = []string{
"msftconnecttest.com",
"msftncsi.com",
}
// ForcedProxyIPs — IPs that must always go through proxy.
var ForcedProxyIPs = []string{
"65.21.33.248/32",
"91.132.135.38/32",
}
// Telegram — hardcoded, applied to ALL modes.
var TelegramDomains = []string{
"telegram.org", "telegram.me", "t.me", "telegra.ph", "telegram.dog",
}
var TelegramDomainRegex = []string{
".*telegram.*", `.*t\.me.*`,
}
var TelegramIPs = []string{
"91.108.56.0/22", "91.108.4.0/22", "91.108.8.0/22",
"91.108.16.0/22", "91.108.12.0/22", "149.154.160.0/20",
"91.105.192.0/23", "91.108.20.0/22", "185.76.151.0/24",
}
var TelegramProcesses = []string{
"Telegram.exe",
}
var TelegramProcessRegex = []string{
`(?i).*telegram.*\\telegram\.exe$`,
}
// ProxyDNSDomains — domains NOT in refilter-domains.srs but must resolve via proxy DNS.
// refilter-domains.srs (81k+ domains) covers all RKN-blocked domains.
// This list only has domains missing from .srs that we still need through proxy.
var ProxyDNSDomains = []string{
// Business-specific (not RKN-blocked)
"lovense.com", "lovense-api.com", "lovense.club",
// Not in refilter but needed
"anthropic.com",
"igcdn.com", "fbsbx.com",
// IP check services (must show proxy exit IP)
"ifconfig.me", "ifconfig.co", "icanhazip.com", "ipinfo.io", "ipify.org",
}
// IPCheckDomains — domains used for exit IP verification.
var IPCheckDomains = []string{
"ifconfig.me", "ifconfig.co", "icanhazip.com", "ipinfo.io",
}
// BuildBypassProcesses merges default + custom bypass processes.
func BuildBypassProcesses(policy *models.RoutingPolicy, custom []string) []string {
effective := EffectiveRoutingPolicy(policy)
seen := make(map[string]bool, len(effective.AlwaysDirectProcesses)+len(custom))
result := make([]string, 0, len(effective.AlwaysDirectProcesses)+len(custom))
for _, p := range effective.AlwaysDirectProcesses {
if !seen[p] {
seen[p] = true
result = append(result, p)
}
}
for _, p := range custom {
if p != "" && !seen[p] {
seen[p] = true
result = append(result, p)
}
}
return result
}
// BuildBypassIPs merges static bypass IPs with dynamic server IPs.
func BuildBypassIPs(policy *models.RoutingPolicy, serverIPs []string) []string {
effective := EffectiveRoutingPolicy(policy)
seen := make(map[string]bool, len(effective.StaticBypassIPs)+len(serverIPs))
result := make([]string, 0, len(effective.StaticBypassIPs)+len(serverIPs))
for _, ip := range effective.StaticBypassIPs {
if !seen[ip] {
seen[ip] = true
result = append(result, ip)
}
}
for _, ip := range serverIPs {
if _, err := netip.ParseAddr(ip); err != nil {
continue
}
cidr := ip + "/32"
if !seen[cidr] {
seen[cidr] = true
result = append(result, cidr)
}
}
return result
}
|