impl cidr as password:CIDR:http://target
This commit is contained in:
@@ -58,6 +58,12 @@ func (s *Server) lookupAuth(host string) (string, error) {
|
||||
return v.String(), err
|
||||
}
|
||||
|
||||
func (s *Server) lookupFrom(host string) (string, error) {
|
||||
v := packable.NewString()
|
||||
err := s.db.Get(nsRouting, host+"//from", v)
|
||||
return v.String(), err
|
||||
}
|
||||
|
||||
func mapKey(host string) string {
|
||||
host = strings.Split(host, ".")[0]
|
||||
host = strings.Split(host, ":")[0]
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -62,6 +63,9 @@ func (s *Server) Route(src string, dst config.Proxy) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.db.Set(nsRouting, src+"//from", packable.NewString(dst.From)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.db.Set(nsRouting, src+"//auth", packable.NewString(dst.Auth)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -167,12 +171,44 @@ func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc {
|
||||
log.Printf("failed to auth: expected %q but got %q", auth, p)
|
||||
w.Header().Set("WWW-Authenticate", "Basic")
|
||||
http.Error(w, "unexpected basic auth", http.StatusUnauthorized)
|
||||
} else if from, err := s.lookupFrom(mapKey(r.Host)); err != nil {
|
||||
log.Printf("failed to lookup from for %s (%s): %v", r.Host, mapKey(r.Host), err)
|
||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||
} else if err := assertFrom(from, r.RemoteAddr); err != nil {
|
||||
log.Printf("failed to from: expected %q but got %q: %v", from, r.RemoteAddr, err)
|
||||
http.Error(w, "unexpected from", http.StatusUnauthorized)
|
||||
} else {
|
||||
foo(w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertFrom(from, remoteAddr string) error {
|
||||
if from == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
pattern := regexp.MustCompile(`[0-9](:[0-9]+)$`).FindStringSubmatchIndex(remoteAddr)
|
||||
if len(pattern) == 4 {
|
||||
remoteAddr = remoteAddr[:pattern[2]]
|
||||
}
|
||||
|
||||
remoteIP := net.ParseIP(remoteAddr)
|
||||
if remoteIP == nil {
|
||||
return fmt.Errorf("cannot parse remote %q", remoteAddr)
|
||||
}
|
||||
|
||||
_, net, err := net.ParseCIDR(from)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if net.Contains(remoteIP) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("expected like %q but got like %q", from, remoteAddr)
|
||||
}
|
||||
|
||||
func withMeta(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
|
||||
meta := map[string]string{
|
||||
"ts": strconv.FormatInt(time.Now().Unix(), 10),
|
||||
@@ -212,14 +248,19 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) List(w http.ResponseWriter) {
|
||||
keys := s.db.Keys(nsRouting)
|
||||
hostURL := map[string]string{}
|
||||
hostFrom := map[string]string{}
|
||||
for _, key := range keys {
|
||||
u, _ := s.lookup(key)
|
||||
if u != nil && strings.TrimSuffix(key, "//auth") == key {
|
||||
hostURL[key] = u.String()
|
||||
}
|
||||
if u != nil && strings.TrimSuffix(key, "//from") == key {
|
||||
hostFrom[key] = u.String()
|
||||
}
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"hostsToURLs": hostURL,
|
||||
"hostsToFrom": hostFrom,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -105,3 +105,32 @@ func TestCORS(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAssertFrom(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
from string
|
||||
remote string
|
||||
err bool
|
||||
}{
|
||||
"empty": {},
|
||||
"ipv6 localhost": {
|
||||
from: "::1/128",
|
||||
remote: "::1:12345",
|
||||
},
|
||||
"ipv4 localhost": {
|
||||
from: "127.0.0.1/32",
|
||||
remote: "127.0.0.1:12345",
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err := assertFrom(c.from, c.remote)
|
||||
got := err != nil
|
||||
if got != c.err {
|
||||
t.Errorf("expected err=%v but got %v", c.err, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user