Use per-source address configs
This commit is contained in:
		@@ -56,7 +56,7 @@ func (a Action) MarshalText() ([]byte, error) {
 | 
				
			|||||||
	return []byte(name), nil
 | 
						return []byte(name), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Config is a list of address and actions.
 | 
					// Config is a list of address and actions, for each source address.
 | 
				
			||||||
// It can just be Marshal/Unmarshaled into/from json.
 | 
					// It can just be Marshal/Unmarshaled into/from json.
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	DefaultAction Action // What we should do when no action is matched.
 | 
						DefaultAction Action // What we should do when no action is matched.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,72 +3,96 @@ package perm
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type int_perm struct {
 | 
				
			||||||
 | 
						match map[string]Action
 | 
				
			||||||
 | 
						def   Action
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Perm matches address:port strings to Actions
 | 
					// Perm matches address:port strings to Actions
 | 
				
			||||||
// loaded from a Config.
 | 
					// loaded from a Config.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					// global permissions are stored under the "$global" address.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
// It's thread safe.
 | 
					// It's thread safe.
 | 
				
			||||||
type Perm struct {
 | 
					type Perm struct {
 | 
				
			||||||
	lock sync.RWMutex
 | 
						lock sync.RWMutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	perm map[string]Action
 | 
						global int_perm
 | 
				
			||||||
	def  Action
 | 
					
 | 
				
			||||||
 | 
						source map[string]int_perm
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New creates a new Perm struct from a Config.
 | 
					// New creates a new Perm struct from a Config.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// You can also &perm.Perm{} and then call Load on it.
 | 
					// You can also &perm.Perm{} and then call Load on it.
 | 
				
			||||||
func New(c *Config) (p *Perm) {
 | 
					func New(c map[string]Config) (p *Perm) {
 | 
				
			||||||
	p = &Perm{}
 | 
						p = &Perm{}
 | 
				
			||||||
	p.Load(c)
 | 
						p.Load(c)
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Load loads/reloads the Perm struct.
 | 
					// Load loads/reloads the Perm struct.
 | 
				
			||||||
func (p *Perm) Load(c *Config) {
 | 
					func (p *Perm) Load(cs map[string]Config) {
 | 
				
			||||||
	p.lock.Lock()
 | 
						p.lock.Lock()
 | 
				
			||||||
	defer p.lock.Unlock()
 | 
						defer p.lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if p.perm == nil {
 | 
						if p.source == nil {
 | 
				
			||||||
		p.perm = make(map[string]Action)
 | 
							p.source = make(map[string]int_perm)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		clear(p.perm)
 | 
							clear(p.source)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p.def = c.DefaultAction
 | 
						// helper to load every source addr
 | 
				
			||||||
 | 
						load_per_source := func(c Config) (p_int int_perm) {
 | 
				
			||||||
 | 
							p_int.match = make(map[string]Action)
 | 
				
			||||||
 | 
							p_int.def = c.DefaultAction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// insert helper to use the most severe action existing
 | 
							// insert helper to use the most severe action existing
 | 
				
			||||||
	insert := func(addrport string, action Action) {
 | 
							insert := func(addrport string, action Action) {
 | 
				
			||||||
		existing_action, ok := p.perm[addrport]
 | 
								existing_action, ok := p_int.match[addrport]
 | 
				
			||||||
		if ok {
 | 
								if ok {
 | 
				
			||||||
			p.perm[addrport] = MostSevere(existing_action, action)
 | 
									p_int.match[addrport] = MostSevere(existing_action, action)
 | 
				
			||||||
		} else {
 | 
								} else {
 | 
				
			||||||
			p.perm[addrport] = action
 | 
									p_int.match[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)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 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
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for src, c := range cs {
 | 
				
			||||||
 | 
							if strings.EqualFold(src, "$global") {
 | 
				
			||||||
 | 
								p.global = load_per_source(c)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								p.source[src] = load_per_source(c)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Match matches an address to an action.
 | 
					// Match matches an address to an action.
 | 
				
			||||||
// addr must be in net.JoinHostPort format.
 | 
					//
 | 
				
			||||||
func (p *Perm) Match(addr string) Action {
 | 
					// src must be a host (either ipv4 or v6), while
 | 
				
			||||||
 | 
					// dest must be in net.JoinHostPort format.
 | 
				
			||||||
 | 
					func (p *Perm) Match(src, dest string) Action {
 | 
				
			||||||
	// sanity check
 | 
						// sanity check
 | 
				
			||||||
	if p == nil {
 | 
						if p == nil {
 | 
				
			||||||
		return ActionDeny
 | 
							return ActionDeny
 | 
				
			||||||
@@ -77,14 +101,28 @@ func (p *Perm) Match(addr string) Action {
 | 
				
			|||||||
	p.lock.RLock()
 | 
						p.lock.RLock()
 | 
				
			||||||
	defer p.lock.RUnlock()
 | 
						defer p.lock.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// sanity check no.2
 | 
						// find its source struct
 | 
				
			||||||
	if p.perm == nil {
 | 
						p_int, ok_int := p.source[src]
 | 
				
			||||||
		return p.def
 | 
						// only check if dest is directly listed
 | 
				
			||||||
 | 
						if ok_int && p_int.match != nil {
 | 
				
			||||||
 | 
							if action, ok := p_int.match[dest]; ok {
 | 
				
			||||||
 | 
								return action
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	action, ok := p.perm[addr]
 | 
						// then check the global struct, also only directly listed
 | 
				
			||||||
	if !ok {
 | 
						if p.global.match != nil {
 | 
				
			||||||
		return p.def
 | 
							if action, ok := p.global.match[dest]; ok {
 | 
				
			||||||
 | 
								return action
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// directly listed in neither.
 | 
				
			||||||
 | 
						if ok_int {
 | 
				
			||||||
 | 
							// if source struct exists, use source struct default.
 | 
				
			||||||
 | 
							return p_int.def
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// if not exist, use global default.
 | 
				
			||||||
 | 
							return p.global.def
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return action
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user