cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
// Copyright (C) 2018 The Syncthing Authors.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-03-27 11:37:34 +00:00
|
|
|
"context"
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
"crypto/tls"
|
|
|
|
"encoding/json"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"math/rand"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2019-10-18 08:50:19 +00:00
|
|
|
"sort"
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
"strconv"
|
2018-01-28 09:24:48 +00:00
|
|
|
"strings"
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/syncthing/syncthing/lib/protocol"
|
|
|
|
)
|
|
|
|
|
|
|
|
// announcement is the format received from and sent to clients
|
|
|
|
type announcement struct {
|
|
|
|
Seen time.Time `json:"seen"`
|
|
|
|
Addresses []string `json:"addresses"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type apiSrv struct {
|
|
|
|
addr string
|
|
|
|
cert tls.Certificate
|
|
|
|
db database
|
|
|
|
listener net.Listener
|
|
|
|
repl replicator // optional
|
|
|
|
useHTTP bool
|
|
|
|
|
|
|
|
mapsMut sync.Mutex
|
|
|
|
misses map[string]int32
|
|
|
|
}
|
|
|
|
|
|
|
|
type requestID int64
|
|
|
|
|
|
|
|
func (i requestID) String() string {
|
|
|
|
return fmt.Sprintf("%016x", int64(i))
|
|
|
|
}
|
|
|
|
|
|
|
|
type contextKey int
|
|
|
|
|
|
|
|
const idKey contextKey = iota
|
|
|
|
|
|
|
|
func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator, useHTTP bool) *apiSrv {
|
|
|
|
return &apiSrv{
|
|
|
|
addr: addr,
|
|
|
|
cert: cert,
|
|
|
|
db: db,
|
|
|
|
repl: repl,
|
|
|
|
useHTTP: useHTTP,
|
|
|
|
misses: make(map[string]int32),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *apiSrv) Serve() {
|
|
|
|
if s.useHTTP {
|
|
|
|
listener, err := net.Listen("tcp", s.addr)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Listen:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.listener = listener
|
|
|
|
} else {
|
|
|
|
tlsCfg := &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{s.cert},
|
|
|
|
ClientAuth: tls.RequestClientCert,
|
|
|
|
SessionTicketsDisabled: true,
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
CipherSuites: []uint16{
|
|
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
tlsListener, err := tls.Listen("tcp", s.addr, tlsCfg)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Listen:", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.listener = tlsListener
|
|
|
|
}
|
|
|
|
|
|
|
|
http.HandleFunc("/", s.handler)
|
|
|
|
http.HandleFunc("/ping", handlePing)
|
|
|
|
|
|
|
|
srv := &http.Server{
|
|
|
|
ReadTimeout: httpReadTimeout,
|
|
|
|
WriteTimeout: httpWriteTimeout,
|
|
|
|
MaxHeaderBytes: httpMaxHeaderBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := srv.Serve(s.listener); err != nil {
|
|
|
|
log.Println("Serve:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var topCtx = context.Background()
|
|
|
|
|
|
|
|
func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
|
|
|
|
t0 := time.Now()
|
|
|
|
|
|
|
|
lw := NewLoggingResponseWriter(w)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
diff := time.Since(t0)
|
|
|
|
apiRequestsSeconds.WithLabelValues(req.Method).Observe(diff.Seconds())
|
|
|
|
apiRequestsTotal.WithLabelValues(req.Method, strconv.Itoa(lw.statusCode)).Inc()
|
|
|
|
}()
|
|
|
|
|
|
|
|
reqID := requestID(rand.Int63())
|
|
|
|
ctx := context.WithValue(topCtx, idKey, reqID)
|
|
|
|
|
|
|
|
if debug {
|
|
|
|
log.Println(reqID, req.Method, req.URL)
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
remoteAddr := &net.TCPAddr{
|
|
|
|
IP: nil,
|
|
|
|
Port: -1,
|
|
|
|
}
|
|
|
|
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
if s.useHTTP {
|
2020-06-16 07:17:07 +00:00
|
|
|
remoteAddr.IP = net.ParseIP(req.Header.Get("X-Forwarded-For"))
|
2020-06-16 08:58:25 +00:00
|
|
|
if parsedPort, err := strconv.ParseInt(req.Header.Get("X-Client-Port"), 10, 0); err == nil {
|
2020-06-16 07:17:07 +00:00
|
|
|
remoteAddr.Port = int(parsedPort)
|
|
|
|
}
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
} else {
|
2020-06-16 07:17:07 +00:00
|
|
|
var err error
|
|
|
|
remoteAddr, err = net.ResolveTCPAddr("tcp", req.RemoteAddr)
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println("remoteAddr:", err)
|
|
|
|
lw.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(lw, "Internal Server Error", http.StatusInternalServerError)
|
|
|
|
apiRequestsTotal.WithLabelValues("no_remote_addr").Inc()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.Method {
|
|
|
|
case "GET":
|
|
|
|
s.handleGET(ctx, lw, req)
|
|
|
|
case "POST":
|
2020-06-16 07:17:07 +00:00
|
|
|
s.handlePOST(ctx, remoteAddr, lw, req)
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
default:
|
|
|
|
http.Error(lw, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
|
|
|
reqID := ctx.Value(idKey).(requestID)
|
|
|
|
|
|
|
|
deviceID, err := protocol.DeviceIDFromString(req.URL.Query().Get("device"))
|
|
|
|
if err != nil {
|
|
|
|
if debug {
|
|
|
|
log.Println(reqID, "bad device param")
|
|
|
|
}
|
|
|
|
lookupRequestsTotal.WithLabelValues("bad_request").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
key := deviceID.String()
|
|
|
|
rec, err := s.db.get(key)
|
|
|
|
if err != nil {
|
|
|
|
// some sort of internal error
|
|
|
|
lookupRequestsTotal.WithLabelValues("internal_error").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(rec.Addresses) == 0 {
|
|
|
|
lookupRequestsTotal.WithLabelValues("not_found").Inc()
|
|
|
|
|
|
|
|
s.mapsMut.Lock()
|
|
|
|
misses := s.misses[key]
|
|
|
|
if misses < rec.Misses {
|
|
|
|
misses = rec.Misses + 1
|
|
|
|
} else {
|
|
|
|
misses++
|
|
|
|
}
|
|
|
|
s.misses[key] = misses
|
|
|
|
s.mapsMut.Unlock()
|
|
|
|
|
|
|
|
if misses%notFoundMissesWriteInterval == 0 {
|
|
|
|
rec.Misses = misses
|
2018-03-06 15:15:29 +00:00
|
|
|
rec.Missed = time.Now().UnixNano()
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
rec.Addresses = nil
|
|
|
|
// rec.Seen retained from get
|
|
|
|
s.db.put(key, rec)
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header().Set("Retry-After", notFoundRetryAfterString(int(misses)))
|
|
|
|
http.Error(w, "Not Found", http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
lookupRequestsTotal.WithLabelValues("success").Inc()
|
|
|
|
|
|
|
|
bs, _ := json.Marshal(announcement{
|
|
|
|
Seen: time.Unix(0, rec.Seen),
|
|
|
|
Addresses: addressStrs(rec.Addresses),
|
|
|
|
})
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
w.Write(bs)
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
func (s *apiSrv) handlePOST(ctx context.Context, remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
reqID := ctx.Value(idKey).(requestID)
|
|
|
|
|
|
|
|
rawCert := certificateBytes(req)
|
|
|
|
if rawCert == nil {
|
|
|
|
if debug {
|
|
|
|
log.Println(reqID, "no certificates")
|
|
|
|
}
|
|
|
|
announceRequestsTotal.WithLabelValues("no_certificate").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Forbidden", http.StatusForbidden)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var ann announcement
|
|
|
|
if err := json.NewDecoder(req.Body).Decode(&ann); err != nil {
|
|
|
|
if debug {
|
|
|
|
log.Println(reqID, "decode:", err)
|
|
|
|
}
|
|
|
|
announceRequestsTotal.WithLabelValues("bad_request").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
deviceID := protocol.NewDeviceID(rawCert)
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
addresses := fixupAddresses(remoteAddr, ann.Addresses)
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
if len(addresses) == 0 {
|
|
|
|
announceRequestsTotal.WithLabelValues("bad_request").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
if err := s.handleAnnounce(deviceID, addresses); err != nil {
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
announceRequestsTotal.WithLabelValues("internal_error").Inc()
|
|
|
|
w.Header().Set("Retry-After", errorRetryAfterString())
|
|
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
announceRequestsTotal.WithLabelValues("success").Inc()
|
|
|
|
|
|
|
|
w.Header().Set("Reannounce-After", reannounceAfterString())
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *apiSrv) Stop() {
|
|
|
|
s.listener.Close()
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
func (s *apiSrv) handleAnnounce(deviceID protocol.DeviceID, addresses []string) error {
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
key := deviceID.String()
|
|
|
|
now := time.Now()
|
|
|
|
expire := now.Add(addressExpiryTime).UnixNano()
|
|
|
|
|
|
|
|
dbAddrs := make([]DatabaseAddress, len(addresses))
|
|
|
|
for i := range addresses {
|
|
|
|
dbAddrs[i].Address = addresses[i]
|
|
|
|
dbAddrs[i].Expires = expire
|
|
|
|
}
|
|
|
|
|
2019-10-18 08:50:19 +00:00
|
|
|
// The address slice must always be sorted for database merges to work
|
|
|
|
// properly.
|
|
|
|
sort.Sort(databaseAddressOrder(dbAddrs))
|
|
|
|
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
seen := now.UnixNano()
|
|
|
|
if s.repl != nil {
|
|
|
|
s.repl.send(key, dbAddrs, seen)
|
|
|
|
}
|
|
|
|
return s.db.merge(key, dbAddrs, seen)
|
|
|
|
}
|
|
|
|
|
|
|
|
func handlePing(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.WriteHeader(204)
|
|
|
|
}
|
|
|
|
|
|
|
|
func certificateBytes(req *http.Request) []byte {
|
|
|
|
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
|
|
|
|
return req.TLS.PeerCertificates[0].Raw
|
|
|
|
}
|
|
|
|
|
2019-10-07 11:55:27 +00:00
|
|
|
var bs []byte
|
|
|
|
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
if hdr := req.Header.Get("X-SSL-Cert"); hdr != "" {
|
2019-10-07 11:55:27 +00:00
|
|
|
if strings.Contains(hdr, "%") {
|
|
|
|
// Nginx using $ssl_client_escaped_cert
|
|
|
|
// The certificate is in PEM format with url encoding.
|
|
|
|
// We need to decode for the PEM decoder
|
|
|
|
hdr, err := url.QueryUnescape(hdr)
|
|
|
|
if err != nil {
|
|
|
|
// Decoding failed
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
bs = []byte(hdr)
|
|
|
|
} else {
|
|
|
|
// Nginx using $ssl_client_cert
|
|
|
|
// The certificate is in PEM format but with spaces for newlines. We
|
|
|
|
// need to reinstate the newlines for the PEM decoder. But we need to
|
|
|
|
// leave the spaces in the BEGIN and END lines - the first and last
|
|
|
|
// space - alone.
|
|
|
|
bs = []byte(hdr)
|
|
|
|
firstSpace := bytes.Index(bs, []byte(" "))
|
|
|
|
lastSpace := bytes.LastIndex(bs, []byte(" "))
|
|
|
|
for i := firstSpace + 1; i < lastSpace; i++ {
|
|
|
|
if bs[i] == ' ' {
|
|
|
|
bs[i] = '\n'
|
|
|
|
}
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-07 11:55:27 +00:00
|
|
|
} else if hdr := req.Header.Get("X-Forwarded-Tls-Client-Cert"); hdr != "" {
|
|
|
|
// Traefik 2 passtlsclientcert
|
|
|
|
// The certificate is in PEM format with url encoding but without newlines
|
|
|
|
// and start/end statements. We need to decode, reinstate the newlines every 64
|
|
|
|
// character and add statements for the PEM decoder
|
|
|
|
hdr, err := url.QueryUnescape(hdr)
|
|
|
|
if err != nil {
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
// Decoding failed
|
|
|
|
return nil
|
|
|
|
}
|
2019-10-07 11:55:27 +00:00
|
|
|
|
|
|
|
for i := 64; i < len(hdr); i += 65 {
|
|
|
|
hdr = hdr[:i] + "\n" + hdr[i:]
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = "-----BEGIN CERTIFICATE-----\n" + hdr
|
|
|
|
hdr = hdr + "\n-----END CERTIFICATE-----\n"
|
|
|
|
bs = []byte(hdr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if bs == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
block, _ := pem.Decode(bs)
|
|
|
|
if block == nil {
|
|
|
|
// Decoding failed
|
|
|
|
return nil
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 11:55:27 +00:00
|
|
|
return block.Bytes
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// fixupAddresses checks the list of addresses, removing invalid ones and
|
|
|
|
// replacing unspecified IPs with the given remote IP.
|
2020-06-16 07:17:07 +00:00
|
|
|
func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
fixed := make([]string, 0, len(addresses))
|
|
|
|
for _, annAddr := range addresses {
|
|
|
|
uri, err := url.Parse(annAddr)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
host, port, err := net.SplitHostPort(uri.Host)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
ip := net.ParseIP(host)
|
2018-08-30 17:06:35 +00:00
|
|
|
|
|
|
|
// Some classes of IP are no-go.
|
|
|
|
if ip.IsLoopback() || ip.IsMulticast() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
if remote != nil {
|
|
|
|
if host == "" || ip.IsUnspecified() {
|
|
|
|
// Replace the unspecified IP with the request source.
|
2018-08-30 17:06:35 +00:00
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
// ... unless the request source is the loopback address or
|
|
|
|
// multicast/unspecified (can't happen, really).
|
|
|
|
if remote.IP.IsLoopback() || remote.IP.IsMulticast() || remote.IP.IsUnspecified() {
|
|
|
|
continue
|
|
|
|
}
|
2018-08-30 17:06:35 +00:00
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
// Do not use IPv6 remote address if requested scheme is ...4
|
|
|
|
// (i.e., tcp4, etc.)
|
|
|
|
if strings.HasSuffix(uri.Scheme, "4") && remote.IP.To4() == nil {
|
|
|
|
continue
|
|
|
|
}
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
// Do not use IPv4 remote address if requested scheme is ...6
|
|
|
|
if strings.HasSuffix(uri.Scheme, "6") && remote.IP.To4() != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
host = remote.IP.String()
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 07:17:07 +00:00
|
|
|
// If zero port was specified, use remote port.
|
|
|
|
if port == "0" && remote.Port > 0 {
|
|
|
|
port = fmt.Sprintf("%d", remote.Port)
|
|
|
|
}
|
cmd/stdiscosrv: New discovery server (fixes #4618)
This is a new revision of the discovery server. Relevant changes and
non-changes:
- Protocol towards clients is unchanged.
- Recommended large scale design is still to be deployed nehind nginx (I
tested, and it's still a lot faster at terminating TLS).
- Database backend is leveldb again, only. It scales enough, is easy to
setup, and we don't need any backend to take care of.
- Server supports replication. This is a simple TCP channel - protect it
with a firewall when deploying over the internet. (We deploy this within
the same datacenter, and with firewall.) Any incoming client announces
are sent over the replication channel(s) to other peer discosrvs.
Incoming replication changes are applied to the database as if they came
from clients, but without the TLS/certificate overhead.
- Metrics are exposed using the prometheus library, when enabled.
- The database values and replication protocol is protobuf, because JSON
was quite CPU intensive when I tried that and benchmarked it.
- The "Retry-After" value for failed lookups gets slowly increased from
a default of 120 seconds, by 5 seconds for each failed lookup,
independently by each discosrv. This lowers the query load over time for
clients that are never seen. The Retry-After maxes out at 3600 after a
couple of weeks of this increase. The number of failed lookups is
stored in the database, now and then (avoiding making each lookup a
database put).
All in all this means clients can be pointed towards a cluster using
just multiple A / AAAA records to gain both load sharing and redundancy
(if one is down, clients will talk to the remaining ones).
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4648
2018-01-14 08:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uri.Host = net.JoinHostPort(host, port)
|
|
|
|
fixed = append(fixed, uri.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
return fixed
|
|
|
|
}
|
|
|
|
|
|
|
|
type loggingResponseWriter struct {
|
|
|
|
http.ResponseWriter
|
|
|
|
statusCode int
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
|
|
|
|
return &loggingResponseWriter{w, http.StatusOK}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lrw *loggingResponseWriter) WriteHeader(code int) {
|
|
|
|
lrw.statusCode = code
|
|
|
|
lrw.ResponseWriter.WriteHeader(code)
|
|
|
|
}
|
|
|
|
|
|
|
|
func addressStrs(dbAddrs []DatabaseAddress) []string {
|
|
|
|
res := make([]string, len(dbAddrs))
|
|
|
|
for i, a := range dbAddrs {
|
|
|
|
res[i] = a.Address
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func errorRetryAfterString() string {
|
|
|
|
return strconv.Itoa(errorRetryAfterSeconds + rand.Intn(errorRetryFuzzSeconds))
|
|
|
|
}
|
|
|
|
|
|
|
|
func notFoundRetryAfterString(misses int) string {
|
|
|
|
retryAfterS := notFoundRetryMinSeconds + notFoundRetryIncSeconds*misses
|
|
|
|
if retryAfterS > notFoundRetryMaxSeconds {
|
|
|
|
retryAfterS = notFoundRetryMaxSeconds
|
|
|
|
}
|
|
|
|
retryAfterS += rand.Intn(notFoundRetryFuzzSeconds)
|
|
|
|
return strconv.Itoa(retryAfterS)
|
|
|
|
}
|
|
|
|
|
|
|
|
func reannounceAfterString() string {
|
|
|
|
return strconv.Itoa(reannounceAfterSeconds + rand.Intn(reannounzeFuzzSeconds))
|
|
|
|
}
|