Compare commits
5
Commits
4b41ba6ff4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28d6bca84a | ||
|
|
74b6bef9df | ||
|
|
052b00caae | ||
|
|
a7d613ff8b | ||
|
|
709b7d46db |
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
@@ -27,17 +28,23 @@ type (
|
|||||||
To string
|
To string
|
||||||
Redir bool
|
Redir bool
|
||||||
BasicAuth string `yaml:"basicAuth"`
|
BasicAuth string `yaml:"basicAuth"`
|
||||||
|
If []IfThen
|
||||||
|
}
|
||||||
|
|
||||||
|
IfThen struct {
|
||||||
|
Headers map[string]string
|
||||||
|
Then Endpoint
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewConfig() (Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
var c Config
|
c := &Config{}
|
||||||
|
|
||||||
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
||||||
fs.StringVar(&c.Cert.CRT, "crt", "", "path to .crt")
|
fs.StringVar(&c.Cert.CRT, "crt", "", "path to .crt")
|
||||||
fs.StringVar(&c.Cert.Key, "key", "", "path to .key")
|
fs.StringVar(&c.Cert.Key, "key", "", "path to .key")
|
||||||
fs.IntVar(&c.Port, "p", 56112, "port to listen on")
|
fs.IntVar(&c.Port, "p", 56112, "port to listen on")
|
||||||
f := fs.String("f", "/dev/null", `file of {domains:{.google.com:{mail:{to: scheme://host:port, basicAuth: u:p, redir: false}}}}`)
|
f := fs.String("f", "/dev/null", `file of {domains:{.google.com:{mail:{to: scheme://host:port, basicAuth: u:p, redir: false, if:{headers:{k:v}, then:{to:...}}}}}}`)
|
||||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
@@ -60,3 +67,26 @@ func NewConfig() (Config, error) {
|
|||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) Start() {
|
||||||
|
go c.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) start() {
|
||||||
|
ch := time.NewTicker(30 * time.Second)
|
||||||
|
defer ch.Stop()
|
||||||
|
|
||||||
|
for range ch.C {
|
||||||
|
func() {
|
||||||
|
c2, err := NewConfig()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if fmt.Sprintf("%+v", c.Domains) != fmt.Sprintf("%+v", c2.Domains) {
|
||||||
|
c.Domains = c2.Domains
|
||||||
|
log.Printf("loaded new conf")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pretty66/websocketproxy"
|
|
||||||
"github.com/viki-org/dnscache"
|
"github.com/viki-org/dnscache"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,6 +20,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
c.Start()
|
||||||
|
|
||||||
s := &http.Server{
|
s := &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", c.Port),
|
Addr: fmt.Sprintf(":%d", c.Port),
|
||||||
@@ -40,7 +40,7 @@ func main() {
|
|||||||
|
|
||||||
var resolver = dnscache.New(time.Minute * 500)
|
var resolver = dnscache.New(time.Minute * 500)
|
||||||
|
|
||||||
func (c Config) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
endpoint := c.endpoint(r)
|
endpoint := c.endpoint(r)
|
||||||
if endpoint.To == "" {
|
if endpoint.To == "" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
@@ -54,7 +54,7 @@ func (c Config) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) serveHTTPRedir(w http.ResponseWriter, r *http.Request, endpoint Endpoint) {
|
func (c *Config) serveHTTPRedir(w http.ResponseWriter, r *http.Request, endpoint Endpoint) {
|
||||||
if !c.basicAuth(w, r) {
|
if !c.basicAuth(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ func (c Config) serveHTTPRedir(w http.ResponseWriter, r *http.Request, endpoint
|
|||||||
|
|
||||||
var someDialer = &net.Dialer{}
|
var someDialer = &net.Dialer{}
|
||||||
|
|
||||||
func (c Config) serveHTTPProxy(w http.ResponseWriter, r *http.Request, endpoint Endpoint) {
|
func (c *Config) serveHTTPProxy(w http.ResponseWriter, r *http.Request, endpoint Endpoint) {
|
||||||
cors(w)
|
cors(w)
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.Header().Set("Content-Length", "0")
|
w.Header().Set("Content-Length", "0")
|
||||||
@@ -94,32 +94,6 @@ func (c Config) serveHTTPProxy(w http.ResponseWriter, r *http.Request, endpoint
|
|||||||
log.Printf("[%s] %v", c.key(r), err)
|
log.Printf("[%s] %v", c.key(r), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isWebsocket := r.Header.Get("Connection") == "Upgrade" || r.Header.Get("Se-Fetch-Mode") == "websocket" || r.Header.Get("Sec-WebSocket-Version") != "" || r.Header.Get("Upgrade") == "websocket"
|
|
||||||
if isWebsocket {
|
|
||||||
wsu := *u
|
|
||||||
if strings.HasPrefix(wsu.Scheme, "s") {
|
|
||||||
wsu.Scheme = "wss"
|
|
||||||
} else {
|
|
||||||
wsu.Scheme = "ws"
|
|
||||||
}
|
|
||||||
wp, err := websocketproxy.NewProxy(wsu.String(), func(r2 *http.Request) error {
|
|
||||||
r2.Header.Set("Cookie", r.Header.Get("Cookie"))
|
|
||||||
u3 := *u
|
|
||||||
u3.Path = "/"
|
|
||||||
r2.Header.Set("Origin", u3.String())
|
|
||||||
if debug {
|
|
||||||
log.Printf("r2.Header[Origin] = %q", r2.Header.Get("Origin"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wp.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var transport http.Transport
|
var transport http.Transport
|
||||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
if ip, _ := resolver.FetchOneString(strings.Split(u.Host, ":")[0]); ip != "" {
|
if ip, _ := resolver.FetchOneString(strings.Split(u.Host, ":")[0]); ip != "" {
|
||||||
@@ -146,11 +120,11 @@ func cors(w http.ResponseWriter) {
|
|||||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) key(r *http.Request) string {
|
func (c *Config) key(r *http.Request) string {
|
||||||
return strings.Split(r.Host, ".")[0]
|
return strings.Split(r.Host, ".")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) handleAdmin(w http.ResponseWriter, r *http.Request) bool {
|
func (c *Config) handleAdmin(w http.ResponseWriter, r *http.Request) bool {
|
||||||
switch c.key(r) {
|
switch c.key(r) {
|
||||||
case "_":
|
case "_":
|
||||||
panic("not impl: list")
|
panic("not impl: list")
|
||||||
@@ -160,7 +134,7 @@ func (c Config) handleAdmin(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) basicAuth(w http.ResponseWriter, r *http.Request) bool {
|
func (c *Config) basicAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||||
basicAuth := c.endpoint(r).BasicAuth
|
basicAuth := c.endpoint(r).BasicAuth
|
||||||
if noAuth := basicAuth == ""; noAuth {
|
if noAuth := basicAuth == ""; noAuth {
|
||||||
return true
|
return true
|
||||||
@@ -176,7 +150,7 @@ func (c Config) basicAuth(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) endpoint(r *http.Request) Endpoint {
|
func (c *Config) endpoint(r *http.Request) Endpoint {
|
||||||
key := c.key(r)
|
key := c.key(r)
|
||||||
domain := strings.Split(strings.TrimPrefix(r.Host, key), ":")[0]
|
domain := strings.Split(strings.TrimPrefix(r.Host, key), ":")[0]
|
||||||
m, ok := c.Domains[domain]
|
m, ok := c.Domains[domain]
|
||||||
@@ -186,7 +160,23 @@ func (c Config) endpoint(r *http.Request) Endpoint {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return Endpoint{}
|
return Endpoint{}
|
||||||
}
|
}
|
||||||
return m[key]
|
|
||||||
|
endpoint, ok := m[key]
|
||||||
|
if !ok {
|
||||||
|
return Endpoint{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iffer := range endpoint.If {
|
||||||
|
matches := true
|
||||||
|
for k, v := range iffer.Headers {
|
||||||
|
matches = matches && r.Header.Get(k) == v
|
||||||
|
}
|
||||||
|
if matches {
|
||||||
|
return iffer.Then
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
type redirPurge struct {
|
type redirPurge struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user