Skip to content
This repository was archived by the owner on Jul 7, 2024. It is now read-only.

Commit 50c4788

Browse files
committed
hokuto: partial impl
something wrong with adding the miekg/dns package, so a partial commit for now...
1 parent 370fc32 commit 50c4788

23 files changed

+347
-55
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/src
22
/pkg
33
/build2
4-
qrystal-*.pkg*
4+
/qrystal-*.pkg*
55
/cs-push-config.yml
66
/tmp-config.yml
77
/cs-push
88
/build.tar.zst
9-
.direnv
9+
/.direnv

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ldflags-mio += -X github.com/nyiyui/qrystal/mio.CommandWg=${shell which wg}
55
ldflags-mio += -X github.com/nyiyui/qrystal/mio.CommandWgQuick=${shell which wg-quick}
66
ldflags-node = -X github.com/nyiyui/qrystal/node.CommandIp=${shell which ip}
77
ldflags-node += -X github.com/nyiyui/qrystal/node.CommandIptables=${shell which iptables}
8-
ldflags-runner = -X github.com/nyiyui/qrystal/runner.nodeUser=qrystal-node
8+
ldflags-runner = -X github.com/nyiyui/qrystal/runner.NodeUser=qrystal-node
99

1010
all: runner-mio runner-node runner gen-keys cs
1111

cmd/runner-hokuto/main.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/nyiyui/qrystal/profile"
7+
"github.com/nyiyui/qrystal/util"
8+
)
9+
10+
func main() {
11+
util.SetupLog()
12+
log.SetPrefix("hokuto: ")
13+
log.SetFlags(log.LstdFlags | log.Lmsgprefix)
14+
util.ShowCurrent()
15+
profile.Profile()
16+
17+
//err := hokuto.Main()
18+
//if err != nil {
19+
// log.Fatalf("%s", err)
20+
//}
21+
}

cmd/runner-node/main.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,19 @@ func main() {
114114
if err != nil {
115115
log.Fatalf("parse MIO_TOKEN: %s", err)
116116
}
117-
n, err := node.NewNode(node.NodeConfig{
117+
nc := node.NodeConfig{
118118
MioAddr: mioAddr,
119119
MioToken: mioToken,
120120
CS: ncscs,
121-
})
121+
}
122+
if os.Getenv("HOKUTO_ADDR") != "" {
123+
nc.HokutoAddr = os.Getenv("HOKUTO_ADDR")
124+
nc.HokutoToken, err = base64.StdEncoding.DecodeString(os.Getenv("HOKUTO_TOKEN"))
125+
if err != nil {
126+
util.S.Fatalf("parse HOKUTO_TOKEN: %s", err)
127+
}
128+
}
129+
n, err := node.NewNode(nc)
122130
if err != nil {
123131
panic(err)
124132
}

cs/haruka.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
)
1111

1212
func (c *CentralSource) HandleHaruka(addr string, tlsCfg TLS) error {
13+
util.S.Info("haruka: starting…")
1314
cert, err := tls.LoadX509KeyPair(tlsCfg.CertPath, tlsCfg.KeyPath)
1415
if err != nil {
1516
return fmt.Errorf("loading cert or key: %w", err)
@@ -29,6 +30,6 @@ func (c *CentralSource) HandleHaruka(addr string, tlsCfg TLS) error {
2930
util.S.Fatalf("haruka: serve failed: %s", err)
3031
}
3132
}()
32-
util.S.Info("haruka: serving")
33+
util.S.Info("haruka: serving")
3334
return nil
3435
}

cs/ryo.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,41 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"log"
78
"net/http"
9+
"os"
810
"time"
911

1012
"github.com/nyiyui/qrystal/api"
1113
"github.com/nyiyui/qrystal/util"
12-
"go.uber.org/zap"
13-
"go.uber.org/zap/zapcore"
1414
)
1515

1616
type tokenInfoKeyType struct{}
1717

1818
var tokenInfoKey = tokenInfoKeyType{}
1919

