main.go 26 KB

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