catch netfilter.d event
This commit is contained in:
parent
1015423a8f
commit
797b85b03a
@ -11,7 +11,7 @@ Realized features:
|
|||||||
- [X] IP integration
|
- [X] IP integration
|
||||||
- [X] IPTables rules to IPSet
|
- [X] IPTables rules to IPSet
|
||||||
- [X] Catch interface up/down
|
- [X] Catch interface up/down
|
||||||
- [ ] Catch `netfilter.d` event
|
- [X] Catch `netfilter.d` event
|
||||||
- [ ] Rule composer (CRUD)
|
- [ ] Rule composer (CRUD)
|
||||||
- [ ] GORM integration
|
- [ ] GORM integration
|
||||||
- [X] Listing of interfaces
|
- [X] Listing of interfaces
|
||||||
|
50
kvas2.go
50
kvas2.go
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -103,6 +104,55 @@ func (a *App) Listen(ctx context.Context) []error {
|
|||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
netlink.LinkSubscribe(link, done)
|
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:
|
Loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -25,6 +25,85 @@ type IfaceToIPSet struct {
|
|||||||
ipRoute *netlink.Route
|
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 {
|
func (r *IfaceToIPSet) IfaceHandle() error {
|
||||||
// Find interface
|
// Find interface
|
||||||
iface, err := netlink.LinkByName(r.IfaceName)
|
iface, err := netlink.LinkByName(r.IfaceName)
|
||||||
@ -98,71 +177,9 @@ func (r *IfaceToIPSet) ForceEnable() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IPTables rules
|
// IPTables rules
|
||||||
if !r.SoftwareMode {
|
err = r.PutIPTable("all")
|
||||||
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 {
|
|
||||||
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to clear chain: %w", err)
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mapping mark with table
|
// Mapping mark with table
|
||||||
@ -180,6 +197,7 @@ func (r *IfaceToIPSet) ForceEnable() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.Enabled = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +262,7 @@ func (r *IfaceToIPSet) Disable() []error {
|
|||||||
r.ipRule = nil
|
r.ipRule = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.Enabled = false
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,20 +15,31 @@ type PortRemap struct {
|
|||||||
Enabled bool
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.IPTables.AppendUnique("nat", r.ChainName, "-p", "udp", "--dport", strconv.Itoa(int(r.From)), "-j", "REDIRECT", "--to-port", strconv.Itoa(int(r.To)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create rule: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.IPTables.InsertUnique("nat", "PREROUTING", 1, "-j", r.ChainName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to linking chain: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *PortRemap) ForceEnable() error {
|
func (r *PortRemap) ForceEnable() error {
|
||||||
err := r.IPTables.ClearChain("nat", r.ChainName)
|
err := r.PutIPTable("all")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to clear chain: %w", err)
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
err = r.IPTables.AppendUnique("nat", r.ChainName, "-p", "udp", "--dport", strconv.Itoa(int(r.From)), "-j", "REDIRECT", "--to-port", strconv.Itoa(int(r.To)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create rule: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = r.IPTables.InsertUnique("nat", "PREROUTING", 1, "-j", r.ChainName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to linking chain: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Enabled = true
|
r.Enabled = true
|
||||||
|
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