Skip to content

Commit 0251ec7

Browse files
committed
update and fix local dns
1 parent a75a151 commit 0251ec7

4 files changed

Lines changed: 272 additions & 154 deletions

File tree

app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt

Lines changed: 84 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ import android.os.CancellationSignal
66
import android.system.ErrnoException
77
import androidx.annotation.RequiresApi
88
import io.nekohasekai.sagernet.SagerNet
9-
import io.nekohasekai.sagernet.ktx.tryResumeWithException
9+
import io.nekohasekai.sagernet.ktx.Logs
1010
import kotlinx.coroutines.Dispatchers
1111
import kotlinx.coroutines.asExecutor
12-
import kotlinx.coroutines.runBlocking
1312
import libcore.ExchangeContext
1413
import libcore.LocalDNSTransport
1514
import java.net.InetAddress
1615
import java.net.UnknownHostException
17-
import kotlin.coroutines.resume
18-
import kotlin.coroutines.suspendCoroutine
1916

2017
object LocalResolverImpl : LocalDNSTransport {
2118

@@ -27,98 +24,106 @@ object LocalResolverImpl : LocalDNSTransport {
2724
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
2825
}
2926

27+
override fun networkHandle(): Long {
28+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
29+
return SagerNet.underlyingNetwork?.networkHandle ?: 0
30+
}
31+
return 0
32+
}
33+
3034
@RequiresApi(Build.VERSION_CODES.Q)
3135
override fun exchange(ctx: ExchangeContext, message: ByteArray) {
32-
return runBlocking {
33-
suspendCoroutine { continuation ->
34-
val signal = CancellationSignal()
35-
ctx.onCancel(signal::cancel)
36-
val callback = object : DnsResolver.Callback<ByteArray> {
37-
override fun onAnswer(answer: ByteArray, rcode: Int) {
38-
// exchange don't generate rcode error
39-
ctx.rawSuccess(answer)
40-
continuation.resume(Unit)
41-
}
36+
val signal = CancellationSignal()
37+
ctx.onCancel(signal::cancel)
4238

43-
override fun onError(error: DnsResolver.DnsException) {
44-
when (val cause = error.cause) {
45-
is ErrnoException -> {
46-
ctx.errnoCode(cause.errno)
47-
continuation.resume(Unit)
48-
return
49-
}
50-
}
51-
continuation.tryResumeWithException(error)
52-
}
39+
val callback = object : DnsResolver.Callback<ByteArray> {
40+
override fun onAnswer(answer: ByteArray, rcode: Int) {
41+
ctx.rawSuccess(answer)
42+
}
43+
44+
override fun onError(error: DnsResolver.DnsException) {
45+
val cause = error.cause
46+
if (cause is ErrnoException) {
47+
ctx.errnoCode(cause.errno)
48+
} else {
49+
Logs.w(error)
50+
ctx.errnoCode(114514)
5351
}
54-
DnsResolver.getInstance().rawQuery(
55-
SagerNet.underlyingNetwork,
56-
message,
57-
DnsResolver.FLAG_NO_RETRY,
58-
Dispatchers.IO.asExecutor(),
59-
signal,
60-
callback
61-
)
6252
}
6353
}
54+
55+
DnsResolver.getInstance().rawQuery(
56+
SagerNet.underlyingNetwork,
57+
message,
58+
DnsResolver.FLAG_NO_RETRY,
59+
Dispatchers.IO.asExecutor(),
60+
signal,
61+
callback
62+
)
6463
}
6564

6665
override fun lookup(ctx: ExchangeContext, network: String, domain: String) {
6766
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
68-
return runBlocking {
69-
suspendCoroutine { continuation ->
70-
val signal = CancellationSignal()
71-
ctx.onCancel(signal::cancel)
72-
val callback = object : DnsResolver.Callback<Collection<InetAddress>> {
73-
override fun onAnswer(answer: Collection<InetAddress>, rcode: Int) {
74-
if (rcode == 0) {
75-
ctx.success((answer as Collection<InetAddress?>).mapNotNull { it?.hostAddress }
76-
.joinToString("\n"))
77-
} else {
78-
ctx.errorCode(rcode)
79-
}
80-
continuation.resume(Unit)
81-
}
67+
val signal = CancellationSignal()
68+
ctx.onCancel(signal::cancel)
8269

83-
override fun onError(error: DnsResolver.DnsException) {
84-
when (val cause = error.cause) {
85-
is ErrnoException -> {
86-
ctx.errnoCode(cause.errno)
87-
continuation.resume(Unit)
88-
return
89-
}
90-
}
91-
continuation.tryResumeWithException(error)
70+
val callback = object : DnsResolver.Callback<Collection<InetAddress>> {
71+
override fun onAnswer(answer: Collection<InetAddress>, rcode: Int) {
72+
try {
73+
if (rcode == 0) {
74+
ctx.success(answer.mapNotNull { it.hostAddress }.joinToString("\n"))
75+
} else {
76+
ctx.errorCode(rcode)
9277
}
78+
} catch (e: Exception) {
79+
Logs.w(e)
80+
ctx.errnoCode(114514)
9381
}
94-
val type = when {
95-
network.endsWith("4") -> DnsResolver.TYPE_A
96-
network.endsWith("6") -> DnsResolver.TYPE_AAAA
97-
else -> null
98-
}
99-
if (type != null) {
100-
DnsResolver.getInstance().query(
101-
SagerNet.underlyingNetwork,
102-
domain,
103-
type,
104-
DnsResolver.FLAG_NO_RETRY,
105-
Dispatchers.IO.asExecutor(),
106-
signal,
107-
callback
108-
)
109-
} else {
110-
DnsResolver.getInstance().query(
111-
SagerNet.underlyingNetwork,
112-
domain,
113-
DnsResolver.FLAG_NO_RETRY,
114-
Dispatchers.IO.asExecutor(),
115-
signal,
116-
callback
117-
)
82+
}
83+
84+
override fun onError(error: DnsResolver.DnsException) {
85+
try {
86+
val cause = error.cause
87+
if (cause is ErrnoException) {
88+
ctx.errnoCode(cause.errno)
89+
} else {
90+
Logs.w(error)
91+
ctx.errnoCode(114514)
92+
}
93+
} catch (e: Exception) {
94+
Logs.w(e)
95+
ctx.errnoCode(114514)
11896
}
11997
}
12098
}
99+
100+
val type = when {
101+
network.endsWith("4") -> DnsResolver.TYPE_A
102+
network.endsWith("6") -> DnsResolver.TYPE_AAAA
103+
else -> null
104+
}
105+
if (type != null) {
106+
DnsResolver.getInstance().query(
107+
SagerNet.underlyingNetwork,
108+
domain,
109+
type,
110+
DnsResolver.FLAG_NO_RETRY,
111+
Dispatchers.IO.asExecutor(),
112+
signal,
113+
callback
114+
)
115+
} else {
116+
DnsResolver.getInstance().query(
117+
SagerNet.underlyingNetwork,
118+
domain,
119+
DnsResolver.FLAG_NO_RETRY,
120+
Dispatchers.IO.asExecutor(),
121+
signal,
122+
callback
123+
)
124+
}
121125
} else {
126+
// 老版本系统,继续用阻塞的 InetAddress
122127
val answer = try {
123128
val u = SagerNet.underlyingNetwork
124129
if (u != null) {

libcore/box_include.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,7 @@ func nekoboxAndroidDNSTransportRegistry(localTransport LocalDNSTransport) *dns.T
114114
local.RegisterTransport(registry)
115115
} else {
116116
dns.RegisterTransport(registry, "local", func(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) {
117-
return &platformLocalDNSTransport{
118-
iif: localTransport,
119-
tag: tag,
120-
}, nil
117+
return newPlatformTransport(localTransport, tag, options), nil
121118
})
122119
}
123120

libcore/dns_android.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//go:build android && cgo
2+
3+
package libcore
4+
5+
/*
6+
#include <stdint.h>
7+
#include <stddef.h>
8+
#include <stdlib.h>
9+
#include <dlfcn.h>
10+
11+
typedef int (*android_res_nsend_t)(uint64_t network, const uint8_t* msg, size_t msglen, int flags);
12+
typedef int (*android_res_nresult_t)(int fd, int* rcode, uint8_t* resp, size_t resp_len);
13+
14+
static int call_android_res_nsend(void* sym, uint64_t network, const uint8_t* msg, size_t msglen, int flags) {
15+
android_res_nsend_t f = (android_res_nsend_t)sym;
16+
if (!f) return -1;
17+
return f(network, msg, msglen, flags);
18+
}
19+
20+
static int call_android_res_nresult(void* sym, int fd, int* rcode, uint8_t* resp, size_t resp_len) {
21+
android_res_nresult_t f = (android_res_nresult_t)sym;
22+
if (!f) return -1;
23+
return f(fd, rcode, resp, resp_len);
24+
}
25+
*/
26+
import "C"
27+
28+
import (
29+
"context"
30+
"errors"
31+
"os"
32+
"unsafe"
33+
34+
"golang.org/x/sys/unix"
35+
)
36+
37+
func init() {
38+
libname := C.CString("libandroid.so")
39+
defer C.free(unsafe.Pointer(libname))
40+
41+
libHandle := C.dlopen(libname, C.int(C.RTLD_NOW))
42+
if libHandle == nil {
43+
return
44+
}
45+
46+
symNameSend := C.CString("android_res_nsend")
47+
defer C.free(unsafe.Pointer(symNameSend))
48+
androidResNSendSym := C.dlsym(libHandle, symNameSend)
49+
if androidResNSendSym == nil {
50+
return
51+
}
52+
53+
symNameResult := C.CString("android_res_nresult")
54+
defer C.free(unsafe.Pointer(symNameResult))
55+
androidResNResultSym := C.dlsym(libHandle, symNameResult)
56+
if androidResNResultSym == nil {
57+
return
58+
}
59+
60+
callAndroidResNSend := func(network uint64, msg []byte) (int, error) {
61+
if len(msg) == 0 {
62+
return 0, errors.New("empty payload")
63+
}
64+
msgPtr := (*C.uint8_t)(unsafe.Pointer(&msg[0]))
65+
msgLen := C.size_t(len(msg))
66+
ret := C.call_android_res_nsend(androidResNSendSym, C.uint64_t(network), msgPtr, msgLen, C.int(0))
67+
return int(ret), nil
68+
}
69+
70+
callAndroidResNResult := func(fd int, resp []byte) (int, int) {
71+
if len(resp) == 0 {
72+
return 0, 0
73+
}
74+
respPtr := (*C.uint8_t)(unsafe.Pointer(&resp[0]))
75+
respLen := C.size_t(len(resp))
76+
var rcode C.int
77+
n := C.call_android_res_nresult(androidResNResultSym, C.int(fd), &rcode, respPtr, respLen)
78+
return int(rcode), int(n)
79+
}
80+
81+
// set rawQueryFunc
82+
rawQueryFunc = func(networkHandle int64, request []byte) ([]byte, error) {
83+
fd, err := callAndroidResNSend(uint64(networkHandle), request)
84+
if err != nil {
85+
return nil, err
86+
}
87+
if fd < 0 {
88+
return nil, unix.Errno(-fd)
89+
}
90+
91+
// wait for response (timeout 5000 ms)
92+
pfds := []unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN | unix.POLLERR}}
93+
nReady, err := unix.Poll(pfds, 5000)
94+
if err != nil {
95+
unix.Close(fd)
96+
return nil, err
97+
}
98+
if nReady == 0 {
99+
unix.Close(fd)
100+
return nil, context.DeadlineExceeded
101+
}
102+
103+
// read response into buffer
104+
response := make([]byte, 8192)
105+
_, n := callAndroidResNResult(fd, response)
106+
if n < 0 {
107+
return nil, unix.Errno(-n)
108+
}
109+
if n == 0 {
110+
return nil, os.ErrInvalid
111+
}
112+
return response[:n], nil
113+
}
114+
}

0 commit comments

Comments
 (0)