Skip to content

Commit

Permalink
Merge pull request v2rayA#1195 from wnxd/sing-tun
Browse files Browse the repository at this point in the history
Add tun mode with sing-tun
  • Loading branch information
MarksonHon authored Apr 14, 2024
2 parents f1e6d72 + 0a0c64e commit b0e207f
Show file tree
Hide file tree
Showing 22 changed files with 1,326 additions and 11 deletions.
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ else
fi
# https://github.com/webpack/webpack/issues/14532#issuecomment-947012063
cd "$CurrentDir"/gui && yarn && OUTPUT_DIR="$CurrentDir"/service/server/router/web yarn build
cd "$CurrentDir"/service && CGO_ENABLED=0 go build -ldflags "-X github.com/v2rayA/v2rayA/conf.Version=$version -s -w" -o "$CurrentDir"/v2raya
cd "$CurrentDir"/service && CGO_ENABLED=0 go build -tags "with_gvisor" -ldflags "-X github.com/v2rayA/v2rayA/conf.Version=$version -s -w" -o "$CurrentDir"/v2raya
2 changes: 2 additions & 0 deletions gui/src/components/modalSetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
<b-select v-model="transparentType" expanded class="left-border">
<option v-show="!lite" value="redirect">redirect</option>
<option v-show="!lite" value="tproxy">tproxy</option>
<option v-show="!lite" value="gvisor_tun">gvisor tun</option>
<option v-show="!lite" value="system_tun">system tun</option>
<option value="system_proxy">system proxy</option>
</b-select>
</b-field>
Expand Down
1 change: 1 addition & 0 deletions service/core/coreObj/coreObj.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ type Mux struct {
type OutboundObject struct {
Tag string `json:"tag"`
Protocol string `json:"protocol"`
SendThrough string `json:"sendThrough,omitempty"`
Settings Settings `json:"settings,omitempty"`
StreamSettings *StreamSettings `json:"streamSettings,omitempty"`
ProxySettings *ProxySettings `json:"proxySettings,omitempty"`
Expand Down
5 changes: 5 additions & 0 deletions service/core/dns/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dns

import "net/netip"

var defaultDNS = []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53"), netip.MustParseAddrPort("[::1]:53")}
67 changes: 67 additions & 0 deletions service/core/dns/dns_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//go:build !js && !windows

package dns

import (
"bufio"
"net/netip"
"os"
"strings"
)

func GetSystemDNS() (servers []netip.AddrPort) {
f, err := os.Open("/etc/resolv.conf")
if err != nil {
return defaultDNS
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
f := getFields(line)
if len(f) < 1 {
continue
}
switch f[0] {
case "nameserver":
if len(f) > 1 {
if addr, err := netip.ParseAddr(f[1]); err == nil {
servers = append(servers, netip.AddrPortFrom(addr, 53))
}
}
}
}
return
}

func countAnyByte(s string, t string) int {
n := 0
for i := 0; i < len(s); i++ {
if strings.IndexByte(t, s[i]) >= 0 {
n++
}
}
return n
}

func splitAtBytes(s string, t string) []string {
a := make([]string, 1+countAnyByte(s, t))
n := 0
last := 0
for i := 0; i < len(s); i++ {
if strings.IndexByte(t, s[i]) >= 0 {
if last < i {
a[n] = s[last:i]
n++
}
last = i + 1
}
}
if last < len(s) {
a[n] = s[last:]
n++
}
return a[0:n]
}

func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
68 changes: 68 additions & 0 deletions service/core/dns/dns_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dns

import (
"net/netip"
"os"
"syscall"
"unsafe"

"golang.org/x/sys/windows"
)

func GetSystemDNS() (servers []netip.AddrPort) {
aas, err := adapterAddresses()
if err != nil {
return defaultDNS
}
for _, aa := range aas {
for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next {
if aa.OperStatus != windows.IfOperStatusUp {
continue
}
sa, err := dns.Address.Sockaddr.Sockaddr()
if err != nil {
continue
}
var addr netip.Addr
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = netip.AddrFrom4(sa.Addr)
case *syscall.SockaddrInet6:
if sa.Addr[0] == 0xfe && sa.Addr[1] == 0xc0 {
continue
}
addr = netip.AddrFrom16(sa.Addr)
default:
continue
}
servers = append(servers, netip.AddrPortFrom(addr, 53))
}
}
return
}

func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
var b []byte
l := uint32(15000)
for {
b = make([]byte, l)
err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
if err == nil {
if l == 0 {
return nil, nil
}
break
}
if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
if l <= uint32(len(b)) {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
}
var aas []*windows.IpAdapterAddresses
for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
aas = append(aas, aa)
}
return aas, nil
}
88 changes: 88 additions & 0 deletions service/core/dns/system_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package dns

