Skip to content

Commit 5ae287f

Browse files
committed
2025-08-20 15:06:25
1 parent 4f15050 commit 5ae287f

File tree

3 files changed

+124
-83
lines changed

3 files changed

+124
-83
lines changed

protocol/etch/cmd/main.go

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,56 +18,49 @@ func main() {
1818
flag.Parse()
1919
switch flag.Arg(0) {
2020
case "server":
21-
server := etch.Server{}
21+
server := etch.NewServer("127.0.0.1:8080")
2222
server.Run()
2323
select {}
2424
case "client":
25-
// client := etch.NewClient()
26-
// log.Println(client.DnsQuery())
27-
r := ResolverDoh("http://127.0.0.1:8080")
28-
log.Println(r.LookupHost(context.Background(), "baidu.com"))
25+
// client := etch.NewClient("http://127.0.0.1:8080")
26+
// log.Println(client.Call("Dns.Wire", []byte{111, 60, 129, 128, 0, 1, 0, 2, 0, 0, 0, 1, 5, 98, 97, 105, 100, 117, 3, 99, 111, 109, 0, 0, 1, 0, 1, 192, 12, 0, 1, 0, 1, 0, 0, 1, 21, 0, 4, 182, 61, 201, 211, 192, 12, 0, 1, 0, 1, 0, 0, 1, 21, 0, 4, 182, 61, 244, 181, 0, 0, 41, 4, 208, 0, 0, 0, 0, 0, 0}))
27+
28+
r := ResolverDoe("http://127.0.0.1:8080")
29+
log.Println(r.LookupHost(context.Background(), "google.com"))
2930
}
3031
}
3132

