-
Notifications
You must be signed in to change notification settings - Fork 2
/
upnp.go
172 lines (149 loc) · 5.05 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package main
import (
"net"
"strings"
"github.com/huin/goupnp/dcps/internetgateway1"
"github.com/nettica-com/nettica-admin/model"
log "github.com/sirupsen/logrus"
)
func isBogon(ip string) bool {
// Check to see if the ip address is a bogon
// https://en.wikipedia.org/wiki/Bogon_filtering
// https://www.team-cymru.org/Bogons/
addr := net.ParseIP(ip)
if addr == nil {
log.Error("Invalid IP address")
return true
}
// check if the address is a bogon
if addr.IsLoopback() || addr.IsLinkLocalUnicast() || addr.IsLinkLocalMulticast() {
log.Error("IP address is a bogon")
return true
}
if ip == "0.0.0.0" {
return true
}
return false
}
func ConfigureUPnP(vpn model.VPN) error {
if vpn.Current.UPnP {
log.Infof("***UPNP*** Configuring UPnP for %s", vpn.Name)
clients, _, err := internetgateway1.NewWANIPConnection1Clients()
if err != nil {
log.Errorf("WAN Error discovering gateway, upnp likely not supported. %v", err)
}
if len(clients) == 0 {
log.Error("***UPNP***WAN No gateway found, upnp likely not supported.")
}
for _, c := range clients {
if vpn.Current.ListenPort != 0 && vpn.Current.Endpoint != "" {
// get local ip address
conn, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
log.Error("Impossible to get local ip address")
} else {
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
// get the external ip address
externalIP, err := c.GetExternalIPAddress()
if err != nil {
log.Errorf("Error getting external ip address, %v", err)
} else {
log.Infof("***UPNP*** External IP address: %s", externalIP)
// compare the externalIP to the endpoint
parts := strings.Split(vpn.Current.Endpoint, ":")
if parts[0] != externalIP && !isBogon(externalIP) {
log.Error("External IP address does not match endpoint")
// Update the vpn endpoint at nettica
vpn.Current.Endpoint = externalIP + ":" + parts[1]
if !vpn.Current.SyncEndpoint {
UpdateVPN(&vpn)
}
}
}
// delete any old port mappings
err = c.DeletePortMapping("", uint16(vpn.Current.ListenPort), "UDP")
if err != nil {
log.Errorf("Error deleting port mapping, %v", err)
}
log.Infof("***UPNP*** AddPortMapping: %d %s %d %s %s", vpn.Current.ListenPort, "UDP", vpn.Current.ListenPort, localAddr.IP.String(), vpn.Name+"-"+vpn.NetName)
// add port mapping
err = c.AddPortMapping("", uint16(vpn.Current.ListenPort), "UDP", uint16(vpn.Current.ListenPort), localAddr.IP.String(), true, vpn.Name+"-"+vpn.NetName, 0)
if err != nil {
log.Errorf("Error adding port mapping, %v", err)
}
}
}
}
ppp, _, err := internetgateway1.NewWANPPPConnection1Clients()
if err != nil { // no ppp connection
log.Errorf("Error discovering PPP gateway, likely doesn not exist. %v", err)
return err
}
if len(ppp) == 0 {
log.Error("No PPP gateway found, likely does not exist.")
return err
}
log.Info("PPP gateway found, configuring external IP and port mapping.")
for _, c := range ppp {
if vpn.Current.ListenPort != 0 && vpn.Current.Endpoint != "" {
// get local ip address
conn, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
log.Error("Impossible to get local ip address")
} else {
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
// get the external ip address
externalIP, err := c.GetExternalIPAddress()
if err != nil {
log.Errorf("PPP Error getting external ip address, %v", err)
} else {
log.Infof("***UPNP***PPP External IP address: %s", externalIP)
// compare the externalIP to the endpoint
parts := strings.Split(vpn.Current.Endpoint, ":")
if parts[0] != externalIP && !isBogon(externalIP) {
log.Error("PPP External IP address does not match endpoint")
// Update the vpn endpoint at nettica
vpn.Current.Endpoint = externalIP + ":" + parts[1]
if !vpn.Current.SyncEndpoint {
UpdateVPN(&vpn)
}
}
}
// delete any old port mappings
err = c.DeletePortMapping("", uint16(vpn.Current.ListenPort), "UDP")
if err != nil {
log.Errorf("PPP Error deleting port mapping, %v", err)
}
log.Infof("***UPNP***PPP AddPortMapping: %d %s %d %s %s", vpn.Current.ListenPort, "UDP", vpn.Current.ListenPort, localAddr.IP.String(), vpn.Name+"-"+vpn.NetName)
// add port mapping
err = c.AddPortMapping("", uint16(vpn.Current.ListenPort), "UDP", uint16(vpn.Current.ListenPort), localAddr.IP.String(), true, vpn.Name+"-"+vpn.NetName, 0)
if err != nil {
log.Errorf("PPP Error adding port mapping, %v", err)
}
}
}
}
}
return nil
}
func UpdateVPN(vpn *model.VPN) error {
// Update the vpn at nettica
for _, s := range Servers {
if s.Worker != nil {
v, _, err := s.Worker.FindVPN(vpn.NetName)
if err != nil {
log.Errorf("Error finding vpn: %v", err)
}
if v != nil {
err = s.Worker.UpdateVPN(vpn)
if err != nil {
log.Errorf("Error updating vpn: %v", err)
}
return err
}
}
}
return nil
}