Skip to content

Commit d3b7a6f

Browse files
stv0gaboch
authored andcommitted
Add firewall mark option to RouteGetOptions
This option allows performing FIB lookups for a particular firewall mark. It is equivalent to iproute2's 'ip route get mark' option.
1 parent 8e1ce96 commit d3b7a6f

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

route_linux.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,7 @@ type RouteGetOptions struct {
13011301
VrfName string
13021302
SrcAddr net.IP
13031303
UID *uint32
1304+
Mark int
13041305
}
13051306

13061307
// RouteGetWithOptions gets a route to a specific destination from the host system.
@@ -1392,8 +1393,16 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
13921393
uid := *options.UID
13931394
b := make([]byte, 4)
13941395
native.PutUint32(b, uid)
1396+
13951397
req.AddData(nl.NewRtAttr(unix.RTA_UID, b))
13961398
}
1399+
1400+
if options.Mark > 0 {
1401+
b := make([]byte, 4)
1402+
native.PutUint32(b, uint32(options.Mark))
1403+
1404+
req.AddData(nl.NewRtAttr(unix.RTA_MARK, b))
1405+
}
13971406
}
13981407

13991408
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)

route_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,3 +1748,98 @@ func TestRouteUIDOption(t *testing.T) {
17481748
t.Fatal(routes)
17491749
}
17501750
}
1751+
1752+
func TestRouteFWMarkOption(t *testing.T) {
1753+
tearDown := setUpNetlinkTest(t)
1754+
defer tearDown()
1755+
1756+
// setup eth0 so that network is reachable
1757+
err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
1758+
if err != nil {
1759+
t.Fatal(err)
1760+
}
1761+
link, err := LinkByName("eth0")
1762+
if err != nil {
1763+
t.Fatal(err)
1764+
}
1765+
if err = LinkSetUp(link); err != nil {
1766+
t.Fatal(err)
1767+
}
1768+
addr := &Addr{
1769+
IPNet: &net.IPNet{
1770+
IP: net.IPv4(192, 168, 1, 1),
1771+
Mask: net.CIDRMask(16, 32),
1772+
},
1773+
}
1774+
if err = AddrAdd(link, addr); err != nil {
1775+
t.Fatal(err)
1776+
}
1777+
1778+
// a table different than unix.RT_TABLE_MAIN
1779+
testtable := 1000
1780+
1781+
gw1 := net.IPv4(192, 168, 1, 254)
1782+
gw2 := net.IPv4(192, 168, 2, 254)
1783+
1784+
// add default route via gw1 (in main route table by default)
1785+
defaultRouteMain := Route{
1786+
Dst: nil,
1787+
Gw: gw1,
1788+
}
1789+
if err := RouteAdd(&defaultRouteMain); err != nil {
1790+
t.Fatal(err)
1791+
}
1792+
1793+
// add default route via gw2 in test route table
1794+
defaultRouteTest := Route{
1795+
Dst: nil,
1796+
Gw: gw2,
1797+
Table: testtable,
1798+
}
1799+
if err := RouteAdd(&defaultRouteTest); err != nil {
1800+
t.Fatal(err)
1801+
}
1802+
1803+
// check the routes are in different tables
1804+
routes, err := RouteListFiltered(FAMILY_V4, &Route{
1805+
Dst: nil,
1806+
Table: unix.RT_TABLE_UNSPEC,
1807+
}, RT_FILTER_DST|RT_FILTER_TABLE)
1808+
if err != nil {
1809+
t.Fatal(err)
1810+
}
1811+
if len(routes) != 2 || routes[0].Table == routes[1].Table {
1812+
t.Fatal("Routes not added properly")
1813+
}
1814+
1815+
// add a rule that fwmark match should result in route lookup of test table
1816+
fwmark := 1000
1817+
1818+
rule := NewRule()
1819+
rule.Mark = fwmark
1820+
rule.Mask = 0xFFFFFFFF
1821+
rule.Table = testtable
1822+
if err := RuleAdd(rule); err != nil {
1823+
t.Fatal(err)
1824+
}
1825+
1826+
dstIP := net.IPv4(10, 1, 1, 1)
1827+
1828+
// check getting route without FWMark option
1829+
routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{})
1830+
if err != nil {
1831+
t.Fatal(err)
1832+
}
1833+
if len(routes) != 1 || !routes[0].Gw.Equal(gw1) {
1834+
t.Fatal(routes)
1835+
}
1836+
1837+
// check getting route with FWMark option
1838+
routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Mark: fwmark})
1839+
if err != nil {
1840+
t.Fatal(err)
1841+
}
1842+
if len(routes) != 1 || !routes[0].Gw.Equal(gw2) {
1843+
t.Fatal(routes)
1844+
}
1845+
}

0 commit comments

Comments
 (0)