Skip to content

Commit 25242e0

Browse files
authored
Merge pull request #72 from synfinatic/better-filter
BPF filter uses src net
2 parents 5a71880 + a829304 commit 25242e0

File tree

8 files changed

+56
-13
lines changed

8 files changed

+56
-13
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
## v0.0.8 - 2021-11-07
6+
57
Changed:
68

79
- Use FreeBSD 12.2 for building binaries (pfSense 2.5.x)
@@ -10,6 +12,13 @@ Changed:
1012
- Update Makefile targets and improve `make help`
1113
- Release binaries no longer end in `-static`
1214
- Release binaries are now stripped and about 33% of their previous sizes
15+
- Improve debug output
16+
17+
Fixed:
18+
19+
- Now use 'src net x.x.x.x/y' in the BPF filter to restrict packets we forward
20+
for platforms like Netgate SG5100 where pcap.SetDirection() doesn't work
21+
to prevent infinite loops #71
1322

1423
## v0.0.7 - 2021-05-23
1524

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ GOARCH ?= $(shell uname -m | sed -E 's/x86_64/amd64/')
44
BUILDINFOSDET ?=
55
UDP_PROXY_2020_ARGS ?=
66

7-
PROJECT_VERSION := 0.0.7
7+
PROJECT_VERSION := 0.0.8
88
DOCKER_REPO := synfinatic
99
PROJECT_NAME := udp-proxy-2020
1010
PROJECT_TAG := $(shell git describe --tags 2>/dev/null $(git rev-list --tags --max-count=1))

cmd/interfaces.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func initializeInterface(l *Listen) {
5050
}
5151

5252
// set our BPF filter
53-
bpf_filter := buildBPFFilter(l.ports)
53+
bpf_filter := buildBPFFilter(l.ports, Interfaces[l.iname].Addresses, l.promisc)
5454
log.Debugf("%s: applying BPF Filter: %s", l.iname, bpf_filter)
5555
err = l.handle.SetBPFFilter(bpf_filter)
5656
if err != nil {

cmd/listen.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"sync"
99
"time"
1010

11+
"github.com/davecgh/go-spew/spew"
1112
"github.com/google/gopacket"
1213
"github.com/google/gopacket/layers"
1314
"github.com/google/gopacket/pcap"
@@ -89,7 +90,7 @@ func newListener(netif *net.Interface, promisc bool, ports []int32, to time.Dura
8990
sendpkt: make(chan Send, SendBufferSize),
9091
clients: clients,
9192
}
92-
log.Debugf("Listen: %v", new)
93+
log.Debugf("Listen: %s", spew.Sdump(new))
9394
return new
9495
}
9596

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

224225
// UDP payload
225226
if err := payload.SerializeTo(buffer, opts); err != nil {
226-
log.Fatalf("can't serialize payload: %v", payload)
227+
log.Fatalf("can't serialize payload: %s", spew.Sdump(payload))
227228
}
228229

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

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

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

263264
// Add our L2 header to the buffer
@@ -267,7 +268,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
267268
Family: layers.ProtocolFamilyIPv4,
268269
}
269270
if err := loop.SerializeTo(buffer, opts); err != nil {
270-
log.Fatalf("can't serialize Loop header: %v", loop)
271+
log.Fatalf("can't serialize Loop header: %s", spew.Sdump(loop))
271272
}
272273
case layers.LinkTypeEthernet.String():
273274
// build a new ethernet header
@@ -278,7 +279,7 @@ func (l *Listen) sendPacket(dstip net.IP, eth layers.Ethernet, loop layers.Loopb
278279
EthernetType: layers.EthernetTypeIPv4,
279280
}
280281
if err := new_eth.SerializeTo(buffer, opts); err != nil {
281-
log.Fatalf("can't serialize Eth header: %v", new_eth)
282+
log.Fatalf("can't serialize Eth header: %s", spew.Sdump(new_eth))
282283
}
283284
case layers.LinkTypeRaw.String():
284285
// no L2 header

cmd/utils.go

+35-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package main
22

33
import (
44
"fmt"
5-
log "github.com/sirupsen/logrus"
5+
"net"
66
"strings"
77
"time"
8+
9+
"github.com/google/gopacket/pcap"
10+
log "github.com/sirupsen/logrus"
811
)
912

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

3033
// takes a list of ports and builds our BPF filter
31-
func buildBPFFilter(ports []int32) string {
34+
func buildBPFFilter(ports []int32, addresses []pcap.InterfaceAddress, promisc bool) string {
3235
if len(ports) < 1 {
3336
log.Fatal("--port must be specified one or more times")
3437
}
@@ -42,6 +45,24 @@ func buildBPFFilter(ports []int32) string {
4245
} else {
4346
bpf_filter = bpf_filters[0]
4447
}
48+
49+
// add filter to accept only traffic with a src IP matching the interface
50+
// This should avoid network loops with NIC/drivers which do not honor the
51+
// pcap.SetDirection() call.
52+
networks := []string{}
53+
for _, addr := range addresses {
54+
if net, err := getNetwork(addr); err == nil {
55+
if maskLen, _ := addr.Netmask.Size(); maskLen > 0 {
56+
networks = append(networks, fmt.Sprintf("src net %s", net))
57+
}
58+
}
59+
}
60+
var networkFilter string
61+
if len(networks) >= 1 {
62+
networkFilter = strings.Join(networks, " or ")
63+
bpf_filter = fmt.Sprintf("(%s) and (%s)", bpf_filter, networkFilter)
64+
}
65+
4566
return bpf_filter
4667
}
4768

@@ -53,3 +74,15 @@ func parseTimeout(timeout int64) time.Duration {
5374
}
5475
return to
5576
}
77+
78+
// takes a net.IP and returns x.x.x.x/len format
79+
func getNetwork(addr pcap.InterfaceAddress) (string, error) {
80+
var ip4 net.IP
81+
if ip4 = addr.IP.To4(); ip4 == nil {
82+
return "", fmt.Errorf("Unable to getNetwork for IPv6 address: %s", addr.IP.String())
83+
}
84+
85+
len, _ := addr.Netmask.Size()
86+
mask := net.CIDRMask(len, 32)
87+
return fmt.Sprintf("%s/%d", ip4.Mask(mask), len), nil
88+
}

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module github.com/synfinatic/udp-proxy-2020
22

3-
go 1.14
3+
go 1.16
44

55
require (
6+
github.com/davecgh/go-spew v1.1.1
67
github.com/google/gopacket v1.1.18
78
github.com/sirupsen/logrus v1.7.0
89
github.com/spf13/pflag v1.0.5

go.sum

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2eP
1515
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
1616
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
1717
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
18-
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
1918
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2019
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
2120
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# change the port and add --dev {dev-name} as many times as needed.
1+
# change the port and add --interface {dev-name} as many times as needed.
22
udp_vars="--port 9003 --interface lagg0,lagg0.200,lagg0.400,ovpns2 --logfile /var/log/udp-proxy-2020.log"

0 commit comments

Comments
 (0)