/// <summary> /// Adds all required middleware to run the back office /// </summary> /// <param name="builder"></param> /// <returns></returns> public static IUmbracoApplicationBuilderContext UseBackOffice(this IUmbracoApplicationBuilderContext builder) { KeepAliveSettings keepAliveSettings = builder.ApplicationServices.GetRequiredService <IOptions <KeepAliveSettings> >().Value; IHostingEnvironment hostingEnvironment = builder.ApplicationServices.GetRequiredService <IHostingEnvironment>(); builder.AppBuilder.Map( hostingEnvironment.ToAbsolute(keepAliveSettings.KeepAlivePingUrl), a => a.UseMiddleware <KeepAliveMiddleware>()); builder.AppBuilder.UseMiddleware <BackOfficeExternalLoginProviderErrorMiddleware>(); return(builder); }
private KeepAlive CreateKeepAlive( bool enabled = true, ServerRole serverRole = ServerRole.Single, bool isMainDom = true) { var settings = new KeepAliveSettings { DisableKeepAliveTask = !enabled }; var mockHostingEnvironment = new Mock <IHostingEnvironment>(); mockHostingEnvironment.SetupGet(x => x.ApplicationMainUrl).Returns(new Uri(ApplicationUrl)); mockHostingEnvironment.Setup(x => x.ToAbsolute(It.IsAny <string>())) .Returns((string s) => s.TrimStart('~')); var mockServerRegistrar = new Mock <IServerRoleAccessor>(); mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock <IMainDom>(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); var mockScopeProvider = new Mock <IScopeProvider>(); var mockLogger = new Mock <ILogger <KeepAlive> >(); var mockProfilingLogger = new Mock <IProfilingLogger>(); _mockHttpMessageHandler = new Mock <HttpMessageHandler>(); _mockHttpMessageHandler.Protected() .Setup <Task <HttpResponseMessage> >( "SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>()) .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK)) .Verifiable(); _mockHttpMessageHandler.As <IDisposable>().Setup(s => s.Dispose()); var httpClient = new HttpClient(_mockHttpMessageHandler.Object); var mockHttpClientFactory = new Mock <IHttpClientFactory>(MockBehavior.Strict); mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny <string>())).Returns(httpClient); return(new KeepAlive( mockHostingEnvironment.Object, mockMainDom.Object, new TestOptionsMonitor <KeepAliveSettings>(settings), mockLogger.Object, mockProfilingLogger.Object, mockServerRegistrar.Object, mockHttpClientFactory.Object)); }
/// <summary> /// Initializes a new instance of the <see cref="KeepAlive"/> class. /// </summary> /// <param name="hostingEnvironment">The current hosting environment</param> /// <param name="mainDom">Representation of the main application domain.</param> /// <param name="keepAliveSettings">The configuration for keep alive settings.</param> /// <param name="logger">The typed logger.</param> /// <param name="profilingLogger">The profiling logger.</param> /// <param name="serverRegistrar">Provider of server registrations to the distributed cache.</param> /// <param name="httpClientFactory">Factory for <see cref="HttpClient" /> instances.</param> public KeepAlive( IHostingEnvironment hostingEnvironment, IMainDom mainDom, IOptions <KeepAliveSettings> keepAliveSettings, ILogger <KeepAlive> logger, IProfilingLogger profilingLogger, IServerRoleAccessor serverRegistrar, IHttpClientFactory httpClientFactory) : base(TimeSpan.FromMinutes(5), DefaultDelay) { _hostingEnvironment = hostingEnvironment; _mainDom = mainDom; _keepAliveSettings = keepAliveSettings.Value; _logger = logger; _profilingLogger = profilingLogger; _serverRegistrar = serverRegistrar; _httpClientFactory = httpClientFactory; }
private static void keepAlive(object state) { KeepAliveSettings settings = (KeepAliveSettings)state; PortSpoofing.Send(settings.SpoofedLocalEndPoint, settings.ServiceEndPoint, settings.Datagram); }
private static unsafe void notificationLoop(object natTraversalSession) { NatTraversalSession session = (NatTraversalSession)natTraversalSession; Timer keepAliveTimer = null; try { IPEndPoint serviceEndPoint = null; // connect to service to open a port on the NAT devices using (Socket notificationSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { notificationSocket.Connect(natTraversalServiceUrl, natTraversalServicePort); serviceEndPoint = (IPEndPoint)notificationSocket.RemoteEndPoint; session.LocalEndPoint = (IPEndPoint)notificationSocket.LocalEndPoint; } // create a new socket in listening mode using the port just opened using (Socket notificationSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { notificationSocket.ReceiveTimeout = 1000; notificationSocket.Bind(session.LocalEndPoint); // send "open notification channel" message { MsgOpenNotificationChannel msg = new MsgOpenNotificationChannel(session.SessionId); byte[] datagram = new byte[sizeof(MsgOpenNotificationChannel)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msg)[i]; } notificationSocket.SendTo(datagram, serviceEndPoint); } while (true) { // block until a message is received or 1 second has elapsed EndPoint any = new IPEndPoint(IPAddress.Any, 0); byte[] bytesReceived = new byte[1024]; int bytesReceivedLength = notificationSocket.ReceiveFrom(bytesReceived, ref any); IPEndPoint remoteEndPoint = (IPEndPoint)any; // test for stop condition: a message send from this local endpoint to itself if (remoteEndPoint.Equals(session.LocalEndPoint)) { break; } else if (remoteEndPoint.Equals(serviceEndPoint)) { // handle the message if (bytesReceivedLength >= 3 && bytesReceived[0] == 'z' && bytesReceived[1] == 't') { switch (bytesReceived[2]) { case (byte)MessageType.AckOpenNotificationChannel: if (bytesReceivedLength == sizeof(MsgAckOpenNotificationChannel)) { MsgAckOpenNotificationChannel msg = new MsgAckOpenNotificationChannel(); for (int i = 0; i < sizeof(MsgAckOpenNotificationChannel); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgAckOpenNotificationChannel // send "host" message, from the same port as DirectPlay (spoofed) IPEndPoint spoofedEndPoint = new IPEndPoint(session.LocalEndPoint.Address, session.PrivatePort); MsgHost msgHost = new MsgHost(session.SessionId, session.LocalEndPoint.Address, (ushort)session.PrivatePort); byte[] datagram = new byte[sizeof(MsgHost)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msgHost)[i]; } PortSpoofing.Send(spoofedEndPoint, serviceEndPoint, datagram); } break; case (byte)MessageType.AckHost: if (bytesReceivedLength == sizeof(MsgAckHost)) { if (keepAliveTimer == null) // ignore if already handled { MsgAckHost msg = new MsgAckHost(); for (int i = 0; i < sizeof(MsgAckHost); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgAckHost // record public address/port session.PublicIpAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.HostPublicIp)).ToString(); session.PublicPort = msg.HostPublicPort; // notify main thread that NAT traversal is enabled session.Enabled = true; if (session.NatTraversalEnabled != null) { session.NatTraversalEnabled.Set(); } // set reception so it can't time-out notificationSocket.ReceiveTimeout = 0; // send a keep alive message every 19 seconds KeepAliveSettings settings = new KeepAliveSettings(); settings.SpoofedLocalEndPoint = session.LocalEndPoint; settings.ServiceEndPoint = serviceEndPoint; MsgKeepAlive msgKeepAlive = new MsgKeepAlive(session.SessionId); settings.Datagram = new byte[sizeof(MsgKeepAlive)]; for (int i = 0; i < settings.Datagram.Length; ++i) { settings.Datagram[i] = ((byte *)&msgKeepAlive)[i]; } keepAliveTimer = new Timer(new TimerCallback(keepAlive), settings, 19000, 19000); } } break; case (byte)MessageType.Connect: if (bytesReceivedLength == sizeof(MsgConnect)) { MsgConnect msg = new MsgConnect(); for (int i = 0; i < sizeof(MsgConnect); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgConnect // punch hole targeting client's public and private addresses IPAddress publicClientAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.ClientPublicIp)); IPAddress privateClientAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.ClientPrivateIp)); IPEndPoint spoofedEndPoint = new IPEndPoint(session.LocalEndPoint.Address, session.PrivatePort); byte[] emptyDatagram = new byte[0]; PortSpoofing.Send(spoofedEndPoint, new IPEndPoint(publicClientAddress, msg.ClientPublicPort), emptyDatagram); PortSpoofing.Send(spoofedEndPoint, new IPEndPoint(privateClientAddress, msg.ClientPrivatePort), emptyDatagram); // send acknowledgement through notification channel MsgAckConnect msgAckConnect = new MsgAckConnect(session.SessionId, publicClientAddress, msg.ClientPublicPort); byte[] datagram = new byte[sizeof(MsgAckConnect)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msgAckConnect)[i]; } notificationSocket.SendTo(datagram, serviceEndPoint); } break; } } } } } } catch { if (!session.Enabled && session.NatTraversalEnabled != null) { session.NatTraversalEnabled.Set(); } } finally { if (keepAliveTimer != null) { keepAliveTimer.Change(Timeout.Infinite, Timeout.Infinite); keepAliveTimer.Dispose(); } } }