Skip to content

Commit

Permalink
Merge pull request #467 from rejmond/issue-463
Browse files Browse the repository at this point in the history
Add iptables4nattemplate chain element, refactor routelocalnet chain element
  • Loading branch information
denis-tingaikin authored May 13, 2022
2 parents 1a5c14d + 1125d6c commit e0f2b84
Show file tree
Hide file tree
Showing 10 changed files with 484 additions and 41 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ module github.com/networkservicemesh/sdk-kernel
go 1.18

require (
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534
github.com/edwarnicke/exechelper v1.0.2
github.com/go-ping/ping v1.0.0
github.com/golang/protobuf v1.5.2
github.com/networkservicemesh/api v1.3.2-0.20220512163820-8c875d61945b
github.com/networkservicemesh/sdk v0.5.1-0.20220512164527-dc8b0c099894
github.com/networkservicemesh/sdk v0.5.1-0.20220513003022-4d9bebd00c37
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
github.com/vishvananda/netlink v1.1.1-0.20220118170537-d6b03fdeb845
Expand All @@ -22,6 +23,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.1 // indirect
github.com/go-logr/stdr v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand All @@ -40,7 +42,6 @@ require (
go.opentelemetry.io/otel/trace v1.3.0 // indirect
go.opentelemetry.io/proto/otlp v0.11.0 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12 // indirect
google.golang.org/protobuf v1.27.1 // indirect
Expand Down
18 changes: 9 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/edwarnicke/exechelper v1.0.2 h1:dD49Ui2U0FBFxxhalnKw6vLS0P0TkgnXBRvKL/xmC5w=
github.com/edwarnicke/exechelper v1.0.2/go.mod h1:/T271jtNX/ND4De6pa2aRy2+8sNtyCDB1A2pp4M+fUs=
github.com/edwarnicke/serialize v1.0.7 h1:geX8vmyu8Ij2S5fFIXjy9gBDkKxXnrMIzMoDvV0Ddac=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
Expand All @@ -37,10 +39,8 @@ github.com/go-logr/logr v1.2.1 h1:DX7uPQ4WgAWfoh+NGGlbJQswnYIVvz0SRlLS3rPZQDA=
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.0 h1:j4LrlVXgrbIWO83mmQUnK0Hi+YnbD+vzrE1z/EphbFE=
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4=
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4=
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-ping/ping v1.0.0 h1:34GZiqLDqqIHEeL5NZIz7jSnMluK7/p0qDB436yO6H0=
github.com/go-ping/ping v1.0.0/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand All @@ -65,6 +65,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand All @@ -77,8 +79,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/networkservicemesh/api v1.3.2-0.20220512163820-8c875d61945b h1:suJRTlWU7/N0gF3FdcN9kCf1MO5Z7CdVSBdb2JTkLhk=
github.com/networkservicemesh/api v1.3.2-0.20220512163820-8c875d61945b/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8=
github.com/networkservicemesh/sdk v0.5.1-0.20220512164527-dc8b0c099894 h1:J69KOXLObKnmtGaR7/uEw3PII/HqNkLwFQwdZffDdyE=
github.com/networkservicemesh/sdk v0.5.1-0.20220512164527-dc8b0c099894/go.mod h1:7Aa9sCLOVzhsbR7LBJ1nSK/YCzd/EO/YK3BbHPB0puw=
github.com/networkservicemesh/sdk v0.5.1-0.20220513003022-4d9bebd00c37 h1:1wQY2oelI/porPJb9KREzozx8UOhJ05DumSBPkbVrhY=
github.com/networkservicemesh/sdk v0.5.1-0.20220513003022-4d9bebd00c37/go.mod h1:7Aa9sCLOVzhsbR7LBJ1nSK/YCzd/EO/YK3BbHPB0puw=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -146,7 +148,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
Expand All @@ -156,7 +158,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand All @@ -166,7 +167,6 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
4 changes: 4 additions & 0 deletions pkg/kernel/networkservice/connectioncontextkernel/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ package connectioncontextkernel
import (
"github.com/networkservicemesh/api/pkg/api/networkservice"

"github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate"
"github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/connectioncontextkernel/mtu"
"github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet"

"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain"

Expand Down Expand Up @@ -62,5 +64,7 @@ func NewClient() networkservice.NetworkServiceClient {
ipneighbors.NewClient(),
routes.NewClient(),
ipaddress.NewClient(),
routelocalnet.NewClient(),
iptables4nattemplate.NewClient(),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) 2022 Xored Software Inc and others.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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.

//go:build linux
// +build linux

package iptables4nattemplate

import (
"context"

"github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors"
"google.golang.org/grpc"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
"github.com/networkservicemesh/sdk/pkg/tools/postpone"

"github.com/networkservicemesh/sdk-kernel/pkg/kernel/tools/nshandle"
)

type iptablesClient struct {
manager IPTablesManager
}

// NewClient - returns a new networkservice.NetworkServiceClient that modify IPTables rules
// by mechanism provided template on Request and rollbacks rules changes on Close
func NewClient() networkservice.NetworkServiceClient {
return &iptablesClient{
manager: &iptableManagerImpl{},
}
}

func (c *iptablesClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
postponeCtxFunc := postpone.ContextWithValues(ctx)

conn, err := next.Client(ctx).Request(ctx, request, opts...)
if err != nil {
return nil, err
}

if err := applyIptablesRules(ctx, conn, c); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()

if _, closeErr := c.Close(closeCtx, conn, opts...); closeErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error())
}

return nil, err
}

return conn, nil
}

