Files
openlan/pkg/network/firewall.go
2022-10-28 20:52:02 +08:00

178 lines
4.5 KiB
Go
Executable File

package network
import (
"github.com/luscis/openlan/pkg/config"
"github.com/luscis/openlan/pkg/libol"
"github.com/moby/libnetwork/iptables"
"sync"
)
const (
OLCInput = "OPENLAN-IN"
OLCForward = "OPENLAN-FWD"
OLCOutput = "OPENLAN-OUT"
OLCPre = "OPENLAN-PRE"
OLCPost = "OPENLAN-POST"
)
type FireWall struct {
lock sync.Mutex
chains IpChains
rules IpRules
}
func NewFireWall(flows []config.FlowRule) *FireWall {
f := &FireWall{
chains: make(IpChains, 0, 8),
rules: make(IpRules, 0, 32),
}
// Load custom rules.
for _, rule := range flows {
f.rules = f.rules.Add(IpRule{
Table: rule.Table,
Chain: rule.Chain,
Source: rule.Source,
Dest: rule.Dest,
Jump: rule.Jump,
ToSource: rule.ToSource,
ToDest: rule.ToDest,
Comment: rule.Comment,
Proto: rule.Proto,
Match: rule.Match,
DstPort: rule.DstPort,
SrcPort: rule.SrcPort,
Input: rule.Input,
Output: rule.Output,
})
}
return f
}
func (f *FireWall) addOLC() {
f.AddChain(IpChain{Table: TFilter, Name: OLCInput})
f.AddChain(IpChain{Table: TFilter, Name: OLCForward})
f.AddChain(IpChain{Table: TFilter, Name: OLCOutput})
f.AddChain(IpChain{Table: TNat, Name: OLCPre})
f.AddChain(IpChain{Table: TNat, Name: OLCInput})
f.AddChain(IpChain{Table: TNat, Name: OLCPost})
f.AddChain(IpChain{Table: TNat, Name: OLCOutput})
f.AddChain(IpChain{Table: TMangle, Name: OLCPre})
f.AddChain(IpChain{Table: TMangle, Name: OLCInput})
f.AddChain(IpChain{Table: TMangle, Name: OLCForward})
f.AddChain(IpChain{Table: TMangle, Name: OLCPost})
f.AddChain(IpChain{Table: TMangle, Name: OLCOutput})
f.AddChain(IpChain{Table: TRaw, Name: OLCPre})
f.AddChain(IpChain{Table: TRaw, Name: OLCOutput})
}
func (f *FireWall) jumpOLC() {
f.AddRule(IpRule{Order: "-I", Table: TFilter, Chain: CInput, Jump: OLCInput})
f.AddRule(IpRule{Order: "-I", Table: TFilter, Chain: CForward, Jump: OLCForward})
f.AddRule(IpRule{Order: "-I", Table: TFilter, Chain: COutput, Jump: OLCOutput})
f.AddRule(IpRule{Order: "-I", Table: TNat, Chain: CPre, Jump: OLCPre})
f.AddRule(IpRule{Order: "-I", Table: TNat, Chain: CInput, Jump: OLCInput})
f.AddRule(IpRule{Order: "-I", Table: TNat, Chain: CPost, Jump: OLCPost})
f.AddRule(IpRule{Order: "-I", Table: TNat, Chain: COutput, Jump: OLCOutput})
f.AddRule(IpRule{Order: "-I", Table: TMangle, Chain: CPre, Jump: OLCPre})
f.AddRule(IpRule{Order: "-I", Table: TMangle, Chain: CInput, Jump: OLCInput})
f.AddRule(IpRule{Order: "-I", Table: TMangle, Chain: CForward, Jump: OLCForward})
f.AddRule(IpRule{Order: "-I", Table: TMangle, Chain: CPost, Jump: OLCPost})
f.AddRule(IpRule{Order: "-I", Table: TMangle, Chain: COutput, Jump: OLCOutput})
f.AddRule(IpRule{Order: "-I", Table: TRaw, Chain: CPre, Jump: OLCPre})
f.AddRule(IpRule{Order: "-I", Table: TRaw, Chain: COutput, Jump: OLCOutput})
}
func (f *FireWall) Initialize() {
IpInit()
// Init chains
f.addOLC()
f.jumpOLC()
}
func (f *FireWall) AddChain(chain IpChain) {
f.chains = f.chains.Add(chain)
}
func (f *FireWall) AddRule(rule IpRule) {
f.rules = f.rules.Add(rule)
}
func (f *FireWall) InstallRule(rule IpRule) error {
f.lock.Lock()
defer f.lock.Unlock()
order := rule.Order
if order == "" {
order = "-A"
}
if _, err := rule.Opr(order); err != nil {
return err
}
f.rules = f.rules.Add(rule)
return nil
}
func (f *FireWall) install() {
for _, c := range f.chains {
if _, err := c.Opr("-N"); err != nil {
libol.Error("FireWall.install %s", err)
}
}
for _, r := range f.rules {
order := r.Order
if order == "" {
order = "-A"
}
if _, err := r.Opr(order); err != nil {
libol.Error("FireWall.install %s", err)
}
}
}
func (f *FireWall) Start() {
f.lock.Lock()
defer f.lock.Unlock()
libol.Info("FireWall.Start")
f.install()
iptables.OnReloaded(func() {
libol.Info("FireWall.Start OnReloaded")
f.lock.Lock()
defer f.lock.Unlock()
f.install()
})
}
func (f *FireWall) cancel() {
for _, r := range f.rules {
if _, err := r.Opr("-D"); err != nil {
libol.Warn("FireWall.cancel %s", err)
}
}
for _, c := range f.chains {
if _, err := c.Opr("-X"); err != nil {
libol.Warn("FireWall.cancel %s", err)
}
}
}
func (f *FireWall) CancelRule(rule IpRule) error {
f.lock.Lock()
defer f.lock.Unlock()
if _, err := rule.Opr("-D"); err != nil {
return err
}
f.rules = f.rules.Remove(rule)
return nil
}
func (f *FireWall) Stop() {
f.lock.Lock()
defer f.lock.Unlock()
libol.Info("FireWall.Stop")
f.cancel()
}
func (f *FireWall) Refresh() {
f.cancel()
f.install()
}