aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-03-23 16:05:38 +0100
committerDimitri Sokolyuk <demon@dim13.org>2016-03-23 16:05:38 +0100
commit62fa5c31ba39ebf968f98a7ee46525f14c0ea97c (patch)
treead67f424dec70a538635542127e96bb95ffe801a
parent955e9ff0855feeb94d8e83c97362c172ced2c663 (diff)
Rewrite into config-les setup
-rw-r--r--.gitignore2
-rw-r--r--Dockerfile2
-rw-r--r--certs/goxy.yml11
-rw-r--r--data/.gitkeep0
-rw-r--r--gob.go24
-rw-r--r--goxyctl/main.go68
-rw-r--r--main.go126
-rw-r--r--rpc.go36
8 files changed, 189 insertions, 80 deletions
diff --git a/.gitignore b/.gitignore
index 9127b54..a1fb9c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-goxy
*.swp
+*.gob
diff --git a/Dockerfile b/Dockerfile
index caef533..5b1a2b1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,4 +3,4 @@ RUN go get dim13.org/goxy
VOLUME /go/src/dim13.org/goxy/certs
WORKDIR /go/src/dim13.org/goxy
ENTRYPOINT /go/bin/goxy
-EXPOSE 80 443
+EXPOSE 80 443 8080
diff --git a/certs/goxy.yml b/certs/goxy.yml
deleted file mode 100644
index a24e58d..0000000
--- a/certs/goxy.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-
-wahlplan.goxy.moccu:
- upstream: http://wahlplan:8080
- certfile: certs/wahlplan/cert.pem
- keyfile: certs/wahlplan/key.pem
-
-gowiki.goxy.moccu:
- upstream: http://gowiki
- certfile: certs/gowiki/cert.pem
- keyfile: certs/gowiki/key.pem
diff --git a/data/.gitkeep b/data/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/data/.gitkeep
diff --git a/gob.go b/gob.go
new file mode 100644
index 0000000..3932a65
--- /dev/null
+++ b/gob.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ "encoding/gob"
+ "os"
+)
+
+func (r Route) Save(fname string) error {
+ fd, err := os.Create(fname)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+ return gob.NewEncoder(fd).Encode(r)
+}
+
+func (r *Route) Load(fname string) error {
+ fd, err := os.Open(fname)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+ return gob.NewDecoder(fd).Decode(r)
+}
diff --git a/goxyctl/main.go b/goxyctl/main.go
new file mode 100644
index 0000000..824f892
--- /dev/null
+++ b/goxyctl/main.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "crypto/rsa"
+ "crypto/tls"
+ "encoding/gob"
+ "flag"
+ "log"
+ "net/rpc"
+)
+
+var (
+ rpcserver = flag.String("server", ":http-alt", "RPC Server port")
+ servername = flag.String("servername", "", "from")
+ upstream = flag.String("upstream", "", "to")
+ keyfile = flag.String("keyfile", "", "TLS Key file")
+ crtfile = flag.String("crtfile", "", "TLC Crt file")
+ remove = flag.Bool("remove", false, "remove entry")
+)
+
+type Entry struct {
+ ServerName string
+ Upstream string
+ Cert *tls.Certificate
+}
+
+func init() {
+ gob.Register(rsa.PrivateKey{})
+}
+
+func main() {
+ flag.Parse()
+
+ e := Entry{
+ ServerName: *servername,
+ Upstream: *upstream,
+ }
+
+ if *keyfile != "" && *crtfile != "" {
+ crt, err := tls.LoadX509KeyPair(*crtfile, *keyfile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ e.Cert = &crt
+ }
+
+ client, err := rpc.DialHTTP("tcp", *rpcserver)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer client.Close()
+
+ switch {
+ case e.ServerName != "" && e.Upstream != "":
+ err = client.Call("GoXY.Add", e, nil)
+ case e.ServerName != "" && *remove:
+ err = client.Call("GoXY.Del", e, nil)
+ default:
+ var r map[string]Entry
+ err = client.Call("GoXY.List", struct{}{}, &r)
+ for k, v := range r {
+ log.Println(k, v)
+ }
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/main.go b/main.go
index 946603f..e54cd96 100644
--- a/main.go
+++ b/main.go
@@ -4,107 +4,99 @@ import (
"crypto/tls"
"errors"
"flag"
- "io/ioutil"
"log"
"net/http"
"net/http/httputil"
+ "net/rpc"
"net/url"
- "sync"
-
- "gopkg.in/yaml.v2"
)
var (
config = flag.String("conf", "certs/goxy.yml", "configuration file")
- listen = flag.String("listen", ":http", "HTTP")
- listenTLS = flag.String("listentls", ":https", "TLS")
+ listen = flag.String("listen", ":http", "HTTP port")
+ listenTLS = flag.String("listentls", ":https", "TLS port")
+ listenRPC = flag.String("listenrpc", ":http-alt", "RPC port")
+ data = flag.String("data", "data/goxy.gob", "persistent storage file")
+ route = make(Route)
+ mux = http.NewServeMux()
)
-type Config map[string]Route
+type Route map[string]Entry
-type Route struct {
- CertFile string
- KeyFile string
- Upstream string
- cert *tls.Certificate
+type Entry struct {
+ ServerName string
+ Upstream string
+ Cert *tls.Certificate
}
-func (c Config) SNI(h *tls.ClientHelloInfo) (*tls.Certificate, error) {
- if r, ok := c[h.ServerName]; ok && r.cert != nil {
- return r.cert, nil
+func (r Route) SNI(h *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ if e, ok := r[h.ServerName]; ok && e.Cert != nil {
+ return e.Cert, nil
}
return nil, errors.New("no cert for " + h.ServerName)
}
-func (r *Route) LoadCert() error {
- if r.CertFile == "" && r.KeyFile == "" {
- return nil
+func (r Route) Restore() {
+ *mux = *http.NewServeMux()
+ for _, e := range route {
+ e.NewHandle()
}
- cert, err := tls.LoadX509KeyPair(r.CertFile, r.KeyFile)
+}
+
+func (e Entry) NewHandle() error {
+ log.Println("New handle", e)
+ up, err := url.Parse(e.Upstream)
if err != nil {
return err
}
- r.cert = &cert
+ mux.Handle(e.ServerName+"/", httputil.NewSingleHostReverseProxy(up))
return nil
}
-func (r Route) String() string {
- if r.cert != nil {
- return r.Upstream + " with TLS"
+func (e Entry) String() string {
+ if e.Cert != nil {
+ return e.ServerName + " -> " + e.Upstream + " with TLS"
} else {
- return r.Upstream
+ return e.ServerName + " -> " + e.Upstream
}
}
-func LoadConfig(fname string) (Config, error) {
- conf, err := ioutil.ReadFile(fname)
- if err != nil {
- return Config{}, err
+func StartHTTP(listen string) {
+ log.Println("listen", listen, "(HTTP)")
+ s := http.Server{
+ Addr: listen,
+ Handler: mux,
+ }
+ log.Fatal(s.ListenAndServe())
+}
+
+func StartTLS(listen string) {
+ log.Println("listen", listen, "(TLS)")
+ s := http.Server{
+ Addr: listen,
+ Handler: mux,
+ TLSConfig: &tls.Config{GetCertificate: route.SNI},
}
- var c Config
- return c, yaml.Unmarshal(conf, &c)
+ log.Fatal(s.ListenAndServeTLS("", ""))
+}
+
+func StartRPC(listen string) {
+ log.Println("listen", listen, "(RPC)")
+ rpc.HandleHTTP()
+ log.Fatal(http.ListenAndServe(listen, nil))
}
func main() {
flag.Parse()
- c, err := LoadConfig(*config)
- if err != nil {
- log.Fatal(err)
- }
- for k, v := range c {
- if err := v.LoadCert(); err != nil {
- log.Println("load", err)
- continue
- }
- c[k] = v
- up, err := url.Parse(v.Upstream)
- if err != nil {
- log.Println("upstream", err)
- continue
- }
- log.Println("map", k, "to", v)
- http.Handle(k+"/", httputil.NewSingleHostReverseProxy(up))
+ if err := route.Load(*data); err != nil {
+ log.Println(err)
}
+ route.Restore()
+
+ go StartHTTP(*listen)
+ go StartTLS(*listenTLS)
+ go StartRPC(*listenRPC)
- var wg sync.WaitGroup
- wg.Add(2)
- go func() {
- defer wg.Done()
- log.Println("listen", *listenTLS)
- s := http.Server{
- Addr: *listenTLS,
- TLSConfig: &tls.Config{GetCertificate: c.SNI},
- }
- log.Fatal(s.ListenAndServeTLS("", ""))
- }()
- go func() {
- defer wg.Done()
- log.Println("listen", *listen)
- s := http.Server{
- Addr: *listen,
- }
- log.Fatal(s.ListenAndServe())
- }()
- wg.Wait()
+ select {}
}
diff --git a/rpc.go b/rpc.go
new file mode 100644
index 0000000..589ca92
--- /dev/null
+++ b/rpc.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "crypto/rsa"
+ "encoding/gob"
+ "log"
+ "net/rpc"
+)
+
+type GoXY struct{}
+
+func init() {
+ gob.Register(rsa.PrivateKey{})
+ rpc.Register(GoXY{})
+}
+
+func (GoXY) Add(e Entry, _ *struct{}) error {
+ log.Println("Add route", e)
+ defer route.Save(*data)
+ route[e.ServerName] = e
+ route.Restore()
+ return nil
+}
+
+func (GoXY) Del(e Entry, _ *struct{}) error {
+ log.Println("Del route", e)
+ defer route.Save(*data)
+ delete(route, e.ServerName)
+ route.Restore()
+ return nil
+}
+
+func (GoXY) List(_ struct{}, r *Route) error {
+ *r = route
+ return nil
+}