[x] I searched existing issues before opening this one
Expected behavior
When connecting to a host on a port behind a firewall using HTTPClient in a Docker Linux container via .NET (eg. http://google.com:8089), the request should time out and raise the following exception:
An unhandled exception of type 'System.Net.Http.HttpRequestException' occurred in System.Private.CoreLib.dll
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
Actual behavior
An unhandled exception of type 'System.Net.Http.HttpRequestException' occurred in System.Private.CoreLib.dll: 'Cannot assign requested address'
Stack trace:
> at System.Net.Http.ConnectHelper.<ConnectAsync>d__1.MoveNext()
> at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
> at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
> at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
> at System.Threading.Tasks.ValueTask`1.get_Result()
> at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
Since Docker sits between the Linux kernel and the connect() call, the assumption is that the execution flow is something like this:
1) you attempt to make a request with C#'s HTTPClient
2) it calls the UNIX socket function connect()
3) the Linux kernel handles the connection
4) if the request takes too long to execute, it's cancelled by the kernel
5) Docker sees the kernel failed the connect() call
Therefore, Docker returns an error that it couldn't assign an address because it thinks the kernel refused an address:port assignment.
Setting the HTTPClient timeout to lower than the kernel limit to something like TimeSpan.FromSeconds(15) correctly raises a TaskCanceledException and not "cannot assign requested address".
Note: This issue does not exist when using Windows Containers. In addition, it does not occur when using barebones C to execute the same network request in a Linux container. It seems to be an issue with Docker and .NET.
Steps to reproduce the behavior
.Net Core Console application:
class Program
{
static async Task Main(string[] args)
{
var client = new HttpClient();
var result = await client.GetAsync("http://google.com:8089");
}
}
Auto-Generated Dockerfile in Visual Studio:
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["ConsoleApp1/ConsoleApp1.csproj", "ConsoleApp1/"]
RUN dotnet restore "ConsoleApp1/ConsoleApp1.csproj"
COPY . .
WORKDIR "/src/ConsoleApp1"
RUN dotnet build "ConsoleApp1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ConsoleApp1.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ConsoleApp1.dll"]
Output of docker version:
Client: Docker Engine - Community
Version: 19.03.12
API version: 1.40
Go version: go1.13.10
Git commit: 48a66213fe
Built: Mon Jun 22 15:43:18 2020
OS/Arch: windows/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.12
API version: 1.40 (minimum version 1.12)
Go version: go1.13.10
Git commit: 48a66213fe
Built: Mon Jun 22 15:49:27 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.2.13
GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc:
Version: 1.0.0-rc10
GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
docker-init:
Version: 0.18.0
GitCommit: fec3683
Expected behavior
When connecting to a host on a port behind a firewall using HTTPClient in a Docker Linux container via .NET (eg. http://google.com:8089), the request should time out and raise the following exception:
Actual behavior
Since Docker sits between the Linux kernel and the connect() call, the assumption is that the execution flow is something like this:
1) you attempt to make a request with C#'s HTTPClient 2) it calls the UNIX socket function connect() 3) the Linux kernel handles the connection 4) if the request takes too long to execute, it's cancelled by the kernel 5) Docker sees the kernel failed the connect() call
Therefore, Docker returns an error that it couldn't assign an address because it thinks the kernel refused an address:port assignment.
Setting the HTTPClient timeout to lower than the kernel limit to something like TimeSpan.FromSeconds(15) correctly raises a TaskCanceledException and not "cannot assign requested address".
Note: This issue does not exist when using Windows Containers. In addition, it does not occur when using barebones C to execute the same network request in a Linux container. It seems to be an issue with Docker and .NET.
Steps to reproduce the behavior
.Net Core Console application:
Auto-Generated Dockerfile in Visual Studio:
Output of
docker version
:Output of
docker info
: