-
Notifications
You must be signed in to change notification settings - Fork 338
/
upnp.go
68 lines (53 loc) · 2.12 KB
/
upnp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package libp2p
import (
"errors"
"strings"
"github.com/libp2p/go-libp2p/core/host"
libp2ppeer "github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
type UpnpAddressResolver struct {
host host.Host
}
// Resolve checks if there is a possible better advertisable underlay then the provided observed address.
// In some NAT situations, for example in the case when nodes are behind upnp, observer might send the observed address with a wrong port.
// In this case, observed address is compared to addresses provided by host, and if there is a same address but with different port, that one is used as advertisable address instead of provided observed one.
// TODO: this is a quickfix and it will be improved in the future
func (r *UpnpAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) {
observableAddrInfo, err := libp2ppeer.AddrInfoFromP2pAddr(observedAddress)
if err != nil {
return nil, err
}
if len(observableAddrInfo.Addrs) < 1 {
return nil, errors.New("invalid observed address")
}
observedAddrSplit := strings.Split(observableAddrInfo.Addrs[0].String(), "/")
// if address is not in a form of '/ipversion/ip/protocol/port/...` don't compare to addresses and return it
if len(observedAddrSplit) < 5 {
return observedAddress, nil
}
observedAddressPort := observedAddrSplit[4]
// observervedAddressShort is an obaserved address without port
observervedAddressShort := strings.Join(append(observedAddrSplit[:4], observedAddrSplit[5:]...), "/")
for _, a := range r.host.Addrs() {
asplit := strings.Split(a.String(), "/")
if len(asplit) != len(observedAddrSplit) {
continue
}
aport := asplit[4]
if strings.Join(append(asplit[:4], asplit[5:]...), "/") != observervedAddressShort {
continue
}
if aport != observedAddressPort {
aaddress, err := buildUnderlayAddress(a, observableAddrInfo.ID)
if err != nil {
continue
}
return aaddress, nil
}
}
return observedAddress, nil
}