Skip to content

Conversation

@sabbour
Copy link

@sabbour sabbour commented Jul 1, 2025

When running az network bastion tunnel inside WSL2, the command hangs for 2 minutes and 15 seconds before opening the tunnel.

Attached is the strace log: bastion-tunnel-strace.log

Upon investigation using strace, the code is attempting to connect to 0.0.0.0:{port} to validate if the port is in use or not, which is an invalid destination address. 0.0.0.0 is not a routable IP address representing "any address" or "no specific address" and cannot be used as a connection target. This is the documented behavior in the Python socket library: https://docs.python.org/3/library/socket.html

A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in internet domain notation like 'daring.cwi.nl' or an IPv4 address like '100.50.200.5', and port is an integer. For IPv4 addresses, two special forms are accepted instead of a host address: '' represents INADDR_ANY, which is used to bind to all interfaces.

See examples executing the connect_ex function directly:

strace -f -tt python3 -c "import socket; import time; s=socket.socket(); s.settimeout(5); t=time.time(); r=s.connect_ex(('', 44444)); print(f'Result: {r}, Time: {time.time()-t:.2f}s')"

Output:

00:03:27.779861 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3 00:03:27.780376 ioctl(3, FIONBIO, [1]) = 0 00:03:27.780642 connect(3, {sa_family=AF_INET, sin_port=htons(44444), sin_addr=inet_addr("0.0.0.0")}, 16) = -1 EINPROGRESS (Operation now in progress) 00:03:27.781179 poll([{fd=3, events=POLLOUT|POLLERR}], 1, 5000) = 0 (Timeout) 00:03:32.787945 write(1, "Result: 11, Time: 5.01s\n", 24Result: 11, Time: 5.01s ) = 24 00:03:32.788904 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7db0bc045330}, {sa_handler=0x6e7170, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7db0bc045330}, 8) = 0 00:03:32.792342 getsockname(3, {sa_family=AF_INET, sin_port=htons(47226), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0

vs

strace -f -tt python3 -c "import socket; import time; s=socket.socket(); s.settimeout(5); t=time.time(); r=s.connect_ex(('127.0.0.1', 44444)); print(f'Result: {r}, Time: {time.time()-t:.2f}s')"

Output:

00:03:32.793450 getpeername(3, 0x7ffde75bdb70, [16]) = -1 ENOTCONN (Transport endpoint is not connected) 00:03:32.794071 close(3) = 0 00:03:32.800493 munmap(0x7db0bc531000, 16384) = 0 00:03:32.801438 exit_group(0) = ? 00:03:32.803541 +++ exited with 0 +++

This checklist is used to make sure that common guidelines for a pull request are followed.

Related command

az network bastion tunnel

General Guidelines

  • Have you run azdev style <YOUR_EXT> locally? (pip install azdev required)
  • Have you run python scripts/ci/test_index.py -q locally? (pip install wheel==0.30.0 required)
  • My extension version conforms to the Extension version schema

For new extensions:

About Extension Publish

There is a pipeline to automatically build, upload and publish extension wheels.
Once your pull request is merged into main branch, a new pull request will be created to update src/index.json automatically.
You only need to update the version information in file setup.py and historical information in file HISTORY.rst in your PR but do not modify src/index.json.

When running az network bastion tunnel inside WSL2, the command hangs for ~60 seconds before opening the tunnel. This is caused by a port availability check using socket.connect_ex(('', port)), which resolves to 0.0.0.0 and causes a timeout in WSL.

See examples

```
strace -f -tt python3 -c "import socket; import time; s=socket.socket(); s.settimeout(5); t=time.time(); r=s.connect_ex(('', 44444)); print(f'Result: {r}, Time: {time.time()-t:.2f}s')"
```

Output:
```
00:03:27.779861 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3 00:03:27.780376 ioctl(3, FIONBIO, [1]) = 0 00:03:27.780642 connect(3, {sa_family=AF_INET, sin_port=htons(44444), sin_addr=inet_addr("0.0.0.0")}, 16) = -1 EINPROGRESS (Operation now in progress) 00:03:27.781179 poll([{fd=3, events=POLLOUT|POLLERR}], 1, 5000) = 0 (Timeout) 00:03:32.787945 write(1, "Result: 11, Time: 5.01s\n", 24Result: 11, Time: 5.01s ) = 24 00:03:32.788904 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7db0bc045330}, {sa_handler=0x6e7170, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7db0bc045330}, 8) = 0 00:03:32.792342 getsockname(3, {sa_family=AF_INET, sin_port=htons(47226), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
```
vs

```
strace -f -tt python3 -c "import socket; import time; s=socket.socket(); s.settimeout(5); t=time.time(); r=s.connect_ex(('127.0.0.1', 44444)); print(f'Result: {r}, Time: {time.time()-t:.2f}s')"
```

Output:
```
00:03:32.793450 getpeername(3, 0x7ffde75bdb70, [16]) = -1 ENOTCONN (Transport endpoint is not connected) 00:03:32.794071 close(3) = 0 00:03:32.800493 munmap(0x7db0bc531000, 16384) = 0 00:03:32.801438 exit_group(0) = ? 00:03:32.803541 +++ exited with 0 +++
```
Copilot AI review requested due to automatic review settings July 1, 2025 07:18
@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Jul 1, 2025

️✔️Azure CLI Extensions Breaking Change Test
️✔️Non Breaking Changes

@azure-client-tools-bot-prd
Copy link

Hi @sabbour,
Please write the description of changes which can be perceived by customers into HISTORY.rst.
If you want to release a new extension version, please update the version in setup.py as well.

@yonzhan
Copy link
Collaborator

yonzhan commented Jul 1, 2025

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link

github-actions bot commented Jul 1, 2025

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes the port availability check in the Bastion tunnel command by using the explicit local address instead of binding to all interfaces, which resolves a 60-second hang in WSL2.

  • Change socket.connect_ex to use self.local_addr rather than ''
  • Retains existing logging, but aligns connection attempt with the provided local address
Comments suppressed due to low confidence (1)

src/bastion/azext_bastion/tunnel.py:73

  • [nitpick] Add or update unit tests for is_port_open to cover cases with explicit local_addr, ensuring correct behavior on different environments (e.g., WSL2 vs. Linux).
            if sock.connect_ex((self.local_addr, self.local_port)) == 0:

@github-actions
Copy link

github-actions bot commented Jul 1, 2025

CodeGen Tools Feedback Collection

Thank you for using our CodeGen tool. We value your feedback, and we would like to know how we can improve our product. Please take a few minutes to fill our codegen survey

@github-actions
Copy link

github-actions bot commented Jul 1, 2025

The logic was inverted. `sock.connect_ex` returns 0 if the connection is successful, hence when the port is open.
@FumingZhang
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@FumingZhang
Copy link
Member

For the failed integration test, I think it's caused by dependency bump in official azure-cli (default API version has changed from 2024-01-01 to 2024-07-01). 2 ways to fix the issue

  • Simply replace 2024-01-01 with 2024-07-01 in file src/bastion/azext_bastion/tests/latest/recordings/test_bastion_host_crud.yaml
  • Re-run the test case (with latest version of azure-cli installed) in live mode and commit the new recording file
      raise AssertionError(ex)

E AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/bastion/azext_bastion/tests/latest/recordings/test_bastion_host_crud.yaml') in your current record mode ('once').
E No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/virtualNetworks/vnet-000002/subnets/subnet-000003?api-version=2024-07-01>) was found.
E Found 2 similar requests with 1 different matcher(s) :
E
E 1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/virtualNetworks/vnet-000002/subnets/subnet-000003?api-version=2024-01-01>)..)
E Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E Matchers failed :
E _custom_request_query_matcher - assertion failure :
E None
E
E 2 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/virtualNetworks/vnet-000002/subnets/subnet-000003?api-version=2024-01-01>)..)
E Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E Matchers failed :
E _custom_request_query_matcher - assertion failure :
E None