func (c *iptablesClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
_, err := next.Client(ctx).Close(ctx, conn, opts...)

var restoreErr error
ctxMap := metadata.Map(ctx, metadata.IsClient(c))
if initialRules, rulesWasApplied := ctxMap.Load(applyIPTablesKey{}); rulesWasApplied {
mechanism := kernel.ToMechanism(conn.GetMechanism())
currentNsHandler, handleErr := nshandle.Current()
if handleErr != nil {
return nil, handleErr
}
defer func() { _ = currentNsHandler.Close() }()

targetHsHandler, handleErr := nshandle.FromURL(mechanism.GetNetNSURL())
if handleErr != nil {
return nil, handleErr
}
defer func() { _ = targetHsHandler.Close() }()

restoreErr = nshandle.RunIn(currentNsHandler, targetHsHandler, func() error {
return c.manager.Restore(initialRules.(string))
})
}

if err != nil && restoreErr != nil {
return nil, errors.Wrap(err, restoreErr.Error())
}
if restoreErr != nil {
return nil, restoreErr
}

return &empty.Empty{}, err
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright (c) 2022 Xored Software Inc and others.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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.

//go:build linux
// +build linux

package iptables4nattemplate

import (
"bytes"
"context"
"fmt"
"os"
"strings"

"github.com/edwarnicke/exechelper"
"github.com/pkg/errors"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"

"github.com/networkservicemesh/sdk-kernel/pkg/kernel/tools/nshandle"
)

type applyIPTablesKey struct {
}

type iptableManagerImpl struct {
}

// IPTablesManager provides methods for iptables nat rules management
type IPTablesManager interface {
Get() (string, error)
Restore(string) error
Apply([]string) error
}

func (m *iptableManagerImpl) Get() (string, error) {
cmdStr := "iptables-save"
buf := bytes.NewBuffer([]byte{})
err := exechelper.Run(cmdStr,
exechelper.WithStdout(buf),
exechelper.WithStderr(buf),
)
if err != nil {
err = errors.Wrapf(err, "%s", buf.String())
return "", err
}

return buf.String(), nil
}

func (m *iptableManagerImpl) Apply(rules []string) error {
for _, rule := range rules {
arguments := strings.Split(rule, " ")

cmdStr := "iptables -t nat"
buf := bytes.NewBuffer([]byte{})
err := exechelper.Run(cmdStr,
exechelper.WithArgs(arguments...),
exechelper.WithStdout(buf),
exechelper.WithStderr(buf),
)
if err != nil {
err = errors.Wrapf(err, "%s", buf.String())
return err
}
}

return nil
}

func (m *iptableManagerImpl) writeTmpRule(rules string) (string, error) {
fo, err := os.CreateTemp("/tmp", "rules-*")
if err != nil {
return "", err
}

defer func() { _ = fo.Close() }()
_, err = fo.WriteString(rules)
if err != nil {
return "", err
}

return fo.Name(), nil
}

func (m *iptableManagerImpl) Restore(rules string) error {
// Save rules to a temp file
tmpFile, err := m.writeTmpRule(rules)
if err != nil {
return err
}

defer func() { _ = os.Remove(tmpFile) }()

// Restore rules
cmdStr := fmt.Sprintf("iptables-restore %s", tmpFile)
buf := bytes.NewBuffer([]byte{})
err = exechelper.Run(cmdStr,
exechelper.WithStdout(buf),
exechelper.WithStderr(buf),
)
if err != nil {
err = errors.Wrapf(err, "%s", buf.String())
return err
}

return nil
}

func applyIptablesRules(ctx context.Context, conn *networkservice.Connection, c *iptablesClient) error {
ctxMap := metadata.Map(ctx, metadata.IsClient(c))
_, rulesWasApplied := ctxMap.Load(applyIPTablesKey{})

// Check refresh requests
if rulesWasApplied {
return nil
}

mechanism := kernel.ToMechanism(conn.GetMechanism())
if mechanism != nil && len(mechanism.GetIPTables4NatTemplate()) != 0 {
rules, err := mechanism.EvaluateIPTables4NatTemplate(conn)
if err != nil {
return err
}

currentNsHandler, err := nshandle.Current()
if err != nil {
return err
}
defer func() { _ = currentNsHandler.Close() }()

targetHsHandler, err := nshandle.FromURL(mechanism.GetNetNSURL())
if err != nil {
return err
}
defer func() { _ = targetHsHandler.Close() }()

err = nshandle.RunIn(currentNsHandler, targetHsHandler, func() error {
initialRules, iptableErr := c.manager.Get()
if iptableErr != nil {
return iptableErr
}

ctxMap.Store(applyIPTablesKey{}, initialRules)

iptableErr = c.manager.Apply(rules)
if iptableErr != nil {
return iptableErr
}

return nil
})

if err != nil {
return err
}
}

return nil
}
Loading

0 comments on commit e0f2b84

Please sign in to comment.