use DuckDNS for demo
This commit is contained in:
parent
5a68908e66
commit
776aabf879
|
@ -17,6 +17,7 @@ type Config struct {
|
||||||
Token string
|
Token string
|
||||||
Insecure bool
|
Insecure bool
|
||||||
Services RouteMap
|
Services RouteMap
|
||||||
|
TLSConfig *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run establishes a connection with the RVPN server specified in the config. If the first attempt
|
// Run establishes a connection with the RVPN server specified in the config. If the first attempt
|
||||||
|
@ -47,7 +48,7 @@ func Run(ctx context.Context, config *Config) error {
|
||||||
return fmt.Errorf(`service %s missing port for "*"`, name)
|
return fmt.Errorf(`service %s missing port for "*"`, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler := NewWsHandler(config.Services)
|
handler := NewWsHandler(config.Services, config.TLSConfig)
|
||||||
|
|
||||||
authenticated := false
|
authenticated := false
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
@ -28,15 +29,17 @@ type WsHandler struct {
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
dataChan chan *packer.Packer
|
dataChan chan *packer.Packer
|
||||||
|
tlsConfig *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWsHandler creates a new handler ready to be given a websocket connection. The services
|
// NewWsHandler creates a new handler ready to be given a websocket connection. The services
|
||||||
// argument specifies what port each service type should be directed to on the local interface.
|
// argument specifies what port each service type should be directed to on the local interface.
|
||||||
func NewWsHandler(services RouteMap) *WsHandler {
|
func NewWsHandler(services RouteMap, tlsConfig *tls.Config) *WsHandler {
|
||||||
h := new(WsHandler)
|
return &WsHandler{
|
||||||
h.servicePorts = services
|
servicePorts: services,
|
||||||
h.localConns = make(map[string]net.Conn)
|
localConns: make(map[string]net.Conn),
|
||||||
return h
|
tlsConfig: tlsConfig,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleConn handles all of the traffic on the provided websocket connection. The function
|
// HandleConn handles all of the traffic on the provided websocket connection. The function
|
||||||
|
@ -81,7 +84,7 @@ func (h *WsHandler) HandleConn(ctx context.Context, conn *websocket.Conn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *WsHandler) writeRemote(conn *websocket.Conn) {
|
func (h *WsHandler) writeRemote(wsconn *websocket.Conn) {
|
||||||
defer h.closeConnections()
|
defer h.closeConnections()
|
||||||
defer func() { h.dataChan = nil }()
|
defer func() { h.dataChan = nil }()
|
||||||
|
|
||||||
|
@ -94,13 +97,13 @@ func (h *WsHandler) writeRemote(conn *websocket.Conn) {
|
||||||
// all errors if it doesn't work.
|
// all errors if it doesn't work.
|
||||||
message := websocket.FormatCloseMessage(websocket.CloseGoingAway, "closing connection")
|
message := websocket.FormatCloseMessage(websocket.CloseGoingAway, "closing connection")
|
||||||
deadline := time.Now().Add(10 * time.Second)
|
deadline := time.Now().Add(10 * time.Second)
|
||||||
conn.WriteControl(websocket.CloseMessage, message, deadline)
|
wsconn.WriteControl(websocket.CloseMessage, message, deadline)
|
||||||
conn.Close()
|
wsconn.Close()
|
||||||
return
|
return
|
||||||
|
|
||||||
case p := <-h.dataChan:
|
case p := <-h.dataChan:
|
||||||
packed := p.PackV1()
|
packed := p.PackV1()
|
||||||
conn.WriteMessage(websocket.BinaryMessage, packed.Bytes())
|
wsconn.WriteMessage(websocket.BinaryMessage, packed.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +142,7 @@ func (h *WsHandler) getLocalConn(p *packer.Packer) net.Conn {
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostname string
|
var hostname string
|
||||||
|
//var terminate bool
|
||||||
if service == "http" {
|
if service == "http" {
|
||||||
if match := hostRegexp.FindSubmatch(p.Data.Data()); match != nil {
|
if match := hostRegexp.FindSubmatch(p.Data.Data()); match != nil {
|
||||||
hostname = strings.Split(string(match[1]), ":")[0]
|
hostname = strings.Split(string(match[1]), ":")[0]
|
||||||
|
@ -146,6 +150,7 @@ func (h *WsHandler) getLocalConn(p *packer.Packer) net.Conn {
|
||||||
}
|
}
|
||||||
} else if service == "https" {
|
} else if service == "https" {
|
||||||
hostname, _ = sni.GetHostname(p.Data.Data())
|
hostname, _ = sni.GetHostname(p.Data.Data())
|
||||||
|
//terminate = true
|
||||||
} else {
|
} else {
|
||||||
hostname = "*"
|
hostname = "*"
|
||||||
}
|
}
|
||||||
|
@ -176,7 +181,14 @@ func (h *WsHandler) getLocalConn(p *packer.Packer) net.Conn {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
h.localConns[key] = conn
|
rconn := conn
|
||||||
|
/*
|
||||||
|
if terminate {
|
||||||
|
rconn = tls.Server(conn, h.tlsConfig)
|
||||||
|
//rconn = tls.Client(conn, h.tlsConfig)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
h.localConns[key] = rconn
|
||||||
loginfo.Printf("new client %q for %s:%d (%d clients)\n", key, hostname, term.Port, len(h.localConns))
|
loginfo.Printf("new client %q for %s:%d (%d clients)\n", key, hostname, term.Port, len(h.localConns))
|
||||||
go h.readLocal(key, &p.Header)
|
go h.readLocal(key, &p.Header)
|
||||||
return conn
|
return conn
|
||||||
|
@ -190,6 +202,7 @@ func (h *WsHandler) writeLocal(p *packer.Packer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Service() == "error" || p.Service() == "end" {
|
if p.Service() == "error" || p.Service() == "end" {
|
||||||
|
// TODO XXX where's the opposite of this?
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
@ -12,7 +13,9 @@ import (
|
||||||
|
|
||||||
"git.coolaj86.com/coolaj86/go-telebitd/client"
|
"git.coolaj86.com/coolaj86/go-telebitd/client"
|
||||||
|
|
||||||
|
"github.com/caddyserver/certmagic"
|
||||||
jwt "github.com/dgrijalva/jwt-go"
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
|
"github.com/go-acme/lego/v3/providers/dns/duckdns"
|
||||||
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
)
|
)
|
||||||
|
@ -264,17 +267,99 @@ func main() {
|
||||||
ctx, quit := context.WithCancel(context.Background())
|
ctx, quit := context.WithCancel(context.Background())
|
||||||
defer quit()
|
defer quit()
|
||||||
|
|
||||||
|
acmeStorage := "./acme.d/"
|
||||||
|
acmeEmail := ""
|
||||||
|
acmeStaging := false
|
||||||
|
//
|
||||||
|
// CertMagic is Greenlock for Go
|
||||||
|
//
|
||||||
|
directory := certmagic.LetsEncryptProductionCA
|
||||||
|
if acmeStaging {
|
||||||
|
directory = certmagic.LetsEncryptStagingCA
|
||||||
|
}
|
||||||
|
magic, err := newCertMagic(directory, acmeEmail, &certmagic.FileStorage{Path: acmeStorage})
|
||||||
|
if nil != err {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to initialize certificate management (discovery url? local folder perms?): %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
|
return magic.GetCertificate(hello)
|
||||||
|
/*
|
||||||
|
if false {
|
||||||
|
_, _ = magic.GetCertificate(hello)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// 1. call out to greenlock for validation
|
||||||
|
// 2. push challenges through http channel
|
||||||
|
// 3. receive certificates (or don't)
|
||||||
|
certbundleT, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||||
|
certbundle := &certbundleT
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return certbundle, nil
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
config := client.Config{
|
config := client.Config{
|
||||||
Insecure: insecure,
|
Insecure: insecure,
|
||||||
Server: relay,
|
Server: relay,
|
||||||
Services: servicePorts,
|
Services: servicePorts,
|
||||||
Token: token,
|
Token: token,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("config:\n%#v\n", config)
|
fmt.Printf("config:\n%#v\n", config)
|
||||||
log.Fatal(client.Run(ctx, &config))
|
log.Fatal(client.Run(ctx, &config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newCertMagic(directory string, email string, storage certmagic.Storage) (*certmagic.Config, error) {
|
||||||
|
cache := certmagic.NewCache(certmagic.CacheOptions{
|
||||||
|
GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
|
||||||
|
// do whatever you need to do to get the right
|
||||||
|
// configuration for this certificate; keep in
|
||||||
|
// mind that this config value is used as a
|
||||||
|
// template, and will be completed with any
|
||||||
|
// defaults that are set in the Default config
|
||||||
|
return &certmagic.Config{}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
provider, err := newDuckDNSProvider(os.Getenv("DUCKDNS_TOKEN"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
magic := certmagic.New(cache, certmagic.Config{
|
||||||
|
Storage: storage,
|
||||||
|
OnDemand: &certmagic.OnDemandConfig{
|
||||||
|
DecisionFunc: func(name string) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Ummm... just a little confusing
|
||||||
|
magic.Issuer = certmagic.NewACMEManager(magic, certmagic.ACMEManager{
|
||||||
|
DNSProvider: provider,
|
||||||
|
CA: directory,
|
||||||
|
Email: email,
|
||||||
|
Agreed: true,
|
||||||
|
DisableHTTPChallenge: true,
|
||||||
|
DisableTLSALPNChallenge: true,
|
||||||
|
// plus any other customizations you need
|
||||||
|
})
|
||||||
|
return magic, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDuckDNSProvider is for the sake of demoing the tunnel
|
||||||
|
func newDuckDNSProvider(token string) (*duckdns.DNSProvider, error) {
|
||||||
|
config := duckdns.NewDefaultConfig()
|
||||||
|
config.Token = token
|
||||||
|
return duckdns.NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
func stringSlice(csv string) []string {
|
func stringSlice(csv string) []string {
|
||||||
list := []string{}
|
list := []string{}
|
||||||
for _, item := range strings.Split(csv, ", ") {
|
for _, item := range strings.Split(csv, ", ") {
|
||||||
|
|
|
@ -332,6 +332,7 @@ func (mx *MPlexy) routeToTarget(ctx context.Context, extConn *tunnel.WedgeConn,
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
fmt.Println("xxyyzz buffer")
|
||||||
buffer, err := extConn.PeekAll()
|
buffer, err := extConn.PeekAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loginfo.Println("unable to peekAll", err)
|
loginfo.Println("unable to peekAll", err)
|
||||||
|
|
Loading…
Reference in New Issue