diff --git a/auto/gui.files.go b/auto/gui.files.go index a231f16cc..028b57906 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -18,7 +18,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["angular.min.js"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffd41b5d73db36f23dbf0255d3928a65cae9dcdcdc44716e5a37edf8d23699b8e98b470f940849a829500740b135aefefb2d3e48020448d11f69729a492c018bfdc6ee62098e9ffdc97342059ab1e29a63f60209b6c523342fa820748bcbdf9b7ccbe53ffd1b3d1b3f193f5be6c52ccdd1d3176891e61c8052badce62933bf25d093680b5fb860642ea2c993271f5386f88ecec58ad0253a2d5724eb22dbe6388eaab968842ea74358518d24922556e439667174518e9e099603ec620bbf494151fc94cf8b0df0f27425c466886e9f20f848b21b863ffe980a0c544f26d5e8128bb76f60484a558f32cc45ca84e65109039cc8498d5db242b122c801e0763f694c2ec8d21f5fefce7f84d128724669916189e4721a40724ea5a00e7b661e3356b0c03a8e317d2de77c4aa0639cfb6c31bc294a446a7c3c46176030bae468861705c3685614394779515cc1881098b9148550c080428ddf92ec058a7e215c600a88c03a20e11cbc42590dbd638528e6458e3404fa3ecb40dd1c730014bb0d785c24f08d805fc60adae5f6230bf9afe9cd05a6d99bd9865be8df6ec5b290367b2fcdfc0b591381e2373f6cf8b0464db7eb19669dc8df03ba949e5390f3639a5f5804f40c2aa7507c67ccc671c2c8cde4fdf1bf4b590afb237f8fffbb05205b37a03104fa819534532aaa41fae30724672bd8b2b8a17889fc279263a467b5fe7b6bde22f0b38a28df53fa9aa6b31c67160d3d8560ae80bd8e6bbcd2393bb9fea598b7e05433f7417921c77fd011d3f66f398cea711b9d593f7503c9724b2ec2fbc76c0b5b031fce1fb2673eb8bc4a6cdf6fc50a439c9fa72a767e70b83e88f05dcaf975c1b26ea4169441bca94742c84b0d55211d42f4c5763ec738c3595c4674f9210b147fa502b83daab41b475f532c80ca950a86d15046bf348fa315c970349c38d07e0e909fbd43a7ce08215af56c37a5505e71e9ed7de17f4a616bf992b773c4b0d832da26c9dd14763b4be757192b366038a0076605b35de1ddac48596612fdbe459fbd0494f9efac586f5286e37484664d31a5d3140b9426bfa56b8cbe3a85b4b6a5195e100a5b197dfb2d3200b32040534e89d1a07a69960c1d805a7fe8f879d3786ad82c7f6596b7a919c04032c8f88a8efa1ab69343a7c65153d3685e556826b61eab24be007f5849a55795904d4e55430918268ec6d271c67c0781640d66e6726b711ed7ebb254a44d56dd3de8eaa5ac031446e040aeb7241aea5a250e336690973e6eafabbfdb954a0215c9eb74beb2f0c971cfa19b02abea671ca12324c113b0464fd12d06148e4bb37eea89da64db11a1c98f5542f6b6822c4d69710d8465210ba5e3753c1c39102283c958c21c5705ef108dd1f393931317926426ce961fab3e86f54113130a79bfae9f1bb3c55654d3ce3c580cc5244384a23605ab502e279355cadf5e5328123798891d2c1b86e0e5a73ca24cbcd9bd3722d8ae058b247a49b26925dcafa95825ebf4263e19a17fa167da120ae29cfeb01398ff5e08a81a8e0367010f4aaa5e64439f438772a5b876d250baf5a1ed80b512df23c8cdf3158a719b6a3da59cf4152100e85bc371a7a3d306391f83eb60f6023dd4d88221e7744f6ccd10d5b14ff541abf7166d1ecfc294f69327cd2318d48e62cb9d00de8c6b563af4021244a3eecc67f249f4815ec1f6a6919d73aaafea782e74108864acf4e9246abe5e5d82abbf9727d344141f36b077cf528e21d21fe909d0de8c0b163f1f5ab141ca63969fa2813c1c423133407ffd85ead1f32cc783a62c7a1afc6080e241cda56c15bcc36c0ed567bac4467d4768f0cd701094d6a8c412a8995437c5590ed5eaa7b78a2cb68f095d148f661747b9110135761337ee1db5d533352eae0dd58d6ec3c83a65bb20ba36a15dedbbd6fce426800cd9267a40d9baf5a562adc27fd20fab63d00d1cf54f250444fa0009a27a3f9ac4380460f13069ea5665923926790c54c2414716de81a0a3eaf18573a690cccaf8097081bc631698e274ea7aa0040cd5e0723c91657f8e1559a943d044281f95de724e915448d408f608cb5663fb321356502cb74d93ec118abe19363176848ae847c28dece049ad6a3d9f4b91fe1f945a5cdd559fe6a47117a5ada14ae3eddaf243ec17ab2e3f48f6d2991f0c0feacc0e8bbeca64ffe76fd698614c29cdb49fba62fbbf3bec6da9fcb389d008029d79aa5d943ff0413348665c4e95a359cf045ad834101f31e3803bc4dfa7544f4e20effed14ebb879d559be42eda91cd98304f36480737aec865cd0987a97f865320ce88b0daaf2dad9338faba7cc6d1b72da6da99c36055937ec48749069f0135da690e50f276a3ac9ee806b1d9a08e63f8501782257c931338eb8ca464e9c63adcdc0043a55e6f1201112c1e4e0247a54dc1ed9e0650014dfce7e2ed6f09570f91c862173b4c0c47e87685d30c7ceb05ba8dcee0140fae76fc3bd46f116833dd0047ba773cfe931734da3b3443c618c856eba0ed68a5baa4adaa763ab26e03b8adb1cb57c575d4a907b32af25b58ad8ff5029e29bdf8d0fe29d16e1903259a154f1328ac31cde2dbfda8dc133e2b9204c8f5fa067c2128be873aa91e3b80e7a83691de6ed570f267412838138a1a262bc5b9d7fe7135936699a798831ab9b5390792d98ea66ba0b9efa195e6b67b5c71a09cc702774b14a2e83d5e501db4b010879f0f34b5503e94b67f260b920b6cf771db32082d13dd5775a2b3ddc86e632bfa6dfb444136f9b01a08aab128b320519d27f8f3d2ed15e7982ec50a268e8e5a1a350aee924c9ba4dcf11eb23f40fea60e7c7b1cc8047f73206eb8b04c699d0eacdbd62a568c5056503c42647257197b6d02430585d4ee41d5712b14cbee991c2b22524e5f0cdd0af7bc556fb00e6fb5da100ab6f44c534dba854fc7138c72712db1df6d359cbbd9a0fccc184eaf7a9c6374431f30b5ec3b2df166cb57b19fa15a0252c20b2662eb81e17de3c667de3085586156b2d85696d86780d6f8db3bfcca73c6c136b458117e70231328299a21f81e0e4d1bd6019f9c781e4f7b9e982ce12fe9b4dd3b0332ab46bd2c877b9a4237f67d5bb49d5c70f23b514f8b9bf7b30e5a639ee394bd2e9f2374163bf6a52f87cf4b976b6d0f748c9e4f155b5d29442d192b26a230830b0667c42cdff99e0cfbc7e6b2234d1ff41375c6b5237ad85bb82a48e17f99b8f3748ee379150e47cd43a99c1b0e3bce9180a7b52a7f0f85c1ddaa72b3a2aeca39d47cb281a814079164df55a65b48ca5ac47b00ee152381b50ed1cb72674dfd6b2ff7382998dc2ce93c4e85ef29f9a076034abd7f6dff4882c8c2a853127dd574533c4661e4f0ec1546868a5718c9551e54953e2fa7fe9ceb475650f65da9daf754477142c35842c54e981c2d9df654d30a27024b085d61dc6a677f611869de576aa608f9d1e7b230bff7adf20e9e49ac2aaf3a7f98ec5732d259dd958b5005ff99aa3b2da9d2bd61a4c7f12691cec8892820af344f625f4ef1a61da33b40f5da928f7a602f2f71bb37a59a450a6b295258123cacbed7179ddcdcf030db7dd1c7d9e6d50fd37aef75f7c3edd63b173f2aad3de4125ef7253b2b0c9b39abe26fa76ff47a07fad5bb0d41fa6d5de6037d6873e676ba875ef3c06f669b585c02f63d2296c8bc4361702705dc3bb4463d132daf2f1e52f8585e6db8bbd6abfda2ec6b8f35c8725cbd6010bb1c8ed445c0130054c015e10ccfc91a762164eb1c6ad1edda7e7126234b22b8bce43d2f6597b14bbea0e05d7d3001e5c479f4a11194f7db167951b0587dcd8ba5fe92ce14e9a1bcb256cd3c3f298b7449b9713d0e7884738cc66ca00c6dcde6de7e73c804c288a60091baef0b95dc9bd5f504a19bad1881067292054454d389287e2237388b2b053aabea00b3775f652a199a112a9f0bf7e7a7f9ec4c0d2a3354175cdaaee59ca0d6bb3d1acb2b708eeffe819ed97fbc0a45418e4f03a09310d56e2d7d3794f7b322f433b90b6b7d787a0033bff663a6938b07907f13266fdfeb610518bbf407b9263ae4676b2cdfc0fb82fc4c5d7ab2fe7468b309fa103fbb0b677d587a889bf5e2a593890750bffa044ec657907befe9630ef3c1e7f62d44d3fc3addf1dfca77cb3ebd7f076f09daecb7719c1126af667cc47154a8f2e775260b8a2ea66dfde87768a1903d8b46f6a15c36bbcc4bbad5b06029e5f37c9b7933aa1a78d1bc4eab1fa803ee53f3d522b1b7d0e2359013f21dae975a61f2d2e5e940dee31c20ba3c56b7134f076e9177697026249b0e5ebd1cab95af0c05a3a6ff010000ffff010000ffff8424d304863c0000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffd41b5d73db36f23dbf0255d3928a65cae9dcdcdc44716e5a37edf8d23699b8e98b470f940849a829500740b135aefefb2d3e48020448d11f69729a492c018bfdc6ee62098e9ffdc97342059ab1e29a63f60209b6c523342fa820748bcbdf9b7ccbe53ffd1b3d1b3f193f5be6c52ccdd1d3176891e61c8052badce62933bf25d093680b5fb860642ea2c993271f5386f88ecec58ad0253a2d5724eb22dbe6388eaab968842ea74358518d24922556e439667174518e9e099603ec620bbf494151fc94cf8b0df0f27425c466886e9f20f848b21b863ffe980a0c544f26d5e8128bb76f60484a558f32cc45ca84e65109039cc8498d5db242b122c801e0763f694c2ec8d21f5fefce7f84d128724669916189e4721a40724ea5a00e7b661e3356b0c03a8e317d2de77c4aa0639cfb6c31bc294a446a7c3c46176030bae468861705c3685614394779515cc1881098b9148550c080428ddf92ec058a7e215c600a88c03a20e11cbc42590dbd638528e6458e3404fa3ecb40dd1c730014bb0d785c24f08d805fc60adae5f6230bf9afe9cd05a6d99bd9865be8df6ec5b290367b2fcdfc0b591381e2373f6cf8b0464db7eb19669dc8df03ba949e5390f3639a5f5804f40c2aa7507c67ccc671c2c8cde4fdf1bf4b590afb237f8fffbb05205b37a03104fa819534532aaa41fae30724672bd8b2b8a17889fc279263a467b5fe7b6bde22f0b38a28df53fa9aa6b31c67160d3d8560ae80bd8e6bbcd2393bb9fea598b7e05433f7417921c77fd011d3f66f398cea711b9db3fec33bface67478f2039195e3c75a3d0724b2ec29bcfec295b7d1fce1fb2e13eb8824a6cdf6fc50a439298a72af07e70443e88f05dcaf975c1b26ea4169441bca94742c84b0d55f900e2fbc5763ec738c3595ca603f9210b147fa5a2bf3daab41b475f532c80ca958aa4d15086ce348fa315c970349c38d07e02919fbd43a74e27215af56c37a5505272e9ed7de17f4a615ffa92b773c4b0d832da26c9dd14763b4be757192b366038a0076605b35de1ddac485966aa847d8b3e7b092893e759b1dea40cc7e908cd9a624aa72916284d7e4bd7187d750a39714b33bc2014361efaf65b6400664180a69c12a341f5d22c193a00b5fed0f1f3a6f1d4b059feca2c6f5333808164502e283aea6bd84e0e9d1a474d4da37955a199d87aac2a8005f8c34a2abd2aa36c72aa944ac0307134968e33e63b08246b3033975b8bf3b85e97a5226db2eaee41572f6511a130020772bd25d150173a71983183bcf4717b5dfddd2e731228675ea7f395854f8e7b0edd1458954ee3081d21099e80357a8a6e31a0705c9af5534fd426db8e084d7eacfab3b715645d4b8b6b202cab60a83bafe3e1c88110194cc612e6b8aa9687688c9e9f9c9cb890243371b6fc58c535ac0f9a9850281aeae2bb315b6c4535edcc83c5504c3244286a53b00ae5723259a5fced35850a738399d8c1b261085e7ecaf3cdc49bdd7b2382ed5ab048a297249b56c2fd9a8a55b24e6fe29311fa177aa62da120cee90f3b81f9ef858092e3387090f0a0a4ea4536f4397428578a6b270d755f1fda0e582bf13d82dc3c5fa118b7a9d653ca495f110280be351c773a3a6d90f331b80e662fd0438d2d18724ef7b8d70c511dfb549fd27a6fd1e6d92e4c693f79d23cbf41e129b6dc09e0cdb866a5432f204134eace7c269f441fe8156c6f1ad939a7faaacef642078148c64a9f4ea2e6ebd525b8fa7b79324d44f161037bf72ce51822fd919e00edcdb860f1f3a1151ba43c66f9291ac89325143303f4d75fa81e3dcf723c68caa2a7c10f06281ed45cca3ec33bcce6507da64b6cd4778406df0c0741698d4a2c819a4975539ce550ad7e7aabc862fb98d045f1687671941b1150633771e3de515b3d53e3e2da50dde8368cac53b60ba26b13dad5be6bcd4f6e02c8906da20794adfb662ad62afc27fdb03a06ddcc0548051010e90324886a1c6912e31080c5c3a4a95b9549e698e4315009071d597807828eaac717ce9942322be327c005f28e59608ad3a9eb8112305483cbf14496fd395664a50e4113a17c547acb394552215123d8232cfb94edcb4c5841b1dc364db24728fa66d8c4d8112aa21f0937b28327b5aaf57c2e45fa7f506a7175577d9a93c65d94b6862a8db76bcb0fb15facbafc20d94b677e303ca8333b2cfa2a93fd9fbf59638631a534d37eea8aedffeeb0b7a5f2cf2642230874e6a97651fec007cd20997139558e663d506861d3407cc48c03ee107f9f523d3981bcfb473bed1e76566d92bb68473663c23cd9201ddcb8229735271ca6fe194e813823c26abfb6b44ee2e8ebf20149dfb6986a670e83554dfa111f26197c80d468a73940c9db8db27aa21bc466833a8ee1435d0896f04d4ee0ac339292a51beb7073030c957abd490444b07838091c953605b77b1a400534f19f8bb7bf255c3d81228b5dec30311ca1db154e33f0ad17e8363a83533cb8daf1ef50bf45a0cd74031ce9def1f84f5ed068efd00c1963205bad83b6a395ea92b6aadae9c8ba0de0b6c62e5f15d751a71eccaac86f61b53e130c78a6f4e243fba744bb650c9468563c4da0b0c6348b6ff7a3724ff8ac481220d7eb1bf085a0f81eeaa47aec009ea3da447abb55c3c99f05a1e04c286a98ac14e75efbc7d54c9a659e620e6ae4d6e61c48663b9aae81e6be87569adbee71c581721e0bdc2d5188a2f7784175d0c2421c7e3ed0d442f944dbfe992c482eb0ddc76dcb20b44c745fd589ce7623bb8dade8b7ed1305d9e4c36a20a8c6a2cc8244759ee0cf4bb7579c63ba142b98383a6a69d428b84b326d9272c77bc8fe00f99b3af0ed712013fccd81b8e1c232a5753ab06e5bab5831425941f10891c95d65ecb5090c151452bb0755c7ad502cbb6772ac8848397d31742bdcf356bdc13abcd56a4328d8d2334d35e9163e1d4f30cac5b5c47eb7d570ee6683f2336338bdea718ed10d7dc0d4b2efb4c49b2d5fc57e866a0948092f9888ad0786f78d1b9f79c314628559c9625b59629f015ae36feff02bcf1907dbd06245f8c18d4ca0a46886e07b38346d58077c72e2793ced7962b284bfa4d376ef0cc8ac1af5b21cee690addd8f76dd17672c1c9ef443d2d6e5eee3a688d798e53f6ba7c8ed059ecd837c61c3e2f5daeb53dd0317a3e556c75a510b564ac9888c20c2e189c11b37ce77b32ec1f9bcb8e347dd04fd419d78ee8616fe1aa2085ff65e2ced3398ee755381c350fa5726e38ec3847029ed6aafc3d140677abcacd8aba2ae750f3c906a2521c44927d57996e21296b11ef01b8578c04d63a442fcb9d35f5afbddce3a46072b3a4f33815bea7e483da0d28f5feb5fd2309220ba34e49f43dd54df1188591c3b35718192a5e612457795055fabc9cfa73ae1f5941d977a56adf531dc5090d6309153b6172b474da534d2b9c082c21748571ab9dfd8561a4795fa99922e4479fcbc2fcdeb7ca3b7826b1aabceafc61b25fc9486775572e4215fc67aaeeb4a44af786911ec79b443a2327a280bcd23c897d39c59b768cee00d56b4b3eea81bdbc01eede946a1629aca5486149f0b0fa5e5f747273c3c36cf7451f679b573f4cebbdd7dd0fb75bef5cfca8b4f6904b78dd97ecac306ce6ac8abf9dbed1eb1de8572f4604e9b775990ff4a1cd99dbe91e7acd03bf996d627109d8f7885822f30e85c19d1470efd01af54cb4bcbe7848e16379b5e1ee5aaff68bb2af3dd620cb71f57642ec72385217014f0050015784333c276bd88590ad73a845b76bfbad9b8c2c89e0f292f7bc945dc62ef9768377f5c1049413e7d1874650de6f5be445c162f5352f96fa4b3a53a487f2ca5a35f3fca42cd225e5c6f538e011ce311ab38132b4359b7bfbb5231308239a0244eabe6c54726f56d713846eb662041ac8491610514d27a2f889dce02cae14e8acaa03ccde7d0faa646846a87c2edc9f9fe6b33335a8cc505d7069bb9673825aeff6682cafc039befb077a66fff12a1405393e0d804e4254bbb5f4dd50decf8ad0cfe42eacf5e1e901ccfcda8f994e2e1e40fe4d98bc7daf871560ecd21fe49ae8909fadb17c7def0bf23375e9c9fad3a1cd26e843fcec2e9cf561e9216ed68b974e261e40fdea1338195f41eebda78f39cc079fdbb7104df3eb74c77f2b5f4cfbf4fe1dbc2568b3dfc6714698bc9af111c751a1ca9fd7992c28ba98b6f5a35fc08542f62c1ad98772d9ec326ff856c382a594cff36de6cda86ae045f33aad7ea00eb84fcd578bc4de428bd7404ec877b85e6a85c94b97a703798f7380e8f258dd4e3c1db845dea5c199906c3a78f572ac56be32148c9afe070000ffff010000ffffdcd42a61c33c0000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["app.js"] = bs diff --git a/cmd/syncthing/config.go b/cmd/syncthing/config.go index 77d33e300..8404598c2 100644 --- a/cmd/syncthing/config.go +++ b/cmd/syncthing/config.go @@ -51,6 +51,7 @@ type OptionsConfiguration struct { ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"` MaxChangeKbps int `xml:"maxChangeKbps" default:"1000"` StartBrowser bool `xml:"startBrowser" default:"true"` + UPnPEnabled bool `xml:"upnpEnabled" default:"true"` Deprecated_ReadOnly bool `xml:"readOnly,omitempty"` Deprecated_GUIEnabled bool `xml:"guiEnabled,omitempty"` diff --git a/cmd/syncthing/config_test.go b/cmd/syncthing/config_test.go index 821636b77..319e768f5 100644 --- a/cmd/syncthing/config_test.go +++ b/cmd/syncthing/config_test.go @@ -19,6 +19,7 @@ func TestDefaultValues(t *testing.T) { ReconnectIntervalS: 60, MaxChangeKbps: 1000, StartBrowser: true, + UPnPEnabled: true, } cfg, err := readConfigXML(bytes.NewReader(nil)) @@ -149,6 +150,7 @@ func TestOverriddenValues(t *testing.T) { 6000 2345 false + false `) @@ -164,6 +166,7 @@ func TestOverriddenValues(t *testing.T) { ReconnectIntervalS: 6000, MaxChangeKbps: 2345, StartBrowser: false, + UPnPEnabled: false, } cfg, err := readConfigXML(bytes.NewReader(data)) diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 2c2bcd0a5..dcc6361f5 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -234,32 +234,8 @@ func main() { // UPnP var externalPort = 0 - if len(cfg.Options.ListenAddress) == 1 { - _, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0]) - if err != nil { - warnln(err) - } else { - // Set up incoming port forwarding, if necessary and possible - port, _ := strconv.Atoi(portStr) - igd, err := upnp.Discover() - if err == nil { - for i := 0; i < 10; i++ { - err := igd.AddPortMapping(upnp.TCP, port+i, port, "syncthing", 0) - if err == nil { - externalPort = port + i - infoln("Created UPnP port mapping - external port", externalPort) - break - } - } - if externalPort == 0 { - warnln("Failed to create UPnP port mapping") - } - } else { - infof("No UPnP IGD device found, no port mapping created (%v)", err) - } - } - } else { - warnln("Multiple listening addresses; not attempting UPnP port mapping") + if cfg.Options.UPnPEnabled { + externalPort = setupUPnP() } // Routine to connect out to configured nodes @@ -290,6 +266,38 @@ func main() { <-stop } +func setupUPnP() int { + var externalPort = 0 + if len(cfg.Options.ListenAddress) == 1 { + _, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0]) + if err != nil { + warnln(err) + } else { + // Set up incoming port forwarding, if necessary and possible + port, _ := strconv.Atoi(portStr) + igd, err := upnp.Discover() + if err == nil { + for i := 0; i < 10; i++ { + err := igd.AddPortMapping(upnp.TCP, port+i, port, "syncthing", 0) + if err == nil { + externalPort = port + i + infoln("Created UPnP port mapping - external port", externalPort) + break + } + } + if externalPort == 0 { + warnln("Failed to create UPnP port mapping") + } + } else { + infof("No UPnP IGD device found, no port mapping created (%v)", err) + } + } + } else { + warnln("Multiple listening addresses; not attempting UPnP port mapping") + } + return externalPort +} + func resetRepositories() { suffix := fmt.Sprintf(".syncthing-reset-%d", time.Now().UnixNano()) for _, repo := range cfg.Repositories { diff --git a/gui/app.js b/gui/app.js index c6b1c8013..2e2a56d86 100644 --- a/gui/app.js +++ b/gui/app.js @@ -32,6 +32,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) { {id: 'GlobalAnnEnabled', descr: 'Global Announce', type: 'bool', restart: true}, {id: 'LocalAnnEnabled', descr: 'Local Announce', type: 'bool', restart: true}, {id: 'StartBrowser', descr: 'Start Browser', type: 'bool'}, + {id: 'UPnPEnabled', descr: 'Enable UPnP', type: 'bool'}, ]; $scope.guiSettings = [