Skip to content

Commit

Permalink
Merge pull request #72 from synfinatic/better-filter
Browse files Browse the repository at this point in the history
BPF filter uses src net
  • Loading branch information
synfinatic authored Nov 7, 2021
2 parents 5a71880 + a829304 commit 25242e0
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 13 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

## v0.0.8 - 2021-11-07

Changed:

- Use FreeBSD 12.2 for building binaries (pfSense 2.5.x)
Expand All @@ -10,6 +12,13 @@ Changed:
- Update Makefile targets and improve `make help`
- Release binaries no longer end in `-static`
- Release binaries are now stripped and about 33% of their previous sizes
- Improve debug output

Fixed:

- Now use 'src net x.x.x.x/y' in the BPF filter to restrict packets we forward
for platforms like Netgate SG5100 where pcap.SetDirection() doesn't work
to prevent infinite loops #71

## v0.0.7 - 2021-05-23

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ GOARCH ?= $(shell uname -m | sed -E 's/x86_64/amd64/')
BUILDINFOSDET ?=
UDP_PROXY_2020_ARGS ?=

PROJECT_VERSION := 0.0.7
PROJECT_VERSION := 0.0.8
DOCKER_REPO := synfinatic
PROJECT_NAME := udp-proxy-2020
PROJECT_TAG := $(shell git describe --tags 2>/dev/null $(git rev-list --tags --max-count=1))
Expand Down
2 changes: 1 addition & 1 deletion cmd/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func initializeInterface(l *Listen) {
}

// set our BPF filter
bpf_filter := buildBPFFilter(l.ports)
bpf_filter := buildBPFFilter(l.ports, Interfaces[l.iname].Addresses, l.promisc)
log.Debugf("%s: applying BPF Filter: %s", l.iname, bpf_filter)
err = l.handle.SetBPFFilter(bpf_filter)
if err != nil {
Expand Down
13 changes: 7 additions & 6 deletions cmd/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sync"
"time"

"github.com/davecgh/go-spew/spew"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
Expand Down Expand Up @@ -89,7 +90,7 @@ func newListener(netif *net.Interface, promisc bool, ports []int32, to time.Dura
sendpkt: make(chan Send, SendBufferSize),
clients: clients,
}
log.Debugf("Listen: %v", new)
log.Debugf("Listen: %s", spew.Sdump(new))
return new
}

Expand Down Expand Up @@ -223,7 +224,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb

// UDP payload
if err := payload.SerializeTo(buffer, opts); err != nil {
log.Fatalf("can't serialize payload: %v", payload)
log.Fatalf("can't serialize payload: %s", spew.Sdump(payload))
}

// UDP checksums can't be calculated via SerializeOptions
Expand All @@ -237,7 +238,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
}

if err := new_udp.SerializeTo(buffer, opts); err != nil {
log.Fatalf("can't serialize UDP header: %v", udp)
log.Fatalf("can't serialize UDP header: %s", spew.Sdump(udp))
}

// IPv4 header
Expand All @@ -257,7 +258,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
Options: ip4.Options,
}
if err := new_ip4.SerializeTo(buffer, csum_opts); err != nil {
log.Fatalf("can't serialize IP header: %v", new_ip4)
log.Fatalf("can't serialize IP header: %s", spew.Sdump(new_ip4))
}

// Add our L2 header to the buffer
Expand All @@ -267,7 +268,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
Family: layers.ProtocolFamilyIPv4,
}
if err := loop.SerializeTo(buffer, opts); err != nil {
log.Fatalf("can't serialize Loop header: %v", loop)
log.Fatalf("can't serialize Loop header: %s", spew.Sdump(loop))
}
case layers.LinkTypeEthernet.String():
// build a new ethernet header
Expand All @@ -278,7 +279,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
EthernetType: layers.EthernetTypeIPv4,
}
if err := new_eth.SerializeTo(buffer, opts); err != nil {
log.Fatalf("can't serialize Eth header: %v", new_eth)
log.Fatalf("can't serialize Eth header: %s", spew.Sdump(new_eth))
}
case layers.LinkTypeRaw.String():
// no L2 header
Expand Down
37 changes: 35 additions & 2 deletions cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package main

import (
"fmt"
log "github.com/sirupsen/logrus"
"net"
"strings"
"time"

"github.com/google/gopacket/pcap"
log "github.com/sirupsen/logrus"
)

// Check to see if the string is in the slice
Expand All @@ -28,7 +31,7 @@ func stringPrefixInSlice(a string, list []string) bool {
}

// takes a list of ports and builds our BPF filter
func buildBPFFilter(ports []int32) string {
func buildBPFFilter(ports []int32, addresses []pcap.InterfaceAddress, promisc bool) string {
if len(ports) < 1 {
log.Fatal("--port must be specified one or more times")
}
Expand All @@ -42,6 +45,24 @@ func buildBPFFilter(ports []int32) string {
} else {
bpf_filter = bpf_filters[0]
}

// add filter to accept only traffic with a src IP matching the interface
// This should avoid network loops with NIC/drivers which do not honor the
// pcap.SetDirection() call.
networks := []string{}
for _, addr := range addresses {
if net, err := getNetwork(addr); err == nil {
if maskLen, _ := addr.Netmask.Size(); maskLen > 0 {
networks = append(networks, fmt.Sprintf("src net %s", net))
}
}
}
var networkFilter string
if len(networks) >= 1 {
networkFilter = strings.Join(networks, " or ")
bpf_filter = fmt.Sprintf("(%s) and (%s)", bpf_filter, networkFilter)
}

return bpf_filter
}

Expand All @@ -53,3 +74,15 @@ func parseTimeout(timeout int64) time.Duration {
}
return to
}

// takes a net.IP and returns x.x.x.x/len format
func getNetwork(addr pcap.InterfaceAddress) (string, error) {
var ip4 net.IP
if ip4 = addr.IP.To4(); ip4 == nil {
return "", fmt.Errorf("Unable to getNetwork for IPv6 address: %s", addr.IP.String())
}

len, _ := addr.Netmask.Size()
mask := net.CIDRMask(len, 32)
return fmt.Sprintf("%s/%d", ip4.Mask(mask), len), nil
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
module github.com/synfinatic/udp-proxy-2020

go 1.14
go 1.16

require (
github.com/davecgh/go-spew v1.1.1
github.com/google/gopacket v1.1.18
github.com/sirupsen/logrus v1.7.0
github.com/spf13/pflag v1.0.5
Expand Down
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2eP
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
2 changes: 1 addition & 1 deletion startup-scripts/pfSense/usr/local/etc/udp-proxy-2020.conf
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# change the port and add --dev {dev-name} as many times as needed.
# change the port and add --interface {dev-name} as many times as needed.
udp_vars="--port 9003 --interface lagg0,lagg0.200,lagg0.400,ovpns2 --logfile /var/log/udp-proxy-2020.log"

0 comments on commit 25242e0

Please sign in to comment.