catch netfilter.d event
This commit is contained in:
parent
1015423a8f
commit
797b85b03a
@ -11,7 +11,7 @@ Realized features:
|
||||
- [X] IP integration
|
||||
- [X] IPTables rules to IPSet
|
||||
- [X] Catch interface up/down
|
||||
- [ ] Catch `netfilter.d` event
|
||||
- [X] Catch `netfilter.d` event
|
||||
- [ ] Rule composer (CRUD)
|
||||
- [ ] GORM integration
|
||||
- [X] Listing of interfaces
|
||||
|
50
kvas2.go
50
kvas2.go
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -103,6 +104,55 @@ func (a *App) Listen(ctx context.Context) []error {
|
||||
done := make(chan struct{})
|
||||
netlink.LinkSubscribe(link, done)
|
||||
|
||||
exitListenerLoop := false
|
||||
listener, err := net.Listen("unix", "/opt/var/run/kvas2-go.sock")
|
||||
if err != nil {
|
||||
handleError(fmt.Errorf("error while serve UNIX socket: %v", err))
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
if exitListenerLoop {
|
||||
break
|
||||
}
|
||||
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error while listening unix socket")
|
||||
}
|
||||
|
||||
go func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
args := strings.Split(string(buf[:n]), ":")
|
||||
if len(args) == 3 && args[0] == "netfilter.d" {
|
||||
log.Debug().Str("table", args[2]).Msg("netfilter.d event")
|
||||
if a.dnsOverrider.Enabled {
|
||||
err := a.dnsOverrider.PutIPTable(args[2])
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error while fixing iptables after netfilter.d")
|
||||
}
|
||||
}
|
||||
for _, group := range a.Groups {
|
||||
if group.ifaceToIPSet.Enabled {
|
||||
err := group.ifaceToIPSet.PutIPTable(args[2])
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error while fixing iptables after netfilter.d")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}(conn)
|
||||
}
|
||||
}()
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
|
@ -25,6 +25,85 @@ type IfaceToIPSet struct {
|
||||
ipRoute *netlink.Route
|
||||
}
|
||||
|
||||
func (r *IfaceToIPSet) PutIPTable(table string) error {
|
||||
var err error
|
||||
|
||||
if !r.SoftwareMode {
|
||||
if table == "all" || table == "mangle" {
|
||||
err = r.IPTables.ClearChain("mangle", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
for _, iptablesArgs := range [][]string{
|
||||
// Source: https://github.com/qzeleza/kvas/blob/3fdbbd1ace7b57b11bf88d8db3882d94a1d6e01c/opt/etc/ndm/ndm#L194-L206
|
||||
{"-m", "set", "!", "--match-set", r.IPSetName, "dst", "-j", "RETURN"},
|
||||
{"-j", "CONNMARK", "--restore-mark"},
|
||||
{"-m", "mark", "--mark", strconv.Itoa(int(r.mark)), "-j", "RETURN"},
|
||||
// This command not working
|
||||
// {"--syn", "-j", "MARK", "--set-mark", strconv.Itoa(int(mark))},
|
||||
{"-m", "conntrack", "--ctstate", "NEW", "-j", "MARK", "--set-mark", strconv.Itoa(int(r.mark))},
|
||||
{"-j", "CONNMARK", "--save-mark"},
|
||||
} {
|
||||
err = r.IPTables.AppendUnique("mangle", r.ChainName, iptablesArgs...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "PREROUTING", "-m", "set", "--match-set", r.IPSetName, "dst", "-j", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to PREROUTING: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "OUTPUT", "-m", "set", "--match-set", r.IPSetName, "dst", "-j", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to OUTPUT: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if table == "all" || table == "mangle" {
|
||||
preroutingChainName := fmt.Sprintf("%s_PREROUTING", r.ChainName)
|
||||
|
||||
err = r.IPTables.ClearChain("mangle", preroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", preroutingChainName, "-m", "set", "--match-set", r.IPSetName, "dst", "-j", "MARK", "--set-mark", strconv.Itoa(int(r.mark)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create rule: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "PREROUTING", "-j", preroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to PREROUTING: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if table == "all" || table == "nat" {
|
||||
postroutingChainName := fmt.Sprintf("%s_POSTROUTING", r.ChainName)
|
||||
|
||||
err = r.IPTables.ClearChain("nat", postroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("nat", postroutingChainName, "-o", r.IfaceName, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create rule: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("nat", "POSTROUTING", "-j", postroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to POSTROUTING: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *IfaceToIPSet) IfaceHandle() error {
|
||||
// Find interface
|
||||
iface, err := netlink.LinkByName(r.IfaceName)
|
||||
@ -98,71 +177,9 @@ func (r *IfaceToIPSet) ForceEnable() error {
|
||||
}
|
||||
|
||||
// IPTables rules
|
||||
if !r.SoftwareMode {
|
||||
err = r.IPTables.ClearChain("mangle", r.ChainName)
|
||||
err = r.PutIPTable("all")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
for _, iptablesArgs := range [][]string{
|
||||
// Source: https://github.com/qzeleza/kvas/blob/3fdbbd1ace7b57b11bf88d8db3882d94a1d6e01c/opt/etc/ndm/ndm#L194-L206
|
||||
{"-m", "set", "!", "--match-set", r.IPSetName, "dst", "-j", "RETURN"},
|
||||
{"-j", "CONNMARK", "--restore-mark"},
|
||||
{"-m", "mark", "--mark", strconv.Itoa(int(r.mark)), "-j", "RETURN"},
|
||||
// This command not working
|
||||
// {"--syn", "-j", "MARK", "--set-mark", strconv.Itoa(int(mark))},
|
||||
{"-m", "conntrack", "--ctstate", "NEW", "-j", "MARK", "--set-mark", strconv.Itoa(int(r.mark))},
|
||||
{"-j", "CONNMARK", "--save-mark"},
|
||||
} {
|
||||
err = r.IPTables.AppendUnique("mangle", r.ChainName, iptablesArgs...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "PREROUTING", "-m", "set", "--match-set", r.IPSetName, "dst", "-j", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to PREROUTING: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "OUTPUT", "-m", "set", "--match-set", r.IPSetName, "dst", "-j", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to OUTPUT: %w", err)
|
||||
}
|
||||
} else {
|
||||
preroutingChainName := fmt.Sprintf("%s_PREROUTING", r.ChainName)
|
||||
|
||||
err = r.IPTables.ClearChain("mangle", preroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", preroutingChainName, "-m", "set", "--match-set", r.IPSetName, "dst", "-j", "MARK", "--set-mark", strconv.Itoa(int(r.mark)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create rule: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("mangle", "PREROUTING", "-j", preroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to PREROUTING: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
postroutingChainName := fmt.Sprintf("%s_POSTROUTING", r.ChainName)
|
||||
|
||||
err = r.IPTables.ClearChain("nat", postroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("nat", postroutingChainName, "-o", r.IfaceName, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create rule: %w", err)
|
||||
}
|
||||
|
||||
err = r.IPTables.AppendUnique("nat", "POSTROUTING", "-j", postroutingChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to append rule to POSTROUTING: %w", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mapping mark with table
|
||||
@ -180,6 +197,7 @@ func (r *IfaceToIPSet) ForceEnable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
r.Enabled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -244,6 +262,7 @@ func (r *IfaceToIPSet) Disable() []error {
|
||||
r.ipRule = nil
|
||||
}
|
||||
|
||||
r.Enabled = false
|
||||
return errs
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@ type PortRemap struct {
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func (r *PortRemap) ForceEnable() error {
|
||||
func (r *PortRemap) PutIPTable(table string) error {
|
||||
if table == "all" || table == "nat" {
|
||||
err := r.IPTables.ClearChain("nat", r.ChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear chain: %w", err)
|
||||
@ -30,6 +31,16 @@ func (r *PortRemap) ForceEnable() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to linking chain: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PortRemap) ForceEnable() error {
|
||||
err := r.PutIPTable("all")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Enabled = true
|
||||
return nil
|
||||
|
6
opt/etc/ndm/netfilter.d/100-kvas2
Executable file
6
opt/etc/ndm/netfilter.d/100-kvas2
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
SOCKET_PATH="/opt/var/run/kvas2-go.sock"
|
||||
if [ ! -S "$SOCKET_PATH" ]; then
|
||||
exit
|
||||
fi
|
||||
echo -n "netfilter.d:${type}:${table}" | socat - UNIX-CONNECT:"${SOCKET_PATH}"
|
Loading…
x
Reference in New Issue
Block a user