import (
"bufio"
"bytes"
"fmt"
"net/netip"
"os/exec"
"strings"
)

const networksetup = "/usr/sbin/networksetup"

func GetValidNetworkInterfaces() ([]string, error) {
cmd := exec.Command(networksetup, "-listallnetworkservices")
output, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("networksetup get: %v", err)
}
var interfaces []string
scanner := bufio.NewScanner(bytes.NewReader(output))
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "*") {
continue
}
cmd = exec.Command(networksetup, "-getinfo", line)
output, err = cmd.CombinedOutput()
if err != nil {
continue
}
valid := false
scanner2 := bufio.NewScanner(bytes.NewReader(output))
for scanner2.Scan() {
line2 := scanner2.Text()
key, value, ok := strings.Cut(line2, ": ")
if !ok {
continue
}
if key == "IP address" || key == "IPv6 IP address" {
if _, err = netip.ParseAddr(value); err == nil {
valid = true
break
}
}
}
if valid {
interfaces = append(interfaces, line)
}
}
return interfaces, nil
}

func GetDNSServer(ifi string) ([]string, error) {
cmd := exec.Command(networksetup, "-getdnsservers", ifi)
output, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("networksetup get: %v", err)
}
var server []string
scanner := bufio.NewScanner(bytes.NewReader(output))
for scanner.Scan() {
line := scanner.Text()
if _, err = netip.ParseAddr(line); err == nil {
server = append(server, line)
}
}
return server, nil
}

func SetDNSServer(ifi string, server ...string) error {
cmd := exec.Command(networksetup, "-setdnsservers", ifi)
if len(server) == 0 {
cmd.Args = append(cmd.Args, "Empty")
} else {
cmd.Args = append(cmd.Args, server...)
}
_, err := cmd.CombinedOutput()
return err
}

func ReplaceDNSServer(ifi string, server ...string) ([]string, error) {
old, err := GetDNSServer(ifi)
if err != nil {
return nil, err
}
return old, SetDNSServer(ifi, server...)
}
21 changes: 21 additions & 0 deletions service/core/dns/system_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build !windows && !darwin

package dns

import "errors"

func GetValidNetworkInterfaces() ([]string, error) {
return nil, errors.New("not implemented")
}

func GetDNSServer(ifi string) ([]string, error) {
return nil, errors.New("not implemented")
}

func SetDNSServer(ifi string, server ...string) error {
return errors.New("not implemented")
}

func ReplaceDNSServer(ifi string, server ...string) ([]string, error) {
return nil, errors.New("not implemented")
}
71 changes: 71 additions & 0 deletions service/core/dns/system_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dns

import (
"errors"
"strings"

"golang.org/x/sys/windows/registry"
)

const basePath = `SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\`

func GetValidNetworkInterfaces() ([]string, error) {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, basePath, registry.ENUMERATE_SUB_KEYS)
if err != nil {
return nil, err
}
defer key.Close()
names, err := key.ReadSubKeyNames(0)
if err != nil {
return nil, err
}
var interfaces []string
for _, name := range names {
key, err = registry.OpenKey(registry.LOCAL_MACHINE, basePath+name, registry.READ)
if err != nil {
continue
}
if ip, _, _ := key.GetStringsValue("IPAddress"); len(ip) != 0 {
interfaces = append(interfaces, name)
} else if ip, _, _ := key.GetStringValue("DhcpIPAddress"); ip != "" {
interfaces = append(interfaces, name)
}
key.Close()
}
return interfaces, nil
}

func GetDNSServer(ifi string) ([]string, error) {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, basePath+ifi, registry.READ)
if err != nil {
return nil, err
}
defer key.Close()
server, _, err := key.GetStringValue("NameServer")
if err != nil && !errors.Is(err, registry.ErrNotExist) {
return nil, err
}
return strings.Split(server, ","), nil
}

func SetDNSServer(ifi string, server ...string) error {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, basePath+ifi, registry.WRITE)
if err != nil {
return err
}
defer key.Close()
return key.SetStringValue("NameServer", strings.Join(server, ","))
}

func ReplaceDNSServer(ifi string, server ...string) ([]string, error) {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, basePath+ifi, registry.READ|registry.WRITE)
if err != nil {
return nil, err
}
defer key.Close()
value, _, err := key.GetStringValue("NameServer")
if err != nil && !errors.Is(err, registry.ErrNotExist) {
return nil, err
}
return strings.Split(value, ","), key.SetStringValue("NameServer", strings.Join(server, ","))
}
Loading

0 comments on commit b0e207f

Please sign in to comment.