Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit a238b49

Browse files
chripelldanderson
authored andcommitted
Support for binding to a specific IP, group of interfaces or blacklisting local
IPs we don't want to use.
1 parent b2edaca commit a238b49

File tree

3 files changed

+90
-12
lines changed

3 files changed

+90
-12
lines changed

gather.go

+37-5
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,48 @@ func setPriorities(c []candidate) {
114114
}
115115
}
116116

117-
func GatherCandidates(sock *net.UDPConn) ([]candidate, error) {
117+
func pruneCandidates(cands []candidate, blacklist []*net.IPNet) []candidate {
118+
ret := []candidate{}
119+
skipCandidate:
120+
for _, c := range cands {
121+
for _, avoid := range blacklist {
122+
if avoid.Contains(c.Addr.IP) {
123+
continue skipCandidate
124+
}
125+
}
126+
ret = append(ret, c)
127+
}
128+
return ret
129+
}
130+
131+
func GatherCandidates(sock *net.UDPConn, ifaces []string, blacklist []*net.IPNet) ([]candidate, error) {
118132
laddr := sock.LocalAddr().(*net.UDPAddr)
119133
ret := []candidate{}
120134
switch {
121135
case laddr.IP.IsLoopback():
122136
return nil, errors.New("Connecting over loopback not supported")
123137
case laddr.IP.IsUnspecified():
124-
addrs, err := net.InterfaceAddrs()
125-
if err != nil {
126-
return nil, err
138+
var (
139+
addrs []net.Addr
140+
err error
141+
)
142+
if len(ifaces) == 0 {
143+
addrs, err = net.InterfaceAddrs()
144+
if err != nil {
145+
return nil, err
146+
}
147+
} else {
148+
for _, iface := range ifaces {
149+
ifi, err := net.InterfaceByName(iface)
150+
if err != nil {
151+
return nil, err
152+
}
153+
iAddrs, err := ifi.Addrs()
154+
if err != nil {
155+
return nil, err
156+
}
157+
addrs = append(addrs, iAddrs...)
158+
}
127159
}
128160

129161
for _, addr := range addrs {
@@ -143,5 +175,5 @@ func GatherCandidates(sock *net.UDPConn) ([]candidate, error) {
143175
}
144176

145177
setPriorities(ret)
146-
return ret, nil
178+
return pruneCandidates(ret, blacklist), nil
147179
}

nat.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ import (
1515
type ExchangeCandidatesFun func([]byte) []byte
1616

1717
type Config struct {
18-
ProbeTimeout time.Duration
19-
ProbeInterval time.Duration
20-
DecisionTime time.Duration
21-
PeerDeadline time.Duration
22-
Verbose bool
18+
ProbeTimeout time.Duration
19+
ProbeInterval time.Duration
20+
DecisionTime time.Duration
21+
PeerDeadline time.Duration
22+
Verbose bool
23+
BindAddress *net.UDPAddr
24+
UseInterfaces []string
25+
BlacklistAddresses []*net.IPNet
2326
}
2427

2528
func DefaultConfig() *Config {
@@ -28,11 +31,12 @@ func DefaultConfig() *Config {
2831
ProbeInterval: 100 * time.Millisecond,
2932
DecisionTime: 2 * time.Second,
3033
PeerDeadline: 5 * time.Second,
34+
BindAddress: &net.UDPAddr{},
3135
}
3236
}
3337

3438
func ConnectOpt(xchg ExchangeCandidatesFun, initiator bool, cfg *Config) (net.Conn, error) {
35-
sock, err := net.ListenUDP("udp", &net.UDPAddr{})
39+
sock, err := net.ListenUDP("udp", cfg.BindAddress)
3640
if err != nil {
3741
return nil, err
3842
}
@@ -76,7 +80,7 @@ type attemptEngine struct {
7680
}
7781

7882
func (e *attemptEngine) init() error {
79-
candidates, err := GatherCandidates(e.sock)
83+
candidates, err := GatherCandidates(e.sock, e.cfg.UseInterfaces, e.cfg.BlacklistAddresses)
8084
if err != nil {
8185
return err
8286
}
@@ -189,6 +193,7 @@ func (e *attemptEngine) read() error {
189193
if e.cfg.Verbose {
190194
log.Printf("RX %v from %v", packet.Tid[:], from)
191195
}
196+
skipAddress:
192197
for i := range e.attempts {
193198
if !bytes.Equal(packet.Tid[:], e.attempts[i].tid) {
194199
continue
@@ -203,6 +208,11 @@ func (e *attemptEngine) read() error {
203208
e.p2pconn = newConn(e.sock, e.attempts[i].localaddr, e.attempts[i].Addr)
204209
return nil
205210
}
211+
for _, avoid := range e.cfg.BlacklistAddresses {
212+
if avoid.Contains(packet.Addr.IP) {
213+
continue skipAddress
214+
}
215+
}
206216
e.attempts[i].success = true
207217
e.attempts[i].localaddr = packet.Addr
208218
e.attempts[i].timeout = time.Now().Add(e.cfg.ProbeInterval)

nattester/nattester.go

+36
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"fmt"
1313
"io"
1414
"log"
15+
"net"
1516
"os"
1617
"os/exec"
1718
"strings"
@@ -25,6 +26,11 @@ var (
2526
testString = flag.String("test_string",
2627
"The quick UDP packet jumped over the lazy TCP stream",
2728
"String to test echo on")
29+
bindAddress = flag.String("bind_address", "", "Bind to a local IP address")
30+
useInterfaces = flag.String("use_interfaces", "", "Comma separated list of interfaces to use. "+
31+
"If not defined use all the suitable ones")
32+
blacklistAddresses = flag.String("blacklist_addresses", "", "Comma separated list of IP ranges "+
33+
"(in CIDR format) to avoid using as possible candidates")
2834
cmd *exec.Cmd
2935
)
3036

@@ -66,11 +72,41 @@ func xchangeCandidates(mine []byte) []byte {
6672
return nil
6773
}
6874

75+
func listize(str string) []string {
76+
var ret []string
77+
for _, s := range strings.Split(str, ",") {
78+
ret = append(ret, strings.TrimSpace(s))
79+
}
80+
return ret
81+
}
82+
6983
func main() {
7084
log.SetOutput(os.Stdout)
7185
flag.Parse()
7286
cfg := nat.DefaultConfig()
7387
cfg.Verbose = true
88+
if *bindAddress != "" {
89+
addr, err := net.ResolveUDPAddr("udp", *bindAddress)
90+
if err != nil {
91+
log.Fatalf("Cannot resolve %q as an UDP address: %v", *bindAddress, err)
92+
}
93+
cfg.BindAddress = addr
94+
}
95+
if *useInterfaces != "" {
96+
cfg.UseInterfaces = listize(*useInterfaces)
97+
}
98+
if *blacklistAddresses != "" {
99+
stringAddrs := listize(*blacklistAddresses)
100+
var addrs []*net.IPNet
101+
for _, a := range stringAddrs {
102+
_, ipNet, err := net.ParseCIDR(a)
103+
if err != nil {
104+
log.Fatalf("Malformed addess %q : %v", a, err)
105+
}
106+
addrs = append(addrs, ipNet)
107+
}
108+
cfg.BlacklistAddresses = addrs
109+
}
74110
conn, err := nat.ConnectOpt(xchangeCandidates, *initiator != "", cfg)
75111
if err != nil {
76112
log.Fatalf("NO CARRIER: %v\n", err)

0 commit comments

Comments
 (0)