Skip to content

Commit e3f4884

Browse files
committed
2025-08-19 23:01:26
1 parent bcc213b commit e3f4884

File tree

3 files changed

+182
-0
lines changed

3 files changed

+182
-0
lines changed

protocol/etch/cmd/main.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"flag"
7+
"log"
8+
"net"
9+
"net/url"
10+
11+
"github.com/mohanson/daze"
12+
"github.com/mohanson/daze/lib/doa"
13+
"github.com/mohanson/daze/protocol/etch"
14+
)
15+
16+
func ResolverDoe(addr string) *net.Resolver {
17+
urls := doa.Try(url.Parse(addr))
18+
host := doa.Try(net.LookupHost(urls.Hostname()))[0]
19+
port := urls.Port()
20+
urls.Host = host
21+
if port != "" {
22+
urls.Host = host + ":" + port
23+
}
24+
return &net.Resolver{
25+
PreferGo: true,
26+
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
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{}),
32+
}
33+
return conn, nil
34+
},
35+
}
36+
}
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: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package etch
2+
3+
import (
4+
"bytes"
5+
"encoding/base64"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"log"
10+
"net"
11+
"net/http"
12+
"net/rpc"
13+
"net/rpc/jsonrpc"
14+
15+
"github.com/mohanson/daze"
16+
"github.com/mohanson/daze/lib/doa"
17+
)
18+
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+
}
23+
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))
31+
if err != nil {
32+
return err
33+
}
34+
b, err := io.ReadAll(r.Body)
35+
if err != nil {
36+
return err
37+
}
38+
*reply = base64.StdEncoding.EncodeToString(b)
39+
return nil
40+
}
41+
42+
// Server implemented the etch protocol.
43+
type Server struct {
44+
Closer io.Closer
45+
Listen string
46+
}
47+
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+
}
55+
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+
}
71+
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+
}
82+
83+
// NewServer returns a new Server.
84+
func NewServer(listen string) *Server {
85+
return &Server{
86+
Closer: nil,
87+
Listen: listen,
88+
}
89+
}
90+
91+
// Client implemented the etch protocol.
92+
type Client struct {
93+
Server string
94+
}
95+
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
122+
}
123+
124+
// NewClient returns a new Client.
125+
func NewClient(server string) *Client {
126+
return &Client{
127+
Server: server,
128+
}
129+
}

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)