main.go 26 KB

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