2016-05-04 12:38:12 -07:00
// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
2017-02-08 23:52:18 -07:00
// You can obtain one at https://mozilla.org/MPL/2.0/.
2016-05-04 12:38:12 -07:00
package connections
import (
"crypto/tls"
2016-05-16 17:05:38 -07:00
"errors"
2016-05-04 12:38:12 -07:00
"fmt"
"net"
"net/url"
2017-04-13 10:43:29 -07:00
"strings"
2016-05-04 12:38:12 -07:00
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/discover"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/nat"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
// Registers NAT service providers
_ "github.com/syncthing/syncthing/lib/pmp"
_ "github.com/syncthing/syncthing/lib/upnp"
"github.com/thejerf/suture"
2017-01-02 04:29:20 -07:00
"golang.org/x/time/rate"
2016-05-04 12:38:12 -07:00
)
var (
dialers = make ( map [ string ] dialerFactory , 0 )
listeners = make ( map [ string ] listenerFactory , 0 )
)
2016-07-02 13:33:31 -07:00
const (
2017-01-02 04:29:20 -07:00
perDeviceWarningIntv = 15 * time . Minute
2016-07-02 13:33:31 -07:00
tlsHandshakeTimeout = 10 * time . Second
)
2016-06-09 05:30:35 -07:00
2016-12-18 14:07:44 -07:00
// From go/src/crypto/tls/cipher_suites.go
var tlsCipherSuiteNames = map [ uint16 ] string {
0x0005 : "TLS_RSA_WITH_RC4_128_SHA" ,
0x000a : "TLS_RSA_WITH_3DES_EDE_CBC_SHA" ,
0x002f : "TLS_RSA_WITH_AES_128_CBC_SHA" ,
0x0035 : "TLS_RSA_WITH_AES_256_CBC_SHA" ,
0x003c : "TLS_RSA_WITH_AES_128_CBC_SHA256" ,
0x009c : "TLS_RSA_WITH_AES_128_GCM_SHA256" ,
0x009d : "TLS_RSA_WITH_AES_256_GCM_SHA384" ,
0xc007 : "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA" ,
0xc009 : "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" ,
0xc00a : "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" ,
0xc011 : "TLS_ECDHE_RSA_WITH_RC4_128_SHA" ,
0xc012 : "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" ,
0xc013 : "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" ,
0xc014 : "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" ,
0xc023 : "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" ,
0xc027 : "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" ,
0xc02f : "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" ,
0xc02b : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ,
0xc030 : "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" ,
0xc02c : "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" ,
0xcca8 : "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" ,
0xcca9 : "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305" ,
}
2016-05-04 12:38:12 -07:00
// Service listens and dials all configured unconnected devices, via supported
// dialers. Successful connections are handed to the model.
type Service struct {
* suture . Supervisor
cfg * config . Wrapper
myID protocol . DeviceID
model Model
tlsCfg * tls . Config
discoverer discover . Finder
2016-11-30 00:54:20 -07:00
conns chan internalConn
2016-05-04 12:38:12 -07:00
bepProtocolName string
tlsDefaultCommonName string
lans [ ] * net . IPNet
2017-01-02 04:29:20 -07:00
limiter * limiter
2016-05-04 12:38:12 -07:00
natService * nat . Service
natServiceToken * suture . ServiceToken
2016-11-19 05:37:14 -07:00
listenersMut sync . RWMutex
listeners map [ string ] genericListener
listenerTokens map [ string ] suture . ServiceToken
listenerSupervisor * suture . Supervisor
2016-05-09 08:03:12 -07:00
curConMut sync . Mutex
2016-11-30 00:54:20 -07:00
currentConnection map [ protocol . DeviceID ] completeConn
2016-05-04 12:38:12 -07:00
}
func NewService ( cfg * config . Wrapper , myID protocol . DeviceID , mdl Model , tlsCfg * tls . Config , discoverer discover . Finder ,
bepProtocolName string , tlsDefaultCommonName string , lans [ ] * net . IPNet ) * Service {
service := & Service {
2016-11-19 05:37:14 -07:00
Supervisor : suture . New ( "connections.Service" , suture . Spec {
Log : func ( line string ) {
l . Infoln ( line )
} ,
} ) ,
2016-05-04 12:38:12 -07:00
cfg : cfg ,
myID : myID ,
model : mdl ,
tlsCfg : tlsCfg ,
discoverer : discoverer ,
2016-11-30 00:54:20 -07:00
conns : make ( chan internalConn ) ,
2016-05-04 12:38:12 -07:00
bepProtocolName : bepProtocolName ,
tlsDefaultCommonName : tlsDefaultCommonName ,
lans : lans ,
2017-01-02 04:29:20 -07:00
limiter : newLimiter ( cfg ) ,
2016-05-04 12:38:12 -07:00
natService : nat . NewService ( myID , cfg ) ,
2016-05-09 08:03:12 -07:00
listenersMut : sync . NewRWMutex ( ) ,
listeners : make ( map [ string ] genericListener ) ,
listenerTokens : make ( map [ string ] suture . ServiceToken ) ,
2016-11-19 05:37:14 -07:00
// A listener can fail twice, rapidly. Any more than that and it
// will be put on suspension for ten minutes. Restarts and changes
// due to config are done by removing and adding services, so are
// not subject to these limitations.
listenerSupervisor : suture . New ( "c.S.listenerSupervisor" , suture . Spec {
Log : func ( line string ) {
l . Infoln ( line )
} ,
FailureThreshold : 2 ,
FailureBackoff : 600 * time . Second ,
} ) ,
2016-05-09 08:03:12 -07:00
curConMut : sync . NewMutex ( ) ,
2016-11-30 00:54:20 -07:00
currentConnection : make ( map [ protocol . DeviceID ] completeConn ) ,
2016-05-04 12:38:12 -07:00
}
cfg . Subscribe ( service )
2017-10-22 05:36:36 -07:00
raw := cfg . RawCopy ( )
// Actually starts the listeners and NAT service
// Need to start this before service.connect so that any dials that
// try punch through already have a listener to cling on.
service . CommitConfiguration ( raw , raw )
2016-05-04 12:38:12 -07:00
// There are several moving parts here; one routine per listening address
// (handled in configuration changing) to handle incoming connections,
// one routine to periodically attempt outgoing connections, one routine to
2017-02-25 01:12:13 -07:00
// the common handling regardless of whether the connection was
2016-05-04 12:38:12 -07:00
// incoming or outgoing.
service . Add ( serviceFunc ( service . connect ) )
service . Add ( serviceFunc ( service . handle ) )
2016-11-19 05:37:14 -07:00
service . Add ( service . listenerSupervisor )
2016-05-04 12:38:12 -07:00
return service
}
2016-05-16 17:05:38 -07:00
var (
errDisabled = errors . New ( "disabled by configuration" )
)
2016-05-04 12:38:12 -07:00
func ( s * Service ) handle ( ) {
next :
for c := range s . conns {
cs := c . ConnectionState ( )
// We should have negotiated the next level protocol "bep/1.0" as part
// of the TLS handshake. Unfortunately this can't be a hard error,
// because there are implementations out there that don't support
// protocol negotiation (iOS for one...).
if ! cs . NegotiatedProtocolIsMutual || cs . NegotiatedProtocol != s . bepProtocolName {
l . Infof ( "Peer %s did not negotiate bep/1.0" , c . RemoteAddr ( ) )
}
// We should have received exactly one certificate from the other
// side. If we didn't, they don't have a device ID and we drop the
// connection.
certs := cs . PeerCertificates
if cl := len ( certs ) ; cl != 1 {
l . Infof ( "Got peer certificate list of length %d != 1 from %s; protocol error" , cl , c . RemoteAddr ( ) )
c . Close ( )
continue
}
remoteCert := certs [ 0 ]
remoteID := protocol . NewDeviceID ( remoteCert . Raw )
// The device ID should not be that of ourselves. It can happen
// though, especially in the presence of NAT hairpinning, multiple
// clients between the same NAT gateway, and global discovery.
if remoteID == s . myID {
l . Infof ( "Connected to myself (%s) - should not happen" , remoteID )
c . Close ( )
continue
}
2016-06-09 03:50:14 -07:00
c . SetDeadline ( time . Now ( ) . Add ( 20 * time . Second ) )
hello , err := protocol . ExchangeHello ( c , s . model . GetHello ( remoteID ) )
2016-05-04 12:38:12 -07:00
if err != nil {
2016-06-09 03:50:14 -07:00
if protocol . IsVersionMismatch ( err ) {
// The error will be a relatively user friendly description
2016-07-04 03:40:29 -07:00
// of what's wrong with the version compatibility. By
// default identify the other side by device ID and IP.
remote := fmt . Sprintf ( "%v (%v)" , remoteID , c . RemoteAddr ( ) )
if hello . DeviceName != "" {
// If the name was set in the hello return, use that to
// give the user more info about which device is the
// affected one. It probably says more than the remote
// IP.
remote = fmt . Sprintf ( "%q (%s %s, %v)" , hello . DeviceName , hello . ClientName , hello . ClientVersion , remoteID )
}
msg := fmt . Sprintf ( "Connecting to %s: %s" , remote , err )
2016-06-09 05:30:35 -07:00
warningFor ( remoteID , msg )
2016-06-09 03:50:14 -07:00
} else {
// It's something else - connection reset or whatever
l . Infof ( "Failed to exchange Hello messages with %s (%s): %s" , remoteID , c . RemoteAddr ( ) , err )
}
2016-05-04 12:38:12 -07:00
c . Close ( )
continue
}
2016-06-09 03:50:14 -07:00
c . SetDeadline ( time . Time { } )
2016-05-04 12:38:12 -07:00
2016-08-05 02:29:49 -07:00
// The Model will return an error for devices that we don't want to
// have a connection with for whatever reason, for example unknown devices.
if err := s . model . OnHello ( remoteID , c . RemoteAddr ( ) , hello ) ; err != nil {
2016-12-02 04:56:14 -07:00
l . Infof ( "Connection from %s at %s (%s) rejected: %v" , remoteID , c . RemoteAddr ( ) , c . Type ( ) , err )
2016-08-05 02:29:49 -07:00
c . Close ( )
continue
}
2016-05-04 12:38:12 -07:00
// If we have a relay connection, and the new incoming connection is
// not a relay connection, we should drop that, and prefer the this one.
2016-08-07 05:20:37 -07:00
connected := s . model . ConnectedTo ( remoteID )
2016-05-09 08:03:12 -07:00
s . curConMut . Lock ( )
2016-05-04 12:38:12 -07:00
ct , ok := s . currentConnection [ remoteID ]
2016-05-09 08:03:12 -07:00
s . curConMut . Unlock ( )
2016-08-07 05:20:37 -07:00
priorityKnown := ok && connected
2016-05-04 12:38:12 -07:00
// Lower priority is better, just like nice etc.
2016-11-30 00:54:20 -07:00
if priorityKnown && ct . internalConn . priority > c . priority {
2016-05-04 12:38:12 -07:00
l . Debugln ( "Switching connections" , remoteID )
2016-08-07 05:20:37 -07:00
} else if connected {
2016-05-04 12:38:12 -07:00
// We should not already be connected to the other party. TODO: This
// could use some better handling. If the old connection is dead but
// hasn't timed out yet we may want to drop *that* connection and keep
// this one. But in case we are two devices connecting to each other
// in parallel we don't want to do that or we end up with no
// connections still established...
l . Infof ( "Connected to already connected device (%s)" , remoteID )
c . Close ( )
2016-05-09 08:03:12 -07:00
continue
2016-05-04 12:38:12 -07:00
}
2016-08-05 02:29:49 -07:00
deviceCfg , ok := s . cfg . Device ( remoteID )
if ! ok {
panic ( "bug: unknown device should already have been rejected" )
}
2016-05-04 12:38:12 -07:00
2016-08-05 02:29:49 -07:00
// Verify the name on the certificate. By default we set it to
// "syncthing" when generating, but the user may have replaced
// the certificate and used another name.
certName := deviceCfg . CertName
if certName == "" {
certName = s . tlsDefaultCommonName
}
if err := remoteCert . VerifyHostname ( certName ) ; err != nil {
// Incorrect certificate name is something the user most
// likely wants to know about, since it's an advanced
// config. Warn instead of Info.
l . Warnf ( "Bad certificate from %s (%v): %v" , remoteID , c . RemoteAddr ( ) , err )
c . Close ( )
continue next
}
2016-05-04 12:38:12 -07:00
2017-01-02 04:29:20 -07:00
// Wrap the connection in rate limiters. The limiter itself will
// keep up with config changes to the rate and whether or not LAN
// connections are limited.
isLAN := s . isLAN ( c . RemoteAddr ( ) )
wr := s . limiter . newWriteLimiter ( c , isLAN )
rd := s . limiter . newReadLimiter ( c , isLAN )
2016-05-04 12:38:12 -07:00
2016-11-30 00:54:20 -07:00
name := fmt . Sprintf ( "%s-%s (%s)" , c . LocalAddr ( ) , c . RemoteAddr ( ) , c . Type ( ) )
2016-08-05 02:29:49 -07:00
protoConn := protocol . NewConnection ( remoteID , rd , wr , s . model , name , deviceCfg . Compression )
2016-11-30 00:54:20 -07:00
modelConn := completeConn { c , protoConn }
2016-05-04 12:38:12 -07:00
2016-12-18 14:07:44 -07:00
l . Infof ( "Established secure connection to %s at %s (%s)" , remoteID , name , tlsCipherSuiteNames [ c . ConnectionState ( ) . CipherSuite ] )
2016-05-04 12:38:12 -07:00
2016-08-05 02:29:49 -07:00
s . model . AddConnection ( modelConn , hello )
s . curConMut . Lock ( )
s . currentConnection [ remoteID ] = modelConn
s . curConMut . Unlock ( )
continue next
2016-05-04 12:38:12 -07:00
}
}
func ( s * Service ) connect ( ) {
nextDial := make ( map [ string ] time . Time )
2016-05-09 08:03:12 -07:00
2016-05-16 17:05:38 -07:00
// Used as delay for the first few connection attempts, increases
// exponentially
initialRampup := time . Second
// Calculated from actual dialers reconnectInterval
var sleep time . Duration
2016-05-09 08:33:25 -07:00
2016-05-04 12:38:12 -07:00
for {
2016-11-12 02:34:18 -07:00
cfg := s . cfg . RawCopy ( )
2016-05-16 17:05:38 -07:00
bestDialerPrio := 1 << 31 - 1 // worse prio won't build on 32 bit
for _ , df := range dialers {
if ! df . Enabled ( cfg ) {
continue
}
if prio := df . Priority ( ) ; prio < bestDialerPrio {
bestDialerPrio = prio
}
}
2016-05-04 12:38:12 -07:00
l . Debugln ( "Reconnect loop" )
now := time . Now ( )
var seen [ ] string
nextDevice :
2016-05-16 17:05:38 -07:00
for _ , deviceCfg := range cfg . Devices {
deviceID := deviceCfg . DeviceID
2016-05-04 12:38:12 -07:00
if deviceID == s . myID {
continue
}
2016-12-21 11:41:25 -07:00
if deviceCfg . Paused {
2016-05-04 12:38:12 -07:00
continue
}
2016-05-09 08:03:12 -07:00
connected := s . model . ConnectedTo ( deviceID )
s . curConMut . Lock ( )
2016-08-07 05:20:37 -07:00
ct , ok := s . currentConnection [ deviceID ]
2016-05-09 08:03:12 -07:00
s . curConMut . Unlock ( )
2016-08-07 05:20:37 -07:00
priorityKnown := ok && connected
2016-05-09 08:03:12 -07:00
2016-11-30 00:54:20 -07:00
if priorityKnown && ct . internalConn . priority == bestDialerPrio {
2016-05-09 08:33:25 -07:00
// Things are already as good as they can get.
continue
}
l . Debugln ( "Reconnect loop for" , deviceID )
2016-05-04 12:38:12 -07:00
var addrs [ ] string
for _ , addr := range deviceCfg . Addresses {
if addr == "dynamic" {
if s . discoverer != nil {
if t , err := s . discoverer . Lookup ( deviceID ) ; err == nil {
addrs = append ( addrs , t ... )
}
}
} else {
addrs = append ( addrs , addr )
}
}
seen = append ( seen , addrs ... )
for _ , addr := range addrs {
2016-05-16 17:05:38 -07:00
nextDialAt , ok := nextDial [ addr ]
if ok && initialRampup >= sleep && nextDialAt . After ( now ) {
l . Debugf ( "Not dialing %v as sleep is %v, next dial is at %s and current time is %s" , addr , sleep , nextDialAt , now )
continue
}
// If we fail at any step before actually getting the dialer
// retry in a minute
nextDial [ addr ] = now . Add ( time . Minute )
2016-05-04 12:38:12 -07:00
uri , err := url . Parse ( addr )
if err != nil {
2016-05-16 17:05:38 -07:00
l . Infof ( "Dialer for %s: %v" , addr , err )
2016-05-04 12:38:12 -07:00
continue
}
2017-04-01 02:52:31 -07:00
if len ( deviceCfg . AllowedNetworks ) > 0 {
if ! IsAllowedNetwork ( uri . Host , deviceCfg . AllowedNetworks ) {
l . Debugln ( "Network for" , uri , "is disallowed" )
continue
}
}
2016-05-16 17:05:38 -07:00
dialerFactory , err := s . getDialerFactory ( cfg , uri )
if err == errDisabled {
l . Debugln ( "Dialer for" , uri , "is disabled" )
2016-05-04 12:38:12 -07:00
continue
}
2016-05-16 17:05:38 -07:00
if err != nil {
l . Infof ( "Dialer for %v: %v" , uri , err )
2016-05-04 12:38:12 -07:00
continue
}
2016-11-30 00:54:20 -07:00
if priorityKnown && dialerFactory . Priority ( ) >= ct . internalConn . priority {
l . Debugf ( "Not dialing using %s as priority is less than current connection (%d >= %d)" , dialerFactory , dialerFactory . Priority ( ) , ct . internalConn . priority )
2016-05-04 12:38:12 -07:00
continue
}
2016-05-16 17:05:38 -07:00
dialer := dialerFactory . New ( s . cfg , s . tlsCfg )
2016-05-04 12:38:12 -07:00
l . Debugln ( "dial" , deviceCfg . DeviceID , uri )
2016-05-16 17:05:38 -07:00
nextDial [ addr ] = now . Add ( dialer . RedialFrequency ( ) )
2016-05-04 12:38:12 -07:00
conn , err := dialer . Dial ( deviceID , uri )
if err != nil {
l . Debugln ( "dial failed" , deviceCfg . DeviceID , uri , err )
continue
}
s . conns <- conn
continue nextDevice
}
}
nextDial , sleep = filterAndFindSleepDuration ( nextDial , seen , now )
2016-05-16 17:05:38 -07:00
if initialRampup < sleep {
l . Debugln ( "initial rampup; sleep" , initialRampup , "and update to" , initialRampup * 2 )
time . Sleep ( initialRampup )
initialRampup *= 2
2016-05-04 12:38:12 -07:00
} else {
2016-05-16 17:05:38 -07:00
l . Debugln ( "sleep until next dial" , sleep )
2016-05-04 12:38:12 -07:00
time . Sleep ( sleep )
}
}
}
2017-01-02 04:29:20 -07:00
func ( s * Service ) isLAN ( addr net . Addr ) bool {
2016-05-04 12:38:12 -07:00
tcpaddr , ok := addr . ( * net . TCPAddr )
if ! ok {
2017-01-02 04:29:20 -07:00
return false
2016-05-04 12:38:12 -07:00
}
for _ , lan := range s . lans {
if lan . Contains ( tcpaddr . IP ) {
2017-01-02 04:29:20 -07:00
return true
2016-05-04 12:38:12 -07:00
}
}
2017-01-02 04:29:20 -07:00
return tcpaddr . IP . IsLoopback ( )
2016-05-04 12:38:12 -07:00
}
2016-05-16 17:05:38 -07:00
func ( s * Service ) createListener ( factory listenerFactory , uri * url . URL ) bool {
2016-05-09 08:03:12 -07:00
// must be called with listenerMut held
2016-05-04 12:38:12 -07:00
2016-05-16 17:05:38 -07:00
l . Debugln ( "Starting listener" , uri )
2016-05-04 12:38:12 -07:00
2016-05-16 17:05:38 -07:00
listener := factory . New ( uri , s . cfg , s . tlsCfg , s . conns , s . natService )
2016-05-04 12:38:12 -07:00
listener . OnAddressesChanged ( s . logListenAddressesChangedEvent )
2016-05-16 17:05:38 -07:00
s . listeners [ uri . String ( ) ] = listener
2016-11-19 05:37:14 -07:00
s . listenerTokens [ uri . String ( ) ] = s . listenerSupervisor . Add ( listener )
2016-05-16 17:05:38 -07:00
return true
2016-05-04 12:38:12 -07:00
}
func ( s * Service ) logListenAddressesChangedEvent ( l genericListener ) {
events . Default . Log ( events . ListenAddressesChanged , map [ string ] interface { } {
"address" : l . URI ( ) ,
"lan" : l . LANAddresses ( ) ,
"wan" : l . WANAddresses ( ) ,
} )
}
func ( s * Service ) VerifyConfiguration ( from , to config . Configuration ) error {
return nil
}
func ( s * Service ) CommitConfiguration ( from , to config . Configuration ) bool {
newDevices := make ( map [ protocol . DeviceID ] bool , len ( to . Devices ) )
for _ , dev := range to . Devices {
newDevices [ dev . DeviceID ] = true
}
for _ , dev := range from . Devices {
if ! newDevices [ dev . DeviceID ] {
2016-08-07 09:21:59 -07:00
s . curConMut . Lock ( )
delete ( s . currentConnection , dev . DeviceID )
s . curConMut . Unlock ( )
warningLimitersMut . Lock ( )
delete ( warningLimiters , dev . DeviceID )
warningLimitersMut . Unlock ( )
2016-05-04 12:38:12 -07:00
}
}
2016-05-09 08:03:12 -07:00
s . listenersMut . Lock ( )
2016-05-04 12:38:12 -07:00
seen := make ( map [ string ] struct { } )
for _ , addr := range config . Wrap ( "" , to ) . ListenAddresses ( ) {
2016-05-16 17:05:38 -07:00
if _ , ok := s . listeners [ addr ] ; ok {
seen [ addr ] = struct { } { }
continue
2016-05-04 12:38:12 -07:00
}
2016-05-16 17:05:38 -07:00
uri , err := url . Parse ( addr )
if err != nil {
l . Infof ( "Listener for %s: %v" , addr , err )
continue
}
factory , err := s . getListenerFactory ( to , uri )
if err == errDisabled {
l . Debugln ( "Listener for" , uri , "is disabled" )
continue
}
if err != nil {
l . Infof ( "Listener for %v: %v" , uri , err )
continue
}
s . createListener ( factory , uri )
2016-05-04 12:38:12 -07:00
seen [ addr ] = struct { } { }
}
2016-05-16 17:05:38 -07:00
for addr , listener := range s . listeners {
if _ , ok := seen [ addr ] ; ! ok || ! listener . Factory ( ) . Enabled ( to ) {
2016-05-04 12:38:12 -07:00
l . Debugln ( "Stopping listener" , addr )
2016-11-19 05:37:14 -07:00
s . listenerSupervisor . Remove ( s . listenerTokens [ addr ] )
2016-05-04 12:38:12 -07:00
delete ( s . listenerTokens , addr )
delete ( s . listeners , addr )
}
}
2016-05-09 08:03:12 -07:00
s . listenersMut . Unlock ( )
2016-05-04 12:38:12 -07:00
if to . Options . NATEnabled && s . natServiceToken == nil {
l . Debugln ( "Starting NAT service" )
token := s . Add ( s . natService )
s . natServiceToken = & token
} else if ! to . Options . NATEnabled && s . natServiceToken != nil {
l . Debugln ( "Stopping NAT service" )
s . Remove ( * s . natServiceToken )
s . natServiceToken = nil
}
2016-08-07 09:21:59 -07:00
return true
2016-05-04 12:38:12 -07:00
}
func ( s * Service ) AllAddresses ( ) [ ] string {
2016-05-09 08:03:12 -07:00
s . listenersMut . RLock ( )
2016-05-04 12:38:12 -07:00
var addrs [ ] string
for _ , listener := range s . listeners {
for _ , lanAddr := range listener . LANAddresses ( ) {
addrs = append ( addrs , lanAddr . String ( ) )
}
for _ , wanAddr := range listener . WANAddresses ( ) {
addrs = append ( addrs , wanAddr . String ( ) )
}
}
2016-05-09 08:03:12 -07:00
s . listenersMut . RUnlock ( )
2016-05-04 12:38:12 -07:00
return util . UniqueStrings ( addrs )
}
func ( s * Service ) ExternalAddresses ( ) [ ] string {
2016-05-09 08:03:12 -07:00
s . listenersMut . RLock ( )
2016-05-04 12:38:12 -07:00
var addrs [ ] string
for _ , listener := range s . listeners {
for _ , wanAddr := range listener . WANAddresses ( ) {
addrs = append ( addrs , wanAddr . String ( ) )
}
}
2016-05-09 08:03:12 -07:00
s . listenersMut . RUnlock ( )
2016-05-04 12:38:12 -07:00
return util . UniqueStrings ( addrs )
}
func ( s * Service ) Status ( ) map [ string ] interface { } {
2016-05-09 08:03:12 -07:00
s . listenersMut . RLock ( )
2016-05-04 12:38:12 -07:00
result := make ( map [ string ] interface { } )
for addr , listener := range s . listeners {
status := make ( map [ string ] interface { } )
err := listener . Error ( )
if err != nil {
status [ "error" ] = err . Error ( )
}
status [ "lanAddresses" ] = urlsToStrings ( listener . LANAddresses ( ) )
status [ "wanAddresses" ] = urlsToStrings ( listener . WANAddresses ( ) )
result [ addr ] = status
}
2016-05-09 08:03:12 -07:00
s . listenersMut . RUnlock ( )
2016-05-04 12:38:12 -07:00
return result
}
2017-10-11 23:16:46 -07:00
func ( s * Service ) NATType ( ) string {
s . listenersMut . RLock ( )
defer s . listenersMut . RUnlock ( )
for _ , listener := range s . listeners {
natType := listener . NATType ( )
if natType != "unknown" {
return natType
}
}
return "unknown"
}
2016-05-16 17:05:38 -07:00
func ( s * Service ) getDialerFactory ( cfg config . Configuration , uri * url . URL ) ( dialerFactory , error ) {
dialerFactory , ok := dialers [ uri . Scheme ]
if ! ok {
return nil , fmt . Errorf ( "unknown address scheme %q" , uri . Scheme )
}
if ! dialerFactory . Enabled ( cfg ) {
return nil , errDisabled
}
return dialerFactory , nil
}
func ( s * Service ) getListenerFactory ( cfg config . Configuration , uri * url . URL ) ( listenerFactory , error ) {
listenerFactory , ok := listeners [ uri . Scheme ]
if ! ok {
return nil , fmt . Errorf ( "unknown address scheme %q" , uri . Scheme )
}
if ! listenerFactory . Enabled ( cfg ) {
return nil , errDisabled
}
return listenerFactory , nil
}
2016-05-04 12:38:12 -07:00
func filterAndFindSleepDuration ( nextDial map [ string ] time . Time , seen [ ] string , now time . Time ) ( map [ string ] time . Time , time . Duration ) {
newNextDial := make ( map [ string ] time . Time )
for _ , addr := range seen {
nextDialAt , ok := nextDial [ addr ]
if ok {
newNextDial [ addr ] = nextDialAt
}
}
min := time . Minute
for _ , next := range newNextDial {
cur := next . Sub ( now )
if cur < min {
min = cur
}
}
return newNextDial , min
}
func urlsToStrings ( urls [ ] * url . URL ) [ ] string {
strings := make ( [ ] string , len ( urls ) )
for i , url := range urls {
strings [ i ] = url . String ( )
}
return strings
}
2016-06-09 05:30:35 -07:00
2017-01-02 04:29:20 -07:00
var warningLimiters = make ( map [ protocol . DeviceID ] * rate . Limiter )
2016-06-09 05:30:35 -07:00
var warningLimitersMut = sync . NewMutex ( )
func warningFor ( dev protocol . DeviceID , msg string ) {
warningLimitersMut . Lock ( )
defer warningLimitersMut . Unlock ( )
lim , ok := warningLimiters [ dev ]
if ! ok {
2017-01-02 04:29:20 -07:00
lim = rate . NewLimiter ( rate . Every ( perDeviceWarningIntv ) , 1 )
2016-06-09 05:30:35 -07:00
warningLimiters [ dev ] = lim
}
2017-01-02 04:29:20 -07:00
if lim . Allow ( ) {
2016-06-09 05:30:35 -07:00
l . Warnln ( msg )
}
}
2016-07-02 13:33:31 -07:00
func tlsTimedHandshake ( tc * tls . Conn ) error {
tc . SetDeadline ( time . Now ( ) . Add ( tlsHandshakeTimeout ) )
defer tc . SetDeadline ( time . Time { } )
return tc . Handshake ( )
}
2017-04-01 02:52:31 -07:00
// IsAllowedNetwork returns true if the given host (IP or resolvable
// hostname) is in the set of allowed networks (CIDR format only).
func IsAllowedNetwork ( host string , allowed [ ] string ) bool {
if hostNoPort , _ , err := net . SplitHostPort ( host ) ; err == nil {
host = hostNoPort
}
addr , err := net . ResolveIPAddr ( "ip" , host )
if err != nil {
return false
}
for _ , n := range allowed {
2017-04-13 10:43:29 -07:00
result := true
if strings . HasPrefix ( n , "!" ) {
result = false
n = n [ 1 : ]
}
2017-04-01 02:52:31 -07:00
_ , cidr , err := net . ParseCIDR ( n )
if err != nil {
continue
}
if cidr . Contains ( addr . IP ) {
2017-04-13 10:43:29 -07:00
return result
2017-04-01 02:52:31 -07:00
}
}
return false
}