mirror of
https://github.com/MetaCubeX/ClashMetaForAndroid.git
synced 2025-02-17 23:33:15 +03:00
add ipv6 support for tun
This commit is contained in:
parent
b661d94278
commit
9edf35c4bc
@ -1,8 +1,11 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"strings"
|
||||||
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -14,16 +17,49 @@ import (
|
|||||||
func Start(fd int, gateway, portal, dns string) (io.Closer, error) {
|
func Start(fd int, gateway, portal, dns string) (io.Closer, error) {
|
||||||
log.Debugln("TUN: fd = %d, gateway = %s, portal = %s, dns = %s", fd, gateway, portal, dns)
|
log.Debugln("TUN: fd = %d, gateway = %s, portal = %s, dns = %s", fd, gateway, portal, dns)
|
||||||
|
|
||||||
|
var prefix4 []netip.Prefix
|
||||||
|
var prefix6 []netip.Prefix
|
||||||
|
for _, gatewayStr := range strings.Split(gateway, ",") { // "172.19.0.1/30" or "172.19.0.1/30,fdfe:dcba:9876::1/126"
|
||||||
|
gatewayStr = strings.TrimSpace(gatewayStr)
|
||||||
|
if len(gatewayStr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prefix, err := netip.ParsePrefix(gatewayStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("TUN:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix.Addr().Is4() {
|
||||||
|
prefix4 = append(prefix4, prefix)
|
||||||
|
} else {
|
||||||
|
prefix6 = append(prefix6, prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dnsHijack []string
|
||||||
|
for _, dnsStr := range strings.Split(dns, ",") { // "172.19.0.2" or "0.0.0.0"
|
||||||
|
dnsStr = strings.TrimSpace(dnsStr)
|
||||||
|
if len(dnsStr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dnsHijack = append(dnsHijack, net.JoinHostPort(dnsStr, "53"))
|
||||||
|
}
|
||||||
|
|
||||||
options := LC.Tun{
|
options := LC.Tun{
|
||||||
Enable: true,
|
Enable: true,
|
||||||
Device: sing_tun.InterfaceName,
|
Device: sing_tun.InterfaceName,
|
||||||
Stack: C.TunSystem,
|
Stack: C.TunSystem,
|
||||||
DNSHijack: []string{dns + ":53"}, // "172.19.0.2" or "0.0.0.0"
|
DNSHijack: dnsHijack,
|
||||||
Inet4Address: []netip.Prefix{netip.MustParsePrefix(gateway)}, // "172.19.0.1/30"
|
Inet4Address: prefix4,
|
||||||
|
Inet6Address: prefix6,
|
||||||
MTU: 9000, // private const val TUN_MTU = 9000 in TunService.kt
|
MTU: 9000, // private const val TUN_MTU = 9000 in TunService.kt
|
||||||
FileDescriptor: fd,
|
FileDescriptor: fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tunOptions, _ := json.Marshal(options)
|
||||||
|
log.Debugln(string(tunOptions))
|
||||||
|
|
||||||
listener, err := sing_tun.New(options, tunnel.Tunnel)
|
listener, err := sing_tun.New(options, tunnel.Tunnel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("TUN:", err)
|
log.Errorln("TUN:", err)
|
||||||
|
@ -77,6 +77,13 @@ class NetworkSettingsDesign(
|
|||||||
configure = vpnDependencies::add,
|
configure = vpnDependencies::add,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
switch(
|
||||||
|
value = srvStore::allowIpv6,
|
||||||
|
title = R.string.allow_ipv6,
|
||||||
|
summary = R.string.allow_ipv6_summary,
|
||||||
|
configure = vpnDependencies::add,
|
||||||
|
)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 29) {
|
if (Build.VERSION.SDK_INT >= 29) {
|
||||||
switch(
|
switch(
|
||||||
value = srvStore::systemProxy,
|
value = srvStore::systemProxy,
|
||||||
|
@ -217,6 +217,8 @@
|
|||||||
<string name="geoip_fallback_code">GeoIP Fallback 区域代码</string>
|
<string name="geoip_fallback_code">GeoIP Fallback 区域代码</string>
|
||||||
<string name="allow_bypass">允许应用绕过</string>
|
<string name="allow_bypass">允许应用绕过</string>
|
||||||
<string name="allow_bypass_summary">允许其他应用绕过 VPN</string>
|
<string name="allow_bypass_summary">允许其他应用绕过 VPN</string>
|
||||||
|
<string name="allow_ipv6">允许Ipv6</string>
|
||||||
|
<string name="allow_ipv6_summary">通过 VpnService 代理Ipv6流量</string>
|
||||||
<string name="clash_meta_wiki">Clash Meta Wiki</string>
|
<string name="clash_meta_wiki">Clash Meta Wiki</string>
|
||||||
<string name="meta_features">Meta Features</string>
|
<string name="meta_features">Meta Features</string>
|
||||||
<string name="unified_delay">Unified Delay</string>
|
<string name="unified_delay">Unified Delay</string>
|
||||||
|
@ -122,6 +122,8 @@
|
|||||||
<string name="block_loopback_summary">Block loopback connections</string>
|
<string name="block_loopback_summary">Block loopback connections</string>
|
||||||
<string name="allow_bypass">Allow Bypass</string>
|
<string name="allow_bypass">Allow Bypass</string>
|
||||||
<string name="allow_bypass_summary">Allows all apps to bypass this VPN connection</string>
|
<string name="allow_bypass_summary">Allows all apps to bypass this VPN connection</string>
|
||||||
|
<string name="allow_ipv6">Allow Ipv6</string>
|
||||||
|
<string name="allow_ipv6_summary">Allows ipv6 traffic via VpnService</string>
|
||||||
<string name="system_proxy">System Proxy</string>
|
<string name="system_proxy">System Proxy</string>
|
||||||
<string name="system_proxy_summary">Attach http proxy to VpnService</string>
|
<string name="system_proxy_summary">Attach http proxy to VpnService</string>
|
||||||
<string name="access_control_mode">Access Control Mode</string>
|
<string name="access_control_mode">Access Control Mode</string>
|
||||||
|
@ -132,17 +132,31 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||||||
val device = with(Builder()) {
|
val device = with(Builder()) {
|
||||||
// Interface address
|
// Interface address
|
||||||
addAddress(TUN_GATEWAY, TUN_SUBNET_PREFIX)
|
addAddress(TUN_GATEWAY, TUN_SUBNET_PREFIX)
|
||||||
|
if (store.allowIpv6) {
|
||||||
|
addAddress(TUN_GATEWAY6, TUN_SUBNET_PREFIX6)
|
||||||
|
}
|
||||||
|
|
||||||
// Route
|
// Route
|
||||||
if (store.bypassPrivateNetwork) {
|
if (store.bypassPrivateNetwork) {
|
||||||
resources.getStringArray(R.array.bypass_private_route).map(::parseCIDR).forEach {
|
resources.getStringArray(R.array.bypass_private_route).map(::parseCIDR).forEach {
|
||||||
addRoute(it.ip, it.prefix)
|
addRoute(it.ip, it.prefix)
|
||||||
}
|
}
|
||||||
|
if (store.allowIpv6) {
|
||||||
|
resources.getStringArray(R.array.bypass_private_route6).map(::parseCIDR).forEach {
|
||||||
|
addRoute(it.ip, it.prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Route of virtual DNS
|
// Route of virtual DNS
|
||||||
addRoute(TUN_DNS, 32)
|
addRoute(TUN_DNS, 32)
|
||||||
|
if (store.allowIpv6) {
|
||||||
|
addRoute(TUN_DNS6, 128)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
addRoute(NET_ANY, 0)
|
addRoute(NET_ANY, 0)
|
||||||
|
if (store.allowIpv6) {
|
||||||
|
addRoute(NET_ANY6, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access Control
|
// Access Control
|
||||||
@ -171,6 +185,9 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||||||
|
|
||||||
// Virtual Dns Server
|
// Virtual Dns Server
|
||||||
addDnsServer(TUN_DNS)
|
addDnsServer(TUN_DNS)
|
||||||
|
if (store.allowIpv6) {
|
||||||
|
addDnsServer(TUN_DNS6)
|
||||||
|
}
|
||||||
|
|
||||||
// Open MainActivity
|
// Open MainActivity
|
||||||
setConfigureIntent(
|
setConfigureIntent(
|
||||||
@ -207,9 +224,9 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||||||
TunModule.TunDevice(
|
TunModule.TunDevice(
|
||||||
fd = establish()?.detachFd()
|
fd = establish()?.detachFd()
|
||||||
?: throw NullPointerException("Establish VPN rejected by system"),
|
?: throw NullPointerException("Establish VPN rejected by system"),
|
||||||
gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX",
|
gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX" + if (store.allowIpv6) ",$TUN_GATEWAY6/$TUN_SUBNET_PREFIX6" else "",
|
||||||
portal = TUN_PORTAL,
|
portal = TUN_PORTAL + if (store.allowIpv6) ",$TUN_PORTAL6" else "",
|
||||||
dns = if (store.dnsHijacking) NET_ANY else TUN_DNS,
|
dns = if (store.dnsHijacking) NET_ANY else (TUN_DNS + if (store.allowIpv6) ",$TUN_DNS6" else ""),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +237,14 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||||||
private const val TUN_MTU = 9000
|
private const val TUN_MTU = 9000
|
||||||
private const val TUN_SUBNET_PREFIX = 30
|
private const val TUN_SUBNET_PREFIX = 30
|
||||||
private const val TUN_GATEWAY = "172.19.0.1"
|
private const val TUN_GATEWAY = "172.19.0.1"
|
||||||
|
private const val TUN_SUBNET_PREFIX6 = 126
|
||||||
|
private const val TUN_GATEWAY6 = "fdfe:dcba:9876::1"
|
||||||
private const val TUN_PORTAL = "172.19.0.2"
|
private const val TUN_PORTAL = "172.19.0.2"
|
||||||
|
private const val TUN_PORTAL6 = "fdfe:dcba:9876::2"
|
||||||
private const val TUN_DNS = TUN_PORTAL
|
private const val TUN_DNS = TUN_PORTAL
|
||||||
|
private const val TUN_DNS6 = TUN_PORTAL6
|
||||||
private const val NET_ANY = "0.0.0.0"
|
private const val NET_ANY = "0.0.0.0"
|
||||||
|
private const val NET_ANY6 = "::"
|
||||||
|
|
||||||
private val HTTP_PROXY_LOCAL_LIST: List<String> = listOf(
|
private val HTTP_PROXY_LOCAL_LIST: List<String> = listOf(
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -51,6 +51,11 @@ class ServiceStore(context: Context) {
|
|||||||
defaultValue = true
|
defaultValue = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var allowIpv6 by store.boolean(
|
||||||
|
key = "allow_ipv6",
|
||||||
|
defaultValue = false
|
||||||
|
)
|
||||||
|
|
||||||
var dynamicNotification by store.boolean(
|
var dynamicNotification by store.boolean(
|
||||||
key = "dynamic_notification",
|
key = "dynamic_notification",
|
||||||
defaultValue = true
|
defaultValue = true
|
||||||
|
@ -77,4 +77,15 @@
|
|||||||
<item>255.255.255.252/31</item>
|
<item>255.255.255.252/31</item>
|
||||||
<item>255.255.255.254/32</item>
|
<item>255.255.255.254/32</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<!-- exclude fc00::/7, fe80::/10, ff00::/8 -->
|
||||||
|
<string-array name="bypass_private_route6" translatable="false">
|
||||||
|
<item>::/1</item>
|
||||||
|
<item>8000::/2</item>
|
||||||
|
<item>c000::/3</item>
|
||||||
|
<item>e000::/4</item>
|
||||||
|
<item>f000::/5</item>
|
||||||
|
<item>f800::/6</item>
|
||||||
|
<item>fe00::/9</item>
|
||||||
|
<item>fec0::/10</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user