github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/server/services.go (about) 1 /* 2 * Copyright (c) 2016, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 // Package server implements the core tunnel functionality of a Psiphon server. 21 // The main function is RunServices, which runs one or all of a Psiphon API web server, 22 // a tunneling SSH server, and an Obfuscated SSH protocol server. The server configuration 23 // is created by the GenerateConfig function. 24 package server 25 26 import ( 27 "fmt" 28 "math/rand" 29 "os" 30 "os/signal" 31 "runtime" 32 "runtime/debug" 33 "sync" 34 "syscall" 35 "time" 36 37 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 38 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/buildinfo" 39 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 40 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/osl" 41 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/packetman" 42 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tactics" 43 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tun" 44 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/server/psinet" 45 ) 46 47 // RunServices initializes support functions including logging and GeoIP services; 48 // and then starts the server components and runs them until os.Interrupt or 49 // os.Kill signals are received. The config determines which components are run. 50 func RunServices(configJSON []byte) (retErr error) { 51 52 loggingInitialized := false 53 54 defer func() { 55 if retErr != nil && loggingInitialized { 56 log.WithTraceFields(LogFields{"error": retErr}).Error("RunServices failed") 57 } 58 }() 59 60 rand.Seed(int64(time.Now().Nanosecond())) 61 62 config, err := LoadConfig(configJSON) 63 if err != nil { 64 return errors.Trace(err) 65 } 66 67 err = InitLogging(config) 68 if err != nil { 69 return errors.Trace(err) 70 } 71 72 loggingInitialized = true 73 74 support, err := NewSupportServices(config) 75 if err != nil { 76 return errors.Trace(err) 77 } 78 79 startupFields := buildinfo.GetBuildInfo().ToMap() 80 startupFields["GODEBUG"] = os.Getenv("GODEBUG") 81 log.WithTraceFields(startupFields).Info("startup") 82 83 waitGroup := new(sync.WaitGroup) 84 shutdownBroadcast := make(chan struct{}) 85 errorChannel := make(chan error, 1) 86 87 tunnelServer, err := NewTunnelServer(support, shutdownBroadcast) 88 if err != nil { 89 return errors.Trace(err) 90 } 91 92 support.TunnelServer = tunnelServer 93 94 if config.RunPacketTunnel { 95 96 packetTunnelServer, err := tun.NewServer(&tun.ServerConfig{ 97 Logger: CommonLogger(log), 98 SudoNetworkConfigCommands: config.PacketTunnelSudoNetworkConfigCommands, 99 GetDNSResolverIPv4Addresses: support.DNSResolver.GetAllIPv4, 100 GetDNSResolverIPv6Addresses: support.DNSResolver.GetAllIPv6, 101 EnableDNSFlowTracking: config.PacketTunnelEnableDNSFlowTracking, 102 EgressInterface: config.PacketTunnelEgressInterface, 103 DownstreamPacketQueueSize: config.PacketTunnelDownstreamPacketQueueSize, 104 SessionIdleExpirySeconds: config.PacketTunnelSessionIdleExpirySeconds, 105 AllowBogons: config.AllowBogons, 106 }) 107 if err != nil { 108 return errors.Trace(err) 109 } 110 111 support.PacketTunnelServer = packetTunnelServer 112 } 113 114 if config.RunPacketManipulator { 115 116 packetManipulatorConfig, err := makePacketManipulatorConfig(support) 117 if err != nil { 118 return errors.Trace(err) 119 } 120 121 packetManipulator, err := packetman.NewManipulator(packetManipulatorConfig) 122 if err != nil { 123 return errors.Trace(err) 124 } 125 126 support.PacketManipulator = packetManipulator 127 } 128 129 // After this point, errors should be delivered to the errors channel and 130 // orderly shutdown should flow through to the end of the function to ensure 131 // all workers are synchronously stopped. 132 133 if config.RunPacketTunnel { 134 support.PacketTunnelServer.Start() 135 waitGroup.Add(1) 136 go func() { 137 defer waitGroup.Done() 138 <-shutdownBroadcast 139 support.PacketTunnelServer.Stop() 140 }() 141 } 142 143 if config.RunPacketManipulator { 144 err := support.PacketManipulator.Start() 145 if err != nil { 146 select { 147 case errorChannel <- err: 148 default: 149 } 150 } else { 151 waitGroup.Add(1) 152 go func() { 153 defer waitGroup.Done() 154 <-shutdownBroadcast 155 support.PacketManipulator.Stop() 156 }() 157 } 158 } 159 160 if config.RunLoadMonitor() { 161 waitGroup.Add(1) 162 go func() { 163 waitGroup.Done() 164 ticker := time.NewTicker(time.Duration(config.LoadMonitorPeriodSeconds) * time.Second) 165 defer ticker.Stop() 166 for { 167 select { 168 case <-shutdownBroadcast: 169 return 170 case <-ticker.C: 171 logServerLoad(support) 172 } 173 } 174 }() 175 } 176 177 if config.RunPeriodicGarbageCollection() { 178 waitGroup.Add(1) 179 go func() { 180 waitGroup.Done() 181 ticker := time.NewTicker(config.periodicGarbageCollection) 182 defer ticker.Stop() 183 for { 184 select { 185 case <-shutdownBroadcast: 186 return 187 case <-ticker.C: 188 debug.FreeOSMemory() 189 } 190 } 191 }() 192 } 193 194 if config.RunWebServer() { 195 waitGroup.Add(1) 196 go func() { 197 defer waitGroup.Done() 198 err := RunWebServer(support, shutdownBroadcast) 199 select { 200 case errorChannel <- err: 201 default: 202 } 203 }() 204 } 205 206 // The tunnel server is always run; it launches multiple 207 // listeners, depending on which tunnel protocols are enabled. 208 waitGroup.Add(1) 209 go func() { 210 defer waitGroup.Done() 211 err := tunnelServer.Run() 212 select { 213 case errorChannel <- err: 214 default: 215 } 216 }() 217 218 // Shutdown doesn't wait for the outputProcessProfiles goroutine 219 // to complete, as it may be sleeping while running a "block" or 220 // CPU profile. 221 signalProcessProfiles := make(chan struct{}, 1) 222 go func() { 223 for { 224 select { 225 case <-signalProcessProfiles: 226 outputProcessProfiles(support.Config, "") 227 case <-shutdownBroadcast: 228 return 229 } 230 } 231 }() 232 233 // In addition to the actual signal handling here, there is 234 // a list of signals that need to be passed through panicwrap 235 // in 'github.com/Psiphon-Labs/psiphon-tunnel-core/Server/main.go' 236 // where 'panicwrap.Wrap' is called. The handled signals below, and the 237 // list there must be kept in sync to ensure proper signal handling 238 239 // An OS signal triggers an orderly shutdown 240 systemStopSignal := make(chan os.Signal, 1) 241 signal.Notify(systemStopSignal, os.Interrupt, syscall.SIGTERM) 242 243 // SIGUSR1 triggers a reload of support services 244 reloadSupportServicesSignal := makeSIGUSR1Channel() 245 246 // SIGUSR2 triggers an immediate load log and optional process profile output 247 logServerLoadSignal := makeSIGUSR2Channel() 248 249 // SIGTSTP triggers tunnelServer to stop establishing new tunnels 250 stopEstablishingTunnelsSignal := makeSIGTSTPChannel() 251 252 // SIGCONT triggers tunnelServer to resume establishing new tunnels 253 resumeEstablishingTunnelsSignal := makeSIGCONTChannel() 254 255 err = nil 256 257 loop: 258 for { 259 select { 260 case <-stopEstablishingTunnelsSignal: 261 tunnelServer.SetEstablishTunnels(false) 262 263 if config.DumpProfilesOnStopEstablishTunnels( 264 tunnelServer.GetEstablishedClientCount()) { 265 266 // Run the profile dump in a goroutine and don't block this loop. Shutdown 267 // doesn't wait for any running outputProcessProfiles to complete. 268 go func() { 269 outputProcessProfiles(support.Config, "stop_establish_tunnels") 270 }() 271 } 272 273 case <-resumeEstablishingTunnelsSignal: 274 tunnelServer.SetEstablishTunnels(true) 275 276 case <-reloadSupportServicesSignal: 277 support.Reload() 278 279 case <-logServerLoadSignal: 280 // Signal profiles writes first to ensure some diagnostics are 281 // available in case logServerLoad hangs (which has happened 282 // in the past due to a deadlock bug). 283 select { 284 case signalProcessProfiles <- struct{}{}: 285 default: 286 } 287 logServerLoad(support) 288 289 case <-systemStopSignal: 290 log.WithTrace().Info("shutdown by system") 291 break loop 292 293 case err = <-errorChannel: 294 break loop 295 } 296 } 297 298 // During any delayed or hung shutdown, periodically dump profiles to help 299 // diagnose the cause. Shutdown doesn't wait for any running 300 // outputProcessProfiles to complete. 301 signalProfileDumperStop := make(chan struct{}) 302 go func() { 303 tickSeconds := 10 304 ticker := time.NewTicker(time.Duration(tickSeconds) * time.Second) 305 defer ticker.Stop() 306 for i := tickSeconds; i <= 60; i += tickSeconds { 307 select { 308 case <-signalProfileDumperStop: 309 return 310 case <-ticker.C: 311 filenameSuffix := fmt.Sprintf("delayed_shutdown_%ds", i) 312 outputProcessProfiles(support.Config, filenameSuffix) 313 } 314 } 315 }() 316 317 close(shutdownBroadcast) 318 waitGroup.Wait() 319 320 close(signalProfileDumperStop) 321 322 return err 323 } 324 325 func getRuntimeMetrics() LogFields { 326 327 numGoroutine := runtime.NumGoroutine() 328 329 var memStats runtime.MemStats 330 runtime.ReadMemStats(&memStats) 331 332 lastGC := "" 333 if memStats.LastGC > 0 { 334 lastGC = time.Unix(0, int64(memStats.LastGC)).UTC().Format(time.RFC3339) 335 } 336 337 return LogFields{ 338 "num_goroutine": numGoroutine, 339 "heap_alloc": memStats.HeapAlloc, 340 "heap_sys": memStats.HeapSys, 341 "heap_idle": memStats.HeapIdle, 342 "heap_inuse": memStats.HeapInuse, 343 "heap_released": memStats.HeapReleased, 344 "heap_objects": memStats.HeapObjects, 345 "num_gc": memStats.NumGC, 346 "num_forced_gc": memStats.NumForcedGC, 347 "last_gc": lastGC, 348 } 349 } 350 351 func outputProcessProfiles(config *Config, filenameSuffix string) { 352 353 log.WithTraceFields(getRuntimeMetrics()).Info("runtime_metrics") 354 355 if config.ProcessProfileOutputDirectory != "" { 356 common.WriteRuntimeProfiles( 357 CommonLogger(log), 358 config.ProcessProfileOutputDirectory, 359 filenameSuffix, 360 config.ProcessBlockProfileDurationSeconds, 361 config.ProcessCPUProfileDurationSeconds) 362 } 363 } 364 365 func logServerLoad(support *SupportServices) { 366 367 serverLoad := getRuntimeMetrics() 368 369 serverLoad["event_name"] = "server_load" 370 371 establishTunnels, establishLimitedCount := 372 support.TunnelServer.GetEstablishTunnelsMetrics() 373 serverLoad["establish_tunnels"] = establishTunnels 374 serverLoad["establish_tunnels_limited_count"] = establishLimitedCount 375 376 serverLoad.Add(support.ReplayCache.GetMetrics()) 377 378 serverLoad.Add(support.ServerTacticsParametersCache.GetMetrics()) 379 380 upstreamStats, protocolStats, regionStats := 381 support.TunnelServer.GetLoadStats() 382 383 for name, value := range upstreamStats { 384 serverLoad[name] = value 385 } 386 387 for protocol, stats := range protocolStats { 388 serverLoad[protocol] = stats 389 } 390 391 log.LogRawFieldsWithTimestamp(serverLoad) 392 393 for region, regionProtocolStats := range regionStats { 394 395 serverLoad := LogFields{ 396 "event_name": "server_load", 397 "region": region, 398 } 399 400 for protocol, stats := range regionProtocolStats { 401 serverLoad[protocol] = stats 402 } 403 404 log.LogRawFieldsWithTimestamp(serverLoad) 405 } 406 } 407 408 func logIrregularTunnel( 409 support *SupportServices, 410 listenerTunnelProtocol string, 411 listenerPort int, 412 clientIP string, 413 tunnelError error, 414 logFields LogFields) { 415 416 if logFields == nil { 417 logFields = make(LogFields) 418 } 419 420 logFields["event_name"] = "irregular_tunnel" 421 logFields["listener_protocol"] = listenerTunnelProtocol 422 logFields["listener_port_number"] = listenerPort 423 support.GeoIPService.Lookup(clientIP).SetLogFields(logFields) 424 logFields["tunnel_error"] = tunnelError.Error() 425 log.LogRawFieldsWithTimestamp(logFields) 426 } 427 428 // SupportServices carries common and shared data components 429 // across different server components. SupportServices implements a 430 // hot reload of traffic rules, psinet database, and geo IP database 431 // components, which allows these data components to be refreshed 432 // without restarting the server process. 433 type SupportServices struct { 434 Config *Config 435 TrafficRulesSet *TrafficRulesSet 436 OSLConfig *osl.Config 437 PsinetDatabase *psinet.Database 438 GeoIPService *GeoIPService 439 DNSResolver *DNSResolver 440 TunnelServer *TunnelServer 441 PacketTunnelServer *tun.Server 442 TacticsServer *tactics.Server 443 Blocklist *Blocklist 444 PacketManipulator *packetman.Manipulator 445 ReplayCache *ReplayCache 446 ServerTacticsParametersCache *ServerTacticsParametersCache 447 } 448 449 // NewSupportServices initializes a new SupportServices. 450 func NewSupportServices(config *Config) (*SupportServices, error) { 451 452 trafficRulesSet, err := NewTrafficRulesSet(config.TrafficRulesFilename) 453 if err != nil { 454 return nil, errors.Trace(err) 455 } 456 457 oslConfig, err := osl.NewConfig(config.OSLConfigFilename) 458 if err != nil { 459 return nil, errors.Trace(err) 460 } 461 462 psinetDatabase, err := psinet.NewDatabase(config.PsinetDatabaseFilename) 463 if err != nil { 464 return nil, errors.Trace(err) 465 } 466 467 geoIPService, err := NewGeoIPService(config.GeoIPDatabaseFilenames) 468 if err != nil { 469 return nil, errors.Trace(err) 470 } 471 472 dnsResolver, err := NewDNSResolver(config.DNSResolverIPAddress) 473 if err != nil { 474 return nil, errors.Trace(err) 475 } 476 477 blocklist, err := NewBlocklist(config.BlocklistFilename) 478 if err != nil { 479 return nil, errors.Trace(err) 480 } 481 482 tacticsServer, err := tactics.NewServer( 483 CommonLogger(log), 484 getTacticsAPIParameterLogFieldFormatter(), 485 getTacticsAPIParameterValidator(config), 486 config.TacticsConfigFilename) 487 if err != nil { 488 return nil, errors.Trace(err) 489 } 490 491 support := &SupportServices{ 492 Config: config, 493 TrafficRulesSet: trafficRulesSet, 494 OSLConfig: oslConfig, 495 PsinetDatabase: psinetDatabase, 496 GeoIPService: geoIPService, 497 DNSResolver: dnsResolver, 498 TacticsServer: tacticsServer, 499 Blocklist: blocklist, 500 } 501 502 support.ReplayCache = NewReplayCache(support) 503 504 support.ServerTacticsParametersCache = 505 NewServerTacticsParametersCache(support) 506 507 return support, nil 508 } 509 510 // Reload reinitializes traffic rules, psinet database, and geo IP database 511 // components. If any component fails to reload, an error is logged and 512 // Reload proceeds, using the previous state of the component. 513 func (support *SupportServices) Reload() { 514 515 reloaders := append( 516 []common.Reloader{ 517 support.TrafficRulesSet, 518 support.OSLConfig, 519 support.PsinetDatabase, 520 support.TacticsServer, 521 support.Blocklist}, 522 support.GeoIPService.Reloaders()...) 523 524 // Note: established clients aren't notified when tactics change after a 525 // reload; new tactics will be obtained on the next client handshake or 526 // tactics request. 527 528 reloadTactics := func() { 529 530 // Don't use stale tactics. 531 support.ReplayCache.Flush() 532 support.ServerTacticsParametersCache.Flush() 533 534 if support.Config.RunPacketManipulator { 535 err := reloadPacketManipulationSpecs(support) 536 if err != nil { 537 log.WithTraceFields( 538 LogFields{"error": errors.Trace(err)}).Warning( 539 "failed to reload packet manipulation specs") 540 } 541 } 542 } 543 544 // Take these actions only after the corresponding Reloader has reloaded. 545 // In both the traffic rules and OSL cases, there is some impact from state 546 // reset, so the reset should be avoided where possible. 547 reloadPostActions := map[common.Reloader]func(){ 548 support.TrafficRulesSet: func() { support.TunnelServer.ResetAllClientTrafficRules() }, 549 support.OSLConfig: func() { support.TunnelServer.ResetAllClientOSLConfigs() }, 550 support.TacticsServer: reloadTactics, 551 } 552 553 for _, reloader := range reloaders { 554 555 if !reloader.WillReload() { 556 // Skip logging 557 continue 558 } 559 560 // "reloaded" flag indicates if file was actually reloaded or ignored 561 reloaded, err := reloader.Reload() 562 563 if reloaded { 564 if action, ok := reloadPostActions[reloader]; ok { 565 action() 566 } 567 } 568 569 if err != nil { 570 log.WithTraceFields( 571 LogFields{ 572 "reloader": reloader.LogDescription(), 573 "error": err}).Error("reload failed") 574 // Keep running with previous state 575 } else { 576 log.WithTraceFields( 577 LogFields{ 578 "reloader": reloader.LogDescription(), 579 "reloaded": reloaded}).Info("reload success") 580 } 581 } 582 }