mirror of
https://github.com/tladesignz/dnstt.git
synced 2026-10-11 16:48:23 +03:00
-privkey-file and -pubkey-file options.
This commit is contained in:
+26
-11
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/base32"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -152,6 +151,15 @@ func dnsNameCapacity(domain dns.Name) int {
|
||||
return capacity
|
||||
}
|
||||
|
||||
func readKeyFromFile(filename string) ([]byte, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return noise.ReadKey(f)
|
||||
}
|
||||
|
||||
func run(pubkey []byte, domain dns.Name, localAddr *net.TCPAddr, remoteAddr net.Addr, pconn net.PacketConn) error {
|
||||
defer pconn.Close()
|
||||
|
||||
@@ -228,19 +236,19 @@ func main() {
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), `Usage:
|
||||
%[1]s [-doh URL|-dot ADDR|-udp ADDR] -pubkey PUBKEY DOMAIN LOCALADDR
|
||||
%[1]s [-doh URL|-dot ADDR|-udp ADDR] -pubkey-file PUBKEYFILE DOMAIN LOCALADDR
|
||||
|
||||
Examples:
|
||||
%[1]s -doh https://resolver.example/dns-query -pubkey 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff t.example.com 127.0.0.1:7000
|
||||
%[1]s -dot resolver.example:853 -pubkey 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff t.example.com 127.0.0.1:7000
|
||||
%[1]s -doh https://resolver.example/dns-query -pubkey-file server.pub t.example.com 127.0.0.1:7000
|
||||
%[1]s -dot resolver.example:853 -pubkey-file server.pub t.example.com 127.0.0.1:7000
|
||||
|
||||
`, os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.StringVar(&dohURL, "doh", "", "URL of DoH resolver")
|
||||
flag.StringVar(&dotAddr, "dot", "", "address of DoT resolver")
|
||||
flag.StringVar(&pubkeyString, "pubkey", "", fmt.Sprintf("server public key (%d hex digits)", hex.EncodedLen(noise.KeyLen)))
|
||||
flag.StringVar(&pubkeyString, "pubkey-file", "", "read server public key from file")
|
||||
flag.StringVar(&pubkeyString, "pubkey", "", fmt.Sprintf("server public key (%d hex digits)", noise.KeyLen*2))
|
||||
flag.StringVar(&pubkeyFilename, "pubkey-file", "", "read server public key from file")
|
||||
flag.StringVar(&udpAddr, "udp", "", "address of UDP DNS resolver")
|
||||
flag.Parse()
|
||||
|
||||
@@ -262,19 +270,26 @@ Examples:
|
||||
}
|
||||
|
||||
var pubkey []byte
|
||||
if pubkeyString != "" {
|
||||
if pubkeyFilename != "" && pubkeyString != "" {
|
||||
fmt.Fprintf(os.Stderr, "only one of -pubkey and -pubkey-file may be used\n")
|
||||
os.Exit(1)
|
||||
} else if pubkeyFilename != "" {
|
||||
var err error
|
||||
pubkey, err = hex.DecodeString(pubkeyString)
|
||||
if err == nil && len(pubkey) != noise.KeyLen {
|
||||
err = fmt.Errorf("length is %d, expected %d", len(pubkey), noise.KeyLen)
|
||||
pubkey, err = readKeyFromFile(pubkeyFilename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "cannot read pubkey from file: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if pubkeyString != "" {
|
||||
var err error
|
||||
pubkey, err = noise.DecodeKey(pubkeyString)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "pubkey format error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if len(pubkey) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "the -pubkey option is required\n")
|
||||
fmt.Fprintf(os.Stderr, "the -pubkey or -pubkey-file option is required\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
+100
-16
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/base32"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -491,16 +490,85 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <-
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateKeypair() error {
|
||||
func generateKeypair(privkeyFilename, pubkeyFilename string) (err error) {
|
||||
// Filenames to delete in case of error (avoid leaving partially written
|
||||
// files).
|
||||
var toDelete []string
|
||||
defer func() {
|
||||
for _, filename := range toDelete {
|
||||
fmt.Fprintf(os.Stderr, "deleting partially written file %s\n", filename)
|
||||
if closeErr := os.Remove(filename); closeErr != nil {
|
||||
fmt.Fprintf(os.Stderr, "cannot remove %s: %v\n", filename, closeErr)
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
privkey, pubkey, err := noise.GenerateKeypair()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("privkey: %x\n", privkey)
|
||||
fmt.Printf("pubkey: %x\n", pubkey)
|
||||
|
||||
if privkeyFilename != "" {
|
||||
// Save the privkey to a file.
|
||||
f, err := os.Create(privkeyFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toDelete = append(toDelete, privkeyFilename)
|
||||
err = noise.WriteKey(f, privkey)
|
||||
if err2 := f.Close(); err == nil {
|
||||
err = err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if pubkeyFilename != "" {
|
||||
// Save the pubkey to a file.
|
||||
f, err := os.Create(pubkeyFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toDelete = append(toDelete, pubkeyFilename)
|
||||
err = noise.WriteKey(f, pubkey)
|
||||
if err2 := f.Close(); err == nil {
|
||||
err = err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// All good, allow the written files to remain.
|
||||
toDelete = nil
|
||||
|
||||
if privkeyFilename != "" {
|
||||
fmt.Printf("privkey written to %s\n", privkeyFilename)
|
||||
} else {
|
||||
fmt.Printf("privkey %x\n", privkey)
|
||||
}
|
||||
if pubkeyFilename != "" {
|
||||
fmt.Printf("pubkey written to %s\n", pubkeyFilename)
|
||||
} else {
|
||||
fmt.Printf("pubkey %x\n", pubkey)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readKeyFromFile(filename string) ([]byte, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return noise.ReadKey(f)
|
||||
}
|
||||
|
||||
func run(privkey, pubkey []byte, domain dns.Name, upstream net.Addr, udpAddr string) error {
|
||||
log.Printf("pubkey %x", pubkey)
|
||||
|
||||
@@ -542,23 +610,27 @@ func run(privkey, pubkey []byte, domain dns.Name, upstream net.Addr, udpAddr str
|
||||
|
||||
func main() {
|
||||
var genKey bool
|
||||
var privkeyFilename string
|
||||
var privkeyString string
|
||||
var pubkeyFilename string
|
||||
var udpAddr string
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), `Usage:
|
||||
%[1]s -gen-key
|
||||
%[1]s -udp ADDR -privkey PRIVKEY DOMAIN UPSTREAMADDR
|
||||
%[1]s -gen-key -privkey-file PRIVKEYFILE -pubkey-file PUBKEYFILE
|
||||
%[1]s -udp ADDR -privkey-file PRIVKEYFILE DOMAIN UPSTREAMADDR
|
||||
|
||||
Example:
|
||||
%[1]s -gen-key
|
||||
%[1]s -udp 127.0.0.1:5300 -privkey 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef server.key t.example.com 127.0.0.1:8000
|
||||
%[1]s -gen-key -privkey-file server.key -pubkey-file server.pub
|
||||
%[1]s -udp 127.0.0.1:5300 -privkey-file server.key t.example.com 127.0.0.1:8000
|
||||
|
||||
`, os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.BoolVar(&genKey, "gen-key", false, "generate a server keypair; print to stdout")
|
||||
flag.StringVar(&privkeyString, "privkey", "", fmt.Sprintf("server private key (%d hex digits)", hex.EncodedLen(noise.KeyLen)))
|
||||
flag.BoolVar(&genKey, "gen-key", false, "generate a server keypair; print to stdout or save to files")
|
||||
flag.StringVar(&privkeyString, "privkey", "", fmt.Sprintf("server private key (%d hex digits)", noise.KeyLen*2))
|
||||
flag.StringVar(&privkeyFilename, "privkey-file", "", "read server private key from file (with -gen-key, write to file)")
|
||||
flag.StringVar(&pubkeyFilename, "pubkey-file", "", "with -gen-key, write server public key to file")
|
||||
flag.StringVar(&udpAddr, "udp", "", "UDP address to listen on (required)")
|
||||
flag.Parse()
|
||||
|
||||
@@ -570,7 +642,7 @@ Example:
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := generateKeypair(); err != nil {
|
||||
if err := generateKeypair(privkeyFilename, pubkeyFilename); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "cannot generate keypair: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -591,13 +663,25 @@ Example:
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if pubkeyFilename != "" {
|
||||
fmt.Fprintf(os.Stderr, "-pubkey-file may only be used with -gen-key\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var privkey []byte
|
||||
if privkeyString != "" {
|
||||
if privkeyFilename != "" && privkeyString != "" {
|
||||
fmt.Fprintf(os.Stderr, "only one of -privkey and -privkey-file may be used\n")
|
||||
os.Exit(1)
|
||||
} else if privkeyFilename != "" {
|
||||
var err error
|
||||
privkey, err = hex.DecodeString(privkeyString)
|
||||
if err == nil && len(privkey) != noise.KeyLen {
|
||||
err = fmt.Errorf("length is %d, expected %d", len(privkey), noise.KeyLen)
|
||||
privkey, err = readKeyFromFile(privkeyFilename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "cannot read privkey from file: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if privkeyString != "" {
|
||||
var err error
|
||||
privkey, err = noise.DecodeKey(privkeyString)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "privkey format error: %v\n", err)
|
||||
os.Exit(1)
|
||||
@@ -605,7 +689,7 @@ Example:
|
||||
}
|
||||
if len(privkey) == 0 {
|
||||
log.Println("generating a temporary one-time keypair")
|
||||
log.Println("use the -privkey option for a persistent server keypair")
|
||||
log.Println("use the -privkey or -privkey-file option for a persistent server keypair")
|
||||
var err error
|
||||
privkey, _, err = noise.GenerateKeypair()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
@@ -205,3 +208,48 @@ func PubkeyFromPrivkey(privkey []byte) []byte {
|
||||
}
|
||||
return pair.Public
|
||||
}
|
||||
|
||||
// ReadKey reads a hex-encoded key from r. r must consist of a single line, with
|
||||
// or without a '\n' line terminator. The line must consist of KeyLen
|
||||
// hex-encoded bytes.
|
||||
func ReadKey(r io.Reader) ([]byte, error) {
|
||||
br := bufio.NewReader(io.LimitReader(r, 100))
|
||||
line, err := br.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
if err == nil {
|
||||
// Check that we're at EOF.
|
||||
_, err = br.ReadByte()
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
} else if err == nil {
|
||||
err = fmt.Errorf("file contains more than one line")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line = strings.TrimSuffix(line, "\n")
|
||||
return DecodeKey(line)
|
||||
}
|
||||
|
||||
// WriteKey writes the hex-encoded key in a single line to w.
|
||||
func WriteKey(w io.Writer, key []byte) error {
|
||||
_, err := fmt.Fprintf(w, "%x\n", key)
|
||||
return err
|
||||
}
|
||||
|
||||
// DecodeKey decodes a hex-encoded private or public key.
|
||||
func DecodeKey(s string) ([]byte, error) {
|
||||
key, err := hex.DecodeString(s)
|
||||
if err == nil && len(key) != KeyLen {
|
||||
err = fmt.Errorf("length is %d, expected %d", len(key), KeyLen)
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
||||
// DecodeKey decodes a hex-encoded private or public key.
|
||||
func EncodeKey(key []byte) string {
|
||||
return hex.EncodeToString(key)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadKey(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
input string
|
||||
output []byte
|
||||
}{
|
||||
{"", nil},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde", nil},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", []byte("\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef")},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n", []byte("\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef")},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0", nil},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\nX", nil},
|
||||
{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n", nil},
|
||||
{"\n0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", nil},
|
||||
{"X123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", nil},
|
||||
{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil},
|
||||
} {
|
||||
output, err := ReadKey(bytes.NewReader([]byte(test.input)))
|
||||
if test.output == nil {
|
||||
if err == nil {
|
||||
t.Errorf("%+q expected error", test.input)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("%+q returned error %v", test.input, err)
|
||||
} else if !bytes.Equal(output, test.output) {
|
||||
t.Errorf("%+q got %x, expected %x", test.input, output, test.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user