use actual virtual hosts
This commit is contained in:
parent
694693e93c
commit
58d983891e
@ -12,6 +12,7 @@ Configuration is in config/yaml in one of the above directories. See the sample
|
||||
but a standard file looks like such:
|
||||
|
||||
---
|
||||
port: 1965
|
||||
active_capsules:
|
||||
- localhost
|
||||
localhost:
|
||||
@ -22,6 +23,9 @@ but a standard file looks like such:
|
||||
KeyFile: "localhost.key"
|
||||
CertFile: "localhost.crt"
|
||||
|
||||
Where each "active_capsule" is a virtual Gemini capsule. SecretShop supports virtual Gemini capsules all listening on port 1965
|
||||
as well as multiple Gopher servers runnning (though not virtual Gopher hosts due to protocol limitations)
|
||||
|
||||
Please note that CGIDir currently not used (waiting on spec clarification).
|
||||
|
||||
## Building
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
port: 1965
|
||||
active_capsules:
|
||||
- localhost
|
||||
- localhost2
|
||||
@ -6,14 +7,12 @@ active_holes:
|
||||
- localhost3
|
||||
localhost:
|
||||
Hostname: "localhost"
|
||||
Port: "1965"
|
||||
RootDir: "/var/gemini"
|
||||
CGIDir: "/var/gemini/cgi"
|
||||
KeyFile: "localhost.key"
|
||||
CertFile: "localhost.crt"
|
||||
localhost2:
|
||||
Hostname: "gemini.foo.bar"
|
||||
Port: "1966"
|
||||
RootDir: "/var/gemini2"
|
||||
CGIDir: "/var/gemini2/cgi"
|
||||
KeyFile: "localhost2.key"
|
||||
|
14
main.go
14
main.go
@ -21,6 +21,7 @@ func main() {
|
||||
//Load configs
|
||||
active_capsules := viper.GetStringSlice("active_capsules")
|
||||
active_holes := viper.GetStringSlice("active_holes")
|
||||
port := viper.GetString("port")
|
||||
capsule_list := make([]GeminiConfig, len(active_capsules))
|
||||
hole_list := make([]GopherConfig, len(active_holes))
|
||||
for i, c := range active_capsules {
|
||||
@ -38,14 +39,14 @@ func main() {
|
||||
log.Printf("%v capsules loaded, %v gopherholes loaded", len(capsule_list), len(hole_list))
|
||||
// Intialize servers
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(len(capsule_list) + len(hole_list))
|
||||
for i, c := range capsule_list {
|
||||
log.Printf("Starting capsule %v %v", i, c.Hostname)
|
||||
wg.Add(1 + len(hole_list))
|
||||
|
||||
log.Printf("Starting gemini capsule")
|
||||
go func(c interface{}) {
|
||||
log.Fatal(ListenAndServeTLS(c.(GeminiConfig)))
|
||||
log.Fatal(ListenAndServeTLS(port, c.([]GeminiConfig)))
|
||||
wg.Done()
|
||||
}(c)
|
||||
}
|
||||
}(capsule_list)
|
||||
|
||||
for i, h := range hole_list {
|
||||
log.Printf("Starting gopherhole %v %v", i, h.Hostname)
|
||||
go func(h interface{}) {
|
||||
@ -56,6 +57,7 @@ func main() {
|
||||
wg.Done()
|
||||
}(h)
|
||||
}
|
||||
|
||||
log.Println("Done bringing up capsules and gopherholes")
|
||||
log.Println("Ho ho! You found me!")
|
||||
wg.Wait()
|
||||
|
3
proto.go
3
proto.go
@ -40,7 +40,6 @@ type Response struct {
|
||||
|
||||
type GeminiConfig struct {
|
||||
Hostname string
|
||||
Port string
|
||||
KeyFile string
|
||||
CertFile string
|
||||
RootDir string
|
||||
@ -48,5 +47,5 @@ type GeminiConfig struct {
|
||||
}
|
||||
|
||||
func (c *GeminiConfig) String() string {
|
||||
return fmt.Sprintf("Gemini Config: %v:%v Files:%v CGI:%v", c.Hostname, c.Port, c.RootDir, c.CGIDir)
|
||||
return fmt.Sprintf("Gemini Config: %v Files:%v CGI:%v", c.Hostname, c.RootDir, c.CGIDir)
|
||||
}
|
||||
|
38
server.go
38
server.go
@ -41,8 +41,7 @@ var (
|
||||
type Server struct {
|
||||
Addr string // TCP address to listen on, ":gemini" if empty
|
||||
|
||||
Hostname string // FQDN Hostname to reach this server on
|
||||
ServerRoot string //Root folder for gemini files
|
||||
HostnameToRoot map[string]string //FQDN hostname to root folder
|
||||
}
|
||||
|
||||
type conn struct {
|
||||
@ -59,19 +58,32 @@ func (s *Server) newConn(rwc net.Conn) *conn {
|
||||
}
|
||||
return c
|
||||
}
|
||||
func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
||||
|
||||
func ListenAndServeTLS(port string, cps []GeminiConfig) error {
|
||||
server := &Server{Addr: ":" + port, HostnameToRoot: make(map[string]string)}
|
||||
for _, c := range cps {
|
||||
server.HostnameToRoot[c.Hostname] = c.RootDir
|
||||
}
|
||||
return server.ListenAndServeTLS(cps)
|
||||
}
|
||||
|
||||
func (s *Server) ListenAndServeTLS(configs []GeminiConfig) error {
|
||||
addr := s.Addr
|
||||
mime.AddExtensionType(".gmi", "text/gemini")
|
||||
mime.AddExtensionType(".gemini", "text/gemini")
|
||||
if addr == "" {
|
||||
addr = ":1965"
|
||||
}
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
certs := make([]tls.Certificate, len(configs))
|
||||
for i, c := range configs {
|
||||
cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile)
|
||||
if err != nil {
|
||||
log.Fatalf("server: loadkeys: %s", err)
|
||||
log.Fatalf("Error loading certs: %s", err)
|
||||
}
|
||||
config := tls.Config{Certificates: []tls.Certificate{cert}}
|
||||
certs[i] = cert
|
||||
}
|
||||
|
||||
config := tls.Config{Certificates: certs}
|
||||
config.Rand = rand.Reader
|
||||
|
||||
ln, err := tls.Listen("tcp", addr, &config)
|
||||
@ -81,10 +93,6 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
||||
|
||||
return s.Serve(ln)
|
||||
}
|
||||
func ListenAndServeTLS(cp GeminiConfig) error {
|
||||
server := &Server{Addr: ":" + cp.Port, ServerRoot: cp.RootDir, Hostname: cp.Hostname}
|
||||
return server.ListenAndServeTLS(cp.CertFile, cp.KeyFile)
|
||||
}
|
||||
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
defer l.Close()
|
||||
@ -135,7 +143,7 @@ func (c *conn) serve(ctx context.Context) {
|
||||
res = c.server.ParseRequest(req)
|
||||
}
|
||||
c.sendResponse(res)
|
||||
log.Printf("%v: %v requested %v; responded with %v %v", c.server.Hostname, c.C.RemoteAddr(), req, res.Status, res.Meta)
|
||||
log.Printf("%v requested %v; responded with %v %v", c.C.RemoteAddr(), req, res.Status, res.Meta)
|
||||
c.C.Close()
|
||||
}
|
||||
|
||||
@ -154,14 +162,14 @@ func (s *Server) ParseRequest(req string) Response {
|
||||
}
|
||||
if u.Host == "" {
|
||||
return Response{STATUS_BAD_REQUEST, "Need to specify a host", ""}
|
||||
} else if u.Hostname() != s.Hostname {
|
||||
} else if s.HostnameToRoot[u.Hostname()] == "" {
|
||||
return Response{STATUS_PROXY_REQUEST_REFUSED, "Proxying by Hostname not currently supported", ""}
|
||||
}
|
||||
if strings.Contains(u.Path, "..") {
|
||||
return Response{STATUS_PERMANENT_FAILURE, "Dots in path, assuming bad faith.", ""}
|
||||
}
|
||||
|
||||
selector := s.ServerRoot + u.Path
|
||||
selector := s.HostnameToRoot[u.Hostname()] + u.Path
|
||||
fi, err := os.Stat(selector)
|
||||
switch {
|
||||
case err != nil:
|
||||
@ -175,7 +183,7 @@ func (s *Server) ParseRequest(req string) Response {
|
||||
if strings.HasSuffix(u.Path, "/") {
|
||||
return generateDirectory(selector)
|
||||
} else {
|
||||
return Response{STATUS_REDIRECT_PERMANENT, "gemini://" + s.Hostname + u.Path + "/", ""}
|
||||
return Response{STATUS_REDIRECT_PERMANENT, "gemini://" + u.Hostname() + u.Path + "/", ""}
|
||||
}
|
||||
default:
|
||||
// it's a file
|
||||
|
Loading…
Reference in New Issue
Block a user