diff --git a/server/server.go b/server/server.go index 821268e..bf28864 100644 --- a/server/server.go +++ b/server/server.go @@ -1,27 +1,15 @@ package server import ( - "crypto/rsa" "crypto/tls" - "crypto/x509" - "encoding/pem" "errors" - "log" "net" "net/http" "net/http/httputil" - "net/rpc" - "path/filepath" - "strings" "time" "git.xeserv.us/xena/route/database" - "git.xeserv.us/xena/route/lib/elfs" "git.xeserv.us/xena/route/lib/tun2" - "git.xeserv.us/xena/route/routerpc" - "github.com/Xe/uuid" - "github.com/Yawning/bulb" - "github.com/brandur/simplebox" "github.com/mtneug/pkg/ulid" "golang.org/x/crypto/acme/autocert" ) @@ -34,114 +22,81 @@ const ( // Server is the main server type type Server struct { cfg *Config + db database.Storage + ts *tun2.Server - db *database.DB - - rpcS *rpc.Server - rpcAddr string - - ts *tun2.Server - - CertCache *database.CertCache + autocert.Manager } // Config configures Server type Config struct { - RethinkDBHost string - RethinkDBDatabase string + BoltDBPath string `env:"BOLTDB_PATH,required"` - TorDataDir string - TorHashedPassword string - TorPassword string + WebAddr string `env:"WEB_ADDR,required"` + SSLAddr string `env:"SSL_ADDR,required"` + BackendTCPAddr string `env:"BACKEND_TCP_ADDR,required"` + BackendKCPAddr string `env:"BACKEND_KCP_ADDR,required"` + GRPCAddr string `env:"GRPC_ADDR,required"` - WebPort string - SSLPort string - BackendPort string - KCPPort string - - DomainSuffix string - ACMEEmail string + DomainSuffix string `env:"DOMAIN_SUFFIX,required"` + ACMEEmail string `env:"ACME_EMAIL,required"` CertKey *[32]byte } // New creates a new Server func New(cfg Config) (*Server, error) { - db, err := database.New(cfg.RethinkDBHost, cfg.RethinkDBDatabase) - if err != nil { - return nil, err - } - - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return nil, err - } - - rpcs := rpc.NewServer() - - s := &Server{ - cfg: &cfg, - - db: db, - - rpcS: rpcs, - rpcAddr: l.Addr().String(), - - CertCache: &database.CertCache{ - DB: db, - }, - } - - m := autocert.Manager{ - Prompt: autocert.AcceptTOS, - Cache: s.CertCache, - HostPolicy: nil, - Email: cfg.ACMEEmail, - } - if cfg.CertKey == nil { return nil, errors.New("no cert decryption key, can't do anything") } - s.CertCache.SimpleBox = simplebox.NewFromSecretKey(cfg.CertKey) + db, err := database.NewBoltStorage(cfg.BoltDBPath, cfg.CertKey) + if err != nil { + return nil, err + } + + m := autocert.Manager{ + Prompt: autocert.AcceptTOS, + Cache: database.Cache(db), + HostPolicy: nil, + Email: cfg.ACMEEmail, + } tcfg := &tun2.ServerConfig{ - TCPAddr: cfg.BackendPort, - KCPAddr: cfg.KCPPort, + TCPAddr: cfg.BackendTCPAddr, + KCPAddr: cfg.BackendKCPAddr, TLSConfig: &tls.Config{ GetCertificate: m.GetCertificate, }, - Storage: s.db, + Storage: &storageWrapper{ + Storage: db, + }, } ts, err := tun2.NewServer(tcfg) if err != nil { return nil, err } + s := &Server{ + cfg: &cfg, + db: db, + ts: ts, + + Manager: m, + } + s.ts = ts go ts.ListenAndServe() - rpcs.RegisterName("Urls", &RPCServer{Server: s}) - go rpcs.Accept(l) - log.Println("rpc at tcp://" + l.Addr().String()) - - err = s.restore() - if err != nil { - return nil, err - } - return s, nil } -func (s *Server) onionPath(name string) string { - return filepath.Join(s.cfg.TorDataDir, name) -} - -func (s *Server) Director(r *http.Request) {} - -func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { +// Director removes headers that are typically stripped off at request ingress. +func (s *Server) Director(r *http.Request) { r.Header.Del("X-Forwarded-For") r.Header.Del("X-Client-Ip") +} +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Header.Get("X-Tor2web") != "" { http.Error(w, "tor2web proxy use is not allowed", 400) return @@ -162,15 +117,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // http://www.gnuterrypratchett.com/ w.Header().Set("X-Clacks-Overhead", "GNU Ashlynn") - if strings.HasSuffix(r.Host, ".onion") { - r.Header.Add("DNT", "1") - } - - if r.RequestURI == rpc.DefaultRPCPath { - s.rpcS.ServeHTTP(w, r) - return - } - rp := &httputil.ReverseProxy{ Director: s.Director, Transport: s.ts, @@ -179,68 +125,3 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { rp.ServeHTTP(w, r) } - -func (s *Server) restore() error { - rts, err := s.db.GetAllRoutes() - if err != nil { - return err - } - - for _, rt := range rts { - var block *pem.Block - - block, _ = pem.Decode([]byte(rt.OnionKey)) - _, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return err - } - - log.Printf("added: %s (%s)", rt.Hostname, rt.OnionHostname) - } - - return nil -} - -func genPortSpec(incoming uint16, outgoing string) bulb.OnionPortSpec { - return bulb.OnionPortSpec{ - VirtPort: incoming, - Target: outgoing, - } -} - -// RPCServer is a Server wrapped to work inside the context of net/rpc -type RPCServer struct { - *Server -} - -// AddHost adds a host to the server. -func (rs *RPCServer) AddHost(req routerpc.AddHostRequest, resp *routerpc.AddHostResponse) error { - if req.APIKey != "hunter2" { - return errors.New("invalid api key") - } - - token := uuid.New() - - var pKey *rsa.PrivateKey - if kk, ok := req.PrivKey.(*rsa.PrivateKey); ok { - pKey = kk - } else { - return errors.New("there must be a 1024 bit RSA private key") - } - - resp.Token = token - resp.PrivKey = pKey - - if req.Hostname != "" { - resp.Hostname = req.Hostname - } else { - resp.Hostname = elfs.MakeName() + rs.cfg.DomainSuffix - } - - err := rs.db.SaveRoute(resp) - if err != nil { - return err - } - - return nil -} diff --git a/server/storage.go b/server/storage.go new file mode 100644 index 0000000..aa90123 --- /dev/null +++ b/server/storage.go @@ -0,0 +1,34 @@ +package server + +import ( + "context" + + "git.xeserv.us/xena/route/database" + "git.xeserv.us/xena/route/lib/tun2" +) + +type storageWrapper struct { + database.Storage +} + +var ( + _ tun2.Storage = &storageWrapper{} +) + +func (s *storageWrapper) HasToken(token string) (string, []string, error) { + t, err := s.Storage.GetToken(context.Background(), token) + if err != nil { + return "", nil, err + } + + return t.Owner, t.Scopes, nil +} + +func (s *storageWrapper) HasRoute(domain string) (string, error) { + r, err := s.Storage.GetRoute(context.Background(), domain) + if err != nil { + return "", err + } + + return r.Creator, nil +}