main.go 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "crypto/sha1"
  7. "crypto/tls"
  8. "flag"
  9. "fmt"
  10. "io"
  11. "log"
  12. "math/rand"
  13. "net"
  14. "net/http"
  15. _ "net/http/pprof"
  16. "os"
  17. "path/filepath"
  18. "regexp"
  19. "runtime"
  20. "runtime/debug"
  21. "runtime/pprof"
  22. "strconv"
  23. "strings"
  24. "time"
  25. "code.google.com/p/go.crypto/bcrypt"
  26. "github.com/juju/ratelimit"
  27. "github.com/syncthing/syncthing/config"
  28. "github.com/syncthing/syncthing/discover"
  29. "github.com/syncthing/syncthing/events"
  30. "github.com/syncthing/syncthing/files"
  31. "github.com/syncthing/syncthing/logger"
  32. "github.com/syncthing/syncthing/model"
  33. "github.com/syncthing/syncthing/protocol"
  34. "github.com/syncthing/syncthing/upgrade"
  35. "github.com/syncthing/syncthing/upnp"
  36. "github.com/syndtr/goleveldb/leveldb"
  37. "github.com/syndtr/goleveldb/leveldb/opt"
  38. )
  39. var (
  40. Version = "unknown-dev"
  41. BuildEnv = "default"
  42. BuildStamp = "0"
  43. BuildDate time.Time
  44. BuildHost = "unknown"
  45. BuildUser = "unknown"
  46. LongVersion string
  47. GoArchExtra string // "", "v5", "v6", "v7"
  48. )
  49. const (
  50. exitSuccess = 0
  51. exitError = 1
  52. exitNoUpgradeAvailable = 2
  53. exitRestarting = 3
  54. exitUpgrading = 4
  55. )
  56. var l = logger.DefaultLogger
  57. var innerProcess = os.Getenv("STNORESTART") != ""
  58. func init() {
  59. if Version != "unknown-dev" {
  60. // If not a generic dev build, version string should come from git describe
  61. exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\+\d+-g[0-9a-f]+)?(-dirty)?$`)
  62. if !exp.MatchString(Version) {
  63. l.Fatalf("Invalid version string %q;\n\tdoes not match regexp %v", Version, exp)
  64. }
  65. }
  66. stamp, _ := strconv.Atoi(BuildStamp)
  67. BuildDate = time.Unix(int64(stamp), 0)
  68. date := BuildDate.UTC().Format("2006-01-02 15:04:05 MST")
  69. LongVersion = fmt.Sprintf("syncthing %s (%s %s-%s %s) %s@%s %s", Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, BuildEnv, BuildUser, BuildHost, date)
  70. if os.Getenv("STTRACE") != "" {
  71. logFlags = log.Ltime | log.Ldate | log.Lmicroseconds | log.Lshortfile
  72. }
  73. }
  74. var (
  75. cfg config.Configuration
  76. myID protocol.NodeID
  77. confDir string
  78. logFlags int = log.Ltime
  79. writeRateLimit *ratelimit.Bucket
  80. readRateLimit *ratelimit.Bucket
  81. stop = make(chan int)
  82. discoverer *discover.Discoverer
  83. externalPort int
  84. cert tls.Certificate
  85. )
  86. const (
  87. usage = "syncthing [options]"
  88. extraUsage = `The value for the -logflags option is a sum of the following:
  89. 1 Date
  90. 2 Time
  91. 4 Microsecond time
  92. 8 Long filename
  93. 16 Short filename
  94. I.e. to prefix each log line with date and time, set -logflags=3 (1 + 2 from
  95. above). The value 0 is used to disable all of the above. The default is to
  96. show time only (2).
  97. The following enviroment variables are interpreted by syncthing:
  98. STGUIADDRESS Override GUI listen address set in config. Expects protocol type
  99. followed by hostname or an IP address, followed by a port, such
  100. as "https://127.0.0.1:8888".
  101. STGUIAUTH Override GUI authentication credentials set in config. Expects
  102. a colon separated username and password, such as "admin:secret".
  103. STGUIAPIKEY Override GUI API key set in config.
  104. STNORESTART Do not attempt to restart when requested to, instead just exit.
  105. Set this variable when running under a service manager such as
  106. runit, launchd, etc.
  107. STTRACE A comma separated string of facilities to trace. The valid
  108. facility strings:
  109. - "beacon" (the beacon package)
  110. - "discover" (the discover package)
  111. - "events" (the events package)
  112. - "files" (the files package)
  113. - "net" (the main package; connections & network messages)
  114. - "model" (the model package)
  115. - "scanner" (the scanner package)
  116. - "stats" (the stats package)
  117. - "upnp" (the upnp package)
  118. - "xdr" (the xdr package)
  119. - "all" (all of the above)
  120. STGUIASSETS Directory to load GUI assets from. Overrides compiled in assets.
  121. STPROFILER Set to a listen address such as "127.0.0.1:9090" to start the
  122. profiler with HTTP access.
  123. STCPUPROFILE Write a CPU profile to cpu-$pid.pprof on exit.
  124. STHEAPPROFILE Write heap profiles to heap-$pid-$timestamp.pprof each time
  125. heap usage increases.
  126. STPERFSTATS Write running performance statistics to perf-$pid.csv. Not
  127. supported on Windows.
  128. GOMAXPROCS Set the maximum number of CPU cores to use. Defaults to all
  129. available CPU cores.`
  130. )
  131. func init() {
  132. rand.Seed(time.Now().UnixNano())
  133. }
  134. // Command line options
  135. var (
  136. reset bool
  137. showVersion bool
  138. doUpgrade bool
  139. doUpgradeCheck bool
  140. noBrowser bool
  141. generateDir string
  142. guiAddress string
  143. guiAuthentication string
  144. guiAPIKey string
  145. )
  146. func main() {
  147. flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory")
  148. flag.BoolVar(&reset, "reset", false, "Prepare to resync from cluster")
  149. flag.BoolVar(&showVersion, "version", false, "Show version")
  150. flag.BoolVar(&doUpgrade, "upgrade", false, "Perform upgrade")
  151. flag.BoolVar(&doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
  152. flag.BoolVar(&noBrowser, "no-browser", false, "Do not start browser")
  153. flag.StringVar(&generateDir, "generate", "", "Generate key in specified dir")
  154. flag.StringVar(&guiAddress, "gui-address", "", "Override GUI address")
  155. flag.StringVar(&guiAuthentication, "gui-authentication", "", "Override GUI authentication. Expects 'username:password'")
  156. flag.StringVar(&guiAPIKey, "gui-apikey", "", "Override GUI API key")
  157. flag.IntVar(&logFlags, "logflags", logFlags, "Set log flags")
  158. flag.Usage = usageFor(flag.CommandLine, usage, extraUsage)
  159. flag.Parse()
  160. if showVersion {
  161. fmt.Println(LongVersion)
  162. return
  163. }
  164. l.SetFlags(logFlags)
  165. if generateDir != "" {
  166. dir := expandTilde(generateDir)
  167. info, err := os.Stat(dir)
  168. if err != nil {
  169. l.Fatalln("generate:", err)
  170. }
  171. if !info.IsDir() {
  172. l.Fatalln(dir, "is not a directory")
  173. }
  174. cert, err := loadCert(dir, "")
  175. if err == nil {
  176. l.Warnln("Key exists; will not overwrite.")
  177. l.Infoln("Node ID:", protocol.NewNodeID(cert.Certificate[0]))
  178. return
  179. }
  180. newCertificate(dir, "")
  181. cert, err = loadCert(dir, "")
  182. if err != nil {
  183. l.Fatalln("load cert:", err)
  184. }
  185. if err == nil {
  186. l.Infoln("Node ID:", protocol.NewNodeID(cert.Certificate[0]))
  187. }
  188. return
  189. }
  190. if doUpgrade || doUpgradeCheck {
  191. rel, err := upgrade.LatestRelease(strings.Contains(Version, "-beta"))
  192. if err != nil {
  193. l.Fatalln("Upgrade:", err) // exits 1
  194. }
  195. if upgrade.CompareVersions(rel.Tag, Version) <= 0 {
  196. l.Infof("No upgrade available (current %q >= latest %q).", Version, rel.Tag)
  197. os.Exit(exitNoUpgradeAvailable)
  198. }
  199. l.Infof("Upgrade available (current %q < latest %q)", Version, rel.Tag)
  200. if doUpgrade {
  201. err = upgrade.UpgradeTo(rel, GoArchExtra)
  202. if err != nil {
  203. l.Fatalln("Upgrade:", err) // exits 1
  204. }
  205. l.Okf("Upgraded to %q", rel.Tag)
  206. return
  207. } else {
  208. return
  209. }
  210. }
  211. if reset {
  212. resetRepositories()
  213. return
  214. }
  215. confDir = expandTilde(confDir)
  216. if info, err := os.Stat(confDir); err == nil && !info.IsDir() {
  217. l.Fatalln("Config directory", confDir, "is not a directory")
  218. }
  219. if os.Getenv("STNORESTART") != "" {
  220. syncthingMain()
  221. } else {
  222. monitorMain()
  223. }
  224. }
  225. func syncthingMain() {
  226. var err error
  227. if len(os.Getenv("GOGC")) == 0 {
  228. debug.SetGCPercent(25)
  229. }
  230. if len(os.Getenv("GOMAXPROCS")) == 0 {
  231. runtime.GOMAXPROCS(runtime.NumCPU())
  232. }
  233. events.Default.Log(events.Starting, map[string]string{"home": confDir})
  234. if _, err = os.Stat(confDir); err != nil && confDir == getDefaultConfDir() {
  235. // We are supposed to use the default configuration directory. It
  236. // doesn't exist. In the past our default has been ~/.syncthing, so if
  237. // that directory exists we move it to the new default location and
  238. // continue. We don't much care if this fails at this point, we will
  239. // be checking that later.
  240. var oldDefault string
  241. if runtime.GOOS == "windows" {
  242. oldDefault = filepath.Join(os.Getenv("AppData"), "Syncthing")
  243. } else {
  244. oldDefault = expandTilde("~/.syncthing")
  245. }
  246. if _, err := os.Stat(oldDefault); err == nil {
  247. os.MkdirAll(filepath.Dir(confDir), 0700)
  248. if err := os.Rename(oldDefault, confDir); err == nil {
  249. l.Infoln("Moved config dir", oldDefault, "to", confDir)
  250. }
  251. }
  252. }
  253. // Ensure that our home directory exists and that we have a certificate and key.
  254. ensureDir(confDir, 0700)
  255. cert, err = loadCert(confDir, "")
  256. if err != nil {
  257. newCertificate(confDir, "")
  258. cert, err = loadCert(confDir, "")
  259. if err != nil {
  260. l.Fatalln("load cert:", err)
  261. }
  262. }
  263. myID = protocol.NewNodeID(cert.Certificate[0])
  264. l.SetPrefix(fmt.Sprintf("[%s] ", myID.String()[:5]))
  265. l.Infoln(LongVersion)
  266. l.Infoln("My ID:", myID)
  267. // Prepare to be able to save configuration
  268. cfgFile := filepath.Join(confDir, "config.xml")
  269. var myName string
  270. // Load the configuration file, if it exists.
  271. // If it does not, create a template.
  272. cfg, err = config.Load(cfgFile, myID)
  273. if err == nil {
  274. myCfg := cfg.GetNodeConfiguration(myID)
  275. if myCfg == nil || myCfg.Name == "" {
  276. myName, _ = os.Hostname()
  277. } else {
  278. myName = myCfg.Name
  279. }
  280. } else {
  281. l.Infoln("No config file; starting with empty defaults")
  282. myName, _ = os.Hostname()
  283. defaultRepo := filepath.Join(getHomeDir(), "Sync")
  284. cfg = config.New(cfgFile, myID)
  285. cfg.Repositories = []config.RepositoryConfiguration{
  286. {
  287. ID: "default",
  288. Directory: defaultRepo,
  289. RescanIntervalS: 60,
  290. Nodes: []config.RepositoryNodeConfiguration{{NodeID: myID}},
  291. },
  292. }
  293. cfg.Nodes = []config.NodeConfiguration{
  294. {
  295. NodeID: myID,
  296. Addresses: []string{"dynamic"},
  297. Name: myName,
  298. },
  299. }
  300. port, err := getFreePort("127.0.0.1", 8080)
  301. if err != nil {
  302. l.Fatalln("get free port (GUI):", err)
  303. }
  304. cfg.GUI.Address = fmt.Sprintf("127.0.0.1:%d", port)
  305. port, err = getFreePort("0.0.0.0", 22000)
  306. if err != nil {
  307. l.Fatalln("get free port (BEP):", err)
  308. }
  309. cfg.Options.ListenAddress = []string{fmt.Sprintf("0.0.0.0:%d", port)}
  310. cfg.Save()
  311. l.Infof("Edit %s to taste or use the GUI\n", cfgFile)
  312. }
  313. if profiler := os.Getenv("STPROFILER"); len(profiler) > 0 {
  314. go func() {
  315. l.Debugln("Starting profiler on", profiler)
  316. runtime.SetBlockProfileRate(1)
  317. err := http.ListenAndServe(profiler, nil)
  318. if err != nil {
  319. l.Fatalln(err)
  320. }
  321. }()
  322. }
  323. // The TLS configuration is used for both the listening socket and outgoing
  324. // connections.
  325. tlsCfg := &tls.Config{
  326. Certificates: []tls.Certificate{cert},
  327. NextProtos: []string{"bep/1.0"},
  328. ServerName: myID.String(),
  329. ClientAuth: tls.RequestClientCert,
  330. SessionTicketsDisabled: true,
  331. InsecureSkipVerify: true,
  332. MinVersion: tls.VersionTLS12,
  333. }
  334. // If the read or write rate should be limited, set up a rate limiter for it.
  335. // This will be used on connections created in the connect and listen routines.
  336. if cfg.Options.MaxSendKbps > 0 {
  337. writeRateLimit = ratelimit.NewBucketWithRate(float64(1000*cfg.Options.MaxSendKbps), int64(5*1000*cfg.Options.MaxSendKbps))
  338. }
  339. if cfg.Options.MaxRecvKbps > 0 {
  340. readRateLimit = ratelimit.NewBucketWithRate(float64(1000*cfg.Options.MaxRecvKbps), int64(5*1000*cfg.Options.MaxRecvKbps))
  341. }
  342. // If this is the first time the user runs v0.9, archive the old indexes and config.
  343. archiveLegacyConfig()
  344. db, err := leveldb.OpenFile(filepath.Join(confDir, "index"), &opt.Options{CachedOpenFiles: 100})
  345. if err != nil {
  346. l.Fatalln("Cannot open database:", err, "- Is another copy of Syncthing already running?")
  347. }
  348. // Remove database entries for repos that no longer exist in the config
  349. repoMap := cfg.RepoMap()
  350. for _, repo := range files.ListRepos(db) {
  351. if _, ok := repoMap[repo]; !ok {
  352. l.Infof("Cleaning data for dropped repo %q", repo)
  353. files.DropRepo(db, repo)
  354. }
  355. }
  356. m := model.NewModel(confDir, &cfg, myName, "syncthing", Version, db)
  357. nextRepo:
  358. for i, repo := range cfg.Repositories {
  359. if repo.Invalid != "" {
  360. continue
  361. }
  362. repo.Directory = expandTilde(repo.Directory)
  363. m.AddRepo(repo)
  364. fi, err := os.Stat(repo.Directory)
  365. if m.LocalVersion(repo.ID) > 0 {
  366. // Safety check. If the cached index contains files but the
  367. // repository doesn't exist, we have a problem. We would assume
  368. // that all files have been deleted which might not be the case,
  369. // so mark it as invalid instead.
  370. if err != nil || !fi.IsDir() {
  371. l.Warnf("Stopping repository %q - directory missing, but has files in index", repo.ID)
  372. cfg.Repositories[i].Invalid = "repo directory missing"
  373. continue nextRepo
  374. }
  375. } else if os.IsNotExist(err) {
  376. // If we don't have ny files in the index, and the directory does
  377. // exist, try creating it.
  378. err = os.MkdirAll(repo.Directory, 0700)
  379. }
  380. if err != nil {
  381. // If there was another error or we could not create the
  382. // directory, the repository is invalid.
  383. l.Warnf("Stopping repository %q - %v", err)
  384. cfg.Repositories[i].Invalid = err.Error()
  385. continue nextRepo
  386. }
  387. }
  388. // GUI
  389. guiCfg := overrideGUIConfig(cfg.GUI, guiAddress, guiAuthentication, guiAPIKey)
  390. if guiCfg.Enabled && guiCfg.Address != "" {
  391. addr, err := net.ResolveTCPAddr("tcp", guiCfg.Address)
  392. if err != nil {
  393. l.Fatalf("Cannot start GUI on %q: %v", guiCfg.Address, err)
  394. } else {
  395. var hostOpen, hostShow string
  396. switch {
  397. case addr.IP == nil:
  398. hostOpen = "localhost"
  399. hostShow = "0.0.0.0"
  400. case addr.IP.IsUnspecified():
  401. hostOpen = "localhost"
  402. hostShow = addr.IP.String()
  403. default:
  404. hostOpen = addr.IP.String()
  405. hostShow = hostOpen
  406. }
  407. var proto = "http"
  408. if guiCfg.UseTLS {
  409. proto = "https"
  410. }
  411. l.Infof("Starting web GUI on %s://%s/", proto, net.JoinHostPort(hostShow, strconv.Itoa(addr.Port)))
  412. err := startGUI(guiCfg, os.Getenv("STGUIASSETS"), m)
  413. if err != nil {
  414. l.Fatalln("Cannot start GUI:", err)
  415. }
  416. if !noBrowser && cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
  417. openURL(fmt.Sprintf("%s://%s:%d", proto, hostOpen, addr.Port))
  418. }
  419. }
  420. }
  421. // Clear out old indexes for other nodes. Otherwise we'll start up and
  422. // start needing a bunch of files which are nowhere to be found. This
  423. // needs to be changed when we correctly do persistent indexes.
  424. for _, repoCfg := range cfg.Repositories {
  425. if repoCfg.Invalid != "" {
  426. continue
  427. }
  428. for _, node := range repoCfg.NodeIDs() {
  429. if node == myID {
  430. continue
  431. }
  432. m.Index(node, repoCfg.ID, nil)
  433. }
  434. }
  435. // Walk the repository and update the local model before establishing any
  436. // connections to other nodes.
  437. m.CleanRepos()
  438. l.Infoln("Performing initial repository scan")
  439. m.ScanRepos()
  440. // Remove all .idx* files that don't belong to an active repo.
  441. validIndexes := make(map[string]bool)
  442. for _, repo := range cfg.Repositories {
  443. dir := expandTilde(repo.Directory)
  444. id := fmt.Sprintf("%x", sha1.Sum([]byte(dir)))
  445. validIndexes[id] = true
  446. }
  447. allIndexes, err := filepath.Glob(filepath.Join(confDir, "*.idx*"))
  448. if err == nil {
  449. for _, idx := range allIndexes {
  450. bn := filepath.Base(idx)
  451. fs := strings.Split(bn, ".")
  452. if len(fs) > 1 {
  453. if _, ok := validIndexes[fs[0]]; !ok {
  454. l.Infoln("Removing old index", bn)
  455. os.Remove(idx)
  456. }
  457. }
  458. }
  459. }
  460. // The default port we announce, possibly modified by setupUPnP next.
  461. addr, err := net.ResolveTCPAddr("tcp", cfg.Options.ListenAddress[0])
  462. if err != nil {
  463. l.Fatalln("Bad listen address:", err)
  464. }
  465. externalPort = addr.Port
  466. // UPnP
  467. if cfg.Options.UPnPEnabled {
  468. setupUPnP()
  469. }
  470. // Routine to connect out to configured nodes
  471. discoverer = discovery(externalPort)
  472. go listenConnect(myID, m, tlsCfg)
  473. for _, repo := range cfg.Repositories {
  474. if repo.Invalid != "" {
  475. continue
  476. }
  477. // Routine to pull blocks from other nodes to synchronize the local
  478. // repository. Does not run when we are in read only (publish only) mode.
  479. if repo.ReadOnly {
  480. l.Okf("Ready to synchronize %s (read only; no external updates accepted)", repo.ID)
  481. m.StartRepoRO(repo.ID)
  482. } else {
  483. l.Okf("Ready to synchronize %s (read-write)", repo.ID)
  484. m.StartRepoRW(repo.ID, cfg.Options.ParallelRequests)
  485. }
  486. }
  487. if cpuprof := os.Getenv("STCPUPROFILE"); len(cpuprof) > 0 {
  488. f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
  489. if err != nil {
  490. log.Fatal(err)
  491. }
  492. pprof.StartCPUProfile(f)
  493. defer pprof.StopCPUProfile()
  494. }
  495. for _, node := range cfg.Nodes {
  496. if len(node.Name) > 0 {
  497. l.Infof("Node %s is %q at %v", node.NodeID, node.Name, node.Addresses)
  498. }
  499. }
  500. if cfg.Options.URAccepted > 0 && cfg.Options.URAccepted < usageReportVersion {
  501. l.Infoln("Anonymous usage report has changed; revoking acceptance")
  502. cfg.Options.URAccepted = 0
  503. }
  504. if cfg.Options.URAccepted >= usageReportVersion {
  505. go usageReportingLoop(m)
  506. go func() {
  507. time.Sleep(10 * time.Minute)
  508. err := sendUsageReport(m)
  509. if err != nil {
  510. l.Infoln("Usage report:", err)
  511. }
  512. }()
  513. }
  514. if cfg.Options.RestartOnWakeup {
  515. go standbyMonitor()
  516. }
  517. events.Default.Log(events.StartupComplete, nil)
  518. go generateEvents()
  519. code := <-stop
  520. l.Okln("Exiting")
  521. os.Exit(code)
  522. }
  523. func generateEvents() {
  524. for {
  525. time.Sleep(300 * time.Second)
  526. events.Default.Log(events.Ping, nil)
  527. }
  528. }
  529. func setupUPnP() {
  530. if len(cfg.Options.ListenAddress) == 1 {
  531. _, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0])
  532. if err != nil {
  533. l.Warnln("Bad listen address:", err)
  534. } else {
  535. // Set up incoming port forwarding, if necessary and possible
  536. port, _ := strconv.Atoi(portStr)
  537. igd, err := upnp.Discover()
  538. if err == nil {
  539. externalPort = setupExternalPort(igd, port)
  540. if externalPort == 0 {
  541. l.Warnln("Failed to create UPnP port mapping")
  542. } else {
  543. l.Infoln("Created UPnP port mapping - external port", externalPort)
  544. }
  545. } else {
  546. l.Infof("No UPnP gateway detected")
  547. if debugNet {
  548. l.Debugf("UPnP: %v", err)
  549. }
  550. }
  551. if cfg.Options.UPnPRenewal > 0 {
  552. go renewUPnP(port)
  553. }
  554. }
  555. } else {
  556. l.Warnln("Multiple listening addresses; not attempting UPnP port mapping")
  557. }
  558. }
  559. func setupExternalPort(igd *upnp.IGD, port int) int {
  560. // We seed the random number generator with the node ID to get a
  561. // repeatable sequence of random external ports.
  562. rnd := rand.NewSource(certSeed(cert.Certificate[0]))
  563. for i := 0; i < 10; i++ {
  564. r := 1024 + int(rnd.Int63()%(65535-1024))
  565. err := igd.AddPortMapping(upnp.TCP, r, port, "syncthing", cfg.Options.UPnPLease*60)
  566. if err == nil {
  567. return r
  568. }
  569. }
  570. return 0
  571. }
  572. func renewUPnP(port int) {
  573. for {
  574. time.Sleep(time.Duration(cfg.Options.UPnPRenewal) * time.Minute)
  575. igd, err := upnp.Discover()
  576. if err != nil {
  577. continue
  578. }
  579. // Just renew the same port that we already have
  580. if externalPort != 0 {
  581. err = igd.AddPortMapping(upnp.TCP, externalPort, port, "syncthing", cfg.Options.UPnPLease*60)
  582. if err == nil {
  583. l.Infoln("Renewed UPnP port mapping - external port", externalPort)
  584. continue
  585. }
  586. }
  587. // Something strange has happened. We didn't have an external port before?
  588. // Or perhaps the gateway has changed?
  589. // Retry the same port sequence from the beginning.
  590. r := setupExternalPort(igd, port)
  591. if r != 0 {
  592. externalPort = r
  593. l.Infoln("Updated UPnP port mapping - external port", externalPort)
  594. discoverer.StopGlobal()
  595. discoverer.StartGlobal(cfg.Options.GlobalAnnServer, uint16(r))
  596. continue
  597. }
  598. l.Warnln("Failed to update UPnP port mapping - external port", externalPort)
  599. }
  600. }
  601. func resetRepositories() {
  602. suffix := fmt.Sprintf(".syncthing-reset-%d", time.Now().UnixNano())
  603. for _, repo := range cfg.Repositories {
  604. if _, err := os.Stat(repo.Directory); err == nil {
  605. l.Infof("Reset: Moving %s -> %s", repo.Directory, repo.Directory+suffix)
  606. os.Rename(repo.Directory, repo.Directory+suffix)
  607. }
  608. }
  609. idx := filepath.Join(confDir, "index")
  610. os.RemoveAll(idx)
  611. }
  612. func archiveLegacyConfig() {
  613. pat := filepath.Join(confDir, "*.idx.gz*")
  614. idxs, err := filepath.Glob(pat)
  615. if err == nil && len(idxs) > 0 {
  616. // There are legacy indexes. This is probably the first time we run as v0.9.
  617. backupDir := filepath.Join(confDir, "backup-of-v0.8")
  618. err = os.MkdirAll(backupDir, 0700)
  619. if err != nil {
  620. l.Warnln("Cannot archive config/indexes:", err)
  621. return
  622. }
  623. for _, idx := range idxs {
  624. l.Infof("Archiving %s", filepath.Base(idx))
  625. os.Rename(idx, filepath.Join(backupDir, filepath.Base(idx)))
  626. }
  627. src, err := os.Open(filepath.Join(confDir, "config.xml"))
  628. if err != nil {
  629. l.Warnf("Cannot archive config:", err)
  630. return
  631. }
  632. defer src.Close()
  633. dst, err := os.Create(filepath.Join(backupDir, "config.xml"))
  634. if err != nil {
  635. l.Warnf("Cannot archive config:", err)
  636. return
  637. }
  638. defer dst.Close()
  639. l.Infoln("Archiving config.xml")
  640. io.Copy(dst, src)
  641. }
  642. }
  643. func restart() {
  644. l.Infoln("Restarting")
  645. stop <- exitRestarting
  646. }
  647. func shutdown() {
  648. l.Infoln("Shutting down")
  649. stop <- exitSuccess
  650. }
  651. func listenConnect(myID protocol.NodeID, m *model.Model, tlsCfg *tls.Config) {
  652. var conns = make(chan *tls.Conn)
  653. // Listen
  654. for _, addr := range cfg.Options.ListenAddress {
  655. go listenTLS(conns, addr, tlsCfg)
  656. }
  657. // Connect
  658. go dialTLS(m, conns, tlsCfg)
  659. next:
  660. for conn := range conns {
  661. certs := conn.ConnectionState().PeerCertificates
  662. if cl := len(certs); cl != 1 {
  663. l.Infof("Got peer certificate list of length %d != 1 from %s; protocol error", cl, conn.RemoteAddr())
  664. conn.Close()
  665. continue
  666. }
  667. remoteCert := certs[0]
  668. remoteID := protocol.NewNodeID(remoteCert.Raw)
  669. if remoteID == myID {
  670. l.Infof("Connected to myself (%s) - should not happen", remoteID)
  671. conn.Close()
  672. continue
  673. }
  674. if m.ConnectedTo(remoteID) {
  675. l.Infof("Connected to already connected node (%s)", remoteID)
  676. conn.Close()
  677. continue
  678. }
  679. for _, nodeCfg := range cfg.Nodes {
  680. if nodeCfg.NodeID == remoteID {
  681. // Verify the name on the certificate. By default we set it to
  682. // "syncthing" when generating, but the user may have replaced
  683. // the certificate and used another name.
  684. certName := nodeCfg.CertName
  685. if certName == "" {
  686. certName = "syncthing"
  687. }
  688. err := remoteCert.VerifyHostname(certName)
  689. if err != nil {
  690. // Incorrect certificate name is something the user most
  691. // likely wants to know about, since it's an advanced
  692. // config. Warn instead of Info.
  693. l.Warnf("Bad certificate from %s (%v): %v", remoteID, conn.RemoteAddr(), err)
  694. conn.Close()
  695. continue next
  696. }
  697. // If rate limiting is set, we wrap the connection in a
  698. // limiter.
  699. var wr io.Writer = conn
  700. if writeRateLimit != nil {
  701. wr = &limitedWriter{conn, writeRateLimit}
  702. }
  703. var rd io.Reader = conn
  704. if readRateLimit != nil {
  705. rd = &limitedReader{conn, readRateLimit}
  706. }
  707. name := fmt.Sprintf("%s-%s", conn.LocalAddr(), conn.RemoteAddr())
  708. protoConn := protocol.NewConnection(remoteID, rd, wr, m, name, nodeCfg.Compression)
  709. l.Infof("Established secure connection to %s at %s", remoteID, name)
  710. if debugNet {
  711. l.Debugf("cipher suite %04X", conn.ConnectionState().CipherSuite)
  712. }
  713. events.Default.Log(events.NodeConnected, map[string]string{
  714. "id": remoteID.String(),
  715. "addr": conn.RemoteAddr().String(),
  716. })
  717. m.AddConnection(conn, protoConn)
  718. continue next
  719. }
  720. }
  721. events.Default.Log(events.NodeRejected, map[string]string{
  722. "node": remoteID.String(),
  723. "address": conn.RemoteAddr().String(),
  724. })
  725. l.Infof("Connection from %s with unknown node ID %s; ignoring", conn.RemoteAddr(), remoteID)
  726. conn.Close()
  727. }
  728. }
  729. func listenTLS(conns chan *tls.Conn, addr string, tlsCfg *tls.Config) {
  730. if debugNet {
  731. l.Debugln("listening on", addr)
  732. }
  733. tcaddr, err := net.ResolveTCPAddr("tcp", addr)
  734. if err != nil {
  735. l.Fatalln("listen (BEP):", err)
  736. }
  737. listener, err := net.ListenTCP("tcp", tcaddr)
  738. if err != nil {
  739. l.Fatalln("listen (BEP):", err)
  740. }
  741. for {
  742. conn, err := listener.Accept()
  743. if err != nil {
  744. l.Warnln("Accepting connection:", err)
  745. continue
  746. }
  747. if debugNet {
  748. l.Debugln("connect from", conn.RemoteAddr())
  749. }
  750. tcpConn := conn.(*net.TCPConn)
  751. setTCPOptions(tcpConn)
  752. tc := tls.Server(conn, tlsCfg)
  753. err = tc.Handshake()
  754. if err != nil {
  755. l.Infoln("TLS handshake:", err)
  756. tc.Close()
  757. continue
  758. }
  759. conns <- tc
  760. }
  761. }
  762. func dialTLS(m *model.Model, conns chan *tls.Conn, tlsCfg *tls.Config) {
  763. var delay time.Duration = 1 * time.Second
  764. for {
  765. nextNode:
  766. for _, nodeCfg := range cfg.Nodes {
  767. if nodeCfg.NodeID == myID {
  768. continue
  769. }
  770. if m.ConnectedTo(nodeCfg.NodeID) {
  771. continue
  772. }
  773. var addrs []string
  774. for _, addr := range nodeCfg.Addresses {
  775. if addr == "dynamic" {
  776. if discoverer != nil {
  777. t := discoverer.Lookup(nodeCfg.NodeID)
  778. if len(t) == 0 {
  779. continue
  780. }
  781. addrs = append(addrs, t...)
  782. }
  783. } else {
  784. addrs = append(addrs, addr)
  785. }
  786. }
  787. for _, addr := range addrs {
  788. host, port, err := net.SplitHostPort(addr)
  789. if err != nil && strings.HasPrefix(err.Error(), "missing port") {
  790. // addr is on the form "1.2.3.4"
  791. addr = net.JoinHostPort(addr, "22000")
  792. } else if err == nil && port == "" {
  793. // addr is on the form "1.2.3.4:"
  794. addr = net.JoinHostPort(host, "22000")
  795. }
  796. if debugNet {
  797. l.Debugln("dial", nodeCfg.NodeID, addr)
  798. }
  799. raddr, err := net.ResolveTCPAddr("tcp", addr)
  800. if err != nil {
  801. if debugNet {
  802. l.Debugln(err)
  803. }
  804. continue
  805. }
  806. conn, err := net.DialTCP("tcp", nil, raddr)
  807. if err != nil {
  808. if debugNet {
  809. l.Debugln(err)
  810. }
  811. continue
  812. }
  813. setTCPOptions(conn)
  814. tc := tls.Client(conn, tlsCfg)
  815. err = tc.Handshake()
  816. if err != nil {
  817. l.Infoln("TLS handshake:", err)
  818. tc.Close()
  819. continue
  820. }
  821. conns <- tc
  822. continue nextNode
  823. }
  824. }
  825. time.Sleep(delay)
  826. delay *= 2
  827. if maxD := time.Duration(cfg.Options.ReconnectIntervalS) * time.Second; delay > maxD {
  828. delay = maxD
  829. }
  830. }
  831. }
  832. func setTCPOptions(conn *net.TCPConn) {
  833. var err error
  834. if err = conn.SetLinger(0); err != nil {
  835. l.Infoln(err)
  836. }
  837. if err = conn.SetNoDelay(false); err != nil {
  838. l.Infoln(err)
  839. }
  840. if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil {
  841. l.Infoln(err)
  842. }
  843. if err = conn.SetKeepAlive(true); err != nil {
  844. l.Infoln(err)
  845. }
  846. }
  847. func discovery(extPort int) *discover.Discoverer {
  848. disc := discover.NewDiscoverer(myID, cfg.Options.ListenAddress)
  849. if cfg.Options.LocalAnnEnabled {
  850. l.Infoln("Starting local discovery announcements")
  851. disc.StartLocal(cfg.Options.LocalAnnPort, cfg.Options.LocalAnnMCAddr)
  852. }
  853. if cfg.Options.GlobalAnnEnabled {
  854. l.Infoln("Starting global discovery announcements")
  855. disc.StartGlobal(cfg.Options.GlobalAnnServer, uint16(extPort))
  856. }
  857. return disc
  858. }
  859. func ensureDir(dir string, mode int) {
  860. fi, err := os.Stat(dir)
  861. if os.IsNotExist(err) {
  862. err := os.MkdirAll(dir, 0700)
  863. if err != nil {
  864. l.Fatalln(err)
  865. }
  866. } else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
  867. err := os.Chmod(dir, os.FileMode(mode))
  868. // This can fail on crappy filesystems, nothing we can do about it.
  869. if err != nil {
  870. l.Warnln(err)
  871. }
  872. }
  873. }
  874. func getDefaultConfDir() string {
  875. switch runtime.GOOS {
  876. case "windows":
  877. return filepath.Join(os.Getenv("LocalAppData"), "Syncthing")
  878. case "darwin":
  879. return expandTilde("~/Library/Application Support/Syncthing")
  880. default:
  881. if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
  882. return filepath.Join(xdgCfg, "syncthing")
  883. } else {
  884. return expandTilde("~/.config/syncthing")
  885. }
  886. }
  887. }
  888. func expandTilde(p string) string {
  889. if p == "~" {
  890. return getHomeDir()
  891. }
  892. p = filepath.FromSlash(p)
  893. if !strings.HasPrefix(p, fmt.Sprintf("~%c", os.PathSeparator)) {
  894. return p
  895. }
  896. return filepath.Join(getHomeDir(), p[2:])
  897. }
  898. func getHomeDir() string {
  899. var home string
  900. switch runtime.GOOS {
  901. case "windows":
  902. home = filepath.Join(os.Getenv("HomeDrive"), os.Getenv("HomePath"))
  903. if home == "" {
  904. home = os.Getenv("UserProfile")
  905. }
  906. default:
  907. home = os.Getenv("HOME")
  908. }
  909. if home == "" {
  910. l.Fatalln("No home directory found - set $HOME (or the platform equivalent).")
  911. }
  912. return home
  913. }
  914. // getFreePort returns a free TCP port fort listening on. The ports given are
  915. // tried in succession and the first to succeed is returned. If none succeed,
  916. // a random high port is returned.
  917. func getFreePort(host string, ports ...int) (int, error) {
  918. for _, port := range ports {
  919. c, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
  920. if err == nil {
  921. c.Close()
  922. return port, nil
  923. }
  924. }
  925. c, err := net.Listen("tcp", host+":0")
  926. if err != nil {
  927. return 0, err
  928. }
  929. addr := c.Addr().(*net.TCPAddr)
  930. c.Close()
  931. return addr.Port, nil
  932. }
  933. func overrideGUIConfig(originalCfg config.GUIConfiguration, address, authentication, apikey string) config.GUIConfiguration {
  934. // Make a copy of the config
  935. cfg := originalCfg
  936. if address == "" {
  937. address = os.Getenv("STGUIADDRESS")
  938. }
  939. if address != "" {
  940. cfg.Enabled = true
  941. addressParts := strings.SplitN(address, "://", 2)
  942. switch addressParts[0] {
  943. case "http":
  944. cfg.UseTLS = false
  945. case "https":
  946. cfg.UseTLS = true
  947. default:
  948. l.Fatalln("Unidentified protocol", addressParts[0])
  949. }
  950. cfg.Address = addressParts[1]
  951. }
  952. if authentication == "" {
  953. authentication = os.Getenv("STGUIAUTH")
  954. }
  955. if authentication != "" {
  956. authenticationParts := strings.SplitN(authentication, ":", 2)
  957. hash, err := bcrypt.GenerateFromPassword([]byte(authenticationParts[1]), 0)
  958. if err != nil {
  959. l.Fatalln("Invalid GUI password:", err)
  960. }
  961. cfg.User = authenticationParts[0]
  962. cfg.Password = string(hash)
  963. }
  964. if apikey == "" {
  965. apikey = os.Getenv("STGUIAPIKEY")
  966. }
  967. if apikey != "" {
  968. cfg.APIKey = apikey
  969. }
  970. return cfg
  971. }
  972. func standbyMonitor() {
  973. restartDelay := time.Duration(60 * time.Second)
  974. now := time.Now()
  975. for {
  976. time.Sleep(10 * time.Second)
  977. if time.Since(now) > 2*time.Minute {
  978. l.Infoln("Paused state detected, possibly woke up from standby. Restarting in", restartDelay)
  979. // We most likely just woke from standby. If we restart
  980. // immediately chances are we won't have networking ready. Give
  981. // things a moment to stabilize.
  982. time.Sleep(restartDelay)
  983. restart()
  984. return
  985. }
  986. now = time.Now()
  987. }
  988. }