/// <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);
        }
示例#2
0
    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));
    }
示例#3
0
 /// <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;
 }
示例#4
0
        private static void keepAlive(object state)
        {
            KeepAliveSettings settings = (KeepAliveSettings)state;

            PortSpoofing.Send(settings.SpoofedLocalEndPoint, settings.ServiceEndPoint, settings.Datagram);
        }
示例#5
0
        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();
                }
            }
        }