Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Clash API does not honor IPv4-only wildcard binding for `0.0.0.0`

Open Beginner friendly
#4,642 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
90/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
go
Domain
networking

Research direction

Start in experimental/clashapi/server.go and compare the listener setup with the inbound TCP listener behavior described in the issue. Reuse M.NetworkFromNetAddr so a 0.0.0.0 address selects tcp4; verify the Clash API binds IPv4-only for that address and preserves existing behavior for other addresses.

Written by the indexing model from the issue text.

Description

Operating system

Linux

System version

Alpine 3.24

Installation type

Original sing-box Command Line

If you are using a graphical client, please provide the version of the client.

No response

Version
sing-box version 1.13.21

Environment: go1.27.0 linux/amd64
Tags: with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,badlinkname,tfogo_checklinkname0
CGO: enabled
Description

Setting experimental.clash_api.external_controller to 0.0.0.0:1090 creates a listener reported as [::]:1090, instead of an IPv4-only listener.

This differs from the behavior of inbound listeners. Inbound listeners use M.NetworkFromNetAddr to select tcp4 for 0.0.0.0, while the Clash API always passes "tcp" to net.Listen.

On systems supporting IPv4-mapped IPv6 sockets, Go can interpret "tcp" with an IPv4 wildcard address as a dual-stack listener. Consequently, the Clash API may also accept IPv6 connections despite being configured with 0.0.0.0.

Expected behavior: the Clash API should handle wildcard addresses consistently with inbound listeners, using tcp4 when the configured address is 0.0.0.0.

Reproduction
  1. Save the following complete configuration as config.json:
{
  "log": {
    "level": "info"
  },
  "experimental": {
    "clash_api": {
      "external_controller": "0.0.0.0:1090"
    }
  }
}
  1. Run:
sing-box run -c config.json
  1. Observe that the Clash API reports [::]:1090, although the configured address is 0.0.0.0:1090.

This reproduction requires no remote server, TUN, or graphical client.

Proposed solution

Reuse M.NetworkFromNetAddr, as the inbound TCP listener already does.

In experimental/clashapi/server.go, add:

M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"

Replace:

listener, err = net.Listen("tcp", s.httpServer.Addr)

with:

listener, err = net.Listen(M.NetworkFromNetAddr(N.NetworkTCP, M.ParseSocksaddr(s.httpServer.Addr).Addr), s.httpServer.Addr)

This selects tcp4 for 0.0.0.0, while preserving the existing "tcp" behavior for other addresses, including ::.

The change has been cross-compiled successfully.

Logs
INFO[0000] network: updated default interface eth0, index 2
INFO[0000] clash-api: restful api listening at [::]:1090
INFO[0000] sing-box started (0.02s)
Supporter
Integrity requirements
  • I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
  • I confirm that I have provided the server and client configuration files and process that can be reproduced locally, instead of a complicated client configuration file that has been stripped of sensitive data.
  • I confirm that I have provided the simplest configuration that can be used to reproduce the error I reported, instead of depending on remote servers, TUN, graphical interface clients, or other closed-source software.
  • I confirm that I have provided the complete configuration files and logs, rather than just providing parts I think are useful out of confidence in my own intelligence.
Dominant language
Go
Stars
38.9k
Forks
4.7k
PR merge metrics
No merged PRs in 30d

Getting set up

  • Ships a Dockerfile or Docker Compose file
  • No pull request template
  • No contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from SagerNet/sing-box

All issues in SagerNet/sing-box

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.