From 5acbf94f210cd7ebc4902bd0bba05dda939d57b9 Mon Sep 17 00:00:00 2001 From: Sergey Shlyanin Date: Tue, 10 May 2022 20:15:43 +0700 Subject: [PATCH] * Add iptables4nattemplate chain client element to connectioncontextkernel chain * Turn routelocalnet chain element to a client element and move to cmnnectioncontextkernel chain * Add setroutelocalnet chain server element Signed-off-by: Sergey Shlyanin --- go.mod | 9 +- go.sum | 22 +-- .../connectioncontextkernel/client.go | 4 + .../iptables4nattemplate/client.go | 104 +++++++++++ .../iptables4nattemplate/common.go | 176 ++++++++++++++++++ .../iptables4nattemplate/doc.go | 18 ++ .../routelocalnet/client.go | 67 +++++++ .../routelocalnet/common.go | 70 +++++++ .../routelocalnet/doc.go | 21 +++ .../setiptables4nattemplate/server.go | 8 +- .../server.go | 40 ++-- 11 files changed, 491 insertions(+), 48 deletions(-) create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/client.go create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/common.go create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/doc.go create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/client.go create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/common.go create mode 100644 pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/doc.go rename pkg/kernel/networkservice/{routelocalnet => setroutelocalnet}/server.go (54%) diff --git a/go.mod b/go.mod index de767339..a2de20d3 100644 --- a/go.mod +++ b/go.mod @@ -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.20220512020524-c57fd2623351 - github.com/networkservicemesh/sdk v0.5.1-0.20220512090615-4f565a9784e0 + github.com/networkservicemesh/api v1.3.2-0.20220512163820-8c875d61945b + github.com/networkservicemesh/sdk v0.5.1-0.20220512164527-dc8b0c099894 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 github.com/vishvananda/netlink v1.1.1-0.20220118170537-d6b03fdeb845 @@ -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 @@ -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 diff --git a/go.sum b/go.sum index e3e45fa0..4f1309a3 100644 --- a/go.sum +++ b/go.sum @@ -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= @@ -36,11 +38,9 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV 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-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-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/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= @@ -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= @@ -75,10 +77,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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.20220512020524-c57fd2623351 h1:xkwnRaajnnqFPEbj5FrVVDjSgp+o5tiHqVb8W5cOAfI= -github.com/networkservicemesh/api v1.3.2-0.20220512020524-c57fd2623351/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8= -github.com/networkservicemesh/sdk v0.5.1-0.20220512090615-4f565a9784e0 h1:7ObtZZ4na7PIkco8XTIiGTgh9FhvDtTqKHTS1epR5HI= -github.com/networkservicemesh/sdk v0.5.1-0.20220512090615-4f565a9784e0/go.mod h1:gOYlqDYMdIMCIAfl257+Jn8KNHKVQDZjRIvYSA6wH9s= +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/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= @@ -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= @@ -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= @@ -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= diff --git a/pkg/kernel/networkservice/connectioncontextkernel/client.go b/pkg/kernel/networkservice/connectioncontextkernel/client.go index 5a4cb2c4..3e2012c0 100644 --- a/pkg/kernel/networkservice/connectioncontextkernel/client.go +++ b/pkg/kernel/networkservice/connectioncontextkernel/client.go @@ -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" @@ -62,5 +64,7 @@ func NewClient() networkservice.NetworkServiceClient { ipneighbors.NewClient(), routes.NewClient(), ipaddress.NewClient(), + routelocalnet.NewClient(), + iptables4nattemplate.NewClient(), ) } diff --git a/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/client.go b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/client.go new file mode 100644 index 00000000..acd112f9 --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/client.go @@ -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 +} diff --git a/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/common.go b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/common.go new file mode 100644 index 00000000..be3ae9a9 --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/common.go @@ -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 +} diff --git a/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/doc.go b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/doc.go new file mode 100644 index 00000000..11e11314 --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/iptables4nattemplate/doc.go @@ -0,0 +1,18 @@ +// 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. + +// Package iptables4nattemplate provides chain element for setup iptables nat rules +package iptables4nattemplate diff --git a/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/client.go b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/client.go new file mode 100644 index 00000000..ec3e9592 --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/client.go @@ -0,0 +1,67 @@ +// 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 routelocalnet + +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/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" +) + +type routeLocalNetClient struct { +} + +// NewClient - returns a new networkservice.NetworkServiceClient that writes route_localnet flag +// for network interface on Request if enabled in mechanism +func NewClient() networkservice.NetworkServiceClient { + return &routeLocalNetClient{} +} + +func (c *routeLocalNetClient) 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 := setRouteLocalNet(conn); 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 *routeLocalNetClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/common.go b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/common.go new file mode 100644 index 00000000..acff31a8 --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/common.go @@ -0,0 +1,70 @@ +// 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 routelocalnet + +import ( + "fmt" + "os" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel" + + "github.com/networkservicemesh/sdk-kernel/pkg/kernel/tools/nshandle" +) + +func setRouteLocalNet(conn *networkservice.Connection) error { + mechanism := kernel.ToMechanism(conn.GetMechanism()) + if mechanism != nil && mechanism.GetRouteLocalNet() { + 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 { + fo, fileErr := os.Create(fmt.Sprintf("/proc/sys/net/ipv4/conf/%s/route_localnet", mechanism.GetInterfaceName())) + + if fileErr != nil { + return fileErr + } + + defer func() { _ = fo.Close() }() + + _, fileErr = fo.WriteString("1") + if fileErr != nil { + return fileErr + } + + return nil + }) + + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/doc.go b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/doc.go new file mode 100644 index 00000000..27d80d6f --- /dev/null +++ b/pkg/kernel/networkservice/connectioncontextkernel/routelocalnet/doc.go @@ -0,0 +1,21 @@ +// 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 routelocalnet provides chain element that enables route_localnet flat for connection network interface +package routelocalnet diff --git a/pkg/kernel/networkservice/setiptables4nattemplate/server.go b/pkg/kernel/networkservice/setiptables4nattemplate/server.go index 0caecc9d..44fc347c 100644 --- a/pkg/kernel/networkservice/setiptables4nattemplate/server.go +++ b/pkg/kernel/networkservice/setiptables4nattemplate/server.go @@ -30,21 +30,21 @@ import ( ) type setIPTablesTemplateServer struct { - template string + rulesTemplate []string } // NewServer - returns a new networkservice.NetworkServiceServer that writes IP Tables rules template // to kernel mechanism -func NewServer(template string) networkservice.NetworkServiceServer { +func NewServer(rulesTemplate []string) networkservice.NetworkServiceServer { return &setIPTablesTemplateServer{ - template: template, + rulesTemplate: rulesTemplate, } } func (s *setIPTablesTemplateServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { mechanism := kernel.ToMechanism(request.GetConnection().GetMechanism()) if mechanism != nil { - mechanism.SetIPTables4NatTemplate(s.template) + mechanism.SetIPTables4NatTemplate(s.rulesTemplate) } return next.Server(ctx).Request(ctx, request) diff --git a/pkg/kernel/networkservice/routelocalnet/server.go b/pkg/kernel/networkservice/setroutelocalnet/server.go similarity index 54% rename from pkg/kernel/networkservice/routelocalnet/server.go rename to pkg/kernel/networkservice/setroutelocalnet/server.go index a84a8dba..bab8d5cb 100644 --- a/pkg/kernel/networkservice/routelocalnet/server.go +++ b/pkg/kernel/networkservice/setroutelocalnet/server.go @@ -17,54 +17,36 @@ //go:build linux // +build linux -// Package routelocalnet provides chain element that enables route_localnet flat for connection network interface -package routelocalnet +// Package setroutelocalnet provides chain element for setup routelocalnet property +package setroutelocalnet import ( "context" - "fmt" - "os" "github.com/golang/protobuf/ptypes/empty" - "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" ) -type routeLocalNetServer struct { +type setRouteLocalNetServer struct { } -// NewServer - returns a new networkservice.NetworkServiceServer that writes route_localnet flag -// for network interface on Request if enabled in mechanism +// NewServer - returns a new networkservice.NetworkServiceServer that writes IP Tables rules template +// to kernel mechanism func NewServer() networkservice.NetworkServiceServer { - return &routeLocalNetServer{} + return &setRouteLocalNetServer{} } -func (s *routeLocalNetServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { - conn, err := next.Server(ctx).Request(ctx, request) - if err != nil { - return nil, err - } - +func (s *setRouteLocalNetServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { mechanism := kernel.ToMechanism(request.GetConnection().GetMechanism()) - if mechanism != nil && mechanism.GetRouteLocalNet() { - fo, err := os.Create(fmt.Sprintf("/proc/sys/net/ipv4/conf/%s/route_localnet", mechanism.GetInterfaceName())) - if err != nil { - return nil, err - } - - defer func() { _ = fo.Close() }() - - _, err = fo.WriteString("1") - if err != nil { - return nil, err - } + if mechanism != nil { + mechanism.SetRouteLocalNet(true) } - return conn, nil + return next.Server(ctx).Request(ctx, request) } -func (s *routeLocalNetServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { +func (s *setRouteLocalNetServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { return next.Server(ctx).Close(ctx, conn) }