3233
// Cdoh structure can be used for DoH protocol processing.
33-
type Cdoh struct {
34+
type Cdoe struct {
3435
Server string
3536
Buffer *bytes.Buffer
3637
}
3738

38-
func (c Cdoh) Read(b []byte) (n int, err error) { return c.Buffer.Read(b) }
39-
func (c Cdoh) Close() error { return nil }
40-
func (c Cdoh) LocalAddr() net.Addr { return nil }
41-
func (c Cdoh) RemoteAddr() net.Addr { return nil }
42-
func (c Cdoh) SetDeadline(t time.Time) error { return nil }
43-
func (c Cdoh) SetReadDeadline(t time.Time) error { return nil }
44-
func (c Cdoh) SetWriteDeadline(t time.Time) error { return nil }
45-
func (c Cdoh) Write(b []byte) (n int, err error) {
39+
func (c Cdoe) Read(b []byte) (n int, err error) { return c.Buffer.Read(b) }
40+
func (c Cdoe) Close() error { return nil }
41+
func (c Cdoe) LocalAddr() net.Addr { return nil }
42+
func (c Cdoe) RemoteAddr() net.Addr { return nil }
43+
func (c Cdoe) SetDeadline(t time.Time) error { return nil }
44+
func (c Cdoe) SetReadDeadline(t time.Time) error { return nil }
45+
func (c Cdoe) SetWriteDeadline(t time.Time) error { return nil }
46+
func (c Cdoe) Write(b []byte) (n int, err error) {
4647
size := int(binary.BigEndian.Uint16(b[:2]))
4748
doa.Doa(size == len(b)-2)
48-
49-
client := etch.NewClient("127.0.0.1:8080")
50-
body := client.DnsQuery(b[2:])
51-
52-
// resp, err := http.Post(c.Server, "application/dns-message", bytes.NewReader(b[2:]))
53-
// if err != nil {
54-
// log.Println("cdoh:", err)
55-
// return len(b), nil
56-
// }
57-
// body, err := io.ReadAll(resp.Body)
58-
// if err != nil {
59-
// log.Println("cdoh:", err)
60-
// return len(b), nil
61-
// }
62-
data := make([]byte, 2+len(body))
63-
binary.BigEndian.PutUint16(data[:2], uint16(len(body)))
64-
copy(data[2:], body)
49+
client := etch.NewClient("http://127.0.0.1:8080")
50+
r, err := client.Call("Dns.Wire", b[2:])
51+
if err != nil {
52+
log.Println("cdoe:", err)
53+
return len(b), nil
54+
}
55+
data := make([]byte, 2+len(r))
56+
binary.BigEndian.PutUint16(data[:2], uint16(len(r)))
57+
copy(data[2:], r)
6558
c.Buffer.Write(data)
6659
return len(b), nil
6760
}
6861

6962
// ResolverDoh returns a DoH resolver. For further information, see https://datatracker.ietf.org/doc/html/rfc8484.
70-
func ResolverDoh(addr string) *net.Resolver {
63+
func ResolverDoe(addr string) *net.Resolver {
7164
urls := doa.Try(url.Parse(addr))
7265
host := doa.Try(net.LookupHost(urls.Hostname()))[0]
7366
port := urls.Port()
@@ -78,7 +71,7 @@ func ResolverDoh(addr string) *net.Resolver {
7871
return &net.Resolver{
7972
PreferGo: true,
8073
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
81-
conn := &Cdoh{
74+
conn := &Cdoe{
8275
Server: urls.String(),
8376
Buffer: bytes.NewBuffer([]byte{}),
8477
}

protocol/etch/engine.go

Lines changed: 94 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,128 @@ package etch
22

33
import (
44
"bytes"
5+
"encoding/base64"
6+
"encoding/json"
7+
"fmt"
58
"io"
9+
"log"
10+
"net"
611
"net/http"
712
"net/rpc"
13+
"net/rpc/jsonrpc"
814

15+
"github.com/mohanson/daze"
916
"github.com/mohanson/daze/lib/doa"
1017
)
1118

12-
type Etch struct{}
19+
// Dns represents a DNS resolver that communicates with a DNS server.
20+
type Dns struct {
21+
Server string // URL of the DNS server (e.g., "https://1.1.1.1/dns-query")
22+
}
1323

14-
func (m *Etch) DnsQuery(arg []byte, ret *[]byte) error {
15-
r, err := http.Post("https://1.1.1.1/dns-query", "application/dns-message", bytes.NewReader(arg))
24+
// Wire processes a DNS query by sending it to the configured DNS server and returning the response.
25+
func (d *Dns) Wire(args string, reply *string) error {
26+
params, err := base64.StdEncoding.DecodeString(args)
27+
if err != nil {
28+
return err
29+
}
30+
r, err := http.Post(d.Server, "application/dns-message", bytes.NewReader(params))
1631
if err != nil {
1732
return err
1833
}
1934
b, err := io.ReadAll(r.Body)
2035
if err != nil {
2136
return err
2237
}
23-
*ret = b
38+
*reply = base64.StdEncoding.EncodeToString(b)
2439
return nil
2540
}
2641

27-
type Server struct{}
28-
29-
func (s *Server) Run() error {
30-
doa.Nil(rpc.Register(&Etch{}))
31-
rpc.HandleHTTP()
32-
doa.Nil(http.ListenAndServe("127.0.0.1:8080", nil))
33-
34-
// l, err := net.Listen("tcp", "127.0.0.1:8080")
35-
// if err != nil {
36-
// log.Fatal("listen error:", err)
37-
// }
38-
39-
// // 设置 JSON-RPC 处理
40-
// http.HandleFunc("/rpc", func(w http.ResponseWriter, r *http.Request) {
41-
// // 设置响应头
42-
// w.Header().Set("Content-Type", "application/json")
42+
// Server implemented the etch protocol.
43+
type Server struct {
44+
Closer io.Closer
45+
Listen string
46+
}
4347

44-
// // 创建 JSON-RPC 编解码器
45-
// conn, _, err := w.(http.Hijacker).Hijack()
46-
// if err != nil {
47-
// log.Println("Hijacking failed:", err)
48-
// return
49-
// }
50-
// defer conn.Close()
48+
// Close listener. Established connections will not be closed.
49+
func (s *Server) Close() error {
50+
if s.Closer != nil {
51+
return s.Closer.Close()
52+
}
53+
return nil
54+
}
5155

52-
// // 处理 JSON-RPC 请求
53-
// codec := jsonrpc.NewServerCodec(conn)
54-
// err = rpc.ServeRequest(codec)
55-
// if err != nil {
56-
// log.Println("ServeRequest error:", err)
57-
// return
58-
// }
59-
// })
56+
// Run it.
57+
func (s *Server) Run() error {
58+
rpc.Register(&Dns{
59+
Server: "https://1.1.1.1/dns-query",
60+
})
61+
l, err := net.Listen("tcp", s.Listen)
62+
if err != nil {
63+
return err
64+
}
65+
log.Println("main: listen and serve on", s.Listen)
66+
srv := &http.Server{Handler: s}
67+
s.Closer = srv
68+
go srv.Serve(l)
69+
return nil
70+
}
6071

61-
// // 启动 HTTP 服务器
62-
// fmt.Println("JSON-RPC server starting on :8080...")
63-
// err = http.ListenAndServe(":8080", nil)
64-
// if err != nil {
65-
// log.Fatal("ListenAndServe error:", err)
66-
// }
72+
// ServeHTTP implements http.Handler.
73+
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
74+
rwc := daze.ReadWriteCloser{
75+
Reader: r.Body,
76+
Writer: w,
77+
Closer: r.Body,
78+
}
79+
codec := jsonrpc.NewServerCodec(rwc)
80+
rpc.ServeRequest(codec)
81+
}
6782

68-
return nil
83+
// NewServer returns a new Server.
84+
func NewServer(listen string) *Server {
85+
return &Server{
86+
Closer: nil,
87+
Listen: listen,
88+
}
6989
}
7090

91+
// Client implemented the etch protocol.
7192
type Client struct {
72-
cli *rpc.Client
93+
Server string
7394
}
7495

75-
func (c *Client) DnsQuery(arg []byte) []byte {
76-
r := []byte{}
77-
doa.Nil(c.cli.Call("Etch.DnsQuery", arg, &r))
78-
return r
96+
func (c *Client) Call(method string, args []byte) ([]byte, error) {
97+
sendJson := map[string]any{
98+
"jsonrpc": "2.0",
99+
"id": 1,
100+
"method": method,
101+
"params": []string{base64.StdEncoding.EncodeToString(args)},
102+
}
103+
sendData := doa.Try(json.Marshal(sendJson))
104+
r, err := http.Post(c.Server, "application/json", bytes.NewBuffer(sendData))
105+
if err != nil {
106+
return nil, err
107+
}
108+
defer r.Body.Close()
109+
110+
recvJson := map[string]any{}
111+
if err := json.NewDecoder(r.Body).Decode(&recvJson); err != nil {
112+
return nil, err
113+
}
114+
if recvJson["error"] != nil {
115+
return nil, fmt.Errorf("%s", recvJson["error"])
116+
}
117+
recvData, err := base64.StdEncoding.DecodeString(recvJson["result"].(string))
118+
if err != nil {
119+
return nil, err
120+
}
121+
return recvData, nil
79122
}
80123

124+
// NewClient returns a new Client.
81125
func NewClient(server string) *Client {
82-
c := doa.Try(rpc.DialHTTP("tcp", server))
83-
client := &Client{cli: c}
84-
return client
126+
return &Client{
127+
Server: server,
128+
}
85129
}

protocol/etch/main.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
set -ex
2+
curl -X POST http://localhost:8080 \
3+
-H "Content-Type: application/json" \
4+
-d '{"jsonrpc": "2.0", "method": "Dns.Wire", "params": ["uygBIAABAAAAAAABBmdvb2dsZQNjb20AABwAAQAAKQTQAAAAAAAA"], "id": 1}'

0 commit comments

Comments
 (0)