Compare commits

..

No commits in common. "5d48ed258d0ef15845c5043c0cb590bbbbb077ef" and "a7b2162433616dea3482dff35f94900262463b79" have entirely different histories.

3 changed files with 10 additions and 199 deletions

View File

@ -28,9 +28,6 @@ func (s *Server) Serve(listener net.Listener) (err error) {
for {
conn, err := listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
return nil
}
return err
}
@ -107,6 +104,10 @@ func (c *cached_conn) Read(b []byte) (int, error) {
return c.Conn.Read(b)
}
type timeout interface {
Timeout() bool
}
// handle_connect returns until the connection is closed by
// the client, or errors. You don't need to close it again.
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
remote_conn, err := dialer.Dial("tcp", req_addr)
if err != nil {
simple_respond(conn, req, http.StatusBadGateway)
var op timeout
if errors.As(err, &op) && op.Timeout() {
simple_respond(conn, req, http.StatusGatewayTimeout)
} else {
simple_respond(conn, req, http.StatusBadGateway)
}
close_err = err
return
}

View File

@ -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
}

View File

@ -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
}