main.go 32 KB

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