mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-21 15:43:12 +01:00
Add sharedsock example (#1116)
This commit is contained in:
parent
00dddb9458
commit
d51dc4fd33
35
sharedsock/example/README.md
Normal file
35
sharedsock/example/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
### How to run
|
||||
|
||||
This will only work on Linux
|
||||
|
||||
1. Run netcat listening on the UDP port 51820. This is going to be our external process:
|
||||
```bash
|
||||
nc -kluvw 1 51820
|
||||
```
|
||||
|
||||
2. Build and run the example Go code:
|
||||
|
||||
```bash
|
||||
go build -o sharedsock && sudo ./sharedsock
|
||||
```
|
||||
|
||||
3. Test the logic by sending a STUN binding request
|
||||
|
||||
```bash
|
||||
STUN_PACKET="000100002112A4425454"
|
||||
echo -n $STUN_PACKET | xxd -r -p | nc -u -w 1 localhost 51820
|
||||
```
|
||||
|
||||
4. You should see a similar output of the Go program. Note that you'll see some binary output in the netcat server too. This is due to the fact that kernel copies packets to both processes.
|
||||
|
||||
```bash
|
||||
read a STUN packet of size 18 from ...
|
||||
```
|
||||
|
||||
5. Send a non-STUN packet
|
||||
|
||||
```bash
|
||||
echo -n 'hello' | nc -u -w 1 localhost 51820
|
||||
```
|
||||
|
||||
6. The Go program won't print anything.
|
56
sharedsock/example/main.go
Normal file
56
sharedsock/example/main.go
Normal file
@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/netbirdio/netbird/sharedsock"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
port := 51820
|
||||
rawSock, err := sharedsock.Listen(port, sharedsock.NewIncomingSTUNFilter())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Infof("attached to to the raw socket on port %d", port)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
// read packets
|
||||
go func() {
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Debugf("stopped reading from the shared socket")
|
||||
return
|
||||
default:
|
||||
size, addr, err := rawSock.ReadFrom(buf)
|
||||
if err != nil {
|
||||
log.Errorf("error while reading packet from the shared socket: %s", err)
|
||||
continue
|
||||
}
|
||||
log.Infof("read a STUN packet of size %d from %s", size, addr.String())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// terminate the program on ^C
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
for range c {
|
||||
log.Infof("received ^C signal, stopping the program")
|
||||
cancel()
|
||||
err = rawSock.Close()
|
||||
if err != nil {
|
||||
log.Errorf("failed closing raw socket")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
@ -2,8 +2,6 @@ package sharedsock
|
||||
|
||||
import "golang.org/x/net/bpf"
|
||||
|
||||
const magicCookie uint32 = 0x2112A442
|
||||
|
||||
// BPFFilter is a generic filter that provides ipv4 and ipv6 BPF instructions
|
||||
type BPFFilter interface {
|
||||
// GetInstructions returns raw BPF instructions for ipv4 and ipv6
|
||||
|
@ -67,17 +67,17 @@ func Listen(port int, filter BPFFilter) (net.PacketConn, error) {
|
||||
|
||||
rawSock.router, err = netroute.New()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create router: %rawSock", err)
|
||||
return nil, fmt.Errorf("failed to create raw socket router: %v", err)
|
||||
}
|
||||
|
||||
rawSock.conn4, err = socket.Socket(unix.AF_INET, unix.SOCK_RAW, unix.IPPROTO_UDP, "raw_udp4", nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("socket.Socket for ipv4 failed with: %rawSock", err)
|
||||
return nil, fmt.Errorf("failed to create ipv4 raw socket: %v", err)
|
||||
}
|
||||
|
||||
rawSock.conn6, err = socket.Socket(unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_UDP, "raw_udp6", nil)
|
||||
if err != nil {
|
||||
log.Errorf("socket.Socket for ipv6 failed with: %rawSock", err)
|
||||
log.Errorf("failed to create ipv6 raw socket: %v", err)
|
||||
}
|
||||
|
||||
ipv4Instructions, ipv6Instructions, err := filter.GetInstructions(uint32(rawSock.port))
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Listen is not supported on other platforms
|
||||
// Listen is not supported on other platforms then Linux
|
||||
func Listen(port int, filter BPFFilter) (net.PacketConn, error) {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("Not supported OS %s. SharedSocket is only supported on Linux", runtime.GOOS))
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package sharedsock
|
||||
|
||||
import "golang.org/x/net/bpf"
|
||||
|
||||
const magicCookie uint32 = 0x2112A442
|
||||
|
||||
// IncomingSTUNFilter implements BPFFilter and filters out anything but incoming STUN packets to a specified destination port.
|
||||
// Other packets (non STUN) will be forwarded to the process that own the port (e.g., WireGuard).
|
||||
type IncomingSTUNFilter struct {
|
Loading…
Reference in New Issue
Block a user