8 Commits

Author SHA1 Message Date
718fc3922e Remove year from license 2023-02-11 00:54:51 +01:00
db6baaf7dc Upgrade golang.org/x/crypto to v0.6.0 2023-02-11 00:53:15 +01:00
f5846dcd12 Add clarification 2023-02-11 00:27:40 +01:00
f8a9ad40b3 Only test received headers when it is required, improve syntax 2023-02-11 00:27:19 +01:00
23bf0ff34c Improve log formatting, syntax and order. Require TLS 1.2 when acting as a server 2023-02-11 00:26:46 +01:00
c28d6e3675 Hard-code testing target host 2023-02-11 00:15:48 +01:00
5907a46658 Fix path 2023-02-11 00:14:45 +01:00
37ede71813 Improve formatting 2023-02-11 00:14:33 +01:00
8 changed files with 36 additions and 30 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
./server
server

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 marco@sdf.org
Copyright (c) marco@sdf.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -4,7 +4,6 @@ GOOS := plan9
GOARCH := amd64
test:
SDF_PROXY_ALLOWED_HOSTS=teapot-dummy-target.example.com \
go test -v
build: test
@@ -13,3 +12,4 @@ build: test
deploy: build
rsync -avz server iceland.sdf.org:html/pub/

View File

@@ -3,7 +3,7 @@
An http server to which one or more domains can be pointed to.
Incoming requests will be proxied to an arbitrary target http server, like Amazon S3, Blogger.com or one of the many options available at sdf.org.
The main idea is to have a server which requires no configuration, handles TLS and can run on mostly any host on the internet with an IP address in one's possession.
The main goal is to serve content for a domain via a server which requires no configuration, handles TLS and can run on mostly any host on the internet with an IP address in one's possession.
Obviously this solution is an end in itself and there already is [Caddy](https://caddyserver.com/).
Thanks to [golang.org/x/crypto/acme/autocert](https://pkg.go.dev/golang.org/x/crypto/acme/autocert), the server will automatically attempt to get a certificate from Let's Encrypt via the [HTTP-01 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) to enable TLS.
@@ -23,6 +23,7 @@ $ ./server
```
## Future Ideas
- Support for rewriting URL paths
- Configuration option to keep keys and TLS certificates in memory only
- Support for [cgi-bin](https://pkg.go.dev/net/http/cgi) and/or [FastCGI](https://pkg.go.dev/net/http/fcgi)

8
go.mod
View File

@@ -2,11 +2,9 @@ module server
go 1.19
require (
golang.org/x/crypto v0.4.0
)
require golang.org/x/crypto v0.6.0
require (
golang.org/x/net v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
golang.org/x/net v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
)

14
go.sum
View File

@@ -1,8 +1,6 @@
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=

View File

@@ -34,6 +34,9 @@ var (
func init() {
setMyIpAndPtrAddr(&myIp, &myPtrAddr)
if len(myPtrAddr) > 0 {
tlsCertManager.HostPolicy = autocert.HostWhitelist(append(allowedHosts, myPtrAddr)...)
}
}
// setMyIpAndPtrAddr attempts to set myIp and myPtrAddr
@@ -75,7 +78,10 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
server.Addr = addr
server.serveTls = serveTls
if server.serveTls {
server.TLSConfig = &tls.Config{GetCertificate: tlsCertManager.GetCertificate}
server.TLSConfig = &tls.Config{
GetCertificate: tlsCertManager.GetCertificate,
MinVersion: tls.VersionTLS12,
}
}
proxy := new(httputil.ReverseProxy)
@@ -91,7 +97,7 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
}
mux := http.NewServeMux()
// Hostnames specified in the variable allowedHosts for which the reverse proxy should direct requests to the target host
// Hostnames for which the reverse proxy should direct requests to the target host
for _, host := range allowedHosts {
mux.Handle(host+"/", proxy)
mux.Handle(host+"/.well-known/acme-challenge/", tlsCertManager.HTTPHandler(nil))
@@ -122,15 +128,17 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
// listenAndServe will call ListenAndServe or ListenAndServeTLS on httpReverseProxy to handle requests on incoming connections
func (t *httpReverseProxy) listenAndServe() {
fmt.Printf("Listening on %s\n", t.Addr)
var err error
fmt.Printf("Listening on %s\n", t.Addr)
if t.serveTls {
err = t.ListenAndServeTLS("", "")
} else {
err = t.ListenAndServe()
}
if err != nil {
log.Fatalf("listenAndServe, Addr: %s, serveTls: %s, error: %s", t.Addr, strconv.FormatBool(t.serveTls), err)
log.Fatalf("listenAndServe, Addr: %s, serveTls: %s, error: %v", t.Addr, strconv.FormatBool(t.serveTls), err)
}
}
@@ -139,10 +147,6 @@ func main() {
log.Fatalf("Invalid Let's Encrypt account email: %v\n", err)
}
if len(myPtrAddr) > 0 {
tlsCertManager.HostPolicy = autocert.HostWhitelist(append(allowedHosts, myPtrAddr)...)
}
fmt.Print("Allowed hosts: ")
fmt.Println(allowedHosts)
fmt.Print("PTR record (if any): ")

View File

@@ -7,6 +7,10 @@ import (
"testing"
)
func init() {
allowedHosts = []string{"teapot-dummy-target.example.com"}
}
func TestHttpReverseProxy(t *testing.T) {
var header map[string][]string
@@ -56,20 +60,21 @@ func TestHttpReverseProxy(t *testing.T) {
response := httptest.NewRecorder()
reverseProxy.Handler.ServeHTTP(response, request)
got := header
gotHeader := header
header = nil
assertStatus(t, response.Code, test.wantResponseCode)
assertHeader(t, got, "X-Forwarded-Host", test.wantXForwardedHostHeader)
if len(test.wantXForwardedHostHeader) > 0 {
assertHeader(t, gotHeader, "X-Forwarded-Host", test.wantXForwardedHostHeader)
}
})
}
}
func assertHeader(t *testing.T, gotHeader map[string][]string, headerName, want string) {
t.Helper()
got := ""
lookup, ok := gotHeader[headerName]
if ok {
var got string
if lookup, ok := gotHeader[headerName]; ok {
got = lookup[0]
}
if got != want {