Disallow address reuse for port bind tests

This commit is contained in:
Jordan Brown
2020-07-14 10:26:24 -04:00
parent 46aee33261
commit fece7567fb
6 changed files with 33 additions and 9 deletions
@@ -5,8 +5,6 @@ using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
@@ -16,6 +14,7 @@ using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Controllers;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Security;
@@ -482,8 +481,7 @@ namespace Tgstation.Server.Host.Components
// This runs before the real socket is opened, ensures we don't perform reattaches unless we're fairly certain the bind won't fail
// If it does fail, DD will be killed.
using var hostingSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
hostingSocket.Bind(new IPEndPoint(IPAddress.Any, serverPortProvider.HttpApiPort));
SocketExtensions.BindTest(serverPortProvider.HttpApiPort);
}
/// <inheritdoc />
@@ -2,7 +2,6 @@
using System;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -16,6 +15,7 @@ using Tgstation.Server.Host.Components.Deployment;
using Tgstation.Server.Host.Components.Interop;
using Tgstation.Server.Host.Components.Interop.Bridge;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Security;
@@ -118,11 +118,9 @@ namespace Tgstation.Server.Host.Components.Session
/// <param name="port">The port number to test.</param>
static void PortBindTest(ushort port)
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Bind(new IPEndPoint(IPAddress.Any, port));
SocketExtensions.BindTest(port);
}
catch (SocketException ex)
{
@@ -0,0 +1,23 @@
using System.Net;
using System.Net.Sockets;
namespace Tgstation.Server.Host.Extensions
{
/// <summary>
/// Extension methods for the <see cref="Socket"/> <see langword="class"/>.
/// </summary>
static class SocketExtensions
{
/// <summary>
/// Attempt to exclusively bind to a given <paramref name="port"/>.
/// </summary>
/// <param name="port">The port number to bind to.</param>
public static void BindTest(ushort port)
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
socket.Bind(new IPEndPoint(IPAddress.Any, port));
}
}
}
@@ -36,7 +36,8 @@ namespace Tgstation.Server.Tests.Instance
}
if (expectFailure ^ job.ExceptionDetails != null)
Assert.Fail(job.ExceptionDetails ?? $"Expected job \"{job.Id}\" \"{job.Description}\" to fail but it didn't");
Assert.Fail(job.ExceptionDetails
?? $"Expected job \"{job.Id}\" \"{job.Description}\" to fail {(expectedCode.HasValue ? $"with ErrorCode \"{expectedCode.Value}\" " : String.Empty)}but it didn't");
if (expectedCode.HasValue)
Assert.AreEqual(expectedCode.Value, job.ErrorCode, job.ExceptionDetails);
@@ -141,6 +141,8 @@ namespace Tgstation.Server.Tests.Instance
Job startJob;
using (var blockSocket = new Socket(SocketType.Stream, ProtocolType.Tcp))
{
blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
blockSocket.Bind(new IPEndPoint(IPAddress.Any, 1337));
startJob = await instanceClient.DreamDaemon.Start(cancellationToken).ConfigureAwait(false);
@@ -200,6 +200,8 @@ namespace Tgstation.Server.Tests
// http bind test https://github.com/tgstation/tgstation-server/issues/1065
using (var blockingSocket = new Socket(SocketType.Stream, ProtocolType.Tcp))
{
blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
blockingSocket.Bind(new IPEndPoint(IPAddress.Any, server.Url.Port));
try
{