From 5b0b9d826054b741b76e8232e88a89c9e10fd5e1 Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Thu, 22 Aug 2024 14:13:23 -0500 Subject: [PATCH] rule: add Rule.Type to allow adding/listing unreachable (RTN_UNREACHABLE) rules Updates #710 Co-authored-by: Brad Fitzpatrick Signed-off-by: Percy Wegmann --- rule.go | 5 +++-- rule_linux.go | 35 +++++++++++++++++++++++++++++++++-- rule_nonlinux.go | 8 ++++++++ rule_test.go | 14 +++++++++++--- 4 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 rule_nonlinux.go diff --git a/rule.go b/rule.go index cc739458..9d74c7cd 100644 --- a/rule.go +++ b/rule.go @@ -28,6 +28,7 @@ type Rule struct { IPProto int UIDRange *RuleUIDRange Protocol uint8 + Type uint8 } func (r Rule) String() string { @@ -41,8 +42,8 @@ func (r Rule) String() string { to = r.Dst.String() } - return fmt.Sprintf("ip rule %d: from %s to %s table %d", - r.Priority, from, to, r.Table) + return fmt.Sprintf("ip rule %d: from %s to %s table %d %s", + r.Priority, from, to, r.Table, r.typeString()) } // NewRule return empty rules. diff --git a/rule_linux.go b/rule_linux.go index 18c03a3e..ddff99cf 100644 --- a/rule_linux.go +++ b/rule_linux.go @@ -43,8 +43,8 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { msg.Protocol = unix.RTPROT_BOOT msg.Scope = unix.RT_SCOPE_UNIVERSE msg.Table = unix.RT_TABLE_UNSPEC - msg.Type = unix.RTN_UNSPEC - if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 { + msg.Type = rule.Type // usually 0, same as unix.RTN_UNSPEC + if msg.Type == 0 && req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 { msg.Type = unix.RTN_UNICAST } if rule.Invert { @@ -332,3 +332,34 @@ func ptrEqual(a, b *uint32) bool { } return *a == *b } + +func (r Rule) typeString() string { + switch r.Type { + case unix.RTN_UNSPEC: // zero + return "" + case unix.RTN_UNICAST: + return "" + case unix.RTN_LOCAL: + return "local" + case unix.RTN_BROADCAST: + return "broadcast" + case unix.RTN_ANYCAST: + return "anycast" + case unix.RTN_MULTICAST: + return "multicast" + case unix.RTN_BLACKHOLE: + return "blackhole" + case unix.RTN_UNREACHABLE: + return "unreachable" + case unix.RTN_PROHIBIT: + return "prohibit" + case unix.RTN_THROW: + return "throw" + case unix.RTN_NAT: + return "nat" + case unix.RTN_XRESOLVE: + return "xresolve" + default: + return fmt.Sprintf("type(0x%x)", r.Type) + } +} diff --git a/rule_nonlinux.go b/rule_nonlinux.go new file mode 100644 index 00000000..2b19aa64 --- /dev/null +++ b/rule_nonlinux.go @@ -0,0 +1,8 @@ +//go:build !linux +// +build !linux + +package netlink + +func (r Rule) typeString() string { + return "" +} diff --git a/rule_test.go b/rule_test.go index c452fe96..59edb405 100644 --- a/rule_test.go +++ b/rule_test.go @@ -613,7 +613,7 @@ func TestRuleString(t *testing.T) { s string }{ "empty rule": { - s: "ip rule 0: from all to all table 0", + s: "ip rule 0: from all to all table 0 ", }, "rule with src and dst equivalent to ": { r: Rule{ @@ -622,7 +622,7 @@ func TestRuleString(t *testing.T) { Dst: &net.IPNet{IP: net.IPv4(20, 0, 0, 0)}, Table: 99, }, - s: "ip rule 100: from all to all table 99", + s: "ip rule 100: from all to all table 99 ", }, "rule with src and dst": { r: Rule{ @@ -631,7 +631,14 @@ func TestRuleString(t *testing.T) { Dst: &net.IPNet{IP: net.IPv4(20, 0, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, Table: 99, }, - s: "ip rule 100: from 10.0.0.0/24 to 20.0.0.0/24 table 99", + s: "ip rule 100: from 10.0.0.0/24 to 20.0.0.0/24 table 99 ", + }, + "rule with type": { + r: Rule{ + Priority: 101, + Type: unix.RTN_UNREACHABLE, + }, + s: "ip rule 101: from all to all table 0 unreachable", }, } @@ -671,6 +678,7 @@ func ruleEquals(a, b Rule) bool { a.IifName == b.IifName && a.Invert == b.Invert && a.Tos == b.Tos && + a.Type == b.Type && a.IPProto == b.IPProto && a.Protocol == b.Protocol && a.Mark == b.Mark &&