From 1015423a8fbaca4934840982dfd20a5d34c6d029 Mon Sep 17 00:00:00 2001 From: Vladimir Avtsenov Date: Fri, 6 Sep 2024 15:48:15 +0300 Subject: [PATCH] catch interface up/down --- README.md | 2 +- kvas2.go | 50 ++++++++++++++++++++++++-- netfilter-helper/interface-to-ipset.go | 50 ++++++++++++++++---------- 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 6e84ede..a5b68fe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Realized features: - [X] IPSet integration - [X] IP integration - [X] IPTables rules to IPSet -- [ ] Catch interface up/down +- [X] Catch interface up/down - [ ] Catch `netfilter.d` event - [ ] Rule composer (CRUD) - [ ] GORM integration diff --git a/kvas2.go b/kvas2.go index 7cd3b83..824c9d7 100644 --- a/kvas2.go +++ b/kvas2.go @@ -13,6 +13,7 @@ import ( "kvas2-go/netfilter-helper" "github.com/rs/zerolog/log" + "github.com/vishvananda/netlink" ) var ( @@ -98,11 +99,54 @@ func (a *App) Listen(ctx context.Context) []error { } }() - select { - case <-ctx.Done(): - case <-isError: + link := make(chan netlink.LinkUpdate) + done := make(chan struct{}) + netlink.LinkSubscribe(link, done) + +Loop: + for { + select { + case event := <-link: + switch event.Change { + case 0x00000001: + log.Debug(). + Str("interface", event.Link.Attrs().Name). + Str("operstatestr", event.Attrs().OperState.String()). + Int("operstate", int(event.Attrs().OperState)). + Msg("interface change") + if event.Attrs().OperState != netlink.OperDown { + for _, group := range a.Groups { + if group.Interface == event.Link.Attrs().Name { + err = group.ifaceToIPSet.IfaceHandle() + if err != nil { + log.Error().Int("group", group.ID).Err(err).Msg("error while handling interface up") + } + } + } + } + case 0xFFFFFFFF: + switch event.Header.Type { + case 16: + log.Debug(). + Str("interface", event.Link.Attrs().Name). + Int("type", int(event.Header.Type)). + Msg("interface add") + case 17: + log.Debug(). + Str("interface", event.Link.Attrs().Name). + Int("type", int(event.Header.Type)). + Msg("interface del") + } + } + case <-ctx.Done(): + break Loop + case <-isError: + break Loop + } } + close(done) + errs2 := a.dnsOverrider.Disable() if errs2 != nil { handleErrors(errs2) diff --git a/netfilter-helper/interface-to-ipset.go b/netfilter-helper/interface-to-ipset.go index 2c3c6d1..03ba3cc 100644 --- a/netfilter-helper/interface-to-ipset.go +++ b/netfilter-helper/interface-to-ipset.go @@ -25,18 +25,41 @@ type IfaceToIPSet struct { ipRoute *netlink.Route } +func (r *IfaceToIPSet) IfaceHandle() error { + // Find interface + iface, err := netlink.LinkByName(r.IfaceName) + if err != nil { + log.Warn().Str("interface", r.IfaceName).Err(err).Msg("error while getting interface") + } + + // Mapping iface with table + if iface != nil { + route := &netlink.Route{ + LinkIndex: iface.Attrs().Index, + Table: r.table, + Dst: &net.IPNet{IP: []byte{0, 0, 0, 0}, Mask: []byte{0, 0, 0, 0}}, + } + // Delete rule if exists + err = netlink.RouteDel(route) + if err != nil { + log.Warn().Str("interface", r.IfaceName).Err(err).Msg("error while deleting route") + } + err = netlink.RouteAdd(route) + if err != nil { + return fmt.Errorf("error while mapping iface with table: %w", err) + } + r.ipRoute = route + } + + return nil +} + func (r *IfaceToIPSet) ForceEnable() error { // Release used mark and table r.Disable() r.mark = 0 r.table = 0 - // Find interface - iface, err := netlink.LinkByName(r.IfaceName) - if err != nil { - log.Warn().Str("interface", r.IfaceName).Msg("error while getting interface") - } - // Find unused mark and table markMap := make(map[uint32]struct{}) tableMap := map[int]struct{}{0: {}, 253: {}, 254: {}, 255: {}} @@ -152,18 +175,9 @@ func (r *IfaceToIPSet) ForceEnable() error { } r.ipRule = rule - // Mapping iface with table - if iface != nil { - route := &netlink.Route{ - LinkIndex: iface.Attrs().Index, - Table: rule.Table, - Dst: &net.IPNet{IP: []byte{0, 0, 0, 0}, Mask: []byte{0, 0, 0, 0}}, - } - err = netlink.RouteAdd(route) - if err != nil { - return fmt.Errorf("error while mapping iface with table: %w", err) - } - r.ipRoute = route + err = r.IfaceHandle() + if err != nil { + return nil } return nil