Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Deploy Go Binaries

on:
push:
tags:
- 'v*.*.*'

permissions:
contents: write
id-token: write
attestations: write

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@v5
with:
check-latest: true
go-version-file: 'go.mod'

- name: Build
run: make dist

- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-path: bin/*

- name: Upload Releases
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: bin/*
draft: true
prerelease: false
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Run Tests

on: push

jobs:
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@v5
with:
check-latest: true
go-version-file: 'go.mod'

# cf. https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
- name: Allow Unconfined NS
run: |
sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

- name: Run Tests
run: make test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ bin/*
*.bc
*.o
*.s

# Build
/slirpnetstack
25 changes: 22 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
BINARY := slirpnetstack

export GOPRIVATE := code.cfops.it
IMPORT_PATH := github.com/cloudflare/slirpnetstack

VERSION := $(shell git describe --tags --always --dirty="-dev")
DATE := $(shell date -u '+%Y-%m-%d-%H:%MUTC')
GOFLAGS := -ldflags='-compressdwarf=false -X "$(IMPORT_PATH)/ext.Version=$(VERSION)" -X "$(IMPORT_PATH)/ext.BuildTime=$(DATE)"'
VERSION := $(shell git describe --tags --always --dirty="-dev")
DATE := $(shell date -u '+%Y-%m-%d-%H:%MUTC')
GOFLAGS := -ldflags='-X "$(IMPORT_PATH)/ext.Version=$(VERSION)" -X "$(IMPORT_PATH)/ext.BuildTime=$(DATE)"'
BUILD_DIR := bin

GO_BUILD = go build $(GOFLAGS)

LINUX_ARCH_LIST = \
linux-amd64 \
linux-arm64

bin/slirpnetstack: *.go go.mod
go build \
Expand Down Expand Up @@ -80,3 +89,13 @@ update-gomod:
go get -u gvisor.dev/gvisor@go all
go mod tidy
$(MAKE) bin/gocovmerge bin/slirpnetstack bin/slirpnetstack.cover


### Distribution section ###
dist: $(LINUX_ARCH_LIST)

linux-amd64:
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@

linux-arm64:
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ Development

You can run tests with:

make tests
make test

Or tests with code coverage

Expand Down
39 changes: 24 additions & 15 deletions addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
)

/* SSH supports this syntax:
/*
SSH supports this syntax:

-R ... connections to given TCP port ... on the remote host are to be forwarded to the local side...
-L ... on the local host are to be forwarded to the given port... on the remote side...

-L [bind_address:]port:host:hostport
-R [bind_address:]port:host:hostport
-R [bind_address:]port

-L [bind_address:]port:remote_socket
-L local_socket:remote_socket
-L local_socket:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-L [bind_address:]port:host:hostport
-R [bind_address:]port:host:hostport
-R [bind_address:]port

-L [bind_address:]port:remote_socket
-L local_socket:remote_socket
-L local_socket:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
*/
type FwdAddr struct {
network string
Expand Down Expand Up @@ -133,8 +134,7 @@ func (f *FwdAddrSlice) Set(value string) error {
func (f *FwdAddrSlice) SetDefaultAddrs(bindAddrDef net.IP, bindAddr6Def net.IP, hostAddrDef net.IP, hostAddr6Def net.IP) {
for i := range *f {
fa := &(*f)[i]
if (fa.bind.static.Addr != "" && fa.bind.static.Addr.To4() == "") ||
(fa.host.static.Addr != "" && fa.host.static.Addr.To4() == "") {
if fa.bind.static.Addr.Len() == 16 || fa.host.static.Addr.Len() == 16 {
// Bind and/or host is IPv6
fa.bind.SetDefaultAddr(bindAddr6Def)
fa.host.SetDefaultAddr(hostAddr6Def)
Expand Down Expand Up @@ -182,16 +182,24 @@ func (f *FwdAddr) HostAddr() (net.Addr, error) {
return nil, fmt.Errorf("unknown network type: %v", f.network)
}

func ipToSmallestSlice(ip net.IP) []byte {
ip4 := ip.To4()
if ip4 != nil {
return ip4
}
return ip
}

func FullAddressFromAddr(a net.Addr) *tcpip.FullAddress {
switch v := a.(type) {
case *net.TCPAddr:
return &tcpip.FullAddress{
Addr: tcpip.Address(v.IP),
Addr: tcpip.AddrFromSlice(ipToSmallestSlice(v.IP)),
Port: uint16(v.Port),
}
case *net.UDPAddr:
return &tcpip.FullAddress{
Addr: tcpip.Address(v.IP),
Addr: tcpip.AddrFromSlice(ipToSmallestSlice(v.IP)),
Port: uint16(v.Port),
}
}
Expand Down Expand Up @@ -233,6 +241,7 @@ func netAddrSetPort(a net.Addr, port int) net.Addr {
}

// Addr that can be set from flag.Var. For example:
//
// flag.Var(&metricAddr, "m", "Metrics address")
type AddrFlags struct {
net.Addr
Expand Down
7 changes: 3 additions & 4 deletions fwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,16 @@ func LocalForward(state *State, s *stack.Stack, conn KaConn, targetAddr net.Addr
// connection had routable IP (unlike
// 127.0.0.1)... well... spoof it! The client might find it
// useful who launched the connection in the first place.
if proxyProtocol == false {
if !proxyProtocol {
srcIP = conn.RemoteAddr()
} else {
ppPrefix = "PP "
srcIP = ppSrc
}
// If the source IP as reported by PP or the client is not routable, still forward
// connection. Just don't use/leak the original IP.
var isSourcev4 = FullAddressFromAddr(srcIP).Addr.To4() != ""
var isTargetv4 = FullAddressFromAddr(targetAddr).Addr.To4() != ""
var isSourcev4 = FullAddressFromAddr(srcIP).Addr.Len() == 4
var isTargetv4 = FullAddressFromAddr(targetAddr).Addr.Len() == 4
if IPNetContains(state.StaticRoutingDeny, netAddrIP(srcIP)) || isSourcev4 != isTargetv4 {
// Source IP not rewritten because:
// * static routing deny
Expand Down Expand Up @@ -251,5 +251,4 @@ pperror:
err)
}
conn.Close()
return
}
42 changes: 22 additions & 20 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
module github.com/cloudflare/slirpnetstack

go 1.13
go 1.23.0

require (
github.com/bazelbuild/rules_go v0.25.0 // indirect
github.com/miekg/dns v1.1.52
github.com/opencontainers/runc v1.2.0
github.com/opencontainers/runtime-spec v1.2.0
github.com/vishvananda/netlink v1.2.1-beta.2
golang.org/x/sys v0.28.0
gopkg.in/netaddr.v1 v1.5.1
gvisor.dev/gvisor v0.0.0-20240629121841-891b40cf7fe0
)

require (
github.com/bazelbuild/rules_go v0.44.2 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/go-cmp v0.5.4 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/miekg/dns v1.1.35
github.com/google/btree v1.1.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/opencontainers/runc v0.1.1
github.com/opencontainers/runtime-spec v1.0.2
github.com/stretchr/testify v1.6.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.8.2 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/vishvananda/netlink v1.1.0
github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad // indirect
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c // indirect
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
golang.org/x/sys v0.0.0-20201202213521-69691e467435
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/netaddr.v1 v1.4.0
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
gvisor.dev/gvisor v0.0.0-20201204040109-0ba39926c86f
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.16.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)
Loading