2020
func (c *CentralSource) HandleRyo(addr string, tlsCfg TLS) error {
21+
util.S.Info("ryo: starting…")
2122
if addr == "" {
2223
return nil
2324
}
2425
mux := http.NewServeMux()
2526
// TODO: only POST
2627
mux.Handle("/push", c.ryoToken(http.HandlerFunc(c.ryoPush)))
2728
mux.Handle("/add-token", c.ryoToken(http.HandlerFunc(c.ryoAddToken)))
28-
el, err := zap.NewStdLogAt(util.L, zapcore.ErrorLevel)
29-
if err != nil {
30-
panic(err)
31-
}
3229
s := &http.Server{
3330
Addr: addr,
3431
Handler: mux,
3532
ReadTimeout: 1 * time.Second,
36-
ErrorLog: el,
33+
ErrorLog: log.New(os.Stderr, "ryo server: ", log.Lmsgprefix|log.LstdFlags|log.Lshortfile),
3734
}
3835
go func() {
3936
err := s.ListenAndServeTLS(tlsCfg.CertPath, tlsCfg.KeyPath)
4037
if err != nil {
4138
util.S.Fatalf("ryo: serve failed: %s", err)
4239
}
4340
}()
44-
util.S.Info("ryo: serving")
41+
util.S.Info("ryo: serving")
4542
return nil
4643
}
4744

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@
6666
{
6767
runner = pkgs.buildGoModule (common // {
6868
pname = "runner";
69-
subPackages = [ "cmd/runner" "cmd/runner-mio" "cmd/runner-node" ];
69+
subPackages = [ "cmd/runner" "cmd/runner-mio" "cmd/runner-node" ]; # "cmd/runner-hokuto" ];
7070
ldflags = (ldflags pkgs) ++ [
71-
"-X github.com/nyiyui/qrystal/runner.nodeUser=qrystal-node"
71+
"-X github.com/nyiyui/qrystal/runner.NodeUser=qrystal-node"
7272
];
7373
postInstall = ''
7474
mkdir $out/lib
@@ -135,6 +135,23 @@
135135
config = mkOption {
136136
type = submodule {
137137
options = {
138+
hokuto = mkOption {
139+
type = submodule {
140+
options = {
141+
enable = mkOption {
142+
type = bool;
143+
default = true;
144+
description = "Enable DNS";
145+
};
146+
parent = mkOption {
147+
type = str;
148+
default = ".qrystal.internal";
149+
description = "All domains inside networks will be of the format <peer>.<network>.<parent>";
150+
};
151+
};
152+
};
153+
default = {};
154+
};
138155
css = mkOption {
139156
type = listOf (submodule {
140157
options = {
@@ -196,6 +213,7 @@
196213
wantedBy = [ "network-online.target" ];
197214
environment = {
198215
"RUNNER_MIO_PATH" = "${pkg}/bin/runner-mio";
216+
#"RUNNER_HOKUTO_PATH" = "${pkg}/bin/runner-hokuto";
199217
"RUNNER_NODE_PATH" = "${pkg}/bin/runner-node";
200218
"RUNNER_NODE_CONFIG_PATH" = mkConfigFile cfg;
201219
};

hokuto/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ Returns `A` records per-peers' allowed IPs, and `TXT` records for other metadata
1111
- Initial protocol to fetch networks from qrystal-node.
1212
- Restrict returned domains to only which the client can see.
1313
- Forward DNS requests.
14+
- Reverse lookups.

hokuto/config-sample.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"parent": ".qrystal.internal"
3+
}

hokuto/server.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package hokuto
2+
3+
import (
4+
"net"
5+
"sync"
6+
7+
//"github.com/miekg/dns"
8+
"github.com/nyiyui/qrystal/central"
9+
)
10+
11+
// ~~stolen~~ copied from <https://gist.github.com/walm/0d67b4fb2d5daf3edd4fad3e13b162cb>.
12+
13+
var cc *central.Config
14+
var ccLock sync.Mutex
15+
16+
var mask32 = net.CIDRMask(32, 32)
17+
18+
var c Config
19+
var token []byte
20+
var suffix string
21+
22+
type Config struct {
23+
Parent string `json:"parent"`
24+
}
25+
26+
/*
27+
func returnPeer(m *dns.Msg, q dns.Question, peer *central.Peer) {
28+
for _, in := range peer.AllowedIPs {
29+
if !bytes.Equal(net.IPNet(in).Mask, mask32) {
30+
// non-/32s seem very *fun* to deal with...
31+
continue
32+
}
33+
rr, err := dns.NewRR(fmt.Sprintf("%s A %s", q.Name, in.IP.String()))
34+
if err == nil {
35+
m.Answer = append(m.Answer, rr)
36+
}
37+
}
38+
}
39+
40+
func handleQuery(m *dns.Msg) (nxdomain bool) {
41+
for _, q := range m.Question {
42+
log.Printf("Query for %s\n", q.Name)
43+
44+
switch q.Qtype {
45+
case dns.TypeA:
46+
if strings.HasSuffix(q.Name, suffix) {
47+
ccLock.Lock()
48+
defer ccLock.Unlock()
49+
parts := strings.Split(strings.TrimSuffix(q.Name, suffix), ".")
50+
if len(parts) == 0 {
51+
nxdomain = true
52+
return
53+
}
54+
cnn := parts[0]
55+
cn := cc.Networks[cnn]
56+
if cn == nil {
57+
nxdomain = true
58+
return
59+
}
60+
switch len(parts) {
61+
case 1:
62+
for _, peer := range cn.Peers {
63+
returnPeer(m, q, peer)
64+
}
65+
case 2:
66+
pn := parts[1]
67+
peer := cn.Peers[pn]
68+
if cn == nil {
69+
nxdomain = true
70+
return
71+
}
72+
returnPeer(m, q, peer)
73+
}
74+
} else {
75+
nxdomain = true
76+
return
77+
}
78+
}
79+
}
80+
return
81+
}
82+
83+
func handle(w dns.ResponseWriter, r *dns.Msg) {
84+
m := new(dns.Msg)
85+
m.SetReply(r)
86+
m.Compress = false
87+
switch r.Opcode {
88+
case dns.OpcodeQuery:
89+
nxdomain := handleQuery(m)
90+
if nxdomain {
91+
m.MsgHdr.Rcode = dns.RcodeNameError
92+
}
93+
}
94+
w.WriteMsg(m)
95+
}
96+
97+
func main2() {
98+
configPath := flag.String("config", "", "config path")
99+
addr := flag.String("addr", "", "dns bind address")
100+
flag.Parse()
101+
102+
buf, err := os.ReadFile(*configPath)
103+
if err != nil {
104+
util.S.Fatalf("read config: %s", err)
105+
}
106+
err = json.Unmarshal(buf, &c)
107+
if err != nil {
108+
util.S.Fatalf("parse config: %s", err)
109+
}
110+
suffix = c.Parent + "."
111+
util.S.Infof("config parsed from %s", *configPath)
112+
113+
dns.HandleFunc(".", handle)
114+
115+
server := &dns.Server{Addr: *addr, Net: "udp"}
116+
util.S.Infof("listening on %s", server.Addr)
117+
err = server.ListenAndServe()
118+
if err != nil {
119+
util.S.Fatalf("listen failed: %s\n ", err.Error())
120+
}
121+
defer server.Shutdown()
122+
}
123+
124+
type rpcServer struct{}
125+
126+
type UpdateCCQ struct {
127+
Token []byte
128+
CC *central.Config
129+
}
130+
131+
func (_ rpcServer) updateCC(q *UpdateCCQ, _ *bool) error {
132+
if !bytes.Equal(token, q.Token) {
133+
return errors.New("token mismatch")
134+
}
135+
if q.CC == nil {
136+
return errors.New("cc is nil")
137+
}
138+
ccLock.Lock()
139+
defer ccLock.Unlock()
140+
cc = q.CC
141+
return nil
142+
}
143+
144+
func Main() error {
145+
var tokenBase64 string
146+
var err error
147+
token, tokenBase64, err = mio.GenToken()
148+
if err != nil {
149+
util.S.Fatalf("GenToken: %s", err)
150+
}
151+
lis, addr, err := mio.Listen()
152+
if err != nil {
153+
util.S.Fatalf("Listen: %s", err)
154+
}
155+
fmt.Printf("addr:%s\n", addr)
156+
fmt.Printf("token:%s\n", tokenBase64)
157+
err = os.Stdout.Close()
158+
if err != nil {
159+
util.S.Fatalf("close stdout: %s", err)
160+
}
161+
util.S.Info("聞きます。")
162+
rs := rpc.NewServer()
163+
rs.RegisterName("updateCC", rpcServer{})
164+
handler := mio.Guard(rs)
165+
err = http.Serve(lis, handler)
166+
if err != nil {
167+
util.S.Fatalf("serve: %s", err)
168+
}
169+
return nil
170+
}
171+
*/

mio/listen.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"strings"
1212
)
1313

14-
func listen() (lis net.Listener, addr string, err error) {
14+
func Listen() (lis net.Listener, addr string, err error) {
1515
lis, err = net.Listen("tcp", "127.0.0.1:0")
1616
if err != nil {
1717
return
@@ -20,13 +20,13 @@ func listen() (lis net.Listener, addr string, err error) {
2020
return
2121
}
2222

23-
// guard aborts connections from hosts that are not localhost.
23+
// Guard aborts connections from hosts that are not localhost.
2424
//
2525
// This is intended to be a last resort; it should not be relied on for
2626
// security.
2727
//
2828
// Note: Server should be listening on 127.0.0.1, not 0.0.0.0.
29-
func guard(handler http.Handler) http.Handler {
29+
func Guard(handler http.Handler) http.Handler {
3030
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3131
if !strings.HasPrefix(r.RemoteAddr, "127.0.0.1:") {
3232
log.Printf("blocked request from %s", r.RemoteAddr)

0 commit comments

Comments
 (0)