Skip to content

Commit 2d12b31

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

File tree

3 files changed

+118
-109
lines changed

3 files changed

+118
-109
lines changed

protocol/etch/cmd/main.go

Lines changed: 20 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,17 @@ package main
33
import (
44
"bytes"
55
"context"
6-
"encoding/binary"
76
"flag"
87
"log"
98
"net"
109
"net/url"
11-
"time"
1210

11+
"github.com/mohanson/daze"
1312
"github.com/mohanson/daze/lib/doa"
1413
"github.com/mohanson/daze/protocol/etch"
1514
)
1615

17-
func main() {
18-
flag.Parse()
19-
switch flag.Arg(0) {
20-
case "server":
21-
server := etch.Server{}
22-
server.Run()
23-
select {}
24-
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"))
29-
}
30-
}
31-
32-
// Cdoh structure can be used for DoH protocol processing.
33-
type Cdoh struct {
34-
Server string
35-
Buffer *bytes.Buffer
36-
}
37-
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) {
46-
size := int(binary.BigEndian.Uint16(b[:2]))
47-
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)
65-
c.Buffer.Write(data)
66-
return len(b), nil
67-
}
68-
69-
// ResolverDoh returns a DoH resolver. For further information, see https://datatracker.ietf.org/doc/html/rfc8484.
70-
func ResolverDoh(addr string) *net.Resolver {
16+
func ResolverDoe(addr string) *net.Resolver {
7117
urls := doa.Try(url.Parse(addr))
7218
host := doa.Try(net.LookupHost(urls.Hostname()))[0]
7319
port := urls.Port()
@@ -78,11 +24,26 @@ func ResolverDoh(addr string) *net.Resolver {
7824
return &net.Resolver{
7925
PreferGo: true,
8026
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
81-
conn := &Cdoh{
82-
Server: urls.String(),
83-
Buffer: bytes.NewBuffer([]byte{}),
27+
conn := &daze.WireConn{
28+
Call: func(b []byte) ([]byte, error) {
29+
return etch.NewClient(addr).Call("Dns.Wire", b)
30+
},
31+
Data: bytes.NewBuffer([]byte{}),
8432
}
8533
return conn, nil
8634
},
8735
}
8836
}
37+
38+
func main() {
39+
flag.Parse()
40+
switch flag.Arg(0) {
41+
case "server":
42+
server := etch.NewServer("127.0.0.1:8080")
43+
server.Run()
44+
select {}
45+
case "client":
46+
dns := ResolverDoe("http://127.0.0.1:8080")
47+
log.Println(dns.LookupHost(context.Background(), "google.com"))
48+
}
49+
}

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)