Compare commits
No commits in common. "5d48ed258d0ef15845c5043c0cb590bbbbb077ef" and "a7b2162433616dea3482dff35f94900262463b79" have entirely different histories.
5d48ed258d
...
a7b2162433
@ -28,9 +28,6 @@ func (s *Server) Serve(listener net.Listener) (err error) {
|
|||||||
for {
|
for {
|
||||||
conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, net.ErrClosed) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +104,10 @@ func (c *cached_conn) Read(b []byte) (int, error) {
|
|||||||
return c.Conn.Read(b)
|
return c.Conn.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type timeout interface {
|
||||||
|
Timeout() bool
|
||||||
|
}
|
||||||
|
|
||||||
// handle_connect returns until the connection is closed by
|
// handle_connect returns until the connection is closed by
|
||||||
// the client, or errors. You don't need to close it again.
|
// the client, or errors. You don't need to close it again.
|
||||||
func (s *Server) handle_connect(conn net.Conn, req *http.Request) {
|
func (s *Server) handle_connect(conn net.Conn, req *http.Request) {
|
||||||
@ -132,7 +133,12 @@ func (s *Server) handle_connect(conn net.Conn, req *http.Request) {
|
|||||||
// dial
|
// dial
|
||||||
remote_conn, err := dialer.Dial("tcp", req_addr)
|
remote_conn, err := dialer.Dial("tcp", req_addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var op timeout
|
||||||
|
if errors.As(err, &op) && op.Timeout() {
|
||||||
|
simple_respond(conn, req, http.StatusGatewayTimeout)
|
||||||
|
} else {
|
||||||
simple_respond(conn, req, http.StatusBadGateway)
|
simple_respond(conn, req, http.StatusBadGateway)
|
||||||
|
}
|
||||||
close_err = err
|
close_err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
package perm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Action defines what to do when a ruleset matches a target address.
|
|
||||||
//
|
|
||||||
// The zero value is ActionDeny.
|
|
||||||
type Action int
|
|
||||||
|
|
||||||
// we really should keep the more severe actions numeric less
|
|
||||||
|
|
||||||
const (
|
|
||||||
ActionDeny Action = iota // Returns 502 Bad Gateway, and then logs the offending access.
|
|
||||||
ActionIgnore // Returns 502 Bad Gateway, and then don't log.
|
|
||||||
ActionAccept // Connects as usual.
|
|
||||||
)
|
|
||||||
|
|
||||||
// MostSevere returns the most severe of the two actions.
|
|
||||||
// E.g., ActionIgnore and ActionAccept will return ActionIgnore.
|
|
||||||
//
|
|
||||||
// This is the default behavior when the same address is matched multiple times.
|
|
||||||
func MostSevere(a, b Action) Action {
|
|
||||||
return min(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal/Unmarshal for Action
|
|
||||||
func (a *Action) UnmarshalText(text []byte) error {
|
|
||||||
switch strings.ToLower(string(text)) {
|
|
||||||
case "deny":
|
|
||||||
*a = ActionDeny
|
|
||||||
case "ignore":
|
|
||||||
*a = ActionIgnore
|
|
||||||
case "accept":
|
|
||||||
*a = ActionAccept
|
|
||||||
default:
|
|
||||||
return errors.New("unknown action: " + string(text))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (a Action) MarshalText() ([]byte, error) {
|
|
||||||
var name string
|
|
||||||
switch a {
|
|
||||||
case ActionDeny:
|
|
||||||
name = "deny"
|
|
||||||
case ActionIgnore:
|
|
||||||
name = "ignore"
|
|
||||||
case ActionAccept:
|
|
||||||
name = "accept"
|
|
||||||
default:
|
|
||||||
name = "<" + strconv.Itoa(int(a)) + ">"
|
|
||||||
}
|
|
||||||
return []byte(name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is a list of address and actions.
|
|
||||||
// It can just be Marshal/Unmarshaled into/from json.
|
|
||||||
type Config struct {
|
|
||||||
DefaultAction Action // What we should do when no action is matched.
|
|
||||||
DefaultPort []uint // Port numbers to add to address without port numbers already in them. Don't put too many entries in here.
|
|
||||||
|
|
||||||
// Object which holds addresses and optionally ports, mapping to actions.
|
|
||||||
//
|
|
||||||
// Port number is extracted by net/url.splitHostPort, copied below.
|
|
||||||
// Port number is optional, but must be numeric when present.
|
|
||||||
Match map[string]Action
|
|
||||||
}
|
|
||||||
|
|
||||||
// validOptionalPort reports whether port is either an empty string
|
|
||||||
// or matches /^:\d*$/
|
|
||||||
func validOptionalPort(port string) bool {
|
|
||||||
if port == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if port[0] != ':' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, b := range port[1:] {
|
|
||||||
if b < '0' || b > '9' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// splitHostPort separates host and port. If the port is not valid, it returns
|
|
||||||
// the entire input as host, and it doesn't check the validity of the host.
|
|
||||||
// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
|
|
||||||
func splitHostPort(hostPort string) (host, port string) {
|
|
||||||
host = hostPort
|
|
||||||
|
|
||||||
colon := strings.LastIndexByte(host, ':')
|
|
||||||
if colon != -1 && validOptionalPort(host[colon:]) {
|
|
||||||
host, port = host[:colon], host[colon+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
|
|
||||||
host = host[1 : len(host)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
package perm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Perm matches address:port strings to Actions
|
|
||||||
// loaded from a Config.
|
|
||||||
//
|
|
||||||
// It's thread safe.
|
|
||||||
type Perm struct {
|
|
||||||
lock sync.RWMutex
|
|
||||||
|
|
||||||
perm map[string]Action
|
|
||||||
def Action
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Perm struct from a Config.
|
|
||||||
//
|
|
||||||
// You can also &perm.Perm{} and then call Load on it.
|
|
||||||
func New(c *Config) (p *Perm) {
|
|
||||||
p = &Perm{}
|
|
||||||
p.Load(c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load loads/reloads the Perm struct.
|
|
||||||
func (p *Perm) Load(c *Config) {
|
|
||||||
p.lock.Lock()
|
|
||||||
defer p.lock.Unlock()
|
|
||||||
|
|
||||||
if p.perm == nil {
|
|
||||||
p.perm = make(map[string]Action)
|
|
||||||
} else {
|
|
||||||
clear(p.perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.def = c.DefaultAction
|
|
||||||
|
|
||||||
// insert helper to use the most severe action existing
|
|
||||||
insert := func(addrport string, action Action) {
|
|
||||||
existing_action, ok := p.perm[addrport]
|
|
||||||
if ok {
|
|
||||||
p.perm[addrport] = MostSevere(existing_action, action)
|
|
||||||
} else {
|
|
||||||
p.perm[addrport] = action
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop around the Match map
|
|
||||||
for addrport, act := range c.Match {
|
|
||||||
addr, port := splitHostPort(addrport)
|
|
||||||
if port != "" {
|
|
||||||
insert(net.JoinHostPort(addr, port), act)
|
|
||||||
} else {
|
|
||||||
// so this is why def_port shouldn't be that big
|
|
||||||
// TODO change this to sth faster
|
|
||||||
for def_port := range c.DefaultPort {
|
|
||||||
insert(net.JoinHostPort(addr, strconv.Itoa(def_port)), act)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match matches an address to an action.
|
|
||||||
// addr must be in net.JoinHostPort format.
|
|
||||||
func (p *Perm) Match(addr string) Action {
|
|
||||||
// sanity check
|
|
||||||
if p == nil {
|
|
||||||
return ActionDeny
|
|
||||||
}
|
|
||||||
|
|
||||||
p.lock.RLock()
|
|
||||||
defer p.lock.RUnlock()
|
|
||||||
|
|
||||||
// sanity check no.2
|
|
||||||
if p.perm == nil {
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
|
|
||||||
action, ok := p.perm[addr]
|
|
||||||
if !ok {
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
return action
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user