../azure-cli/src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError

https://dev.azure.com/azclitools/public/_build/results?buildId=259052&view=logs&j=155127ab-52f1-52e7-0e45-625d9d7884a4&t=4bb67950-ef03-52d4-44f5-d1a8cd56c919&l=492

@sabbour
Copy link
Author

sabbour commented Jul 3, 2025

@FumingZhang I've pushed the revert.

@FumingZhang
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@FumingZhang
Copy link
Member

Unfortunately, the integration test has failed again. I attempted to re-run it locally to regenerate the recording file, but that also failed. As a temporary workaround, you can manually update the existing recording file. Based on the error message, you may need to modify the following section

https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/bastionHosts/bastion-000006?api-version=2024-07-01

to

https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/bastionHosts/bastion-000006?api-version=2024-01-01

      raise AssertionError(ex)

E AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/bastion/azext_bastion/tests/latest/recordings/test_bastion_host_crud.yaml') in your current record mode ('once').
E No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/bastionHosts/bastion-000006?api-version=2024-01-01>) was found.
E Found 3 similar requests with 1 different matcher(s) :
E
E 1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_bastion_host_000001/providers/Microsoft.Network/bastionHosts/bastion-000006?api-version=2024-07-01>)..)
E Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E Matchers failed :
E _custom_request_query_matcher - assertion failure :
E None

https://dev.azure.com/azclitools/public/_build/results?buildId=259247&view=logs&j=155127ab-52f1-52e7-0e45-625d9d7884a4&t=4bb67950-ef03-52d4-44f5-d1a8cd56c919&l=503

@sabbour
Copy link
Author

sabbour commented Jul 4, 2025

Ok I will try to do that. Thank you.

Attempting to fix the test case
@sabbour
Copy link
Author

sabbour commented Jul 8, 2025

/azp run

@azure-pipelines
Copy link

Commenter does not have sufficient privileges for PR 8916 in repo Azure/azure-cli-extensions

@yonzhan
Copy link
Collaborator

yonzhan commented Jul 8, 2025

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@FumingZhang
Copy link
Member

replaced by #8952

@FumingZhang FumingZhang closed this Jul 9, 2025
@sabbour sabbour deleted the patch-1 branch July 9, 2025 05:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Auto-Assign Auto assign by bot Network

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants