Merge pull request #639 from EdDev/bridge-macspoofchk
bridge: Add macspoofchk support
This commit is contained in:
commit
f1f128e3c9
3
.github/workflows/test.yaml
vendored
3
.github/workflows/test.yaml
vendored
@ -35,6 +35,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install linux-modules-extra-$(uname -r)
|
sudo apt-get install linux-modules-extra-$(uname -r)
|
||||||
|
- name: Install nftables
|
||||||
|
run: sudo apt-get install nftables
|
||||||
|
|
||||||
- name: setup go
|
- name: setup go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
|
1
go.mod
1
go.mod
@ -15,6 +15,7 @@ require (
|
|||||||
github.com/godbus/dbus/v5 v5.0.4
|
github.com/godbus/dbus/v5 v5.0.4
|
||||||
github.com/j-keck/arping v1.0.2
|
github.com/j-keck/arping v1.0.2
|
||||||
github.com/mattn/go-shellwords v1.0.12
|
github.com/mattn/go-shellwords v1.0.12
|
||||||
|
github.com/networkplumbing/go-nft v0.2.0
|
||||||
github.com/onsi/ginkgo v1.16.4
|
github.com/onsi/ginkgo v1.16.4
|
||||||
github.com/onsi/gomega v1.15.0
|
github.com/onsi/gomega v1.15.0
|
||||||
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1
|
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1
|
||||||
|
12
go.sum
12
go.sum
@ -438,6 +438,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
|||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||||
|
github.com/networkplumbing/go-nft v0.2.0 h1:eKapmyVUt/3VGfhYaDos5yeprm+LPt881UeksmKKZHY=
|
||||||
|
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
@ -567,8 +569,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
@ -599,6 +602,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
|
|||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||||
@ -659,6 +663,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -694,6 +699,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -710,6 +716,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -771,7 +778,9 @@ golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
@ -826,6 +835,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
|
|||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
27
pkg/link/link_suite_test.go
Normal file
27
pkg/link/link_suite_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2021 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package link_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIp(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "pkg/link")
|
||||||
|
}
|
245
pkg/link/spoofcheck.go
Normal file
245
pkg/link/spoofcheck.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
// Copyright 2021 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package link
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/networkplumbing/go-nft/nft"
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
natTableName = "nat"
|
||||||
|
preRoutingBaseChainName = "PREROUTING"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NftConfigurer interface {
|
||||||
|
Apply(*nft.Config) error
|
||||||
|
Read() (*nft.Config, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpoofChecker struct {
|
||||||
|
iface string
|
||||||
|
macAddress string
|
||||||
|
refID string
|
||||||
|
configurer NftConfigurer
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultNftConfigurer struct{}
|
||||||
|
|
||||||
|
func (_ defaultNftConfigurer) Apply(cfg *nft.Config) error {
|
||||||
|
return nft.ApplyConfig(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ defaultNftConfigurer) Read() (*nft.Config, error) {
|
||||||
|
return nft.ReadConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSpoofChecker(iface, macAddress, refID string) *SpoofChecker {
|
||||||
|
return NewSpoofCheckerWithConfigurer(iface, macAddress, refID, defaultNftConfigurer{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSpoofCheckerWithConfigurer(iface, macAddress, refID string, configurer NftConfigurer) *SpoofChecker {
|
||||||
|
return &SpoofChecker{iface, macAddress, refID, configurer}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup applies nftables configuration to restrict traffic
|
||||||
|
// from the provided interface. Only traffic with the mentioned mac address
|
||||||
|
// is allowed to pass, all others are blocked.
|
||||||
|
// The configuration follows the format libvirt and ebtables implemented, allowing
|
||||||
|
// extensions to the rules in the future.
|
||||||
|
// refID is used to label the rules with a unique comment, identifying the rule-set.
|
||||||
|
//
|
||||||
|
// In order to take advantage of the nftables configuration change atomicity, the
|
||||||
|
// following steps are taken to apply the configuration:
|
||||||
|
// - Declare the table and chains (they will be created in case not present).
|
||||||
|
// - Apply the rules, while first flushing the iface/mac specific regular chain rules.
|
||||||
|
// Two transactions are used because the flush succeeds only if the table/chain it targets
|
||||||
|
// exists. This avoids the need to query the existing state and acting upon it (a raceful pattern).
|
||||||
|
// Although two transactions are taken place, only the 2nd one where the rules
|
||||||
|
// are added has a real impact on the system.
|
||||||
|
func (sc *SpoofChecker) Setup() error {
|
||||||
|
baseConfig := nft.NewConfig()
|
||||||
|
|
||||||
|
baseConfig.AddTable(&schema.Table{Family: schema.FamilyBridge, Name: natTableName})
|
||||||
|
|
||||||
|
baseConfig.AddChain(sc.baseChain())
|
||||||
|
ifaceChain := sc.ifaceChain()
|
||||||
|
baseConfig.AddChain(ifaceChain)
|
||||||
|
macChain := sc.macChain(ifaceChain.Name)
|
||||||
|
baseConfig.AddChain(macChain)
|
||||||
|
|
||||||
|
if err := sc.configurer.Apply(baseConfig); err != nil {
|
||||||
|
return fmt.Errorf("failed to setup spoof-check: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesConfig := nft.NewConfig()
|
||||||
|
|
||||||
|
rulesConfig.FlushChain(ifaceChain)
|
||||||
|
rulesConfig.FlushChain(macChain)
|
||||||
|
|
||||||
|
rulesConfig.AddRule(sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name))
|
||||||
|
rulesConfig.AddRule(sc.jumpToChainRule(ifaceChain.Name, macChain.Name))
|
||||||
|
rulesConfig.AddRule(sc.matchMacRule(macChain.Name))
|
||||||
|
rulesConfig.AddRule(sc.dropRule(macChain.Name))
|
||||||
|
|
||||||
|
if err := sc.configurer.Apply(rulesConfig); err != nil {
|
||||||
|
return fmt.Errorf("failed to setup spoof-check: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teardown removes the interface and mac-address specific chains and their rules.
|
||||||
|
// The table and base-chain are expected to survive while the base-chain rule that matches the
|
||||||
|
// interface is removed.
|
||||||
|
func (sc *SpoofChecker) Teardown() error {
|
||||||
|
ifaceChain := sc.ifaceChain()
|
||||||
|
currentConfig, ifaceMatchRuleErr := sc.configurer.Read()
|
||||||
|
if ifaceMatchRuleErr == nil {
|
||||||
|
expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name)
|
||||||
|
// It is safer to exclude the statement matching, avoiding cases where a current statement includes
|
||||||
|
// additional default entries (e.g. counters).
|
||||||
|
ruleToFindExcludingStatements := *expectedRuleToFind
|
||||||
|
ruleToFindExcludingStatements.Expr = nil
|
||||||
|
rules := currentConfig.LookupRule(&ruleToFindExcludingStatements)
|
||||||
|
if len(rules) > 0 {
|
||||||
|
c := nft.NewConfig()
|
||||||
|
for _, rule := range rules {
|
||||||
|
c.DeleteRule(rule)
|
||||||
|
}
|
||||||
|
if err := sc.configurer.Apply(c); err != nil {
|
||||||
|
ifaceMatchRuleErr = fmt.Errorf("failed to delete iface match rule: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "spoofcheck/teardown: unable to detect iface match rule for deletion: %+v", expectedRuleToFind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regularChainsConfig := nft.NewConfig()
|
||||||
|
regularChainsConfig.DeleteChain(ifaceChain)
|
||||||
|
regularChainsConfig.DeleteChain(sc.macChain(ifaceChain.Name))
|
||||||
|
|
||||||
|
var regularChainsErr error
|
||||||
|
if err := sc.configurer.Apply(regularChainsConfig); err != nil {
|
||||||
|
regularChainsErr = fmt.Errorf("failed to delete regular chains: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ifaceMatchRuleErr != nil || regularChainsErr != nil {
|
||||||
|
return fmt.Errorf("failed to teardown spoof-check: %v, %v", ifaceMatchRuleErr, regularChainsErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SpoofChecker) matchIfaceJumpToChainRule(chain, toChain string) *schema.Rule {
|
||||||
|
return &schema.Rule{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Chain: chain,
|
||||||
|
Expr: []schema.Statement{
|
||||||
|
{Match: &schema.Match{
|
||||||
|
Op: schema.OperEQ,
|
||||||
|
Left: schema.Expression{RowData: []byte(`{"meta":{"key":"iifname"}}`)},
|
||||||
|
Right: schema.Expression{String: &sc.iface},
|
||||||
|
}},
|
||||||
|
{Verdict: schema.Verdict{Jump: &schema.ToTarget{Target: toChain}}},
|
||||||
|
},
|
||||||
|
Comment: ruleComment(sc.refID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SpoofChecker) jumpToChainRule(chain, toChain string) *schema.Rule {
|
||||||
|
return &schema.Rule{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Chain: chain,
|
||||||
|
Expr: []schema.Statement{
|
||||||
|
{Verdict: schema.Verdict{Jump: &schema.ToTarget{Target: toChain}}},
|
||||||
|
},
|
||||||
|
Comment: ruleComment(sc.refID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SpoofChecker) matchMacRule(chain string) *schema.Rule {
|
||||||
|
return &schema.Rule{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Chain: chain,
|
||||||
|
Expr: []schema.Statement{
|
||||||
|
{Match: &schema.Match{
|
||||||
|
Op: schema.OperEQ,
|
||||||
|
Left: schema.Expression{Payload: &schema.Payload{
|
||||||
|
Protocol: schema.PayloadProtocolEther,
|
||||||
|
Field: schema.PayloadFieldEtherSAddr,
|
||||||
|
}},
|
||||||
|
Right: schema.Expression{String: &sc.macAddress},
|
||||||
|
}},
|
||||||
|
{Verdict: schema.Verdict{SimpleVerdict: schema.SimpleVerdict{Return: true}}},
|
||||||
|
},
|
||||||
|
Comment: ruleComment(sc.refID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SpoofChecker) dropRule(chain string) *schema.Rule {
|
||||||
|
macRulesIndex := nft.NewRuleIndex()
|
||||||
|
return &schema.Rule{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Chain: chain,
|
||||||
|
Index: macRulesIndex.Next(),
|
||||||
|
Expr: []schema.Statement{
|
||||||
|
{Verdict: schema.Verdict{SimpleVerdict: schema.SimpleVerdict{Drop: true}}},
|
||||||
|
},
|
||||||
|
Comment: ruleComment(sc.refID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *SpoofChecker) baseChain() *schema.Chain {
|
||||||
|
chainPriority := -300
|
||||||
|
return &schema.Chain{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Name: preRoutingBaseChainName,
|
||||||
|
Type: schema.TypeFilter,
|
||||||
|
Hook: schema.HookPreRouting,
|
||||||
|
Prio: &chainPriority,
|
||||||
|
Policy: schema.PolicyAccept,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SpoofChecker) ifaceChain() *schema.Chain {
|
||||||
|
ifaceChainName := "cni-br-iface-" + sc.refID
|
||||||
|
return &schema.Chain{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Name: ifaceChainName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *SpoofChecker) macChain(ifaceChainName string) *schema.Chain {
|
||||||
|
macChainName := ifaceChainName + "-mac"
|
||||||
|
return &schema.Chain{
|
||||||
|
Family: schema.FamilyBridge,
|
||||||
|
Table: natTableName,
|
||||||
|
Name: macChainName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ruleComment(id string) string {
|
||||||
|
const refIDPrefix = "macspoofchk-"
|
||||||
|
return refIDPrefix + id
|
||||||
|
}
|
297
pkg/link/spoofcheck_test.go
Normal file
297
pkg/link/spoofcheck_test.go
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
// Copyright 2021 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package link_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/networkplumbing/go-nft/nft"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/containernetworking/plugins/pkg/link"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("spoofcheck", func() {
|
||||||
|
iface := "net0"
|
||||||
|
mac := "02:00:00:00:12:34"
|
||||||
|
id := "container99-net1"
|
||||||
|
|
||||||
|
Context("setup", func() {
|
||||||
|
It("succeeds", func() {
|
||||||
|
c := configurerStub{}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer(iface, mac, id, &c)
|
||||||
|
Expect(sc.Setup()).To(Succeed())
|
||||||
|
|
||||||
|
assertExpectedTableAndChainsInSetupConfig(c)
|
||||||
|
assertExpectedRulesInSetupConfig(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails to setup config when 1st apply is unsuccessful (declare table and chains)", func() {
|
||||||
|
c := &configurerStub{failFirstApplyConfig: true}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer(iface, mac, id, c)
|
||||||
|
Expect(sc.Setup()).To(MatchError("failed to setup spoof-check: " + errorFirstApplyText))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails to setup config when 2nd apply is unsuccessful (flush and add the rules)", func() {
|
||||||
|
c := &configurerStub{failSecondApplyConfig: true}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer(iface, mac, id, c)
|
||||||
|
Expect(sc.Setup()).To(MatchError("failed to setup spoof-check: " + errorSecondApplyText))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("teardown", func() {
|
||||||
|
It("succeeds", func() {
|
||||||
|
existingConfig := nft.NewConfig()
|
||||||
|
existingConfig.FromJSON([]byte(rowConfigWithRulesOnly()))
|
||||||
|
c := configurerStub{readConfig: existingConfig}
|
||||||
|
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer("", "", id, &c)
|
||||||
|
Expect(sc.Teardown()).To(Succeed())
|
||||||
|
|
||||||
|
assertExpectedBaseChainRuleDeletionInTeardownConfig(c)
|
||||||
|
assertExpectedRegularChainsDeletionInTeardownConfig(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails, 1st apply is unsuccessful (delete iface match rule)", func() {
|
||||||
|
config := nft.NewConfig()
|
||||||
|
config.FromJSON([]byte(rowConfigWithRulesOnly()))
|
||||||
|
c := &configurerStub{applyConfig: []*nft.Config{config}, readConfig: config, failFirstApplyConfig: true}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer("", "", id, c)
|
||||||
|
Expect(sc.Teardown()).To(MatchError(fmt.Sprintf(
|
||||||
|
"failed to teardown spoof-check: failed to delete iface match rule: %s, <nil>", errorFirstApplyText,
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails, read current config is unsuccessful", func() {
|
||||||
|
config := nft.NewConfig()
|
||||||
|
config.FromJSON([]byte(rowConfigWithRulesOnly()))
|
||||||
|
c := &configurerStub{applyConfig: []*nft.Config{config}, readConfig: config, failReadConfig: true}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer("", "", id, c)
|
||||||
|
Expect(sc.Teardown()).To(MatchError(fmt.Sprintf(
|
||||||
|
"failed to teardown spoof-check: %s, <nil>", errorReadText,
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails, 2nd apply is unsuccessful (delete the regular chains)", func() {
|
||||||
|
config := nft.NewConfig()
|
||||||
|
config.FromJSON([]byte(rowConfigWithRulesOnly()))
|
||||||
|
c := &configurerStub{applyConfig: []*nft.Config{config}, readConfig: config, failSecondApplyConfig: true}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer("", "", id, c)
|
||||||
|
Expect(sc.Teardown()).To(MatchError(fmt.Sprintf(
|
||||||
|
"failed to teardown spoof-check: <nil>, failed to delete regular chains: %s", errorSecondApplyText,
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails, both applies are unsuccessful", func() {
|
||||||
|
config := nft.NewConfig()
|
||||||
|
config.FromJSON([]byte(rowConfigWithRulesOnly()))
|
||||||
|
c := &configurerStub{
|
||||||
|
applyConfig: []*nft.Config{config},
|
||||||
|
readConfig: config,
|
||||||
|
failFirstApplyConfig: true,
|
||||||
|
failSecondApplyConfig: true,
|
||||||
|
}
|
||||||
|
sc := link.NewSpoofCheckerWithConfigurer("", "", id, c)
|
||||||
|
Expect(sc.Teardown()).To(MatchError(fmt.Sprintf(
|
||||||
|
"failed to teardown spoof-check: "+
|
||||||
|
"failed to delete iface match rule: %s, "+
|
||||||
|
"failed to delete regular chains: %s",
|
||||||
|
errorFirstApplyText, errorSecondApplyText,
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub) {
|
||||||
|
deleteRegularChainRulesJsonConfig, err := action.applyConfig[1].ToJSON()
|
||||||
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedDeleteRegularChainRulesJsonConfig := `
|
||||||
|
{"nftables": [
|
||||||
|
{"delete": {"chain": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"name": "cni-br-iface-container99-net1"
|
||||||
|
}}},
|
||||||
|
{"delete": {"chain": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"name": "cni-br-iface-container99-net1-mac"
|
||||||
|
}}}
|
||||||
|
]}`
|
||||||
|
|
||||||
|
ExpectWithOffset(1, string(deleteRegularChainRulesJsonConfig)).To(MatchJSON(expectedDeleteRegularChainRulesJsonConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertExpectedBaseChainRuleDeletionInTeardownConfig(action configurerStub) {
|
||||||
|
deleteBaseChainRuleJsonConfig, err := action.applyConfig[0].ToJSON()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedDeleteIfaceMatchRuleJsonConfig := `
|
||||||
|
{"nftables": [
|
||||||
|
{"delete": {"rule": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"chain": "PREROUTING",
|
||||||
|
"expr": [
|
||||||
|
{"match": {
|
||||||
|
"op": "==",
|
||||||
|
"left": {"meta": {"key": "iifname"}},
|
||||||
|
"right": "net0"
|
||||||
|
}},
|
||||||
|
{"jump": {"target": "cni-br-iface-container99-net1"}}
|
||||||
|
],
|
||||||
|
"comment": "macspoofchk-container99-net1"
|
||||||
|
}}}
|
||||||
|
]}`
|
||||||
|
Expect(string(deleteBaseChainRuleJsonConfig)).To(MatchJSON(expectedDeleteIfaceMatchRuleJsonConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func rowConfigWithRulesOnly() string {
|
||||||
|
return `
|
||||||
|
{"nftables":[
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"PREROUTING",
|
||||||
|
"expr":[
|
||||||
|
{"match":{"op":"==","left":{"meta":{"key":"iifname"}},"right":"net0"}},
|
||||||
|
{"jump":{"target":"cni-br-iface-container99-net1"}}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1",
|
||||||
|
"expr":[
|
||||||
|
{"jump":{"target":"cni-br-iface-container99-net1-mac"}}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac",
|
||||||
|
"expr":[
|
||||||
|
{"match":{
|
||||||
|
"op":"==",
|
||||||
|
"left":{"payload":{"protocol":"ether","field":"saddr"}},
|
||||||
|
"right":"02:00:00:00:12:34"
|
||||||
|
}},
|
||||||
|
{"return":null}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac",
|
||||||
|
"expr":[{"drop":null}],
|
||||||
|
"index":0,
|
||||||
|
"comment":"macspoofchk-container99-net1"}}
|
||||||
|
]}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertExpectedTableAndChainsInSetupConfig(c configurerStub) {
|
||||||
|
config := c.applyConfig[0]
|
||||||
|
jsonConfig, err := config.ToJSON()
|
||||||
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedConfig := `
|
||||||
|
{"nftables": [
|
||||||
|
{"table": {"family": "bridge", "name": "nat"}},
|
||||||
|
{"chain": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"name": "PREROUTING",
|
||||||
|
"type": "filter",
|
||||||
|
"hook": "prerouting",
|
||||||
|
"prio": -300,
|
||||||
|
"policy": "accept"
|
||||||
|
}},
|
||||||
|
{"chain": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"name": "cni-br-iface-container99-net1"
|
||||||
|
}},
|
||||||
|
{"chain": {
|
||||||
|
"family": "bridge",
|
||||||
|
"table": "nat",
|
||||||
|
"name": "cni-br-iface-container99-net1-mac"
|
||||||
|
}}
|
||||||
|
]}`
|
||||||
|
ExpectWithOffset(1, string(jsonConfig)).To(MatchJSON(expectedConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertExpectedRulesInSetupConfig(c configurerStub) {
|
||||||
|
config := c.applyConfig[1]
|
||||||
|
jsonConfig, err := config.ToJSON()
|
||||||
|
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedConfig := `
|
||||||
|
{"nftables":[
|
||||||
|
{"flush":{"chain":{"family":"bridge","table":"nat","name":"cni-br-iface-container99-net1"}}},
|
||||||
|
{"flush":{"chain":{"family":"bridge","table":"nat","name":"cni-br-iface-container99-net1-mac"}}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"PREROUTING",
|
||||||
|
"expr":[
|
||||||
|
{"match":{"op":"==","left":{"meta":{"key":"iifname"}},"right":"net0"}},
|
||||||
|
{"jump":{"target":"cni-br-iface-container99-net1"}}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1",
|
||||||
|
"expr":[
|
||||||
|
{"jump":{"target":"cni-br-iface-container99-net1-mac"}}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac",
|
||||||
|
"expr":[
|
||||||
|
{"match":{
|
||||||
|
"op":"==",
|
||||||
|
"left":{"payload":{"protocol":"ether","field":"saddr"}},
|
||||||
|
"right":"02:00:00:00:12:34"
|
||||||
|
}},
|
||||||
|
{"return":null}
|
||||||
|
],
|
||||||
|
"comment":"macspoofchk-container99-net1"}},
|
||||||
|
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac",
|
||||||
|
"expr":[{"drop":null}],
|
||||||
|
"index":0,
|
||||||
|
"comment":"macspoofchk-container99-net1"}}
|
||||||
|
]}`
|
||||||
|
ExpectWithOffset(1, string(jsonConfig)).To(MatchJSON(expectedConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
errorFirstApplyText = "1st apply failed"
|
||||||
|
errorSecondApplyText = "2nd apply failed"
|
||||||
|
errorReadText = "read failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type configurerStub struct {
|
||||||
|
applyConfig []*nft.Config
|
||||||
|
readConfig *nft.Config
|
||||||
|
|
||||||
|
applyCounter int
|
||||||
|
|
||||||
|
failFirstApplyConfig bool
|
||||||
|
failSecondApplyConfig bool
|
||||||
|
failReadConfig bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *configurerStub) Apply(c *nft.Config) error {
|
||||||
|
a.applyCounter++
|
||||||
|
if a.failFirstApplyConfig && a.applyCounter == 1 {
|
||||||
|
return fmt.Errorf(errorFirstApplyText)
|
||||||
|
}
|
||||||
|
if a.failSecondApplyConfig && a.applyCounter == 2 {
|
||||||
|
return fmt.Errorf(errorSecondApplyText)
|
||||||
|
}
|
||||||
|
a.applyConfig = append(a.applyConfig, c)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *configurerStub) Read() (*nft.Config, error) {
|
||||||
|
if a.failReadConfig {
|
||||||
|
return nil, fmt.Errorf(errorReadText)
|
||||||
|
}
|
||||||
|
return a.readConfig, nil
|
||||||
|
}
|
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -33,6 +34,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
"github.com/containernetworking/plugins/pkg/ipam"
|
"github.com/containernetworking/plugins/pkg/ipam"
|
||||||
|
"github.com/containernetworking/plugins/pkg/link"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/utils"
|
"github.com/containernetworking/plugins/pkg/utils"
|
||||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||||
@ -55,6 +57,7 @@ type NetConf struct {
|
|||||||
HairpinMode bool `json:"hairpinMode"`
|
HairpinMode bool `json:"hairpinMode"`
|
||||||
PromiscMode bool `json:"promiscMode"`
|
PromiscMode bool `json:"promiscMode"`
|
||||||
Vlan int `json:"vlan"`
|
Vlan int `json:"vlan"`
|
||||||
|
MacSpoofChk bool `json:"macspoofchk,omitempty"`
|
||||||
|
|
||||||
Args struct {
|
Args struct {
|
||||||
Cni BridgeArgs `json:"cni,omitempty"`
|
Cni BridgeArgs `json:"cni,omitempty"`
|
||||||
@ -460,6 +463,20 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.MacSpoofChk {
|
||||||
|
sc := link.NewSpoofChecker(hostInterface.Name, containerInterface.Mac, uniqueID(args.ContainerID, args.IfName))
|
||||||
|
if err := sc.Setup(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if !success {
|
||||||
|
if err := sc.Teardown(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
if isLayer3 {
|
if isLayer3 {
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||||
@ -658,6 +675,13 @@ func cmdDel(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.MacSpoofChk {
|
||||||
|
sc := link.NewSpoofChecker("", "", uniqueID(args.ContainerID, args.IfName))
|
||||||
|
if err := sc.Teardown(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if isLayer3 && n.IPMasq {
|
if isLayer3 && n.IPMasq {
|
||||||
chain := utils.FormatChainName(n.Name, args.ContainerID)
|
chain := utils.FormatChainName(n.Name, args.ContainerID)
|
||||||
comment := utils.FormatComment(n.Name, args.ContainerID)
|
comment := utils.FormatComment(n.Name, args.ContainerID)
|
||||||
@ -938,3 +962,7 @@ func cmdCheck(args *skel.CmdArgs) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uniqueID(containerID, cniIface string) string {
|
||||||
|
return containerID + "-" + cniIface
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
|
"github.com/networkplumbing/go-nft/nft"
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
@ -65,19 +66,20 @@ type Net struct {
|
|||||||
// testCase defines the CNI network configuration and the expected
|
// testCase defines the CNI network configuration and the expected
|
||||||
// bridge addresses for a test case.
|
// bridge addresses for a test case.
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
cniVersion string // CNI Version
|
cniVersion string // CNI Version
|
||||||
subnet string // Single subnet config: Subnet CIDR
|
subnet string // Single subnet config: Subnet CIDR
|
||||||
gateway string // Single subnet config: Gateway
|
gateway string // Single subnet config: Gateway
|
||||||
ranges []rangeInfo // Ranges list (multiple subnets config)
|
ranges []rangeInfo // Ranges list (multiple subnets config)
|
||||||
isGW bool
|
isGW bool
|
||||||
isLayer2 bool
|
isLayer2 bool
|
||||||
expGWCIDRs []string // Expected gateway addresses in CIDR form
|
expGWCIDRs []string // Expected gateway addresses in CIDR form
|
||||||
vlan int
|
vlan int
|
||||||
ipMasq bool
|
ipMasq bool
|
||||||
AddErr020 string
|
macspoofchk bool
|
||||||
DelErr020 string
|
AddErr020 string
|
||||||
AddErr010 string
|
DelErr020 string
|
||||||
DelErr010 string
|
AddErr010 string
|
||||||
|
DelErr010 string
|
||||||
|
|
||||||
envArgs string // CNI_ARGS
|
envArgs string // CNI_ARGS
|
||||||
runtimeConfig struct {
|
runtimeConfig struct {
|
||||||
@ -164,6 +166,9 @@ const (
|
|||||||
ipamEndStr = `
|
ipamEndStr = `
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
macspoofchkFormat = `,
|
||||||
|
"macspoofchk": %t`
|
||||||
|
|
||||||
argsFormat = `,
|
argsFormat = `,
|
||||||
"args": {
|
"args": {
|
||||||
"cni": {
|
"cni": {
|
||||||
@ -193,6 +198,9 @@ func (tc testCase) netConfJSON(dataDir string) string {
|
|||||||
if tc.runtimeConfig.mac != "" {
|
if tc.runtimeConfig.mac != "" {
|
||||||
conf += fmt.Sprintf(runtimeConfig, tc.runtimeConfig.mac)
|
conf += fmt.Sprintf(runtimeConfig, tc.runtimeConfig.mac)
|
||||||
}
|
}
|
||||||
|
if tc.macspoofchk {
|
||||||
|
conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk)
|
||||||
|
}
|
||||||
|
|
||||||
if !tc.isLayer2 {
|
if !tc.isLayer2 {
|
||||||
conf += netDefault
|
conf += netDefault
|
||||||
@ -2175,6 +2183,35 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] configures mac spoof-check (no mac spoofing)", ver), func() {
|
||||||
|
Expect(originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
tc := testCase{
|
||||||
|
cniVersion: ver,
|
||||||
|
subnet: "10.1.2.0/24",
|
||||||
|
macspoofchk: true,
|
||||||
|
}
|
||||||
|
args := tc.createCmdArgs(originalNS, dataDir)
|
||||||
|
_, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
assertMacSpoofCheckRulesExist()
|
||||||
|
|
||||||
|
Expect(testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
if err := cmdDel(args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
assertMacSpoofCheckRulesMissing()
|
||||||
|
return nil
|
||||||
|
})).To(Succeed())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})).To(Succeed())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
It("check vlan id when loading net conf", func() {
|
It("check vlan id when loading net conf", func() {
|
||||||
@ -2211,3 +2248,50 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func assertMacSpoofCheckRulesExist() {
|
||||||
|
assertMacSpoofCheckRules(
|
||||||
|
func(actual interface{}, expectedLen int) {
|
||||||
|
ExpectWithOffset(3, actual).To(HaveLen(expectedLen))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertMacSpoofCheckRulesMissing() {
|
||||||
|
assertMacSpoofCheckRules(
|
||||||
|
func(actual interface{}, _ int) {
|
||||||
|
ExpectWithOffset(3, actual).To(BeEmpty())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertMacSpoofCheckRules(assert func(actual interface{}, expectedLen int)) {
|
||||||
|
c, err := nft.ReadConfig()
|
||||||
|
ExpectWithOffset(2, err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedTable := nft.NewTable("nat", "bridge")
|
||||||
|
filter := nft.TypeFilter
|
||||||
|
hook := nft.HookPreRouting
|
||||||
|
prio := -300
|
||||||
|
policy := nft.PolicyAccept
|
||||||
|
expectedBaseChain := nft.NewChain(expectedTable, "PREROUTING", &filter, &hook, &prio, &policy)
|
||||||
|
|
||||||
|
assert(c.LookupRule(nft.NewRule(
|
||||||
|
expectedTable,
|
||||||
|
expectedBaseChain,
|
||||||
|
nil, nil, nil,
|
||||||
|
"macspoofchk-dummy-0-eth0",
|
||||||
|
)), 1)
|
||||||
|
|
||||||
|
assert(c.LookupRule(nft.NewRule(
|
||||||
|
expectedTable,
|
||||||
|
nft.NewRegularChain(expectedTable, "cni-br-iface-dummy-0-eth0"),
|
||||||
|
nil, nil, nil,
|
||||||
|
"macspoofchk-dummy-0-eth0",
|
||||||
|
)), 1)
|
||||||
|
|
||||||
|
assert(c.LookupRule(nft.NewRule(
|
||||||
|
expectedTable,
|
||||||
|
nft.NewRegularChain(expectedTable, "cni-br-iface-dummy-0-eth0-mac"),
|
||||||
|
nil, nil, nil,
|
||||||
|
"macspoofchk-dummy-0-eth0",
|
||||||
|
)), 2)
|
||||||
|
}
|
||||||
|
201
vendor/github.com/networkplumbing/go-nft/LICENSE
generated
vendored
Normal file
201
vendor/github.com/networkplumbing/go-nft/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
82
vendor/github.com/networkplumbing/go-nft/nft/chain.go
generated
vendored
Normal file
82
vendor/github.com/networkplumbing/go-nft/nft/chain.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nft
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChainType string
|
||||||
|
type ChainHook string
|
||||||
|
type ChainPolicy string
|
||||||
|
|
||||||
|
// Chain Types
|
||||||
|
const (
|
||||||
|
TypeFilter ChainType = schema.TypeFilter
|
||||||
|
TypeNAT ChainType = schema.TypeNAT
|
||||||
|
TypeRoute ChainType = schema.TypeRoute
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chain Hooks
|
||||||
|
const (
|
||||||
|
HookPreRouting ChainHook = schema.HookPreRouting
|
||||||
|
HookInput ChainHook = schema.HookInput
|
||||||
|
HookOutput ChainHook = schema.HookOutput
|
||||||
|
HookForward ChainHook = schema.HookForward
|
||||||
|
HookPostRouting ChainHook = schema.HookPostRouting
|
||||||
|
HookIngress ChainHook = schema.HookIngress
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chain Policies
|
||||||
|
const (
|
||||||
|
PolicyAccept ChainPolicy = schema.PolicyAccept
|
||||||
|
PolicyDrop ChainPolicy = schema.PolicyDrop
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRegularChain returns a new schema chain structure for a regular chain.
|
||||||
|
func NewRegularChain(table *schema.Table, name string) *schema.Chain {
|
||||||
|
return NewChain(table, name, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChain returns a new schema chain structure for a base chain.
|
||||||
|
// For base chains, all arguments are required except the policy.
|
||||||
|
// Missing arguments will cause an error once the config is applied.
|
||||||
|
func NewChain(table *schema.Table, name string, ctype *ChainType, hook *ChainHook, prio *int, policy *ChainPolicy) *schema.Chain {
|
||||||
|
c := &schema.Chain{
|
||||||
|
Family: table.Family,
|
||||||
|
Table: table.Name,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctype != nil {
|
||||||
|
c.Type = string(*ctype)
|
||||||
|
}
|
||||||
|
if hook != nil {
|
||||||
|
c.Hook = string(*hook)
|
||||||
|
}
|
||||||
|
if prio != nil {
|
||||||
|
c.Prio = prio
|
||||||
|
}
|
||||||
|
if policy != nil {
|
||||||
|
c.Policy = string(*policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
45
vendor/github.com/networkplumbing/go-nft/nft/config.go
generated
vendored
Normal file
45
vendor/github.com/networkplumbing/go-nft/nft/config.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nft
|
||||||
|
|
||||||
|
import (
|
||||||
|
nftconfig "github.com/networkplumbing/go-nft/nft/config"
|
||||||
|
nftexec "github.com/networkplumbing/go-nft/nft/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config = nftconfig.Config
|
||||||
|
|
||||||
|
// NewConfig returns a new nftables config structure.
|
||||||
|
func NewConfig() *nftconfig.Config {
|
||||||
|
return nftconfig.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadConfig loads the nftables configuration from the system and
|
||||||
|
// returns it as a nftables config structure.
|
||||||
|
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
|
||||||
|
func ReadConfig() (*Config, error) {
|
||||||
|
return nftexec.ReadConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyConfig applies the given nftables config on the system.
|
||||||
|
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
|
||||||
|
func ApplyConfig(c *Config) error {
|
||||||
|
return nftexec.ApplyConfig(c)
|
||||||
|
}
|
80
vendor/github.com/networkplumbing/go-nft/nft/config/chain.go
generated
vendored
Normal file
80
vendor/github.com/networkplumbing/go-nft/nft/config/chain.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddChain appends the given chain to the nftable config.
|
||||||
|
// The chain is added without an explicit action (`add`).
|
||||||
|
// Adding multiple times the same chain has no affect when the config is applied.
|
||||||
|
func (c *Config) AddChain(chain *schema.Chain) {
|
||||||
|
nftable := schema.Nftable{Chain: chain}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteChain appends a given chain to the nftable config
|
||||||
|
// with the `delete` action.
|
||||||
|
// Attempting to delete a non-existing chain, results with a failure when the config is applied.
|
||||||
|
// The chain must not contain any rules or be used as a jump target.
|
||||||
|
func (c *Config) DeleteChain(chain *schema.Chain) {
|
||||||
|
nftable := schema.Nftable{Delete: &schema.Objects{Chain: chain}}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlushChain appends a given chain to the nftable config
|
||||||
|
// with the `flush` action.
|
||||||
|
// All rules under the chain are removed (when applied).
|
||||||
|
// Attempting to flush a non-existing chain, results with a failure when the config is applied.
|
||||||
|
func (c *Config) FlushChain(chain *schema.Chain) {
|
||||||
|
nftable := schema.Nftable{Flush: &schema.Objects{Chain: chain}}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupChain searches the configuration for a matching chain and returns it.
|
||||||
|
// The chain is matched first by the table and chain name.
|
||||||
|
// Other matching fields are optional (for matching base chains).
|
||||||
|
// Mutating the returned chain will result in mutating the configuration.
|
||||||
|
func (c *Config) LookupChain(toFind *schema.Chain) *schema.Chain {
|
||||||
|
for _, nftable := range c.Nftables {
|
||||||
|
if chain := nftable.Chain; chain != nil {
|
||||||
|
match := chain.Table == toFind.Table && chain.Family == toFind.Family && chain.Name == toFind.Name
|
||||||
|
if match {
|
||||||
|
if t := toFind.Type; t != "" {
|
||||||
|
match = match && chain.Type == t
|
||||||
|
}
|
||||||
|
if h := toFind.Hook; h != "" {
|
||||||
|
match = match && chain.Hook == h
|
||||||
|
}
|
||||||
|
if p := toFind.Prio; p != nil {
|
||||||
|
match = match && chain.Prio != nil && *chain.Prio == *p
|
||||||
|
}
|
||||||
|
if p := toFind.Policy; p != "" {
|
||||||
|
match = match && chain.Policy == p
|
||||||
|
}
|
||||||
|
if match {
|
||||||
|
return chain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
59
vendor/github.com/networkplumbing/go-nft/nft/config/config.go
generated
vendored
Normal file
59
vendor/github.com/networkplumbing/go-nft/nft/config/config.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
schema.Root
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new nftables config structure.
|
||||||
|
func New() *Config {
|
||||||
|
c := &Config{}
|
||||||
|
c.Nftables = []schema.Nftable{}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON returns the JSON encoding of the nftables config.
|
||||||
|
func (c *Config) ToJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(*c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromJSON decodes the provided JSON-encoded data and populates the nftables config.
|
||||||
|
func (c *Config) FromJSON(data []byte) error {
|
||||||
|
if err := json.Unmarshal(data, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlushRuleset adds a command to the nftables config that erases all the configuration when applied.
|
||||||
|
// It is commonly used as the first config instruction, followed by a declarative configuration.
|
||||||
|
// When used, any previous configuration is flushed away before adding the new one.
|
||||||
|
// Calling FlushRuleset updates the configuration and will take effect only
|
||||||
|
// when applied on the system.
|
||||||
|
func (c *Config) FlushRuleset() {
|
||||||
|
c.Nftables = append(c.Nftables, schema.Nftable{Flush: &schema.Objects{Ruleset: true}})
|
||||||
|
}
|
94
vendor/github.com/networkplumbing/go-nft/nft/config/rule.go
generated
vendored
Normal file
94
vendor/github.com/networkplumbing/go-nft/nft/config/rule.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddRule appends the given rule to the nftable config.
|
||||||
|
// The rule is added without an explicit action (`add`).
|
||||||
|
// Adding multiple times the same rule will result in multiple identical rules when applied.
|
||||||
|
func (c *Config) AddRule(rule *schema.Rule) {
|
||||||
|
nftable := schema.Nftable{Rule: rule}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRule appends a given rule to the nftable config
|
||||||
|
// with the `delete` action.
|
||||||
|
// A rule is identified by its handle ID and it must be present in the given rule.
|
||||||
|
// Attempting to delete a non-existing rule, results with a failure when the config is applied.
|
||||||
|
// A common usage is to use LookupRule() and then to pass the result to DeleteRule.
|
||||||
|
func (c *Config) DeleteRule(rule *schema.Rule) {
|
||||||
|
nftable := schema.Nftable{Delete: &schema.Objects{Rule: rule}}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupRule searches the configuration for a matching rule and returns it.
|
||||||
|
// The rule is matched first by the table and chain.
|
||||||
|
// Other matching fields are optional (nil or an empty string arguments imply no-matching).
|
||||||
|
// Mutating the returned chain will result in mutating the configuration.
|
||||||
|
func (c *Config) LookupRule(toFind *schema.Rule) []*schema.Rule {
|
||||||
|
var rules []*schema.Rule
|
||||||
|
|
||||||
|
for _, nftable := range c.Nftables {
|
||||||
|
if r := nftable.Rule; r != nil {
|
||||||
|
match := r.Table == toFind.Table && r.Family == toFind.Family && r.Chain == toFind.Chain
|
||||||
|
if match {
|
||||||
|
if h := toFind.Handle; h != nil {
|
||||||
|
match = match && r.Handle != nil && *r.Handle == *h
|
||||||
|
}
|
||||||
|
if i := toFind.Index; i != nil {
|
||||||
|
match = match && r.Index != nil && *r.Index == *i
|
||||||
|
}
|
||||||
|
if co := toFind.Comment; co != "" {
|
||||||
|
match = match && r.Comment == co
|
||||||
|
}
|
||||||
|
if toFindStatements := toFind.Expr; toFindStatements != nil {
|
||||||
|
if match = match && len(toFindStatements) == len(r.Expr); match {
|
||||||
|
for i, toFindStatement := range toFindStatements {
|
||||||
|
equal, err := areStatementsEqual(toFindStatement, r.Expr[i])
|
||||||
|
match = match && err == nil && equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if match {
|
||||||
|
rules = append(rules, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func areStatementsEqual(statementA, statementB schema.Statement) (bool, error) {
|
||||||
|
statementARow, err := json.Marshal(statementA)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
statementBRow, err := json.Marshal(statementB)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return bytes.Equal(statementARow, statementBRow), nil
|
||||||
|
}
|
63
vendor/github.com/networkplumbing/go-nft/nft/config/table.go
generated
vendored
Normal file
63
vendor/github.com/networkplumbing/go-nft/nft/config/table.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddTable appends the given table to the nftable config.
|
||||||
|
// The table is added without an explicit action (`add`).
|
||||||
|
// Adding multiple times the same table has no effect when the config is applied.
|
||||||
|
func (c *Config) AddTable(table *schema.Table) {
|
||||||
|
nftable := schema.Nftable{Table: table}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTable appends a given table to the nftable config
|
||||||
|
// with the `delete` action.
|
||||||
|
// Attempting to delete a non-existing table, results with a failure when the config is applied.
|
||||||
|
// All chains and rules under the table are removed as well (when applied).
|
||||||
|
func (c *Config) DeleteTable(table *schema.Table) {
|
||||||
|
nftable := schema.Nftable{Delete: &schema.Objects{Table: table}}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlushTable appends a given table to the nftable config
|
||||||
|
// with the `flush` action.
|
||||||
|
// All chains and rules under the table are removed (when applied).
|
||||||
|
// Attempting to flush a non-existing table, results with a failure when the config is applied.
|
||||||
|
func (c *Config) FlushTable(table *schema.Table) {
|
||||||
|
nftable := schema.Nftable{Flush: &schema.Objects{Table: table}}
|
||||||
|
c.Nftables = append(c.Nftables, nftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupTable searches the configuration for a matching table and returns it.
|
||||||
|
// Mutating the returned table will result in mutating the configuration.
|
||||||
|
func (c *Config) LookupTable(toFind *schema.Table) *schema.Table {
|
||||||
|
for _, nftable := range c.Nftables {
|
||||||
|
if t := nftable.Table; t != nil {
|
||||||
|
if t.Name == toFind.Name && t.Family == toFind.Family {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
48
vendor/github.com/networkplumbing/go-nft/nft/doc.go
generated
vendored
Normal file
48
vendor/github.com/networkplumbing/go-nft/nft/doc.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package nft provides a GO API to nftables.
|
||||||
|
// Together with the schema package, it allows to build, read and apply
|
||||||
|
// nftables configuration on a supporting system.
|
||||||
|
//
|
||||||
|
// The schema structures are based on libnftables-json (https://www.mankier.com/5/libnftables-json)
|
||||||
|
// and implement a subset of them.
|
||||||
|
//
|
||||||
|
// To create a new configuration, use `NewConfig` followed by methods
|
||||||
|
// which populates the configuration with tables, chains and rules, accompanied
|
||||||
|
// to specific actions (add, delete, flush).
|
||||||
|
//
|
||||||
|
// config := nft.NewConfig()
|
||||||
|
// table := nft.NewTable("mytable", nft.FamilyIP)
|
||||||
|
// config.AddTable(table)
|
||||||
|
// chain := nft.NewRegularChain(table, "mychain")
|
||||||
|
// config.AddChain(chain)
|
||||||
|
// rule := nft.NewRule(table, chain, statements, nil, nil, "mycomment")
|
||||||
|
//
|
||||||
|
// To apply a configuration on the system, use the `ApplyConfig` function.
|
||||||
|
// err := nft.ApplyConfig(config)
|
||||||
|
//
|
||||||
|
// To read the configuration from the system, use the `ReadConfig` function.
|
||||||
|
// config, err := nft.ReadConfig()
|
||||||
|
//
|
||||||
|
// For full setup example, see the integration test: tests/config_test.go
|
||||||
|
//
|
||||||
|
// The nft package is dependent on the `nft` binary and the kernel nftables
|
||||||
|
// support.
|
||||||
|
package nft
|
102
vendor/github.com/networkplumbing/go-nft/nft/exec/exec.go
generated
vendored
Normal file
102
vendor/github.com/networkplumbing/go-nft/nft/exec/exec.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package exec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
nftconfig "github.com/networkplumbing/go-nft/nft/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cmdBin = "nft"
|
||||||
|
cmdFile = "-f"
|
||||||
|
cmdJSON = "-j"
|
||||||
|
cmdList = "list"
|
||||||
|
cmdRuleset = "ruleset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadConfig loads the nftables configuration from the system and
|
||||||
|
// returns it as a nftables config structure.
|
||||||
|
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
|
||||||
|
func ReadConfig() (*nftconfig.Config, error) {
|
||||||
|
stdout, err := execCommand(cmdJSON, cmdList, cmdRuleset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := nftconfig.New()
|
||||||
|
if err := config.FromJSON(stdout.Bytes()); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to list ruleset: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyConfig applies the given nftables config on the system.
|
||||||
|
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
|
||||||
|
func ApplyConfig(c *nftconfig.Config) error {
|
||||||
|
data, err := c.ToJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpFile, err := ioutil.TempFile(os.TempDir(), "spoofcheck-")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create temporary file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpFile.Name())
|
||||||
|
|
||||||
|
if _, err = tmpFile.Write(data); err != nil {
|
||||||
|
return fmt.Errorf("failed to write to temporary file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpFile.Close(); err != nil {
|
||||||
|
return fmt.Errorf("failed to close temporary file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := execCommand(cmdJSON, cmdFile, tmpFile.Name()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func execCommand(args ...string) (*bytes.Buffer, error) {
|
||||||
|
cmd := exec.Command(cmdBin, args...)
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"failed to execute %s %s: %v stdout:'%s' stderr:'%s'",
|
||||||
|
cmd.Path, strings.Join(cmd.Args, " "), err, stdout.String(), stderr.String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stdout, nil
|
||||||
|
}
|
58
vendor/github.com/networkplumbing/go-nft/nft/rule.go
generated
vendored
Normal file
58
vendor/github.com/networkplumbing/go-nft/nft/rule.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nft
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRule returns a new schema rule structure.
|
||||||
|
func NewRule(table *schema.Table, chain *schema.Chain, expr []schema.Statement, handle *int, index *int, comment string) *schema.Rule {
|
||||||
|
c := &schema.Rule{
|
||||||
|
Family: table.Family,
|
||||||
|
Table: table.Name,
|
||||||
|
Chain: chain.Name,
|
||||||
|
Expr: expr,
|
||||||
|
Handle: handle,
|
||||||
|
Index: index,
|
||||||
|
Comment: comment,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleIndex int
|
||||||
|
|
||||||
|
// NewRuleIndex returns a rule index object which acts as an iterator.
|
||||||
|
// When multiple rules are added to a chain, index allows to define an order between them.
|
||||||
|
// The first rule which is added to a chain should have no index (it is assigned index 0),
|
||||||
|
// following rules should have the index set, referencing after/before which rule the new one is to be added/inserted.
|
||||||
|
func NewRuleIndex() *RuleIndex {
|
||||||
|
var index RuleIndex = -1
|
||||||
|
return &index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next iteration value as an integer pointer.
|
||||||
|
// When first time called, it returns the value 0.
|
||||||
|
func (i *RuleIndex) Next() *int {
|
||||||
|
*i++
|
||||||
|
var index = int(*i)
|
||||||
|
return &index
|
||||||
|
}
|
53
vendor/github.com/networkplumbing/go-nft/nft/schema/chain.go
generated
vendored
Normal file
53
vendor/github.com/networkplumbing/go-nft/nft/schema/chain.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schema
|
||||||
|
|
||||||
|
// Chain Types
|
||||||
|
const (
|
||||||
|
TypeFilter = "filter"
|
||||||
|
TypeNAT = "nat"
|
||||||
|
TypeRoute = "route"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chain Hooks
|
||||||
|
const (
|
||||||
|
HookPreRouting = "prerouting"
|
||||||
|
HookInput = "input"
|
||||||
|
HookOutput = "output"
|
||||||
|
HookForward = "forward"
|
||||||
|
HookPostRouting = "postrouting"
|
||||||
|
HookIngress = "ingress"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chain Policies
|
||||||
|
const (
|
||||||
|
PolicyAccept = "accept"
|
||||||
|
PolicyDrop = "drop"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Chain struct {
|
||||||
|
Family string `json:"family"`
|
||||||
|
Table string `json:"table"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Hook string `json:"hook,omitempty"`
|
||||||
|
Prio *int `json:"prio,omitempty"`
|
||||||
|
Policy string `json:"policy,omitempty"`
|
||||||
|
}
|
366
vendor/github.com/networkplumbing/go-nft/nft/schema/rule.go
generated
vendored
Normal file
366
vendor/github.com/networkplumbing/go-nft/nft/schema/rule.go
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Rule struct {
|
||||||
|
Family string `json:"family"`
|
||||||
|
Table string `json:"table"`
|
||||||
|
Chain string `json:"chain"`
|
||||||
|
Expr []Statement `json:"expr,omitempty"`
|
||||||
|
Handle *int `json:"handle,omitempty"`
|
||||||
|
Index *int `json:"index,omitempty"`
|
||||||
|
Comment string `json:"comment,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Statement struct {
|
||||||
|
Counter *Counter `json:"counter,omitempty"`
|
||||||
|
Match *Match `json:"match,omitempty"`
|
||||||
|
Verdict
|
||||||
|
Nat
|
||||||
|
}
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
Packets int `json:"packets"`
|
||||||
|
Bytes int `json:"bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Nat struct {
|
||||||
|
Snat *Snat `json:"snat,omitempty"`
|
||||||
|
Dnat *Dnat `json:"dnat,omitempty"`
|
||||||
|
Masquerade *Masquerade `json:"masquerade,omitempty"`
|
||||||
|
Redirect *Redirect `json:"redirect,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Snat struct {
|
||||||
|
Addr *Expression `json:"addr,omitempty"`
|
||||||
|
Family *string `json:"family,omitempty"`
|
||||||
|
Port *Expression `json:"port,omitempty"`
|
||||||
|
Flags *Flags `json:"flags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dnat struct {
|
||||||
|
Addr *Expression `json:"addr,omitempty"`
|
||||||
|
Family *string `json:"family,omitempty"`
|
||||||
|
Port *Expression `json:"port,omitempty"`
|
||||||
|
Flags *Flags `json:"flags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const masquerade = "masquerade"
|
||||||
|
|
||||||
|
type Masquerade struct {
|
||||||
|
Enabled bool `json:"-"`
|
||||||
|
Port *Expression `json:"port,omitempty"`
|
||||||
|
Flags *Flags `json:"flags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirect = "redirect"
|
||||||
|
|
||||||
|
type Redirect struct {
|
||||||
|
Enabled bool `json:"-"`
|
||||||
|
Port *Expression `json:"port,omitempty"`
|
||||||
|
Flags *Flags `json:"flags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flags struct {
|
||||||
|
Flags []string `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NAT Flags
|
||||||
|
const (
|
||||||
|
NATFlagRandom = "random"
|
||||||
|
NATFlagFullyRandom = "fully-random"
|
||||||
|
NATFlagPersistent = "persistent"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Verdict struct {
|
||||||
|
SimpleVerdict
|
||||||
|
Jump *ToTarget `json:"jump,omitempty"`
|
||||||
|
Goto *ToTarget `json:"goto,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleVerdict struct {
|
||||||
|
Accept bool `json:"-"`
|
||||||
|
Continue bool `json:"-"`
|
||||||
|
Drop bool `json:"-"`
|
||||||
|
Return bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToTarget struct {
|
||||||
|
Target string `json:"target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Op string `json:"op"`
|
||||||
|
Left Expression `json:"left"`
|
||||||
|
Right Expression `json:"right"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Expression struct {
|
||||||
|
String *string `json:"-"`
|
||||||
|
Bool *bool `json:"-"`
|
||||||
|
Float64 *float64 `json:"-"`
|
||||||
|
Payload *Payload `json:"payload,omitempty"`
|
||||||
|
// RowData accepts arbitrary data which cannot be composed from the existing schema.
|
||||||
|
// Use `json.RawMessage()` or `[]byte()` for the value.
|
||||||
|
// Example:
|
||||||
|
// `schema.Expression{RowData: json.RawMessage(`{"meta":{"key":"iifname"}}`)}`
|
||||||
|
RowData json.RawMessage `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Payload struct {
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Field string `json:"field"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verdict Operations
|
||||||
|
const (
|
||||||
|
VerdictAccept = "accept"
|
||||||
|
VerdictContinue = "continue"
|
||||||
|
VerdictDrop = "drop"
|
||||||
|
VerdictReturn = "return"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Match Operators
|
||||||
|
const (
|
||||||
|
OperAND = "&" // Binary AND
|
||||||
|
OperOR = "|" // Binary OR
|
||||||
|
OperXOR = "^" // Binary XOR
|
||||||
|
OperLSH = "<<" // Left shift
|
||||||
|
OperRSH = ">>" // Right shift
|
||||||
|
OperEQ = "==" // Equal
|
||||||
|
OperNEQ = "!=" // Not equal
|
||||||
|
OperLS = "<" // Less than
|
||||||
|
OperGR = ">" // Greater than
|
||||||
|
OperLSE = "<=" // Less than or equal to
|
||||||
|
OperGRE = ">=" // Greater than or equal to
|
||||||
|
OperIN = "in" // Perform a lookup, i.e. test if bits on RHS are contained in LHS value
|
||||||
|
)
|
||||||
|
|
||||||
|
// Payload Expressions
|
||||||
|
const (
|
||||||
|
PayloadKey = "payload"
|
||||||
|
// Ethernet
|
||||||
|
PayloadProtocolEther = "ether"
|
||||||
|
PayloadFieldEtherDAddr = "daddr"
|
||||||
|
PayloadFieldEtherSAddr = "saddr"
|
||||||
|
PayloadFieldEtherType = "type"
|
||||||
|
|
||||||
|
// IP (common)
|
||||||
|
PayloadFieldIPVer = "version"
|
||||||
|
PayloadFieldIPDscp = "dscp"
|
||||||
|
PayloadFieldIPEcn = "ecn"
|
||||||
|
PayloadFieldIPLen = "length"
|
||||||
|
PayloadFieldIPSAddr = "saddr"
|
||||||
|
PayloadFieldIPDAddr = "daddr"
|
||||||
|
|
||||||
|
// IPv4
|
||||||
|
PayloadProtocolIP4 = "ip"
|
||||||
|
PayloadFieldIP4HdrLen = "hdrlength"
|
||||||
|
PayloadFieldIP4Id = "id"
|
||||||
|
PayloadFieldIP4FragOff = "frag-off"
|
||||||
|
PayloadFieldIP4Ttl = "ttl"
|
||||||
|
PayloadFieldIP4Protocol = "protocol"
|
||||||
|
PayloadFieldIP4Chksum = "checksum"
|
||||||
|
|
||||||
|
// IPv6
|
||||||
|
PayloadProtocolIP6 = "ip6"
|
||||||
|
PayloadFieldIP6FlowLabel = "flowlabel"
|
||||||
|
PayloadFieldIP6NextHdr = "nexthdr"
|
||||||
|
PayloadFieldIP6HopLimit = "hoplimit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Statement) MarshalJSON() ([]byte, error) {
|
||||||
|
type _Statement Statement
|
||||||
|
statement := _Statement(s)
|
||||||
|
|
||||||
|
// Convert to a dynamic structure
|
||||||
|
data, err := json.Marshal(statement)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dynamicStructure := make(map[string]json.RawMessage)
|
||||||
|
if err := json.Unmarshal(data, &dynamicStructure); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case s.Accept:
|
||||||
|
dynamicStructure[VerdictAccept] = nil
|
||||||
|
case s.Continue:
|
||||||
|
dynamicStructure[VerdictContinue] = nil
|
||||||
|
case s.Drop:
|
||||||
|
dynamicStructure[VerdictDrop] = nil
|
||||||
|
case s.Return:
|
||||||
|
dynamicStructure[VerdictReturn] = nil
|
||||||
|
case s.Masquerade != nil && s.Masquerade.Enabled && s.Masquerade.Port == nil && s.Masquerade.Flags == nil:
|
||||||
|
dynamicStructure[masquerade] = nil
|
||||||
|
case s.Redirect != nil && s.Redirect.Enabled && s.Redirect.Port == nil && s.Redirect.Flags == nil:
|
||||||
|
dynamicStructure[redirect] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err = json.Marshal(dynamicStructure)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Statement) UnmarshalJSON(data []byte) error {
|
||||||
|
type _Statement Statement
|
||||||
|
statement := _Statement{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &statement); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*s = Statement(statement)
|
||||||
|
|
||||||
|
dynamicStructure := make(map[string]json.RawMessage)
|
||||||
|
if err := json.Unmarshal(data, &dynamicStructure); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, s.Accept = dynamicStructure[VerdictAccept]
|
||||||
|
_, s.Continue = dynamicStructure[VerdictContinue]
|
||||||
|
_, s.Drop = dynamicStructure[VerdictDrop]
|
||||||
|
_, s.Return = dynamicStructure[VerdictReturn]
|
||||||
|
|
||||||
|
if _, masqueradeDefined := dynamicStructure[masquerade]; s.Masquerade == nil && masqueradeDefined {
|
||||||
|
s.Masquerade = &Masquerade{Enabled: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, redirectDefined := dynamicStructure[redirect]; s.Redirect == nil && redirectDefined {
|
||||||
|
s.Redirect = &Redirect{Enabled: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Expression) MarshalJSON() ([]byte, error) {
|
||||||
|
var dynamicStruct interface{}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case e.RowData != nil:
|
||||||
|
return e.RowData, nil
|
||||||
|
case e.String != nil:
|
||||||
|
dynamicStruct = *e.String
|
||||||
|
case e.Float64 != nil:
|
||||||
|
dynamicStruct = *e.Float64
|
||||||
|
case e.Bool != nil:
|
||||||
|
dynamicStruct = *e.Bool
|
||||||
|
default:
|
||||||
|
type _Expression Expression
|
||||||
|
dynamicStruct = _Expression(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(dynamicStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Expression) UnmarshalJSON(data []byte) error {
|
||||||
|
var dynamicStruct interface{}
|
||||||
|
if err := json.Unmarshal(data, &dynamicStruct); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch dynamicStruct.(type) {
|
||||||
|
case string:
|
||||||
|
d := dynamicStruct.(string)
|
||||||
|
e.String = &d
|
||||||
|
case float64:
|
||||||
|
d := dynamicStruct.(float64)
|
||||||
|
e.Float64 = &d
|
||||||
|
case bool:
|
||||||
|
d := dynamicStruct.(bool)
|
||||||
|
e.Bool = &d
|
||||||
|
case []interface{}:
|
||||||
|
e.RowData = data
|
||||||
|
case map[string]interface{}:
|
||||||
|
type _Expression Expression
|
||||||
|
expression := _Expression(*e)
|
||||||
|
if err := json.Unmarshal(data, &expression); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = Expression(expression)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported field type in expression: %T(%v)", dynamicStruct, dynamicStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.String == nil && e.Float64 == nil && e.Bool == nil && e.Payload == nil {
|
||||||
|
e.RowData = data
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Flags) MarshalJSON() ([]byte, error) {
|
||||||
|
var dynamicStruct interface{}
|
||||||
|
|
||||||
|
switch flagCount := len(f.Flags); {
|
||||||
|
case flagCount == 1:
|
||||||
|
dynamicStruct = f.Flags[0]
|
||||||
|
case flagCount > 1:
|
||||||
|
dynamicStruct = f.Flags
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(dynamicStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Flags) UnmarshalJSON(data []byte) error {
|
||||||
|
var dynamicStruct interface{}
|
||||||
|
if err := json.Unmarshal(data, &dynamicStruct); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := dynamicStruct.(type) {
|
||||||
|
case string:
|
||||||
|
f.Flags = []string{v}
|
||||||
|
case []interface{}:
|
||||||
|
for _, val := range v {
|
||||||
|
stringVal, ok := val.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("flags values require string type: %T(%v)", dynamicStruct, dynamicStruct)
|
||||||
|
}
|
||||||
|
f.Flags = append(f.Flags, stringVal)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("flags values require string type: %T(%v)", dynamicStruct, dynamicStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Accept() Verdict {
|
||||||
|
return Verdict{SimpleVerdict: SimpleVerdict{Accept: true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Continue() Verdict {
|
||||||
|
return Verdict{SimpleVerdict: SimpleVerdict{Continue: true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Drop() Verdict {
|
||||||
|
return Verdict{SimpleVerdict: SimpleVerdict{Drop: true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Return() Verdict {
|
||||||
|
return Verdict{SimpleVerdict: SimpleVerdict{Return: true}}
|
||||||
|
}
|
80
vendor/github.com/networkplumbing/go-nft/nft/schema/schema.go
generated
vendored
Normal file
80
vendor/github.com/networkplumbing/go-nft/nft/schema/schema.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Root struct {
|
||||||
|
Nftables []Nftable `json:"nftables"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const ruleSetKey = "ruleset"
|
||||||
|
|
||||||
|
type Objects struct {
|
||||||
|
Table *Table `json:"table,omitempty"`
|
||||||
|
Chain *Chain `json:"chain,omitempty"`
|
||||||
|
Rule *Rule `json:"rule,omitempty"`
|
||||||
|
Ruleset bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Objects) MarshalJSON() ([]byte, error) {
|
||||||
|
type _Objects Objects
|
||||||
|
objects := _Objects(o)
|
||||||
|
|
||||||
|
data, err := json.Marshal(objects)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Ruleset {
|
||||||
|
// Convert to a dynamic structure
|
||||||
|
var dynamicStructure map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &dynamicStructure); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dynamicStructure[ruleSetKey] = nil
|
||||||
|
data, err = json.Marshal(dynamicStructure)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Nftable struct {
|
||||||
|
Table *Table `json:"table,omitempty"`
|
||||||
|
Chain *Chain `json:"chain,omitempty"`
|
||||||
|
Rule *Rule `json:"rule,omitempty"`
|
||||||
|
|
||||||
|
Add *Objects `json:"add,omitempty"`
|
||||||
|
Delete *Objects `json:"delete,omitempty"`
|
||||||
|
Flush *Objects `json:"flush,omitempty"`
|
||||||
|
|
||||||
|
Metainfo *Metainfo `json:"metainfo,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metainfo struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
ReleaseName string `json:"release_name"`
|
||||||
|
JsonSchemaVersion int `json:"json_schema_version"`
|
||||||
|
}
|
35
vendor/github.com/networkplumbing/go-nft/nft/schema/table.go
generated
vendored
Normal file
35
vendor/github.com/networkplumbing/go-nft/nft/schema/table.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schema
|
||||||
|
|
||||||
|
// Table Address Families
|
||||||
|
const (
|
||||||
|
FamilyIP = "ip" // IPv4 address AddressFamily.
|
||||||
|
FamilyIP6 = "ip6" // IPv6 address AddressFamily.
|
||||||
|
FamilyINET = "inet" // Internet (IPv4/IPv6) address AddressFamily.
|
||||||
|
FamilyARP = "arp" // ARP address AddressFamily, handling IPv4 ARP packets.
|
||||||
|
FamilyBridge = "bridge" // Bridge address AddressFamily, handling packets which traverse a bridge device.
|
||||||
|
FamilyNETDEV = "netdev" // Netdev address AddressFamily, handling packets from ingress.
|
||||||
|
)
|
||||||
|
|
||||||
|
type Table struct {
|
||||||
|
Family string `json:"family"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
51
vendor/github.com/networkplumbing/go-nft/nft/table.go
generated
vendored
Normal file
51
vendor/github.com/networkplumbing/go-nft/nft/table.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the go-nft project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2021 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nft
|
||||||
|
|
||||||
|
import "github.com/networkplumbing/go-nft/nft/schema"
|
||||||
|
|
||||||
|
type AddressFamily string
|
||||||
|
|
||||||
|
// Address Families
|
||||||
|
const (
|
||||||
|
FamilyIP AddressFamily = schema.FamilyIP
|
||||||
|
FamilyIP6 AddressFamily = schema.FamilyIP6
|
||||||
|
FamilyINET AddressFamily = schema.FamilyINET
|
||||||
|
FamilyARP AddressFamily = schema.FamilyARP
|
||||||
|
FamilyBridge AddressFamily = schema.FamilyBridge
|
||||||
|
FamilyNETDEV AddressFamily = schema.FamilyNETDEV
|
||||||
|
)
|
||||||
|
|
||||||
|
type TableAction string
|
||||||
|
|
||||||
|
// Table Actions
|
||||||
|
const (
|
||||||
|
TableADD TableAction = "add"
|
||||||
|
TableDELETE TableAction = "delete"
|
||||||
|
TableFLUSH TableAction = "flush"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewTable returns a new schema table structure.
|
||||||
|
func NewTable(name string, family AddressFamily) *schema.Table {
|
||||||
|
return &schema.Table{
|
||||||
|
Name: name,
|
||||||
|
Family: string(family),
|
||||||
|
}
|
||||||
|
}
|
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
@ -84,6 +84,12 @@ github.com/j-keck/arping
|
|||||||
# github.com/mattn/go-shellwords v1.0.12
|
# github.com/mattn/go-shellwords v1.0.12
|
||||||
## explicit
|
## explicit
|
||||||
github.com/mattn/go-shellwords
|
github.com/mattn/go-shellwords
|
||||||
|
# github.com/networkplumbing/go-nft v0.2.0
|
||||||
|
## explicit
|
||||||
|
github.com/networkplumbing/go-nft/nft
|
||||||
|
github.com/networkplumbing/go-nft/nft/config
|
||||||
|
github.com/networkplumbing/go-nft/nft/exec
|
||||||
|
github.com/networkplumbing/go-nft/nft/schema
|
||||||
# github.com/nxadm/tail v1.4.8
|
# github.com/nxadm/tail v1.4.8
|
||||||
github.com/nxadm/tail
|
github.com/nxadm/tail
|
||||||
github.com/nxadm/tail/ratelimiter
|
github.com/nxadm/tail/ratelimiter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user