Restart port sequence when UPnP renewal fails

This commit is contained in:
Audrius Butkevicius 2014-08-13 22:41:32 +01:00
parent 870e3ca893
commit 7cc9921615

View File

@ -83,6 +83,7 @@ var (
lockConn *net.TCPListener lockConn *net.TCPListener
lockPort int lockPort int
externalPort int externalPort int
cert tls.Certificate
) )
const ( const (
@ -249,7 +250,7 @@ func main() {
// Ensure that our home directory exists and that we have a certificate and key. // Ensure that our home directory exists and that we have a certificate and key.
ensureDir(confDir, 0700) ensureDir(confDir, 0700)
cert, err := loadCert(confDir, "") cert, err = loadCert(confDir, "")
if err != nil { if err != nil {
newCertificate(confDir, "") newCertificate(confDir, "")
cert, err = loadCert(confDir, "") cert, err = loadCert(confDir, "")
@ -472,9 +473,7 @@ nextRepo:
// UPnP // UPnP
if cfg.Options.UPnPEnabled { if cfg.Options.UPnPEnabled {
// We seed the random number generator with the node ID to get a setupUPnP()
// repeatable sequence of random external ports.
setupUPnP(rand.NewSource(certSeed(cert.Certificate[0])))
} }
// Routine to connect out to configured nodes // Routine to connect out to configured nodes
@ -561,7 +560,7 @@ func waitForParentExit() {
l.Infoln("Continuing") l.Infoln("Continuing")
} }
func setupUPnP(rnd rand.Source) { func setupUPnP() {
if len(cfg.Options.ListenAddress) == 1 { if len(cfg.Options.ListenAddress) == 1 {
_, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0]) _, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0])
if err != nil { if err != nil {
@ -571,17 +570,11 @@ func setupUPnP(rnd rand.Source) {
port, _ := strconv.Atoi(portStr) port, _ := strconv.Atoi(portStr)
igd, err := upnp.Discover() igd, err := upnp.Discover()
if err == nil { if err == nil {
for i := 0; i < 10; i++ { externalPort = setupExternalPort(igd, port)
r := 1024 + int(rnd.Int63()%(65535-1024))
err := igd.AddPortMapping(upnp.TCP, r, port, "syncthing", cfg.Options.UPnPLease*60)
if err == nil {
externalPort = r
l.Infoln("Created UPnP port mapping - external port", externalPort)
break
}
}
if externalPort == 0 { if externalPort == 0 {
l.Warnln("Failed to create UPnP port mapping") l.Warnln("Failed to create UPnP port mapping")
} else {
l.Infoln("Created UPnP port mapping - external port", externalPort)
} }
} else { } else {
l.Infof("No UPnP gateway detected") l.Infof("No UPnP gateway detected")
@ -590,7 +583,7 @@ func setupUPnP(rnd rand.Source) {
} }
} }
if cfg.Options.UPnPRenewal > 0 { if cfg.Options.UPnPRenewal > 0 {
go renewUPnP(rnd, port) go renewUPnP(port)
} }
} }
} else { } else {
@ -598,7 +591,21 @@ func setupUPnP(rnd rand.Source) {
} }
} }
func renewUPnP(rnd rand.Source, port int) { func setupExternalPort(igd *upnp.IGD, port int) int {
// We seed the random number generator with the node ID to get a
// repeatable sequence of random external ports.
rnd := rand.NewSource(certSeed(cert.Certificate[0]))
for i := 0; i < 10; i++ {
r := 1024 + int(rnd.Int63()%(65535-1024))
err := igd.AddPortMapping(upnp.TCP, r, port, "syncthing", cfg.Options.UPnPLease*60)
if err == nil {
return r
}
}
return 0
}
func renewUPnP(port int) {
for { for {
time.Sleep(time.Duration(cfg.Options.UPnPRenewal) * time.Minute) time.Sleep(time.Duration(cfg.Options.UPnPRenewal) * time.Minute)
@ -607,21 +614,23 @@ func renewUPnP(rnd rand.Source, port int) {
continue continue
} }
// Just renew the same port that we already have
err = igd.AddPortMapping(upnp.TCP, externalPort, port, "syncthing", cfg.Options.UPnPLease*60) err = igd.AddPortMapping(upnp.TCP, externalPort, port, "syncthing", cfg.Options.UPnPLease*60)
if err == nil { if err == nil {
l.Infoln("Renewed UPnP port mapping - external port", externalPort) l.Infoln("Renewed UPnP port mapping - external port", externalPort)
continue continue
} }
r := 1024 + int(rnd.Int63()%(65535-1024)) // Something strange has happened. Perhaps the gateway has changed?
err = igd.AddPortMapping(upnp.TCP, r, port, "syncthing", cfg.Options.UPnPLease*60) // Retry the same port sequence from the beginning.
if err == nil { r := setupExternalPort(igd, port)
l.Infoln("Updated UPnP port mapping - external port", externalPort) if r != 0 {
externalPort = r externalPort = r
l.Infoln("Updated UPnP port mapping - external port", externalPort)
discoverer.StartGlobal(cfg.Options.GlobalAnnServer, uint16(r)) discoverer.StartGlobal(cfg.Options.GlobalAnnServer, uint16(r))
continue continue
} }
l.Warnln("Failed to update UPnP port mapping - externalPort", externalPort) l.Warnln("Failed to update UPnP port mapping - external port", externalPort)
} }
} }