Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0542d913f2 | |||
| 746254bb7e | |||
| 2227ea3ed6 | |||
| 4d0e9e2b44 | |||
| 5cba8a228c | |||
| 2d8ed22dba |
@@ -0,0 +1,28 @@
|
|||||||
|
在提出问题前请先自行排除服务器端问题,同时也请通过搜索确认是否有人提出过相同问题。
|
||||||
|
|
||||||
|
|
||||||
|
### 预期行为
|
||||||
|
描述你认为应该发生什么
|
||||||
|
|
||||||
|
### 实际行为
|
||||||
|
描述实际发生了什么
|
||||||
|
|
||||||
|
### 复现方法
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
### 日志信息
|
||||||
|
<details>
|
||||||
|
通过 `adb logcat -s com.v2ray.ang GoLog V2rayConfigUtilGoLog Main` 获取日志。请自行删减日志中可能出现的敏感信息。
|
||||||
|
|
||||||
|
如果问题可重现,建议先执行`adb logcat -c`清空系统日志再执行上述命令,再操作重现问题。
|
||||||
|
```
|
||||||
|
在这里粘贴日志
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### 环境信息
|
||||||
|
|
||||||
|
### 额外信息(可选)
|
||||||
|
|
||||||
@@ -4,7 +4,6 @@ V2rayNG/app/src/main/assets/geosite.dat
|
|||||||
V2rayNG/app/src/main/java/com/v2ray/ang/InappBuyActivity.java
|
V2rayNG/app/src/main/java/com/v2ray/ang/InappBuyActivity.java
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||||
*.aar
|
|
||||||
*.dat
|
*.dat
|
||||||
*.jks
|
*.jks
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
sudo: required
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.12"
|
||||||
|
go_import_path: github.com/2dust/AndroidLibV2rayLite
|
||||||
|
git:
|
||||||
|
depth: 5
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
update: true
|
||||||
|
before_script:
|
||||||
|
- sudo ntpdate -u time.google.com
|
||||||
|
- date
|
||||||
|
- make all
|
||||||
|
- make downloadGoMobile
|
||||||
|
script:
|
||||||
|
- make BuildMobile
|
||||||
|
after_success:
|
||||||
|
deploy:
|
||||||
|
provider: releases
|
||||||
|
api_key: ${GH_TOKEN}
|
||||||
|
file:
|
||||||
|
- libv2ray.aar
|
||||||
|
skip_cleanup: true
|
||||||
|
on:
|
||||||
|
tags: true
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package CoreI
|
||||||
|
|
||||||
|
import (
|
||||||
|
v2core "v2ray.com/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Status struct {
|
||||||
|
IsRunning bool
|
||||||
|
PackageName string
|
||||||
|
|
||||||
|
Vpoint v2core.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckVersion() int {
|
||||||
|
return 20
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Status) GetDataDir() string {
|
||||||
|
return v.PackageName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Status) GetApp(name string) string {
|
||||||
|
return v.PackageName + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Status) GetTun2socksArgs(localDNS bool, enableIPv6 bool) (ret []string) {
|
||||||
|
ret = []string{"--netif-ipaddr",
|
||||||
|
"26.26.26.2",
|
||||||
|
"--netif-netmask",
|
||||||
|
"255.255.255.252",
|
||||||
|
"--socks-server-addr",
|
||||||
|
"127.0.0.1:10808",
|
||||||
|
"--tunmtu",
|
||||||
|
"1500",
|
||||||
|
"--loglevel",
|
||||||
|
"notice",
|
||||||
|
"--enable-udprelay",
|
||||||
|
"--sock-path",
|
||||||
|
v.GetDataDir() + "sock_path",
|
||||||
|
}
|
||||||
|
|
||||||
|
if enableIPv6 {
|
||||||
|
ret = append(ret, "--netif-ip6addr", "da26:2626::2")
|
||||||
|
}
|
||||||
|
|
||||||
|
if localDNS {
|
||||||
|
ret = append(ret, "--dnsgw", "127.0.0.1:10807")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Status) GetVPNSetupArg(localDNS bool, enableIPv6 bool) (ret string) {
|
||||||
|
ret = "m,1500 a,26.26.26.1,30 r,0.0.0.0,0"
|
||||||
|
|
||||||
|
if enableIPv6 {
|
||||||
|
ret += " a,da26:2626::1,126 r,::,0"
|
||||||
|
}
|
||||||
|
if localDNS {
|
||||||
|
ret += " d,26.26.26.2"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
pb:
|
||||||
|
go get -u github.com/golang/protobuf/protoc-gen-go
|
||||||
|
@echo "pb Start"
|
||||||
|
asset:
|
||||||
|
bash gen_assets.sh download
|
||||||
|
mkdir assets
|
||||||
|
cp -v data/*.dat assets/
|
||||||
|
# cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geosite.dat > geosite.dat
|
||||||
|
# cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geoip.dat > geoip.dat
|
||||||
|
|
||||||
|
shippedBinary:
|
||||||
|
cd shippedBinarys; $(MAKE) shippedBinary
|
||||||
|
|
||||||
|
fetchDep:
|
||||||
|
-go get github.com/2dust/AndroidLibV2rayLite
|
||||||
|
go get github.com/2dust/AndroidLibV2rayLite
|
||||||
|
|
||||||
|
ANDROID_HOME=$(HOME)/android-sdk-linux
|
||||||
|
export ANDROID_HOME
|
||||||
|
PATH:=$(PATH):$(GOPATH)/bin
|
||||||
|
export PATH
|
||||||
|
downloadGoMobile:
|
||||||
|
go get golang.org/x/mobile/cmd/...
|
||||||
|
sudo apt-get install -qq libstdc++6:i386 lib32z1 expect
|
||||||
|
cd ~ ;curl -L https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/ubuntu-cli-install-android-sdk.sh | sudo bash - > /dev/null
|
||||||
|
ls ~
|
||||||
|
ls ~/android-sdk-linux/
|
||||||
|
gomobile init ;gomobile bind -v -tags json github.com/2dust/AndroidLibV2rayLite
|
||||||
|
|
||||||
|
BuildMobile:
|
||||||
|
@echo Stub
|
||||||
|
|
||||||
|
all: asset pb shippedBinary fetchDep
|
||||||
|
@echo DONE
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package Escort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/CoreI"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string, sendFd func() int) {
|
||||||
|
log.Println(proc, pt)
|
||||||
|
count := 0
|
||||||
|
for count <= 42 {
|
||||||
|
cmd := exec.Command(proc, pt...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
if len(additionalEnv) > 0 {
|
||||||
|
//additionalEnv := "FOO=bar"
|
||||||
|
newEnv := append(os.Environ(), additionalEnv)
|
||||||
|
cmd.Env = newEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Println("EscortRun cmd.Start err", err)
|
||||||
|
goto CMDERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.escortProcess == nil {
|
||||||
|
log.Println("EscortRun v.escortProcess nil")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
*v.escortProcess = append(*v.escortProcess, cmd.Process)
|
||||||
|
log.Println("EscortRun Waiting....")
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
sendFd()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Println("EscortRun cmd.Wait err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
CMDERROR:
|
||||||
|
if v.Status.IsRunning {
|
||||||
|
log.Println("EscortRun Unexpected Exit, Restart now.")
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
log.Println("EscortRun Exit")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Escorting) EscortingUp() {
|
||||||
|
if v.escortProcess != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.escortProcess = new([](*os.Process))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Escorting) EscortingDown() {
|
||||||
|
if v.escortProcess == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("EscortingDown() Killing all escorted process ")
|
||||||
|
for _, pr := range *v.escortProcess {
|
||||||
|
pr.Kill()
|
||||||
|
if _, err := pr.Wait(); err != nil {
|
||||||
|
log.Println("EscortingDown pr.Wait err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.escortProcess = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Escorting struct {
|
||||||
|
escortProcess *[](*os.Process)
|
||||||
|
Status *CoreI.Status
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# AndroidLibV2rayLite
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
package VPN
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
v2net "v2ray.com/core/common/net"
|
||||||
|
v2internet "v2ray.com/core/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type protectSet interface {
|
||||||
|
Protect(int) int
|
||||||
|
}
|
||||||
|
|
||||||
|
type resolved struct {
|
||||||
|
domain string
|
||||||
|
IPs []net.IP
|
||||||
|
Port int
|
||||||
|
ipIdx uint8
|
||||||
|
ipLock sync.Mutex
|
||||||
|
lastSwitched time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextIP switch to another resolved result.
|
||||||
|
// there still be race-condition here if multiple err concurently occured
|
||||||
|
// may cause idx keep switching,
|
||||||
|
// but that's an outside error can hardly handled here
|
||||||
|
func (r *resolved) NextIP() {
|
||||||
|
r.ipLock.Lock()
|
||||||
|
defer r.ipLock.Unlock()
|
||||||
|
|
||||||
|
if len(r.IPs) > 1 {
|
||||||
|
|
||||||
|
// throttle, don't switch too quickly
|
||||||
|
now := time.Now()
|
||||||
|
if now.Sub(r.lastSwitched) < time.Second*5 {
|
||||||
|
log.Println("switch too quickly")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.lastSwitched = now
|
||||||
|
r.ipIdx++
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ipIdx >= uint8(len(r.IPs)) {
|
||||||
|
r.ipIdx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := r.currentIP()
|
||||||
|
log.Printf("switched to next IP: %s", cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *resolved) currentIP() net.IP {
|
||||||
|
if len(r.IPs) > 0 {
|
||||||
|
return r.IPs[r.ipIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPreotectedDialer ...
|
||||||
|
func NewPreotectedDialer(p protectSet) *ProtectedDialer {
|
||||||
|
d := &ProtectedDialer{
|
||||||
|
// prefer native lookup on Android
|
||||||
|
resolver: &net.Resolver{PreferGo: false},
|
||||||
|
protectSet: p,
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtectedDialer ...
|
||||||
|
type ProtectedDialer struct {
|
||||||
|
currentServer string
|
||||||
|
resolveChan chan struct{}
|
||||||
|
|
||||||
|
vServer *resolved
|
||||||
|
resolver *net.Resolver
|
||||||
|
|
||||||
|
protectSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ProtectedDialer) IsVServerReady() bool {
|
||||||
|
return (d.vServer != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ProtectedDialer) PrepareResolveChan() {
|
||||||
|
d.resolveChan = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ProtectedDialer) ResolveChan() <-chan struct{} {
|
||||||
|
return d.resolveChan
|
||||||
|
}
|
||||||
|
|
||||||
|
// simplicated version of golang: internetAddrList in src/net/ipsock.go
|
||||||
|
func (d *ProtectedDialer) lookupAddr(addr string) (*resolved, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
host, port string
|
||||||
|
portnum int
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if host, port, err = net.SplitHostPort(addr); err != nil {
|
||||||
|
log.Printf("PrepareDomain SplitHostPort Err: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if portnum, err = d.resolver.LookupPort(ctx, "tcp", port); err != nil {
|
||||||
|
log.Printf("PrepareDomain LookupPort Err: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := d.resolver.LookupIPAddr(ctx, host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
return nil, fmt.Errorf("domain %s Failed to resolve", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
IPs := make([]net.IP, len(addrs))
|
||||||
|
for i, ia := range addrs {
|
||||||
|
IPs[i] = ia.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := &resolved{
|
||||||
|
domain: host,
|
||||||
|
IPs: IPs,
|
||||||
|
Port: portnum,
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareDomain caches direct v2ray server host
|
||||||
|
func (d *ProtectedDialer) PrepareDomain(domainName string, closeCh <-chan struct{}) {
|
||||||
|
log.Printf("Preparing Domain: %s", domainName)
|
||||||
|
d.currentServer = domainName
|
||||||
|
|
||||||
|
defer close(d.resolveChan)
|
||||||
|
maxRetry := 10
|
||||||
|
for {
|
||||||
|
if maxRetry == 0 {
|
||||||
|
log.Println("PrepareDomain maxRetry reached. exiting.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved, err := d.lookupAddr(domainName)
|
||||||
|
if err != nil {
|
||||||
|
maxRetry--
|
||||||
|
log.Printf("PrepareDomain err: %v\n", err)
|
||||||
|
select {
|
||||||
|
case <-closeCh:
|
||||||
|
log.Printf("PrepareDomain exit due to v2ray closed")
|
||||||
|
return
|
||||||
|
case <-time.After(time.Second * 2):
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d.vServer = resolved
|
||||||
|
log.Printf("Prepare Result:\n Domain: %s\n Port: %d\n IPs: %v\n",
|
||||||
|
resolved.domain, resolved.Port, resolved.IPs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ProtectedDialer) getFd(network v2net.Network) (fd int, err error) {
|
||||||
|
switch network {
|
||||||
|
case v2net.Network_TCP:
|
||||||
|
fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, unix.IPPROTO_TCP)
|
||||||
|
case v2net.Network_UDP:
|
||||||
|
fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unknow network")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial exported as the protected dial method
|
||||||
|
func (d *ProtectedDialer) Dial(ctx context.Context,
|
||||||
|
src v2net.Address, dest v2net.Destination, sockopt *v2internet.SocketConfig) (net.Conn, error) {
|
||||||
|
|
||||||
|
network := dest.Network.SystemString()
|
||||||
|
Address := dest.NetAddr()
|
||||||
|
|
||||||
|
// v2ray server address,
|
||||||
|
// try to connect fixed IP if multiple IP parsed from domain,
|
||||||
|
// and switch to next IP if error occurred
|
||||||
|
if strings.Compare(Address, d.currentServer) == 0 {
|
||||||
|
if d.vServer == nil {
|
||||||
|
log.Println("Dial pending prepare ...", Address)
|
||||||
|
<-d.resolveChan
|
||||||
|
|
||||||
|
// user may close connection during PrepareDomain,
|
||||||
|
// fast return release resources.
|
||||||
|
if d.vServer == nil {
|
||||||
|
return nil, fmt.Errorf("fail to prepare domain %s", d.currentServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := d.getFd(dest.Network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
curIP := d.vServer.currentIP()
|
||||||
|
conn, err := d.fdConn(ctx, curIP, d.vServer.Port, fd)
|
||||||
|
if err != nil {
|
||||||
|
d.vServer.NextIP()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Printf("Using Prepared: %s", curIP)
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// v2ray connecting to "domestic" servers, no caching results
|
||||||
|
log.Printf("Not Using Prepared: %s,%s", network, Address)
|
||||||
|
resolved, err := d.lookupAddr(Address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := d.getFd(dest.Network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the first resolved address.
|
||||||
|
// the result IP may vary, eg: IPv6 addrs comes first if client has ipv6 address
|
||||||
|
return d.fdConn(ctx, resolved.IPs[0], resolved.Port, fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ProtectedDialer) fdConn(ctx context.Context, ip net.IP, port int, fd int) (net.Conn, error) {
|
||||||
|
|
||||||
|
defer unix.Close(fd)
|
||||||
|
|
||||||
|
// call android VPN service to "protect" the fd connecting straight out
|
||||||
|
d.Protect(fd)
|
||||||
|
|
||||||
|
sa := &unix.SockaddrInet6{
|
||||||
|
Port: port,
|
||||||
|
}
|
||||||
|
copy(sa.Addr[:], ip)
|
||||||
|
|
||||||
|
if err := unix.Connect(fd, sa); err != nil {
|
||||||
|
log.Printf("fdConn unix.Connect err, Close Fd: %d Err: %v", fd, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
file := os.NewFile(uintptr(fd), "Socket")
|
||||||
|
if file == nil {
|
||||||
|
// returned value will be nil if fd is not a valid file descriptor
|
||||||
|
return nil, errors.New("fdConn fd invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
//Closing conn does not affect file, and closing file does not affect conn.
|
||||||
|
conn, err := net.FileConn(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("fdConn FileConn Close Fd: %d Err: %v", fd, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package VPN
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v2net "v2ray.com/core/common/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeSupportSet struct{}
|
||||||
|
|
||||||
|
func (f fakeSupportSet) Protect(int) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProtectedDialer_PrepareDomain(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
domainName string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
{"", args{"baidu.com:80"}},
|
||||||
|
// {"", args{"cloudflare.com:443"}},
|
||||||
|
// {"", args{"apple.com:443"}},
|
||||||
|
// {"", args{"110.110.110.110:443"}},
|
||||||
|
// {"", args{"[2002:1234::1]:443"}},
|
||||||
|
}
|
||||||
|
d := NewPreotectedDialer(fakeSupportSet{})
|
||||||
|
for _, tt := range tests {
|
||||||
|
ch := make(chan struct{})
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
go d.PrepareDomain(tt.args.domainName, ch)
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
go d.vServer.NextIP()
|
||||||
|
t.Log(d.vServer.currentIP())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProtectedDialer_Dial(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
{"baidu.com:80", false},
|
||||||
|
{"cloudflare.com:80", false},
|
||||||
|
{"172.16.192.11:80", true},
|
||||||
|
// {"172.16.192.10:80", true},
|
||||||
|
// {"[2fff:4322::1]:443", true},
|
||||||
|
// {"[fc00::1]:443", true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ch := make(chan struct{})
|
||||||
|
|
||||||
|
d := NewPreotectedDialer(fakeSupportSet{})
|
||||||
|
d.currentServer = tt.name
|
||||||
|
|
||||||
|
go d.PrepareDomain(tt.name, ch)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
dial := func() {
|
||||||
|
defer wg.Done()
|
||||||
|
dest, _ := v2net.ParseDestination("tcp:" + tt.name)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
conn, err := d.Dial(ctx, nil, dest, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_host, _, _ := net.SplitHostPort(tt.name)
|
||||||
|
fmt.Fprintf(conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", _host))
|
||||||
|
status, err := bufio.NewReader(conn).ReadString('\n')
|
||||||
|
t.Logf("%#v, %#v\n", status, err)
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := 0; n < 3; n++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go dial()
|
||||||
|
// time.Sleep(time.Millisecond * 10)
|
||||||
|
// d.pendingMap[tt.name] = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_resolved_NextIP(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
domain string
|
||||||
|
IPs []net.IP
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
{"test1",
|
||||||
|
fields{
|
||||||
|
domain: "www.baidu.com",
|
||||||
|
IPs: []net.IP{
|
||||||
|
net.ParseIP("1.2.3.4"),
|
||||||
|
net.ParseIP("4.3.2.1"),
|
||||||
|
net.ParseIP("1234::1"),
|
||||||
|
net.ParseIP("4321::1"),
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &resolved{
|
||||||
|
domain: tt.fields.domain,
|
||||||
|
IPs: tt.fields.IPs,
|
||||||
|
Port: tt.fields.Port,
|
||||||
|
}
|
||||||
|
t.Logf("%v", r.IPs)
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
r.NextIP()
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
r.NextIP()
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
r.NextIP()
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
r.NextIP()
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
r.NextIP()
|
||||||
|
t.Logf("%v", r.currentIP())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Set magic variables for current file & dir
|
||||||
|
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||||
|
__base="$(basename ${__file} .sh)"
|
||||||
|
|
||||||
|
if [[ ! -d $NDK_HOME ]]; then
|
||||||
|
echo "Android NDK: NDK_HOME not found. please set env \$NDK_HOME"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
clear_tmp () {
|
||||||
|
rm -rf $TMPDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; clear_tmp; exit 1' ERR INT
|
||||||
|
install -m644 $__dir/tun2socks.mk $TMPDIR/
|
||||||
|
|
||||||
|
pushd $TMPDIR
|
||||||
|
git clone --depth=1 https://github.com/shadowsocks/badvpn.git
|
||||||
|
git clone --depth=1 https://github.com/shadowsocks/libancillary.git
|
||||||
|
$NDK_HOME/ndk-build \
|
||||||
|
NDK_PROJECT_PATH=. \
|
||||||
|
APP_BUILD_SCRIPT=./tun2socks.mk \
|
||||||
|
APP_ABI=all \
|
||||||
|
APP_PLATFORM=android-19 \
|
||||||
|
NDK_LIBS_OUT=$TMPDIR/libs \
|
||||||
|
NDK_OUT=$TMPDIR/tmp \
|
||||||
|
APP_SHORT_COMMANDS=false LOCAL_SHORT_COMMANDS=false -B -j4
|
||||||
|
|
||||||
|
install -v -m755 libs/armeabi-v7a/tun2socks $__dir/shippedBinarys/ArchDep/arm/
|
||||||
|
install -v -m755 libs/arm64-v8a/tun2socks $__dir/shippedBinarys/ArchDep/arm64/
|
||||||
|
install -v -m755 libs/x86/tun2socks $__dir/shippedBinarys/ArchDep/386/
|
||||||
|
install -v -m755 libs/x86_64/tun2socks $__dir/shippedBinarys/ArchDep/amd64/
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd $__dir/shippedBinarys
|
||||||
|
make clean && make shippedBinary
|
||||||
|
popd
|
||||||
|
|
||||||
|
rm -rf $TMPDIR
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Set magic variables for current file & dir
|
||||||
|
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||||
|
__base="$(basename ${__file} .sh)"
|
||||||
|
|
||||||
|
|
||||||
|
DATADIR=${__dir}/data
|
||||||
|
|
||||||
|
compile_dat () {
|
||||||
|
local TMPDIR=$(mktemp -d)
|
||||||
|
|
||||||
|
trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; rm -rf $TMPDIR; trap ERR; exit 1' ERR
|
||||||
|
|
||||||
|
local GEOSITE=${GOPATH}/src/github.com/v2ray/domain-list-community
|
||||||
|
if [[ -d ${GEOSITE} ]]; then
|
||||||
|
cd ${GEOSITE} && git pull
|
||||||
|
else
|
||||||
|
mkdir -p ${GEOSITE}
|
||||||
|
cd ${GEOSITE} && git clone https://github.com/v2ray/domain-list-community.git .
|
||||||
|
fi
|
||||||
|
go run main.go
|
||||||
|
|
||||||
|
if [[ -e dlc.dat ]]; then
|
||||||
|
rm -f $DATADIR/geosite.dat
|
||||||
|
mv dlc.dat $DATADIR/geosite.dat
|
||||||
|
echo "----------> geosite.dat updated."
|
||||||
|
else
|
||||||
|
echo "----------> geosite.dat failed to update."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [[ ! -x $GOPATH/bin/geoip ]]; then
|
||||||
|
go get -v -u github.com/v2ray/geoip
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $TMPDIR
|
||||||
|
curl -L -O http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip
|
||||||
|
unzip -q GeoLite2-Country-CSV.zip
|
||||||
|
mkdir geoip && find . -name '*.csv' -exec mv -t ./geoip {} +
|
||||||
|
$GOPATH/bin/geoip \
|
||||||
|
--country=./geoip/GeoLite2-Country-Locations-en.csv \
|
||||||
|
--ipv4=./geoip/GeoLite2-Country-Blocks-IPv4.csv \
|
||||||
|
--ipv6=./geoip/GeoLite2-Country-Blocks-IPv6.csv
|
||||||
|
|
||||||
|
if [[ -e geoip.dat ]]; then
|
||||||
|
rm -f $DATADIR/geoip.dat
|
||||||
|
mv ./geoip.dat $DATADIR/geoip.dat
|
||||||
|
echo "----------> geoip.dat updated."
|
||||||
|
else
|
||||||
|
echo "----------> geoip.dat failed to update."
|
||||||
|
fi
|
||||||
|
trap ERR
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
download_dat () {
|
||||||
|
wget -qO - https://api.github.com/repos/v2ray/geoip/releases/latest \
|
||||||
|
| grep browser_download_url | cut -d '"' -f 4 \
|
||||||
|
| wget -i - -O $DATADIR/geoip.dat
|
||||||
|
|
||||||
|
wget -qO - https://api.github.com/repos/v2ray/domain-list-community/releases/latest \
|
||||||
|
| grep browser_download_url | cut -d '"' -f 4 \
|
||||||
|
| wget -i - -O $DATADIR/geosite.dat
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION="${1:-}"
|
||||||
|
if [[ -z $ACTION ]]; then
|
||||||
|
ACTION=download
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $ACTION in
|
||||||
|
"download") download_dat;;
|
||||||
|
"compile") compile_dat;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
package libv2ray
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/CoreI"
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/Process/Escort"
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/VPN"
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/shippedBinarys"
|
||||||
|
mobasset "golang.org/x/mobile/asset"
|
||||||
|
|
||||||
|
v2core "v2ray.com/core"
|
||||||
|
v2filesystem "v2ray.com/core/common/platform/filesystem"
|
||||||
|
v2stats "v2ray.com/core/features/stats"
|
||||||
|
v2serial "v2ray.com/core/infra/conf/serial"
|
||||||
|
_ "v2ray.com/core/main/distro/all"
|
||||||
|
v2internet "v2ray.com/core/transport/internet"
|
||||||
|
|
||||||
|
v2applog "v2ray.com/core/app/log"
|
||||||
|
v2commlog "v2ray.com/core/common/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
v2Assert = "v2ray.location.asset"
|
||||||
|
assetperfix = "/dev/libv2rayfs0/asset"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*V2RayPoint V2Ray Point Server
|
||||||
|
This is territory of Go, so no getter and setters!
|
||||||
|
*/
|
||||||
|
type V2RayPoint struct {
|
||||||
|
SupportSet V2RayVPNServiceSupportsSet
|
||||||
|
statsManager v2stats.Manager
|
||||||
|
|
||||||
|
dialer *VPN.ProtectedDialer
|
||||||
|
status *CoreI.Status
|
||||||
|
escorter *Escort.Escorting
|
||||||
|
v2rayOP *sync.Mutex
|
||||||
|
closeChan chan struct{}
|
||||||
|
|
||||||
|
PackageName string
|
||||||
|
DomainName string
|
||||||
|
ConfigureFileContent string
|
||||||
|
EnableLocalDNS bool
|
||||||
|
ForwardIpv6 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
/*V2RayVPNServiceSupportsSet To support Android VPN mode*/
|
||||||
|
type V2RayVPNServiceSupportsSet interface {
|
||||||
|
Setup(Conf string) int
|
||||||
|
Prepare() int
|
||||||
|
Shutdown() int
|
||||||
|
Protect(int) int
|
||||||
|
OnEmitStatus(int, string) int
|
||||||
|
SendFd() int
|
||||||
|
}
|
||||||
|
|
||||||
|
/*RunLoop Run V2Ray main loop
|
||||||
|
*/
|
||||||
|
func (v *V2RayPoint) RunLoop() (err error) {
|
||||||
|
v.v2rayOP.Lock()
|
||||||
|
defer v.v2rayOP.Unlock()
|
||||||
|
//Construct Context
|
||||||
|
v.status.PackageName = v.PackageName
|
||||||
|
|
||||||
|
if !v.status.IsRunning {
|
||||||
|
v.closeChan = make(chan struct{})
|
||||||
|
v.dialer.PrepareResolveChan()
|
||||||
|
go v.dialer.PrepareDomain(v.DomainName, v.closeChan)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
// wait until resolved
|
||||||
|
case <-v.dialer.ResolveChan():
|
||||||
|
// shutdown VPNService if server name can not reolved
|
||||||
|
if !v.dialer.IsVServerReady() {
|
||||||
|
log.Println("vServer cannot resolved, shutdown")
|
||||||
|
v.StopLoop()
|
||||||
|
v.SupportSet.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop waiting if manually closed
|
||||||
|
case <-v.closeChan:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = v.pointloop()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*StopLoop Stop V2Ray main loop
|
||||||
|
*/
|
||||||
|
func (v *V2RayPoint) StopLoop() (err error) {
|
||||||
|
v.v2rayOP.Lock()
|
||||||
|
defer v.v2rayOP.Unlock()
|
||||||
|
if v.status.IsRunning {
|
||||||
|
close(v.closeChan)
|
||||||
|
v.shutdownInit()
|
||||||
|
v.SupportSet.OnEmitStatus(0, "Closed")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delegate Funcation
|
||||||
|
func (v *V2RayPoint) GetIsRunning() bool {
|
||||||
|
return v.status.IsRunning
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delegate Funcation
|
||||||
|
func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
|
||||||
|
if v.statsManager == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
counter := v.statsManager.GetCounter(fmt.Sprintf("inbound>>>%s>>>traffic>>>%s", tag, direct))
|
||||||
|
if counter == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return counter.Set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *V2RayPoint) shutdownInit() {
|
||||||
|
v.status.IsRunning = false
|
||||||
|
v.status.Vpoint.Close()
|
||||||
|
v.status.Vpoint = nil
|
||||||
|
v.statsManager = nil
|
||||||
|
v.escorter.EscortingDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *V2RayPoint) pointloop() error {
|
||||||
|
if err := v.runTun2socks(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
|
||||||
|
v.EnableLocalDNS,
|
||||||
|
v.ForwardIpv6,
|
||||||
|
v.DomainName)
|
||||||
|
|
||||||
|
log.Println("loading v2ray config")
|
||||||
|
config, err := v2serial.LoadJSONConfig(strings.NewReader(v.ConfigureFileContent))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("new v2ray core")
|
||||||
|
inst, err := v2core.New(config)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.status.Vpoint = inst
|
||||||
|
v.statsManager = inst.GetFeature(v2stats.ManagerType()).(v2stats.Manager)
|
||||||
|
|
||||||
|
log.Println("start v2ray core")
|
||||||
|
v.status.IsRunning = true
|
||||||
|
if err := v.status.Vpoint.Start(); err != nil {
|
||||||
|
v.status.IsRunning = false
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.SupportSet.Prepare()
|
||||||
|
v.SupportSet.Setup(v.status.GetVPNSetupArg(v.EnableLocalDNS, v.ForwardIpv6))
|
||||||
|
v.SupportSet.OnEmitStatus(0, "Running")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initV2Env() {
|
||||||
|
if os.Getenv(v2Assert) != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//Initialize asset API, Since Raymond Will not let notify the asset location inside Process,
|
||||||
|
//We need to set location outside V2Ray
|
||||||
|
os.Setenv(v2Assert, assetperfix)
|
||||||
|
//Now we handle read
|
||||||
|
v2filesystem.NewFileReader = func(path string) (io.ReadCloser, error) {
|
||||||
|
if strings.HasPrefix(path, assetperfix) {
|
||||||
|
p := path[len(assetperfix)+1:]
|
||||||
|
//is it overridden?
|
||||||
|
//by, ok := overridedAssets[p]
|
||||||
|
//if ok {
|
||||||
|
// return os.Open(by)
|
||||||
|
//}
|
||||||
|
return mobasset.Open(p)
|
||||||
|
}
|
||||||
|
return os.Open(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delegate Funcation
|
||||||
|
func TestConfig(ConfigureFileContent string) error {
|
||||||
|
initV2Env()
|
||||||
|
_, err := v2serial.LoadJSONConfig(strings.NewReader(ConfigureFileContent))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*NewV2RayPoint new V2RayPoint*/
|
||||||
|
func NewV2RayPoint(s V2RayVPNServiceSupportsSet) *V2RayPoint {
|
||||||
|
initV2Env()
|
||||||
|
|
||||||
|
// inject our own log writer
|
||||||
|
v2applog.RegisterHandlerCreator(v2applog.LogType_Console,
|
||||||
|
func(lt v2applog.LogType,
|
||||||
|
options v2applog.HandlerCreatorOptions) (v2commlog.Handler, error) {
|
||||||
|
return v2commlog.NewLogger(createStdoutLogWriter()), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
dialer := VPN.NewPreotectedDialer(s)
|
||||||
|
v2internet.UseAlternativeSystemDialer(dialer)
|
||||||
|
status := &CoreI.Status{}
|
||||||
|
return &V2RayPoint{
|
||||||
|
SupportSet: s,
|
||||||
|
v2rayOP: new(sync.Mutex),
|
||||||
|
status: status,
|
||||||
|
dialer: dialer,
|
||||||
|
escorter: &Escort.Escorting{Status: status},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v V2RayPoint) runTun2socks() error {
|
||||||
|
shipb := shippedBinarys.FirstRun{Status: v.status}
|
||||||
|
if err := shipb.CheckAndExport(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.escorter.EscortingUp()
|
||||||
|
go v.escorter.EscortRun(
|
||||||
|
v.status.GetApp("tun2socks"),
|
||||||
|
v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "",
|
||||||
|
v.SupportSet.SendFd)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CheckVersion int
|
||||||
|
This func will return libv2ray binding version.
|
||||||
|
*/
|
||||||
|
func CheckVersion() int {
|
||||||
|
return CoreI.CheckVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CheckVersionX string
|
||||||
|
This func will return libv2ray binding version and V2Ray version used.
|
||||||
|
*/
|
||||||
|
func CheckVersionX() string {
|
||||||
|
return fmt.Sprintf("Libv2rayLite V%d, Core V%s", CheckVersion(), v2core.Version())
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package libv2ray
|
||||||
|
|
||||||
|
//go:generate make all
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
readme.txt
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
|
|||||||
|
Platdep=shippedBinary.386 shippedBinary.amd64 shippedBinary.arm64 shippedBinary.arm
|
||||||
|
|
||||||
|
shippedBinaryDep:
|
||||||
|
go get -u github.com/jteeuwen/go-bindata/...
|
||||||
|
|
||||||
|
shippedBinary.%:
|
||||||
|
go-bindata -nometadata -nomemcopy -pkg shippedBinarys -o ./binary_$*.go -tags $* ArchIndep/ ArchDep/$*/
|
||||||
|
|
||||||
|
shippedBinary:shippedBinaryDep $(Platdep)
|
||||||
|
@echo "Done"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm binary*
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package shippedBinarys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/2dust/AndroidLibV2rayLite/CoreI"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FirstRun struct {
|
||||||
|
Status *CoreI.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *FirstRun) checkIfRcExist() error {
|
||||||
|
datadir := v.Status.GetDataDir()
|
||||||
|
if _, err := os.Stat(datadir + strconv.Itoa(CoreI.CheckVersion())); !os.IsNotExist(err) {
|
||||||
|
log.Println("file exists")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndepDir, err := AssetDir("ArchIndep")
|
||||||
|
log.Println(IndepDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, fn := range IndepDir {
|
||||||
|
log.Println(datadir+"ArchIndep/"+fn)
|
||||||
|
|
||||||
|
err := RestoreAsset(datadir, "ArchIndep/"+fn)
|
||||||
|
log.Println(err)
|
||||||
|
|
||||||
|
//GrantPremission
|
||||||
|
os.Chmod(datadir+"ArchIndep/"+fn, 0700)
|
||||||
|
log.Println(os.Remove(datadir + fn))
|
||||||
|
log.Println(os.Symlink(datadir+"ArchIndep/"+fn, datadir + fn))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DepDir, err := AssetDir("ArchDep")
|
||||||
|
log.Println(DepDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, fn := range DepDir {
|
||||||
|
DepDir2, err := AssetDir("ArchDep/" + fn)
|
||||||
|
log.Println("ArchDep/" + fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, FND := range DepDir2 {
|
||||||
|
log.Println(datadir+"ArchDep/"+fn+"/"+FND)
|
||||||
|
|
||||||
|
RestoreAsset(datadir, "ArchDep/"+fn+"/"+FND)
|
||||||
|
os.Chmod(datadir+"ArchDep/"+fn+"/"+FND, 0700)
|
||||||
|
log.Println(os.Remove(datadir + FND))
|
||||||
|
log.Println(os.Symlink(datadir+"ArchDep/"+fn+"/"+FND, datadir+FND))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s, _ := os.Create(datadir + strconv.Itoa(CoreI.CheckVersion()))
|
||||||
|
s.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *FirstRun) CheckAndExport() error {
|
||||||
|
return v.checkIfRcExist()
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# Copyright (C) 2009 The Android Open Source Project
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
ROOT_PATH := $(LOCAL_PATH)
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
## libancillary
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
ANCILLARY_SOURCE := fd_recv.c fd_send.c
|
||||||
|
|
||||||
|
LOCAL_MODULE := libancillary
|
||||||
|
#LOCAL_CFLAGS += -I$(LOCAL_PATH)/libancillary
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libancillary
|
||||||
|
LOCAL_SRC_FILES := $(addprefix libancillary/, $(ANCILLARY_SOURCE))
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
## tun2socks
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := -std=gnu99
|
||||||
|
LOCAL_CFLAGS += -DBADVPN_THREADWORK_USE_PTHREAD -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE
|
||||||
|
LOCAL_CFLAGS += -DBADVPN_USE_SIGNALFD -DBADVPN_USE_EPOLL
|
||||||
|
LOCAL_CFLAGS += -DBADVPN_LITTLE_ENDIAN -DBADVPN_THREAD_SAFE
|
||||||
|
LOCAL_CFLAGS += -DNDEBUG -DANDROID
|
||||||
|
LOCAL_CFLAGS += -I
|
||||||
|
|
||||||
|
LOCAL_STATIC_LIBRARIES := libancillary
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
$(LOCAL_PATH)/badvpn/libancillary \
|
||||||
|
$(LOCAL_PATH)/badvpn/lwip/src/include/ipv4 \
|
||||||
|
$(LOCAL_PATH)/badvpn/lwip/src/include/ipv6 \
|
||||||
|
$(LOCAL_PATH)/badvpn/lwip/src/include \
|
||||||
|
$(LOCAL_PATH)/badvpn/lwip/custom \
|
||||||
|
$(LOCAL_PATH)/badvpn \
|
||||||
|
$(LOCAL_PATH)/libancillary
|
||||||
|
|
||||||
|
TUN2SOCKS_SOURCES := \
|
||||||
|
base/BLog_syslog.c \
|
||||||
|
system/BReactor_badvpn.c \
|
||||||
|
system/BSignal.c \
|
||||||
|
system/BConnection_common.c \
|
||||||
|
system/BConnection_unix.c \
|
||||||
|
system/BTime.c \
|
||||||
|
system/BUnixSignal.c \
|
||||||
|
system/BNetwork.c \
|
||||||
|
flow/StreamRecvInterface.c \
|
||||||
|
flow/PacketRecvInterface.c \
|
||||||
|
flow/PacketPassInterface.c \
|
||||||
|
flow/StreamPassInterface.c \
|
||||||
|
flow/SinglePacketBuffer.c \
|
||||||
|
flow/BufferWriter.c \
|
||||||
|
flow/PacketBuffer.c \
|
||||||
|
flow/PacketStreamSender.c \
|
||||||
|
flow/PacketPassConnector.c \
|
||||||
|
flow/PacketProtoFlow.c \
|
||||||
|
flow/PacketPassFairQueue.c \
|
||||||
|
flow/PacketProtoEncoder.c \
|
||||||
|
flow/PacketProtoDecoder.c \
|
||||||
|
socksclient/BSocksClient.c \
|
||||||
|
tuntap/BTap.c \
|
||||||
|
lwip/src/core/udp.c \
|
||||||
|
lwip/src/core/memp.c \
|
||||||
|
lwip/src/core/init.c \
|
||||||
|
lwip/src/core/pbuf.c \
|
||||||
|
lwip/src/core/tcp.c \
|
||||||
|
lwip/src/core/tcp_out.c \
|
||||||
|
lwip/src/core/netif.c \
|
||||||
|
lwip/src/core/def.c \
|
||||||
|
lwip/src/core/ip.c \
|
||||||
|
lwip/src/core/mem.c \
|
||||||
|
lwip/src/core/tcp_in.c \
|
||||||
|
lwip/src/core/stats.c \
|
||||||
|
lwip/src/core/inet_chksum.c \
|
||||||
|
lwip/src/core/timeouts.c \
|
||||||
|
lwip/src/core/ipv4/icmp.c \
|
||||||
|
lwip/src/core/ipv4/igmp.c \
|
||||||
|
lwip/src/core/ipv4/ip4_addr.c \
|
||||||
|
lwip/src/core/ipv4/ip4_frag.c \
|
||||||
|
lwip/src/core/ipv4/ip4.c \
|
||||||
|
lwip/src/core/ipv4/autoip.c \
|
||||||
|
lwip/src/core/ipv6/ethip6.c \
|
||||||
|
lwip/src/core/ipv6/inet6.c \
|
||||||
|
lwip/src/core/ipv6/ip6_addr.c \
|
||||||
|
lwip/src/core/ipv6/mld6.c \
|
||||||
|
lwip/src/core/ipv6/dhcp6.c \
|
||||||
|
lwip/src/core/ipv6/icmp6.c \
|
||||||
|
lwip/src/core/ipv6/ip6.c \
|
||||||
|
lwip/src/core/ipv6/ip6_frag.c \
|
||||||
|
lwip/src/core/ipv6/nd6.c \
|
||||||
|
lwip/custom/sys.c \
|
||||||
|
tun2socks/tun2socks.c \
|
||||||
|
base/DebugObject.c \
|
||||||
|
base/BLog.c \
|
||||||
|
base/BPending.c \
|
||||||
|
system/BDatagram_unix.c \
|
||||||
|
flowextra/PacketPassInactivityMonitor.c \
|
||||||
|
tun2socks/SocksUdpGwClient.c \
|
||||||
|
udpgw_client/UdpGwClient.c
|
||||||
|
|
||||||
|
LOCAL_MODULE := tun2socks
|
||||||
|
|
||||||
|
LOCAL_LDLIBS := -ldl -llog
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(addprefix badvpn/, $(TUN2SOCKS_SOURCES))
|
||||||
|
|
||||||
|
include $(BUILD_SYSTEM)/build-executable.mk
|
||||||
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Thanks to https://gist.github.com/wenzhixin/43cf3ce909c24948c6e7
|
||||||
|
# Execute this script in your home directory. Lines 17 and 21 will prompt you for a y/n
|
||||||
|
|
||||||
|
# Install Oracle JDK 8
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y openjdk-8-jdk
|
||||||
|
apt-get install -y unzip make expect # NDK stuff
|
||||||
|
|
||||||
|
# Get SDK tools (link from https://developer.android.com/studio/index.html#downloads)
|
||||||
|
wget -q https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
|
||||||
|
mkdir android-sdk-linux
|
||||||
|
unzip sdk*.zip -d android-sdk-linux
|
||||||
|
|
||||||
|
# Get NDK (https://developer.android.com/ndk/downloads/index.html)
|
||||||
|
# wget -q https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
|
||||||
|
# unzip android-ndk*.zip >> /dev/null
|
||||||
|
|
||||||
|
ACCEPT_LICENSES_URL=https://gist.githubusercontent.com/xiaokangwang/1489fd223d26581bfec92adb3cb0088e/raw/328eb6925099df5aae3e76790f8232f0fc378f8b/accept-licenses
|
||||||
|
|
||||||
|
ACCEPT_LICENSES_ITEM="android-sdk-license-bcbbd656|intel-android-sysimage-license-1ea702d1|android-sdk-license-2742d1c5"
|
||||||
|
|
||||||
|
# Let it update itself and install some stuff
|
||||||
|
cd android-sdk-linux/tools
|
||||||
|
|
||||||
|
curl -L -o accept-licenses $ACCEPT_LICENSES_URL
|
||||||
|
|
||||||
|
chmod +x accept-licenses
|
||||||
|
|
||||||
|
./accept-licenses "./android update sdk --use-sdk-wrapper --all --no-ui" $ACCEPT_LICENSES_ITEM >/dev/null
|
||||||
|
|
||||||
|
# Download every build-tools version that has ever existed
|
||||||
|
# This will save you time! Thank me later for this
|
||||||
|
|
||||||
|
#./accept-licenses "./android update sdk --use-sdk-wrapper --all --no-ui --filter 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" $ACCEPT_LICENSES_ITEM
|
||||||
|
|
||||||
|
PACKAGE_PARSE_URL=https://gist.githubusercontent.com/xiaokangwang/06268fb23034ed94bc301880e862da09/raw/afd95cbbe2f8c1d9e7b0277b7c5ef39af756a6ee/parse.awk
|
||||||
|
|
||||||
|
reduceout=https://gist.githubusercontent.com/xiaokangwang/4684bdb5c3415b943f52aa4803386480/raw/b46dab1cc60f02c0d87f88f01e27157034218faa/out.awk
|
||||||
|
|
||||||
|
cd bin
|
||||||
|
|
||||||
|
curl -L -o parse.awk $PACKAGE_PARSE_URL
|
||||||
|
|
||||||
|
curl -L -o reduce.awk $reduceout
|
||||||
|
|
||||||
|
sudo apt-get install gawk
|
||||||
|
|
||||||
|
./sdkmanager --verbose --list |awk -f parse.awk > ~/package_to_install
|
||||||
|
|
||||||
|
readarray -t filenames < $HOME/package_to_install
|
||||||
|
|
||||||
|
cat $HOME/package_to_install
|
||||||
|
|
||||||
|
yes|./sdkmanager --verbose "${filenames[@]}" |awk -f reduce.awk
|
||||||
|
|
||||||
|
# If you need additional packages for your app, check available packages with:
|
||||||
|
# ./android list sdk --all
|
||||||
|
|
||||||
|
# install certain packages with:
|
||||||
|
# ./android update sdk --no-ui --all --filter 1,2,3,<...>,N
|
||||||
|
# where N is the number of the package in the list (see previous command)
|
||||||
|
|
||||||
|
./sdkmanager "ndk-bundle"
|
||||||
|
|
||||||
|
# Add the directory containing executables in PATH so that they can be found
|
||||||
|
echo 'export ANDROID_HOME=$HOME/android-sdk-linux' >> ~/.bashrc
|
||||||
|
echo 'export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools' >> ~/.bashrc
|
||||||
|
# echo 'export NDK_HOME=$HOME/android-ndk-r15c' >> ~/.bashrc
|
||||||
|
# echo 'export ANDROID_NDK_HOME=$NDK_HOME' >> ~/.bashrc
|
||||||
|
|
||||||
|
|
||||||
|
source ~/.bashrc
|
||||||
|
|
||||||
|
# Make sure you can execute 32 bit executables if this is 64 bit machine, otherwise skip this
|
||||||
|
dpkg --add-architecture i386
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y libc6:i386 libstdc++6:i386 zlib1g:i386
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package libv2ray
|
||||||
|
|
||||||
|
// This struct creates our own log writer without datatime stamp
|
||||||
|
// As Android adds time stamps on each line
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
v2commlog "v2ray.com/core/common/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type consoleLogWriter struct {
|
||||||
|
logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *consoleLogWriter) Write(s string) error {
|
||||||
|
w.logger.Print(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *consoleLogWriter) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This logger won't print data/time stamps
|
||||||
|
func createStdoutLogWriter() v2commlog.WriterCreator {
|
||||||
|
return func() v2commlog.Writer {
|
||||||
|
return &consoleLogWriter{
|
||||||
|
logger: log.New(os.Stdout, "", 0)}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
https://github.com/2dust/v2rayNG/tree/master/AndroidLibV2rayLite
|
||||||
Binary file not shown.
@@ -57,7 +57,7 @@
|
|||||||
<activity android:name=".ui.SettingsActivity" />
|
<activity android:name=".ui.SettingsActivity" />
|
||||||
<activity android:name=".ui.PerAppProxyActivity" />
|
<activity android:name=".ui.PerAppProxyActivity" />
|
||||||
<activity android:name=".ui.ScannerActivity" />
|
<activity android:name=".ui.ScannerActivity" />
|
||||||
<activity android:name=".InappBuyActivity" />
|
<!-- <activity android:name=".InappBuyActivity" />-->
|
||||||
<activity android:name=".ui.LogcatActivity" />
|
<activity android:name=".ui.LogcatActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.RoutingSettingsActivity"
|
android:name=".ui.RoutingSettingsActivity"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class AngApplication : Application() {
|
|||||||
const val PREF_LAST_VERSION = "pref_last_version"
|
const val PREF_LAST_VERSION = "pref_last_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var curIndex = -1 //Current proxy that is opened. (Used to implement restart feature)
|
||||||
var firstRun = false
|
var firstRun = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import java.lang.ref.SoftReference
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import go.Seq
|
||||||
import org.jetbrains.anko.doAsync
|
import org.jetbrains.anko.doAsync
|
||||||
|
|
||||||
class V2RayVpnService : VpnService() {
|
class V2RayVpnService : VpnService() {
|
||||||
@@ -55,8 +56,7 @@ class V2RayVpnService : VpnService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val v2rayPoint = Libv2ray.newV2RayPoint()
|
private val v2rayPoint = Libv2ray.newV2RayPoint(V2RayCallback())
|
||||||
private val v2rayCallback = V2RayCallback()
|
|
||||||
private lateinit var configContent: String
|
private lateinit var configContent: String
|
||||||
private lateinit var mInterface: ParcelFileDescriptor
|
private lateinit var mInterface: ParcelFileDescriptor
|
||||||
val fd: Int get() = mInterface.fd
|
val fd: Int get() = mInterface.fd
|
||||||
@@ -65,7 +65,6 @@ class V2RayVpnService : VpnService() {
|
|||||||
private var mNotificationManager: NotificationManager? = null
|
private var mNotificationManager: NotificationManager? = null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unfortunately registerDefaultNetworkCallback is going to return our VPN interface: https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
|
* Unfortunately registerDefaultNetworkCallback is going to return our VPN interface: https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
|
||||||
*
|
*
|
||||||
@@ -104,15 +103,20 @@ class V2RayVpnService : VpnService() {
|
|||||||
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
|
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
|
||||||
StrictMode.setThreadPolicy(policy)
|
StrictMode.setThreadPolicy(policy)
|
||||||
v2rayPoint.packageName = Utils.packagePath(applicationContext)
|
v2rayPoint.packageName = Utils.packagePath(applicationContext)
|
||||||
|
Seq.setContext(applicationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRevoke() {
|
override fun onRevoke() {
|
||||||
stopV2Ray()
|
stopV2Ray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onLowMemory() {
|
||||||
|
stopV2Ray()
|
||||||
|
super.onLowMemory()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
cancelNotification()
|
cancelNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,22 +184,11 @@ class V2RayVpnService : VpnService() {
|
|||||||
// Create a new interface using the builder and save the parameters.
|
// Create a new interface using the builder and save the parameters.
|
||||||
mInterface = builder.establish()
|
mInterface = builder.establish()
|
||||||
sendFd()
|
sendFd()
|
||||||
|
startSpeedNotification()
|
||||||
if (defaultDPreference.getPrefBoolean(SettingsActivity.PREF_SPEED_ENABLED, false)) {
|
|
||||||
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
|
||||||
.subscribe {
|
|
||||||
val uplink = v2rayPoint.queryStats("socks", "uplink")
|
|
||||||
val downlink = v2rayPoint.queryStats("socks", "downlink")
|
|
||||||
updateNotification("${(uplink / 3).toSpeedString()} ↑ ${(downlink / 3).toSpeedString()} ↓")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shutdown() {
|
fun shutdown() {
|
||||||
try {
|
stopV2Ray(true)
|
||||||
mInterface.close()
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendFd() {
|
fun sendFd() {
|
||||||
@@ -231,12 +224,15 @@ class V2RayVpnService : VpnService() {
|
|||||||
if (!v2rayPoint.isRunning) {
|
if (!v2rayPoint.isRunning) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE))
|
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE)
|
||||||
|
mFilter.addAction(Intent.ACTION_SCREEN_ON)
|
||||||
|
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
|
||||||
|
mFilter.addAction(Intent.ACTION_USER_PRESENT)
|
||||||
|
registerReceiver(mMsgReceive, mFilter)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
configContent = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
|
configContent = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
|
||||||
v2rayPoint.supportSet = v2rayCallback
|
|
||||||
v2rayPoint.configureFileContent = configContent
|
v2rayPoint.configureFileContent = configContent
|
||||||
v2rayPoint.enableLocalDNS = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
v2rayPoint.enableLocalDNS = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
||||||
v2rayPoint.forwardIpv6 = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_FORWARD_IPV6, false)
|
v2rayPoint.forwardIpv6 = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_FORWARD_IPV6, false)
|
||||||
@@ -286,12 +282,19 @@ class V2RayVpnService : VpnService() {
|
|||||||
unregisterReceiver(mMsgReceive)
|
unregisterReceiver(mMsgReceive)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stopSelf has to be called ahead of mInterface.close(). otherwise v2ray core cannot be stooped
|
||||||
|
//It's strage but true.
|
||||||
|
//This can be verified by putting stopself() behind and call stopLoop and startLoop
|
||||||
|
//in a row for several times. You will find that later created v2ray core report port in use
|
||||||
|
//which means the first v2ray core somehow failed to stop and release the port.
|
||||||
|
stopSelf()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mInterface.close()
|
mInterface.close()
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSelf()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +324,6 @@ class V2RayVpnService : VpnService() {
|
|||||||
mBuilder = NotificationCompat.Builder(applicationContext, channelId)
|
mBuilder = NotificationCompat.Builder(applicationContext, channelId)
|
||||||
.setSmallIcon(R.drawable.ic_v)
|
.setSmallIcon(R.drawable.ic_v)
|
||||||
.setContentTitle(defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, ""))
|
.setContentTitle(defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, ""))
|
||||||
.setContentText(getString(R.string.notification_action_more))
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setShowWhen(false)
|
.setShowWhen(false)
|
||||||
@@ -359,7 +361,7 @@ class V2RayVpnService : VpnService() {
|
|||||||
|
|
||||||
private fun updateNotification(contentText: String) {
|
private fun updateNotification(contentText: String) {
|
||||||
if (mBuilder != null) {
|
if (mBuilder != null) {
|
||||||
mBuilder?.setContentText(contentText)
|
mBuilder?.setContentTitle(contentText)
|
||||||
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
|
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,8 +373,41 @@ class V2RayVpnService : VpnService() {
|
|||||||
return mNotificationManager!!
|
return mNotificationManager!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startSpeedNotification() {
|
||||||
|
if (mSubscription == null &&
|
||||||
|
v2rayPoint.isRunning &&
|
||||||
|
defaultDPreference.getPrefBoolean(SettingsActivity.PREF_SPEED_ENABLED, false)) {
|
||||||
|
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
|
||||||
|
var last_zero_speed = false
|
||||||
|
|
||||||
|
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
||||||
|
.subscribe {
|
||||||
|
val uplink = v2rayPoint.queryStats("socks", "uplink")
|
||||||
|
val downlink = v2rayPoint.queryStats("socks", "downlink")
|
||||||
|
val zero_speed = (uplink == 0L && downlink == 0L)
|
||||||
|
if (!zero_speed || !last_zero_speed) {
|
||||||
|
updateNotification("${cf_name} • ${(uplink / 3).toSpeedString()}↑ ${(downlink / 3).toSpeedString()}↓")
|
||||||
|
}
|
||||||
|
last_zero_speed = zero_speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun stopSpeedNotification() {
|
||||||
|
if (mSubscription != null) {
|
||||||
|
mSubscription?.unsubscribe() //stop queryStats
|
||||||
|
mSubscription = null
|
||||||
|
|
||||||
|
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
|
||||||
|
updateNotification(cf_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inner class V2RayCallback : V2RayVPNServiceSupportsSet {
|
private inner class V2RayCallback : V2RayVPNServiceSupportsSet {
|
||||||
override fun shutdown(): Long {
|
override fun shutdown(): Long {
|
||||||
|
// called by go
|
||||||
|
// shutdown the whole vpn service
|
||||||
try {
|
try {
|
||||||
this@V2RayVpnService.shutdown()
|
this@V2RayVpnService.shutdown()
|
||||||
return 0
|
return 0
|
||||||
@@ -447,6 +482,17 @@ class V2RayVpnService : VpnService() {
|
|||||||
vpnService?.startV2ray()
|
vpnService?.startV2ray()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (intent?.action) {
|
||||||
|
Intent.ACTION_SCREEN_OFF -> {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "SCREEN_OFF, stop querying stats")
|
||||||
|
vpnService?.stopSpeedNotification()
|
||||||
|
}
|
||||||
|
Intent.ACTION_SCREEN_ON -> {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "SCREEN_ON, start querying stats")
|
||||||
|
vpnService?.startSpeedNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import android.support.v7.widget.Toolbar
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.v2ray.ang.InappBuyActivity
|
//import com.v2ray.ang.InappBuyActivity
|
||||||
|
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import org.jetbrains.anko.startActivity
|
import org.jetbrains.anko.startActivity
|
||||||
@@ -63,7 +63,7 @@ abstract class BaseDrawerActivity : BaseActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
R.id.donate -> {
|
R.id.donate -> {
|
||||||
startActivity<InappBuyActivity>()
|
// startActivity<InappBuyActivity>()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import android.support.v4.view.GravityCompat
|
|||||||
import android.support.v7.app.ActionBarDrawerToggle
|
import android.support.v7.app.ActionBarDrawerToggle
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper
|
import android.support.v7.widget.helper.ItemTouchHelper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.v2ray.ang.InappBuyActivity
|
//import com.v2ray.ang.InappBuyActivity
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -232,7 +232,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
|
|
||||||
R.id.export_all -> {
|
R.id.export_all -> {
|
||||||
if (AngConfigManager.shareAll2Clipboard() == 0) {
|
if (AngConfigManager.shareAll2Clipboard() == 0) {
|
||||||
toast(R.string.toast_success)
|
//remove toast, otherwise it will block previous warning message
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.toast_failure)
|
toast(R.string.toast_failure)
|
||||||
}
|
}
|
||||||
@@ -561,7 +561,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
Utils.openUri(this, AppConfig.promotionUrl)
|
Utils.openUri(this, AppConfig.promotionUrl)
|
||||||
}
|
}
|
||||||
R.id.donate -> {
|
R.id.donate -> {
|
||||||
startActivity<InappBuyActivity>()
|
// startActivity<InappBuyActivity>()
|
||||||
}
|
}
|
||||||
R.id.logcat -> {
|
R.id.logcat -> {
|
||||||
startActivity<LogcatActivity>()
|
startActivity<LogcatActivity>()
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.v2ray.ang.ui
|
package com.v2ray.ang.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
@@ -12,6 +14,7 @@ import com.v2ray.ang.util.AngConfigManager
|
|||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
import kotlinx.android.synthetic.main.activity_server2.*
|
import kotlinx.android.synthetic.main.activity_server2.*
|
||||||
import org.jetbrains.anko.*
|
import org.jetbrains.anko.*
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
|
||||||
class Server2Activity : BaseActivity() {
|
class Server2Activity : BaseActivity() {
|
||||||
@@ -50,7 +53,7 @@ class Server2Activity : BaseActivity() {
|
|||||||
*/
|
*/
|
||||||
fun bindingServer(vmess: AngConfig.VmessBean): Boolean {
|
fun bindingServer(vmess: AngConfig.VmessBean): Boolean {
|
||||||
et_remarks.text = Utils.getEditable(vmess.remarks)
|
et_remarks.text = Utils.getEditable(vmess.remarks)
|
||||||
tv_content.text = defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + edit_guid, "")
|
tv_content.text = Editable.Factory.getInstance().newEditable(defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + edit_guid, ""))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,21 +69,40 @@ class Server2Activity : BaseActivity() {
|
|||||||
* save server config
|
* save server config
|
||||||
*/
|
*/
|
||||||
fun saveServer(): Boolean {
|
fun saveServer(): Boolean {
|
||||||
|
var saveSuccess: Boolean
|
||||||
val vmess = configs.vmess[edit_index]
|
val vmess = configs.vmess[edit_index]
|
||||||
|
|
||||||
vmess.remarks = et_remarks.text.toString()
|
vmess.remarks = et_remarks.text.toString()
|
||||||
|
|
||||||
if (TextUtils.isEmpty(vmess.remarks)) {
|
if (TextUtils.isEmpty(vmess.remarks)) {
|
||||||
toast(R.string.server_lab_remarks)
|
toast(R.string.server_lab_remarks)
|
||||||
return false
|
saveSuccess = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
||||||
toast(R.string.toast_success)
|
toast(R.string.toast_success)
|
||||||
|
saveSuccess = true
|
||||||
|
} else {
|
||||||
|
toast(R.string.toast_failure)
|
||||||
|
saveSuccess = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
Gson().fromJson<Object>(tv_content.text.toString(), Object::class.java)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
toast(R.string.toast_malformed_josn)
|
||||||
|
saveSuccess = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveSuccess) {
|
||||||
|
//update config
|
||||||
|
defaultDPreference.setPrefString(AppConfig.ANG_CONFIG + edit_guid, tv_content.text.toString())
|
||||||
finish()
|
finish()
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.toast_failure)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import android.content.Intent
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.CheckBoxPreference
|
import android.preference.*
|
||||||
import android.preference.EditTextPreference
|
import com.v2ray.ang.AngApplication
|
||||||
import android.preference.Preference
|
|
||||||
import android.preference.PreferenceFragment
|
|
||||||
import com.v2ray.ang.BuildConfig
|
import com.v2ray.ang.BuildConfig
|
||||||
import com.v2ray.ang.InappBuyActivity
|
//import com.v2ray.ang.InappBuyActivity
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
@@ -29,6 +27,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
// const val PREF_MUX_ENAimport libv2ray.Libv2rayBLED = "pref_mux_enabled"
|
// const val PREF_MUX_ENAimport libv2ray.Libv2rayBLED = "pref_mux_enabled"
|
||||||
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
|
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
|
||||||
const val PREF_SNIFFING_ENABLED = "pref_sniffing_enabled"
|
const val PREF_SNIFFING_ENABLED = "pref_sniffing_enabled"
|
||||||
|
const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled"
|
||||||
const val PREF_LOCAL_DNS_ENABLED = "pref_local_dns_enabled"
|
const val PREF_LOCAL_DNS_ENABLED = "pref_local_dns_enabled"
|
||||||
const val PREF_REMOTE_DNS = "pref_remote_dns"
|
const val PREF_REMOTE_DNS = "pref_remote_dns"
|
||||||
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
|
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
|
||||||
@@ -59,12 +58,19 @@ class SettingsActivity : BaseActivity() {
|
|||||||
|
|
||||||
class SettingsFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
class SettingsFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
val perAppProxy by lazy { findPreference(PREF_PER_APP_PROXY) as CheckBoxPreference }
|
val perAppProxy by lazy { findPreference(PREF_PER_APP_PROXY) as CheckBoxPreference }
|
||||||
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
|
val sppedEnabled by lazy { findPreference(PREF_SPEED_ENABLED) as CheckBoxPreference }
|
||||||
val remoteDns by lazy { findPreference(PREF_REMOTE_DNS) as EditTextPreference }
|
val sniffingEnabled by lazy { findPreference(PREF_SNIFFING_ENABLED) as CheckBoxPreference }
|
||||||
val domesticDns by lazy { findPreference(PREF_DOMESTIC_DNS) as EditTextPreference }
|
val proxySharing by lazy { findPreference(PREF_PROXY_SHARING) as CheckBoxPreference }
|
||||||
|
val domainStrategy by lazy { findPreference(PREF_ROUTING_DOMAIN_STRATEGY) as ListPreference }
|
||||||
|
val routingMode by lazy { findPreference(PREF_ROUTING_MODE) as ListPreference }
|
||||||
|
|
||||||
val enableLocalDns by lazy { findPreference(PREF_LOCAL_DNS_ENABLED) as CheckBoxPreference }
|
|
||||||
val forwardIpv6 by lazy { findPreference(PREF_FORWARD_IPV6) as CheckBoxPreference }
|
val forwardIpv6 by lazy { findPreference(PREF_FORWARD_IPV6) as CheckBoxPreference }
|
||||||
|
val enableLocalDns by lazy { findPreference(PREF_LOCAL_DNS_ENABLED) as CheckBoxPreference }
|
||||||
|
val domesticDns by lazy { findPreference(PREF_DOMESTIC_DNS) as EditTextPreference }
|
||||||
|
val remoteDns by lazy { findPreference(PREF_REMOTE_DNS) as EditTextPreference }
|
||||||
|
|
||||||
|
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
|
||||||
|
|
||||||
|
|
||||||
// val socksPort by lazy { findPreference(PREF_SOCKS_PORT) as EditTextPreference }
|
// val socksPort by lazy { findPreference(PREF_SOCKS_PORT) as EditTextPreference }
|
||||||
// val httpPort by lazy { findPreference(PREF_HTTP_PORT) as EditTextPreference }
|
// val httpPort by lazy { findPreference(PREF_HTTP_PORT) as EditTextPreference }
|
||||||
@@ -76,14 +82,95 @@ class SettingsActivity : BaseActivity() {
|
|||||||
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
|
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
|
||||||
val version: Preference by lazy { findPreference(PREF_VERSION) }
|
val version: Preference by lazy { findPreference(PREF_VERSION) }
|
||||||
|
|
||||||
|
private fun restartProxy() {
|
||||||
|
Utils.stopVService(activity)
|
||||||
|
Utils.startVService(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isRunning(): Boolean {
|
||||||
|
return Utils.isServiceRun(activity, "com.v2ray.ang.service.V2RayVpnService")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
addPreferencesFromResource(R.xml.pref_settings)
|
addPreferencesFromResource(R.xml.pref_settings)
|
||||||
|
var app = activity.application as AngApplication
|
||||||
|
|
||||||
|
perAppProxy.setOnPreferenceClickListener {
|
||||||
|
if (isRunning()) {
|
||||||
|
Utils.stopVService(activity)
|
||||||
|
}
|
||||||
|
startActivity<PerAppProxyActivity>()
|
||||||
|
perAppProxy.isChecked = true
|
||||||
|
true
|
||||||
|
}
|
||||||
|
sppedEnabled.setOnPreferenceClickListener {
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
sniffingEnabled.setOnPreferenceClickListener {
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
proxySharing.setOnPreferenceClickListener {
|
||||||
|
if (proxySharing.isChecked)
|
||||||
|
toast(R.string.toast_warning_pref_proxysharing)
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
domainStrategy.setOnPreferenceChangeListener { _, _ ->
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
routingMode.setOnPreferenceChangeListener { _, _ ->
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
routingCustom.onClick {
|
routingCustom.onClick {
|
||||||
|
if (isRunning())
|
||||||
|
Utils.stopVService(activity)
|
||||||
startActivity<RoutingSettingsActivity>()
|
startActivity<RoutingSettingsActivity>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forwardIpv6.setOnPreferenceClickListener {
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
enableLocalDns.setOnPreferenceClickListener {
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
domesticDns.setOnPreferenceChangeListener { preference, any ->
|
||||||
|
// domesticDns.summary = any as String
|
||||||
|
val nval = any as String
|
||||||
|
domesticDns.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteDns.setOnPreferenceChangeListener { preference, any ->
|
||||||
|
// remoteDns.summary = any as String
|
||||||
|
val nval = any as String
|
||||||
|
remoteDns.summary = if (nval == "") AppConfig.DNS_AGENT else nval
|
||||||
|
if (isRunning())
|
||||||
|
restartProxy()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// donate.onClick {
|
// donate.onClick {
|
||||||
// startActivity<InappBuyActivity>()
|
// startActivity<InappBuyActivity>()
|
||||||
// }
|
// }
|
||||||
@@ -110,24 +197,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
perAppProxy.setOnPreferenceClickListener {
|
|
||||||
startActivity<PerAppProxyActivity>()
|
|
||||||
perAppProxy.isChecked = true
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteDns.setOnPreferenceChangeListener { preference, any ->
|
|
||||||
// remoteDns.summary = any as String
|
|
||||||
val nval = any as String
|
|
||||||
remoteDns.summary = if (nval == "") AppConfig.DNS_AGENT else nval
|
|
||||||
true
|
|
||||||
}
|
|
||||||
domesticDns.setOnPreferenceChangeListener { preference, any ->
|
|
||||||
// domesticDns.summary = any as String
|
|
||||||
val nval = any as String
|
|
||||||
domesticDns.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
|
|
||||||
true
|
|
||||||
}
|
|
||||||
// socksPort.setOnPreferenceChangeListener { preference, any ->
|
// socksPort.setOnPreferenceChangeListener { preference, any ->
|
||||||
// socksPort.summary = any as String
|
// socksPort.summary = any as String
|
||||||
// true
|
// true
|
||||||
|
|||||||
@@ -147,13 +147,15 @@ object AngConfigManager {
|
|||||||
fun setActiveServer(index: Int): Int {
|
fun setActiveServer(index: Int): Int {
|
||||||
try {
|
try {
|
||||||
if (index < 0 || index > angConfig.vmess.count() - 1) {
|
if (index < 0 || index > angConfig.vmess.count() - 1) {
|
||||||
|
app.curIndex = -1
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
angConfig.index = index
|
angConfig.index = index
|
||||||
|
app.curIndex = index
|
||||||
storeConfigFile()
|
storeConfigFile()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
app.curIndex = -1
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.v2ray.ang.AngApplication
|
|||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.responseLength
|
import com.v2ray.ang.extension.responseLength
|
||||||
|
import com.v2ray.ang.extension.v2RayApplication
|
||||||
import com.v2ray.ang.service.V2RayVpnService
|
import com.v2ray.ang.service.V2RayVpnService
|
||||||
import com.v2ray.ang.ui.SettingsActivity
|
import com.v2ray.ang.ui.SettingsActivity
|
||||||
import kotlinx.android.synthetic.main.activity_logcat.*
|
import kotlinx.android.synthetic.main.activity_logcat.*
|
||||||
@@ -311,7 +312,11 @@ object Utils {
|
|||||||
* startVService
|
* startVService
|
||||||
*/
|
*/
|
||||||
fun startVService(context: Context): Boolean {
|
fun startVService(context: Context): Boolean {
|
||||||
context.toast(R.string.toast_services_start)
|
if (context.v2RayApplication.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
|
||||||
|
context.toast(R.string.toast_warning_pref_proxysharing_short)
|
||||||
|
}else{
|
||||||
|
context.toast(R.string.toast_services_start)
|
||||||
|
}
|
||||||
if (AngConfigManager.genStoreV2rayConfig(-1)) {
|
if (AngConfigManager.genStoreV2rayConfig(-1)) {
|
||||||
val configContent = AngConfigManager.currGeneratedV2rayConfig()
|
val configContent = AngConfigManager.currGeneratedV2rayConfig()
|
||||||
val configType = AngConfigManager.currConfigType()
|
val configType = AngConfigManager.currConfigType()
|
||||||
@@ -335,6 +340,7 @@ object Utils {
|
|||||||
*/
|
*/
|
||||||
fun startVService(context: Context, guid: String): Boolean {
|
fun startVService(context: Context, guid: String): Boolean {
|
||||||
val index = AngConfigManager.getIndexViaGuid(guid)
|
val index = AngConfigManager.getIndexViaGuid(guid)
|
||||||
|
context.v2RayApplication.curIndex=index
|
||||||
return startVService(context, index)
|
return startVService(context, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,12 @@ object V2rayConfigUtil {
|
|||||||
*/
|
*/
|
||||||
private fun inbounds(vmess: VmessBean, v2rayConfig: V2rayConfig, app: AngApplication): Boolean {
|
private fun inbounds(vmess: VmessBean, v2rayConfig: V2rayConfig, app: AngApplication): Boolean {
|
||||||
try {
|
try {
|
||||||
|
v2rayConfig.inbounds.forEach { curInbound ->
|
||||||
|
if (!app.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
|
||||||
|
//bind all inbounds to localhost if the user requests
|
||||||
|
curInbound.listen = "127.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
v2rayConfig.inbounds[0].port = 10808
|
v2rayConfig.inbounds[0].port = 10808
|
||||||
// val socksPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
|
// val socksPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
|
||||||
// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_HTTP_PORT, ""))
|
// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_HTTP_PORT, ""))
|
||||||
@@ -547,7 +553,7 @@ object V2rayConfigUtil {
|
|||||||
mux = null))
|
mux = null))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNS routing
|
// DNS routing
|
||||||
v2rayConfig.routing.rules.add(0, V2rayConfig.RoutingBean.RulesBean(
|
v2rayConfig.routing.rules.add(0, V2rayConfig.RoutingBean.RulesBean(
|
||||||
type = "field",
|
type = "field",
|
||||||
outboundTag = AppConfig.TAG_DIRECT,
|
outboundTag = AppConfig.TAG_DIRECT,
|
||||||
|
|||||||
@@ -68,20 +68,15 @@
|
|||||||
android:text="@string/server_lab_content"
|
android:text="@string/server_lab_content"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||||
|
|
||||||
<TextView
|
<EditText
|
||||||
android:id="@+id/tv_content"
|
android:id="@+id/tv_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||||
android:text="" />
|
android:text="" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:layout_marginBottom="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -180,5 +180,10 @@
|
|||||||
<item>绕过大陆地址</item>
|
<item>绕过大陆地址</item>
|
||||||
<item>绕过局域网及大陆地址</item>
|
<item>绕过局域网及大陆地址</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string name="title_pref_proxy_sharing_enabled">代理共享</string>
|
||||||
|
<string name="summary_pref_proxy_sharing_enabled">绑定代理入口ip到0.0.0.0</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing">其他设备可以使用socks/http协议通过您的IP地址连接到代理\nHttp 代理: http://您的ip:10809\nSocks 代理: socks(4/5)://您的ip:10808\n仅在受信任的网络中启用以避免未经授权的连接</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing_short">代理共享已启用,请确保处于受信网络</string>
|
||||||
|
<string name="toast_malformed_josn">配置格式错误</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -182,4 +182,9 @@
|
|||||||
<item>略過中國大陸</item>
|
<item>略過中國大陸</item>
|
||||||
<item>略過局域網及中國大陸</item>
|
<item>略過局域網及中國大陸</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string name="title_pref_proxy_sharing_enabled">代理共享</string>
|
||||||
|
<string name="summary_pref_proxy_sharing_enabled">綁定代理入口ip到0.0.0.0</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing">其他設備可以使用socks/http協議通過您的IP地址連接到代理\nHttp 代理: http://您的ip:10809\nSocks 代理: socks(4/5)://您的ip:10808\n僅在受信任的網絡中啟用以避免未經授權的連接</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing_short">代理共享已啟用,請確保處於受信網絡</string>
|
||||||
|
<string name="toast_malformed_josn">配置格式錯誤</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -181,5 +181,10 @@
|
|||||||
<item>Bypass mainland address</item>
|
<item>Bypass mainland address</item>
|
||||||
<item>Bypassing LAN and mainland address</item>
|
<item>Bypassing LAN and mainland address</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string name="title_pref_proxy_sharing_enabled">Proxy sharing</string>
|
||||||
|
<string name="summary_pref_proxy_sharing_enabled">Bind inbound to 0.0.0.0</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing">Other devices can connect to proxy by your ip address through socks/http protocol\nHttp Proxy: http://yourIP:10809\nSocks Proxy: socks(4/5)://yourIP:10808\nOnly enable in trusted network to avoid unauthorized connection</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing_short">Proxy sharing enabled\nMake sure you are in a trusted network</string>
|
||||||
|
<string name="toast_malformed_josn">Config malformed</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -22,6 +22,13 @@
|
|||||||
android:summary="@string/summary_pref_sniffing_enabled"
|
android:summary="@string/summary_pref_sniffing_enabled"
|
||||||
android:title="@string/title_pref_sniffing_enabled" />
|
android:title="@string/title_pref_sniffing_enabled" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="pref_proxy_sharing_enabled"
|
||||||
|
android:onClick="proxySharingOnClick"
|
||||||
|
android:summary="@string/summary_pref_proxy_sharing_enabled"
|
||||||
|
android:title="@string/title_pref_proxy_sharing_enabled" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/title_pref_routing">
|
<PreferenceCategory android:title="@string/title_pref_routing">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
#
|
#
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
|||||||
Reference in New Issue
Block a user