Skip to content

Commit

Permalink
Add tcp-to-tcp cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
syndbg committed May 20, 2021
1 parent 9eb1e4a commit d838e7a
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
name: Test
strategy:
matrix:
golang: ["1.14"]
golang: ["1.16"]
os: ["ubuntu-latest", "macos-latest"]
runs-on: ${{ matrix.os }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.14.0
1.16.4
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func NewRootCmd(osExecutor os.OsExecutor, logger logger.Logger) *cobra.Command {
cmdInstance.AddCommand(
NewFakeCmd(logger),
NewTCPToUnixCmd(logger),
NewTCPToTCPcmd(logger),
NewUnixToTCPCmd(logger),
NewVersionCmd(osExecutor),
)
Expand Down
111 changes: 111 additions & 0 deletions cmd/tcp_to_tcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2018 SumUp Ltd.
//
// 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 cmd

import (
"context"
"os"
"os/signal"
"syscall"
"time"

"github.com/palantir/stacktrace"
"github.com/spf13/cobra"
"github.com/sumup-oss/go-pkgs/logger"

"github.com/sumup-oss/gocat/internal/relay"
)

func NewTCPToTCPcmd(logger logger.Logger) *cobra.Command {
var tcpSourceAddress string
var tcpDestinationAddress string
var bufferSize int
var tcpToUnixHealthCheckInterval time.Duration

cmdInstance := &cobra.Command{
Use: "tcp-to-tcp",
Short: "relay from a TCP source to TCP destination",
Long: `relay from a TCP source to TCP destination`,
RunE: func(command *cobra.Command, args []string) error {
// nolint: gocritic
if len(tcpSourceAddress) < 0 {
return stacktrace.NewError("blank/empty `src` specified")
}

// nolint: gocritic
if len(tcpDestinationAddress) < 0 {
return stacktrace.NewError("blank/empty `dst` specified")
}

relayer, err := relay.NewTCPtoTCPsocket(
logger,
tcpToUnixHealthCheckInterval,
tcpSourceAddress,
tcpDestinationAddress,
bufferSize,
)
if err != nil {
return stacktrace.Propagate(err, "couldn't create relay from TCP to TCP")
}

osSignalCh := make(chan os.Signal, 1)
defer close(osSignalCh)

signal.Notify(osSignalCh, os.Interrupt, syscall.SIGTERM)

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()

// Ctrl+C handler
go func() {
<-osSignalCh
signal.Stop(osSignalCh)

_ = os.RemoveAll(tcpSourceAddress)
cancelFunc()
}()

err = relayer.Relay(ctx)
if err != nil {
_ = os.RemoveAll(tcpSourceAddress)
return stacktrace.Propagate(err, "couldn't relay from TCP to TCP")
}

_ = os.RemoveAll(tcpSourceAddress)
return nil
},
}

cmdInstance.Flags().DurationVar(
&tcpToUnixHealthCheckInterval,
"health-check-interval",
30*time.Second,
"health check interval for `src`, e.g values are 30m, 60s, 1h.",
)

cmdInstance.Flags().StringVar(&tcpSourceAddress, "src", "", "source of TCP address")
_ = cmdInstance.MarkFlagRequired("src")

cmdInstance.Flags().StringVar(&tcpDestinationAddress, "dst", "", "destination of TCP address")
_ = cmdInstance.MarkFlagRequired("dst")

cmdInstance.Flags().IntVar(
&bufferSize,
"buffer-size",
DefaultBufferSize,
"Buffer size in bytes of the data stream",
)
return cmdInstance
}
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/elliotchance/orderedmap v1.2.0 h1:Z2kiPPgjjlS8NN+1EFzE4ZO/HpW02gl9ZH3MHL+bNkg=
github.com/elliotchance/orderedmap v1.2.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
Expand Down Expand Up @@ -55,7 +52,6 @@ github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -104,7 +100,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
Expand Down Expand Up @@ -145,7 +140,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -174,7 +168,6 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
101 changes: 101 additions & 0 deletions internal/relay/tcp_tcp_socket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2018 SumUp Ltd.
//
// 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 relay

import (
"context"
"net"
"strconv"
"strings"
"time"

"github.com/palantir/stacktrace"
"github.com/sumup-oss/go-pkgs/logger"
)

type TCPtoTCPsocket struct {
AbstractDuplexRelay
}

func NewTCPtoTCPsocket(
logger logger.Logger,
healthCheckInterval time.Duration,
srcAddress,
dstAddress string,
bufferSize int,
) (*TCPtoTCPsocket, error) {
tcpAddressParts := strings.Split(srcAddress, ":")
if len(tcpAddressParts) != 2 {
return nil, stacktrace.NewError(
"wrong format for tcp address %s. Expected <addr>:<port>",
srcAddress,
)
}

_, err := strconv.ParseInt(tcpAddressParts[1], 10, 32)
if err != nil {
return nil, stacktrace.Propagate(
err,
"could not parse specified port number %s",
tcpAddressParts[1],
)
}

return &TCPtoTCPsocket{
AbstractDuplexRelay{
healthCheckInterval: healthCheckInterval,
logger: logger,
sourceName: "source TCP connection",
destinationName: "destination TCP connection",
destinationAddr: dstAddress,
bufferSize: bufferSize,
dialSourceConn: func(ctx context.Context) (net.Conn, error) {
dialer := &net.Dialer{
KeepAlive: tcpKeepAlivePeriod,
}
conn, err := dialer.DialContext(
ctx,
"tcp",
srcAddress,
)
if err != nil {
return nil, stacktrace.Propagate(
err,
"failed to dial TCP address: %s",
srcAddress,
)
}

tcpConn := conn.(*net.TCPConn)
// TODO: Re-evaluate if this is redundant when `KeepAlive` and `net.Dialer` is used.
_ = tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlivePeriod(tcpKeepAlivePeriod)
return tcpConn, nil
},
listenTargetConn: func(ctx context.Context) (net.Listener, error) {
var lc net.ListenConfig
listener, err := lc.Listen(ctx, "tcp", dstAddress)
if err != nil {
return nil, stacktrace.Propagate(
err,
"failed to listen at destination TCP address: %s",
dstAddress,
)
}
return listener, nil
},
},
}, nil
}

0 comments on commit d838e7a

Please sign in to comment.