mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-05 08:54:11 -04:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67ddaade58 | ||
|
|
138cf35e00 | ||
|
|
2555a6c3e8 | ||
|
|
86a66c6202 | ||
|
|
275d364df6 | ||
|
|
a3c5fa1307 | ||
|
|
75a69ca26b |
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -40,6 +40,9 @@ jobs:
|
||||
-
|
||||
name: Install modules
|
||||
run: go mod tidy
|
||||
-
|
||||
name: check git status
|
||||
run: git --no-pager diff --exit-code
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
FROM gcr.io/distroless/base:debug
|
||||
ENV WT_LOG_FILE=console
|
||||
ENV PATH=/sbin:/usr/sbin:/bin:/usr/bin:/busybox
|
||||
SHELL ["/busybox/sh","-c"]
|
||||
RUN sed -i -E 's/(^root:.+)\/sbin\/nologin/\1\/busybox\/sh/g' /etc/passwd
|
||||
ENTRYPOINT [ "/go/bin/netbird","up"]
|
||||
|
||||
@@ -64,6 +64,14 @@ func createNewConfig(managementURL, adminURL, configPath, preSharedKey string) (
|
||||
config.PreSharedKey = preSharedKey
|
||||
}
|
||||
|
||||
if adminURL != "" {
|
||||
newURL, err := parseURL("Admin Panel URL", adminURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.AdminURL = newURL
|
||||
}
|
||||
|
||||
config.IFaceBlackList = []string{iface.WgInterfaceDefault, "tun0", "zt", "ZeroTier", "utun", "wg", "ts",
|
||||
"Tailscale", "tailscale"}
|
||||
|
||||
|
||||
@@ -657,7 +657,7 @@ func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
func (e *Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
for {
|
||||
|
||||
// randomize starting time a bit
|
||||
@@ -676,6 +676,13 @@ func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
continue
|
||||
}
|
||||
|
||||
// we might have received new STUN and TURN servers meanwhile, so update them
|
||||
e.syncMsgMux.Lock()
|
||||
conf := conn.GetConf()
|
||||
conf.StunTurn = append(e.STUNs, e.TURNs...)
|
||||
conn.UpdateConf(conf)
|
||||
e.syncMsgMux.Unlock()
|
||||
|
||||
err := conn.Open()
|
||||
if err != nil {
|
||||
log.Debugf("connection to peer %s failed: %v", peerKey, err)
|
||||
|
||||
@@ -75,6 +75,11 @@ func (conn *Conn) GetConf() ConnConfig {
|
||||
return conn.config
|
||||
}
|
||||
|
||||
// UpdateConf updates the connection config
|
||||
func (conn *Conn) UpdateConf(conf ConnConfig) {
|
||||
conn.config = conf
|
||||
}
|
||||
|
||||
// NewConn creates a new not opened Conn to the remote peer.
|
||||
// To establish a connection run Conn.Open
|
||||
func NewConn(config ConnConfig, statusRecorder *nbStatus.Status) (*Conn, error) {
|
||||
@@ -283,6 +288,10 @@ func shouldUseProxy(pair *ice.CandidatePair) bool {
|
||||
remoteIsPublic := IsPublicIP(remoteIP)
|
||||
myIsPublic := IsPublicIP(myIp)
|
||||
|
||||
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
||||
return true
|
||||
}
|
||||
|
||||
//one of the hosts has a public IP
|
||||
if remoteIsPublic && pair.Remote.Type() == ice.CandidateTypeHost {
|
||||
return false
|
||||
@@ -415,7 +424,7 @@ func (conn *Conn) SetSignalCandidate(handler func(candidate ice.Candidate) error
|
||||
// and then signals them to the remote peer
|
||||
func (conn *Conn) onICECandidate(candidate ice.Candidate) {
|
||||
if candidate != nil {
|
||||
// log.Debugf("discovered local candidate %s", candidate.String())
|
||||
log.Debugf("discovered local candidate %s", candidate.String())
|
||||
go func() {
|
||||
err := conn.signalCandidate(candidate)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,17 +8,17 @@ import (
|
||||
)
|
||||
|
||||
// CreateCertManager wraps common logic of generating Let's encrypt certificate.
|
||||
func CreateCertManager(datadir string, letsencryptDomain string) *autocert.Manager {
|
||||
func CreateCertManager(datadir string, letsencryptDomain string) (*autocert.Manager, error) {
|
||||
certDir := filepath.Join(datadir, "letsencrypt")
|
||||
|
||||
if _, err := os.Stat(certDir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(certDir, os.ModeDir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating Let's encrypt certdir: %s: %v", certDir, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("running with Let's encrypt with domain %s. Cert will be stored in %s", letsencryptDomain, certDir)
|
||||
log.Infof("running with LetsEncrypt (%s). Cert will be stored in %s", letsencryptDomain, certDir)
|
||||
|
||||
certManager := &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
@@ -26,5 +26,5 @@ func CreateCertManager(datadir string, letsencryptDomain string) *autocert.Manag
|
||||
HostPolicy: autocert.HostWhitelist(letsencryptDomain),
|
||||
}
|
||||
|
||||
return certManager
|
||||
return certManager, nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
volumes:
|
||||
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
||||
ports:
|
||||
- 10000:10000
|
||||
- 10000:80
|
||||
# # port and command for Let's Encrypt validation
|
||||
# - 443:443
|
||||
# command: ["--letsencrypt-domain", "$NETBIRD_DOMAIN", "--log-file", "console"]
|
||||
|
||||
@@ -46,6 +46,17 @@ var (
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
// TLS enabled:
|
||||
// - HTTP 80 for LetsEncrypt
|
||||
// - if --port not specified gRPC and HTTP servers on 443 (with multiplexing)
|
||||
// - if --port=X specified then run gRPC and HTTP servers on X (with multiplexing)
|
||||
// - if --port=80 forbid this (throw error, otherwise we need to overcomplicate the logic with multiplexing)
|
||||
// TLS disabled:
|
||||
// - if --port not specified gRPC and HTTP servers on 443 on 80 (with multiplexing)
|
||||
// - if --port=X specified then run gRPC and HTTP servers on 443 on X (with multiplexing)
|
||||
// Always run gRPC on port 33073 regardless of TLS to be backward compatible
|
||||
// Remove HTTP port 33071 from the configuration.
|
||||
|
||||
mgmtCmd = &cobra.Command{
|
||||
Use: "management",
|
||||
Short: "start Netbird Management Server",
|
||||
@@ -97,7 +108,10 @@ var (
|
||||
var httpServer *http.Server
|
||||
if config.HttpConfig.LetsEncryptDomain != "" {
|
||||
// automatically generate a new certificate with Let's Encrypt
|
||||
certManager := encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
|
||||
certManager, err := encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating Let's Encrypt cert manager: %v", err)
|
||||
}
|
||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||
opts = append(opts, grpc.Creds(transportCredentials))
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo
|
||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||
}
|
||||
|
||||
sigCtx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
sigCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
conn, err := grpc.DialContext(
|
||||
sigCtx,
|
||||
@@ -75,6 +75,8 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("connected to Signal Service: %v", conn.Target())
|
||||
|
||||
return &GrpcClient{
|
||||
realClient: proto.NewSignalExchangeClient(conn),
|
||||
ctx: ctx,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/encryption"
|
||||
@@ -29,6 +31,7 @@ var (
|
||||
signalLetsencryptDomain string
|
||||
signalSSLDir string
|
||||
defaultSignalSSLDir string
|
||||
tlsEnabled bool
|
||||
|
||||
signalKaep = grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
||||
MinTime: 5 * time.Second,
|
||||
@@ -44,9 +47,26 @@ var (
|
||||
|
||||
runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "start Netbird Signal Server daemon",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Short: "start NetBird Signal Server daemon",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
// detect whether user specified a port
|
||||
userPort := cmd.Flag("port").Changed
|
||||
if signalLetsencryptDomain != "" {
|
||||
tlsEnabled = true
|
||||
}
|
||||
|
||||
if !userPort {
|
||||
// different defaults for signalPort
|
||||
if tlsEnabled {
|
||||
signalPort = 443
|
||||
} else {
|
||||
signalPort = 80
|
||||
}
|
||||
}
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
flag.Parse()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed initializing log %v", err)
|
||||
@@ -62,47 +82,120 @@ var (
|
||||
}
|
||||
|
||||
var opts []grpc.ServerOption
|
||||
if signalLetsencryptDomain != "" {
|
||||
if _, err := os.Stat(signalSSLDir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(signalSSLDir, os.ModeDir)
|
||||
if err != nil {
|
||||
log.Fatalf("failed creating datadir: %s: %v", signalSSLDir, err)
|
||||
}
|
||||
var certManager *autocert.Manager
|
||||
if tlsEnabled {
|
||||
// Let's encrypt enabled -> generate certificate automatically
|
||||
certManager, err = encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certManager := encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain)
|
||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||
opts = append(opts, grpc.Creds(transportCredentials))
|
||||
|
||||
listener := certManager.Listener()
|
||||
log.Infof("http server listening on %s", listener.Addr())
|
||||
go func() {
|
||||
if err := http.Serve(listener, certManager.HTTPHandler(nil)); err != nil {
|
||||
log.Errorf("failed to serve https server: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
opts = append(opts, signalKaep, signalKasp)
|
||||
grpcServer := grpc.NewServer(opts...)
|
||||
|
||||
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", signalPort))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to listen: %v", err)
|
||||
}
|
||||
|
||||
proto.RegisterSignalExchangeServer(grpcServer, server.NewServer())
|
||||
log.Printf("started server: localhost:%v", signalPort)
|
||||
if err := grpcServer.Serve(lis); err != nil {
|
||||
log.Fatalf("failed to serve: %v", err)
|
||||
|
||||
var compatListener net.Listener
|
||||
if signalPort != 10000 {
|
||||
// The Signal gRPC server was running on port 10000 previously. Old agents that are already connected to Signal
|
||||
// are using port 10000. For compatibility purposes we keep running a 2nd gRPC server on port 10000.
|
||||
compatListener, err = serveGRPC(grpcServer, 10000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("running gRPC backward compatibility server: %s", compatListener.Addr().String())
|
||||
}
|
||||
|
||||
var grpcListener net.Listener
|
||||
var httpListener net.Listener
|
||||
if tlsEnabled {
|
||||
httpListener = certManager.Listener()
|
||||
if signalPort == 443 {
|
||||
// running gRPC and HTTP cert manager on the same port
|
||||
serveHTTP(httpListener, certManager.HTTPHandler(grpcHandlerFunc(grpcServer)))
|
||||
log.Infof("running HTTP server (LetsEncrypt challenge handler) and gRPC server on the same port: %s", httpListener.Addr().String())
|
||||
} else {
|
||||
serveHTTP(httpListener, certManager.HTTPHandler(nil))
|
||||
log.Infof("running HTTP server (LetsEncrypt challenge handler): %s", httpListener.Addr().String())
|
||||
}
|
||||
}
|
||||
|
||||
if signalPort != 443 || !tlsEnabled {
|
||||
grpcListener, err = serveGRPC(grpcServer, signalPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("running gRPC server: %s", grpcListener.Addr().String())
|
||||
}
|
||||
|
||||
log.Infof("started Signal Service")
|
||||
|
||||
SetupCloseHandler()
|
||||
|
||||
<-stopCh
|
||||
log.Println("Receive signal to stop running the Signal server")
|
||||
if grpcListener != nil {
|
||||
_ = grpcListener.Close()
|
||||
log.Infof("stopped gRPC server")
|
||||
}
|
||||
if httpListener != nil {
|
||||
_ = httpListener.Close()
|
||||
log.Infof("stopped HTTP server")
|
||||
}
|
||||
if compatListener != nil {
|
||||
_ = compatListener.Close()
|
||||
log.Infof("stopped gRPC backward compatibility server")
|
||||
}
|
||||
log.Infof("stopped Signal Service")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func grpcHandlerFunc(grpcServer *grpc.Server) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
grpcHeader := strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") ||
|
||||
strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc+proto")
|
||||
if r.ProtoMajor == 2 && grpcHeader {
|
||||
grpcServer.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func notifyStop(msg string) {
|
||||
select {
|
||||
case stopCh <- 1:
|
||||
log.Error(msg)
|
||||
default:
|
||||
// stop has been already called, nothing to report
|
||||
}
|
||||
}
|
||||
|
||||
func serveHTTP(httpListener net.Listener, handler http.Handler) {
|
||||
go func() {
|
||||
err := http.Serve(httpListener, handler)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running HTTP server %v", err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func serveGRPC(grpcServer *grpc.Server, port int) (net.Listener, error) {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
err := grpcServer.Serve(listener)
|
||||
if err != nil {
|
||||
notifyStop(fmt.Sprintf("failed running gRPC server on port %d: %v", port, err))
|
||||
}
|
||||
}()
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
func cpFile(src, dst string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
@@ -191,7 +284,7 @@ func migrateToNetbird(oldPath, newPath string) bool {
|
||||
}
|
||||
|
||||
func init() {
|
||||
runCmd.PersistentFlags().IntVar(&signalPort, "port", 10000, "Server port to listen on (e.g. 10000)")
|
||||
runCmd.PersistentFlags().IntVar(&signalPort, "port", 80, "Server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
||||
runCmd.Flags().StringVar(&signalSSLDir, "ssl-dir", defaultSignalSSLDir, "server ssl directory location. *Required only for Let's Encrypt certificates.")
|
||||
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user