2021-05-01 12:45:37 +02:00
package cmd
import (
2022-05-22 18:53:47 +02:00
"errors"
2021-05-01 12:45:37 +02:00
"flag"
"fmt"
2022-05-13 21:51:41 +02:00
"io"
2022-05-22 18:53:47 +02:00
"io/fs"
2022-05-13 21:51:41 +02:00
"io/ioutil"
"net"
"net/http"
"os"
"path"
"time"
2022-03-26 12:08:54 +01:00
"github.com/netbirdio/netbird/encryption"
"github.com/netbirdio/netbird/signal/proto"
"github.com/netbirdio/netbird/signal/server"
"github.com/netbirdio/netbird/util"
2021-05-01 12:45:37 +02:00
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"google.golang.org/grpc"
2021-07-22 15:23:24 +02:00
"google.golang.org/grpc/credentials"
2021-07-21 20:23:11 +02:00
"google.golang.org/grpc/keepalive"
2021-05-01 12:45:37 +02:00
)
var (
2021-07-21 20:23:11 +02:00
signalPort int
signalLetsencryptDomain string
2021-08-13 08:46:30 +02:00
signalSSLDir string
2022-05-13 21:51:41 +02:00
defaultSignalSSLDir string
2021-07-21 20:23:11 +02:00
signalKaep = grpc . KeepaliveEnforcementPolicy ( keepalive . EnforcementPolicy {
MinTime : 5 * time . Second ,
PermitWithoutStream : true ,
} )
signalKasp = grpc . KeepaliveParams ( keepalive . ServerParameters {
MaxConnectionIdle : 15 * time . Second ,
MaxConnectionAgeGrace : 5 * time . Second ,
Time : 5 * time . Second ,
Timeout : 2 * time . Second ,
} )
2021-05-01 12:45:37 +02:00
2021-08-13 08:46:30 +02:00
runCmd = & cobra . Command {
Use : "run" ,
2022-05-13 21:51:41 +02:00
Short : "start Netbird Signal Server daemon" ,
2021-05-01 12:45:37 +02:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
flag . Parse ( )
2021-09-07 09:53:18 +02:00
err := util . InitLog ( logLevel , logFile )
if err != nil {
log . Fatalf ( "failed initializing log %v" , err )
}
2021-05-01 12:45:37 +02:00
2022-05-13 21:51:41 +02:00
if signalSSLDir == "" {
oldPath := "/var/lib/wiretrustee"
if migrateToNetbird ( oldPath , defaultSignalSSLDir ) {
if err := cpDir ( oldPath , defaultSignalSSLDir ) ; err != nil {
log . Fatal ( err )
}
}
}
2021-07-21 20:23:11 +02:00
var opts [ ] grpc . ServerOption
2021-07-22 15:23:24 +02:00
if signalLetsencryptDomain != "" {
2021-08-13 08:46:30 +02:00
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 )
}
}
certManager := encryption . CreateCertManager ( signalSSLDir , signalLetsencryptDomain )
2021-08-07 12:26:07 +02:00
transportCredentials := credentials . NewTLS ( certManager . TLSConfig ( ) )
2021-07-21 20:23:11 +02:00
opts = append ( opts , grpc . Creds ( transportCredentials ) )
2021-08-15 16:56:26 +02:00
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 )
}
} ( )
2021-07-21 20:23:11 +02:00
}
opts = append ( opts , signalKaep , signalKasp )
grpcServer := grpc . NewServer ( opts ... )
2021-07-17 14:38:59 +02:00
lis , err := net . Listen ( "tcp" , fmt . Sprintf ( ":%d" , signalPort ) )
2021-05-01 12:45:37 +02:00
if err != nil {
log . Fatalf ( "failed to listen: %v" , err )
}
2021-08-13 08:46:30 +02:00
proto . RegisterSignalExchangeServer ( grpcServer , server . NewServer ( ) )
2021-07-17 14:38:59 +02:00
log . Printf ( "started server: localhost:%v" , signalPort )
2021-05-01 12:45:37 +02:00
if err := grpcServer . Serve ( lis ) ; err != nil {
log . Fatalf ( "failed to serve: %v" , err )
}
SetupCloseHandler ( )
2021-07-21 20:23:11 +02:00
<- stopCh
log . Println ( "Receive signal to stop running the Signal server" )
2021-05-01 12:45:37 +02:00
} ,
}
)
2022-05-13 21:51:41 +02:00
func cpFile ( src , dst string ) error {
var err error
var srcfd * os . File
var dstfd * os . File
var srcinfo os . FileInfo
if srcfd , err = os . Open ( src ) ; err != nil {
return err
}
defer srcfd . Close ( )
if dstfd , err = os . Create ( dst ) ; err != nil {
return err
}
defer dstfd . Close ( )
if _ , err = io . Copy ( dstfd , srcfd ) ; err != nil {
return err
}
if srcinfo , err = os . Stat ( src ) ; err != nil {
return err
}
return os . Chmod ( dst , srcinfo . Mode ( ) )
}
func copySymLink ( source , dest string ) error {
link , err := os . Readlink ( source )
if err != nil {
return err
}
return os . Symlink ( link , dest )
}
func cpDir ( src string , dst string ) error {
var err error
var fds [ ] os . FileInfo
var srcinfo os . FileInfo
if srcinfo , err = os . Stat ( src ) ; err != nil {
return err
}
if err = os . MkdirAll ( dst , srcinfo . Mode ( ) ) ; err != nil {
return err
}
if fds , err = ioutil . ReadDir ( src ) ; err != nil {
return err
}
for _ , fd := range fds {
srcfp := path . Join ( src , fd . Name ( ) )
dstfp := path . Join ( dst , fd . Name ( ) )
fileInfo , err := os . Stat ( srcfp )
if err != nil {
log . Fatalf ( "Couldn't get fileInfo; %v" , err )
}
switch fileInfo . Mode ( ) & os . ModeType {
case os . ModeSymlink :
if err = copySymLink ( srcfp , dstfp ) ; err != nil {
log . Fatalf ( "Failed to copy from %s to %s; %v" , srcfp , dstfp , err )
}
case os . ModeDir :
if err = cpDir ( srcfp , dstfp ) ; err != nil {
log . Fatalf ( "Failed to copy from %s to %s; %v" , srcfp , dstfp , err )
}
default :
if err = cpFile ( srcfp , dstfp ) ; err != nil {
log . Fatalf ( "Failed to copy from %s to %s; %v" , srcfp , dstfp , err )
}
}
}
return nil
}
func migrateToNetbird ( oldPath , newPath string ) bool {
2022-05-22 18:53:47 +02:00
_ , errOld := os . Stat ( oldPath )
_ , errNew := os . Stat ( newPath )
2022-05-13 21:51:41 +02:00
2022-05-22 18:53:47 +02:00
if errors . Is ( errOld , fs . ErrNotExist ) || errNew == nil {
2022-05-13 21:51:41 +02:00
return false
}
return true
}
2021-05-01 12:45:37 +02:00
func init ( ) {
2021-08-13 08:46:30 +02:00
runCmd . PersistentFlags ( ) . IntVar ( & signalPort , "port" , 10000 , "Server port to listen on (e.g. 10000)" )
2022-05-13 21:51:41 +02:00
runCmd . Flags ( ) . StringVar ( & signalSSLDir , "ssl-dir" , defaultSignalSSLDir , "server ssl directory location. *Required only for Let's Encrypt certificates." )
2021-08-13 08:46:30 +02:00
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" )
2021-05-01 12:45:37 +02:00
}