Skip to content
Permalink
Browse files

Added proxy proto support and made bind random use ranges

  • Loading branch information...
antoniomika committed Aug 31, 2019
1 parent 8c29827 commit a3ffd2b7594174e32addcf0cb928f7529a6fdb79
Showing with 110 additions and 7 deletions.
  1. +27 −0 channels.go
  2. +1 −0 go.mod
  3. +2 −0 go.sum
  4. +7 −4 main.go
  5. +22 −0 requests.go
  6. +51 −3 utils.go
@@ -1,12 +1,16 @@
package main

import (
"fmt"
"io"
"log"
"strings"

"golang.org/x/crypto/ssh"
)

var proxyProtoPrefix = "proxyproto:"

func handleSession(newChannel ssh.NewChannel, sshConn *SSHConnection, state *State) {
connection, requests, err := newChannel.Accept()
if err != nil {
@@ -58,6 +62,14 @@ func handleSession(newChannel ssh.NewChannel, sshConn *SSHConnection, state *Sta
switch req.Type {
case "shell":
req.Reply(true, nil)
case "exec":
payloadString := string(req.Payload[4:])
if strings.HasPrefix(payloadString, proxyProtoPrefix) && *proxyProtoEnabled {
sshConn.ProxyProto = getProxyProtoVersion(strings.TrimPrefix(payloadString, proxyProtoPrefix))
if sshConn.ProxyProto != 0 {
sshConn.Messages <- fmt.Sprintf("Proxy protocol enabled for TCP connections. Using protocol version %d", int(sshConn.ProxyProto))
}
}
default:
if *debug {
log.Println("Sub Channel Type", req.Type, req.WantReply, string(req.Payload))
@@ -66,3 +78,18 @@ func handleSession(newChannel ssh.NewChannel, sshConn *SSHConnection, state *Sta
}
}()
}

func getProxyProtoVersion(proxyProtoUserVersion string) byte {
if *proxyProtoVersion != "userdefined" {
proxyProtoUserVersion = *proxyProtoVersion
}

realProtoVersion := 0
if proxyProtoUserVersion == "1" {
realProtoVersion = 1
} else if proxyProtoUserVersion == "2" {
realProtoVersion = 2
}

return byte(realProtoVersion)
}
1 go.mod
@@ -13,6 +13,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/oschwald/maxminddb-golang v1.3.0 // indirect
github.com/pires/go-proxyproto v0.0.0-20190615163442-2c19fd512994
github.com/stretchr/testify v1.3.0 // indirect
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 // indirect
2 go.sum
@@ -24,6 +24,8 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/oschwald/maxminddb-golang v1.3.0 h1:oTh8IBSj10S5JNlUDg5WjJ1QdBMdeaZIkPEVfESSWgE=
github.com/oschwald/maxminddb-golang v1.3.0/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/pires/go-proxyproto v0.0.0-20190615163442-2c19fd512994 h1:3ssKn22MN6oLH+l2iimsBdCliSgELXTBWWR+yooB2lQ=
github.com/pires/go-proxyproto v0.0.0-20190615163442-2c19fd512994/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11 main.go
@@ -18,10 +18,11 @@ import (

// SSHConnection handles state for a SSHConnection
type SSHConnection struct {
SSHConn *ssh.ServerConn
Listeners *sync.Map
Close chan bool
Messages chan string
SSHConn *ssh.ServerConn
Listeners *sync.Map
Close chan bool
Messages chan string
ProxyProto byte
}

// State handles overall state
@@ -61,6 +62,8 @@ var (
bindRange = flag.String("sish.bindrange", "0,1024-65535", "Ports that are allowed to be bound")
cleanupUnbound = flag.Bool("sish.cleanupunbound", true, "Whether or not to cleanup unbound (forwarded) SSH connections")
bindRandom = flag.Bool("sish.bindrandom", true, "Bind ports randomly (OS chooses)")
proxyProtoEnabled = flag.Bool("sish.proxyprotoenabled", false, "Whether or not to enable the use of the proxy protocol")
proxyProtoVersion = flag.String("sish.proxyprotoversion", "1", "What version of the proxy protocol to use. Can either be 1, 2, or userdefined. If userdefined, the user needs to add a command to SSH called proxy:version (ie proxy:1)")
debug = flag.Bool("sish.debug", false, "Whether or not to print debug information")
bannedSubdomainList = []string{""}
filter ipfilter.IPFilter
@@ -8,6 +8,7 @@ import (
"os"
"strconv"

"github.com/pires/go-proxyproto"
"golang.org/x/crypto/ssh"
)

@@ -40,6 +41,10 @@ func handleRemoteForward(newRequest *ssh.Request, sshConn *SSHConnection, state
bindPort = checkedPort
if *bindRandom {
bindPort = 0

if *bindRange != "" {
bindPort = getRandomPortInRange(*bindRange)
}
}
}

@@ -146,6 +151,23 @@ func handleRemoteForward(newRequest *ssh.Request, sshConn *SSHConnection, state

defer newChan.Close()

if sshConn.ProxyProto != 0 && listenType != "unix" {
sourceInfo := cl.RemoteAddr().(*net.TCPAddr)
destInfo := cl.LocalAddr().(*net.TCPAddr)

proxyProtoHeader := proxyproto.Header{
Version: sshConn.ProxyProto,
Command: proxyproto.ProtocolVersionAndCommand(proxyproto.PROXY),
TransportProtocol: proxyproto.AddressFamilyAndProtocol(proxyproto.TCPv4),
SourceAddress: sourceInfo.IP,
DestinationAddress: destInfo.IP,
SourcePort: uint16(sourceInfo.Port),
DestinationPort: uint16(destInfo.Port),
}

proxyProtoHeader.WriteTo(newChan)
}

go copyBoth(cl, newChan)
go ssh.DiscardRequests(newReqs)
}
@@ -10,6 +10,7 @@ import (
"io/ioutil"
"log"
mathrand "math/rand"
"net"
"os"
"os/signal"
"path/filepath"
@@ -27,6 +28,55 @@ var (
holderLock = sync.Mutex{}
)

func getRandomPortInRange(portRange string) uint32 {
var bindPort uint32

ranges := strings.Split(strings.TrimSpace(portRange), ",")
possible := [][]uint64{}
for _, r := range ranges {
ends := strings.Split(strings.TrimSpace(r), "-")

if len(ends) == 1 {
ui, err := strconv.ParseUint(ends[0], 0, 64)
if err != nil {
return 0
}

possible = append(possible, []uint64{uint64(ui)})
} else if len(ends) == 2 {
ui1, err := strconv.ParseUint(ends[0], 0, 64)
if err != nil {
return 0
}

ui2, err := strconv.ParseUint(ends[1], 0, 64)
if err != nil {
return 0
}

possible = append(possible, []uint64{uint64(ui1), uint64(ui2)})
}
}

mathrand.Seed(time.Now().UnixNano())
locHolder := mathrand.Intn(len(possible))

if len(possible[locHolder]) == 1 {
bindPort = uint32(possible[locHolder][0])
} else if len(possible[locHolder]) == 2 {
bindPort = uint32(mathrand.Intn(int(possible[locHolder][1]-possible[locHolder][0])) + int(possible[locHolder][0]))
}

ln, err := net.Listen("tcp", fmt.Sprintf(":%d", bindPort))
if err != nil {
return getRandomPortInRange(portRange)
}

ln.Close()

return bindPort
}

func checkPort(port uint32, portRanges string) (uint32, error) {
ranges := strings.Split(strings.TrimSpace(portRanges), ",")
checks := false
@@ -43,9 +93,7 @@ func checkPort(port uint32, portRanges string) (uint32, error) {
checks = true
continue
}
}

if len(ends) == 2 {
} else if len(ends) == 2 {
ui1, err := strconv.ParseUint(ends[0], 0, 64)
if err != nil {
return 0, err

0 comments on commit a3ffd2b

Please sign in to comment.
You can’t perform that action at this time.