Skip to content

Conversation

@Jovis7
Copy link
Contributor

@Jovis7 Jovis7 commented Jun 25, 2025

This PR adds/fixes a few things that makes unbounded ready for singbox integration.

New:

  • support a new client type "singbox-inbound", which reads data from WebRTC datachannel from the "desktop" client, and bridges the data to a net.PacketConn (BroflakeConn). This client type does not connect to the egress server.
  • allow setting custom HTTP client and UDP PacketConn, so that unbounded can use custom network for netstate and WebRTC peer connection establishment
  • enable QUIC datagram so in singbox integration, UDP can go through QUIC datagram

Fixes

  • fix a possible concurrency panic in netstated
  • fix/enhance close sequence for BroflakeConn, QUIC listener, and clientcore

API change:

  • NewListenerFromPacketConn() can have a custom datagram handler for handling QUIC datagram
  • DialAndMaintainQUICConnection() will now optionally expose underlying quic.Connection
  • add BroflakeEngine.Close() to properly exit the engine

This is part of #2035.

@Jovis7 Jovis7 requested a review from Copilot June 25, 2025 06:44
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 adds support for a new “singbox-inbound” client type, enables custom HTTP/UDP clients for both netstate and WebRTC, and turns on QUIC datagram support for singbox integration.

  • Introduce singbox-inbound mode bridging WebRTC datachannels to a net.PacketConn
  • Allow injecting custom *http.Client and net.PacketConn into netstate and WebRTC layers
  • Enable QUIC datagrams and add a datagram handler to the QUIC listener

Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
netstate/d/netstated.go Extracted vertex edge update into updateVertexEdge with proper locking
netstate/client/client.go Extended Exec to take an *http.Client parameter
go.mod Upgraded Pion libraries and removed duplicate ICE dependency
egress/egresslib.go Added datagramHandler to proxyListener and updated listener teardown
common/network.go Turned on EnableDatagrams in the default QUIC config
cmd/proxy.go Updated DialAndMaintainQUICConnection invocation to pass a channel
clientcore/webrtc.go Added createPeerConnection to wrap custom net.PacketConn
clientcore/user.go Refactored BroflakeConn, its methods, and added user stream constructors
clientcore/ui.go Changed UpstreamUIHandler signature to accept *http.Client
clientcore/settings.go Exposed HttpClient and UDPConn in options
clientcore/quic.go Updated DialAndMaintainQUICConnection to optionally output the quic.Connection
clientcore/producer.go Added ctx.Done() checks in producer FSM states
clientcore/consumer.go Added ctx.Done() checks in consumer FSM states
clientcore/broflake.go Added singbox-inbound case, HTTP client injection, and Close() API
Comments suppressed due to low confidence (2)

clientcore/user.go:125

  • Missing import: uuid.NewString() requires importing "github.com/google/uuid".
		localAddr:          common.DebugAddr(uuid.NewString()),

clientcore/user.go:126

  • Missing import: uuid.NewString() requires importing "github.com/google/uuid".
		remoteAddr:         common.DebugAddr(uuid.NewString()),

Comment on lines 121 to 122
bfconn := BroflakeConn{
PacketConn: &net.UDPConn{},
Copy link

Copilot AI Jun 25, 2025

Choose a reason for hiding this comment

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

Using &net.UDPConn{} creates an uninitialized UDPConn which will panic on use; consider using net.ListenUDP, passing nil, or injecting a mock implementation.

Suggested change
bfconn := BroflakeConn{
PacketConn: &net.UDPConn{},
listenAddr, err := net.ResolveUDPAddr("udp", ":0")
if err != nil {
panic(fmt.Sprintf("Failed to resolve UDP address: %v", err))
}
packetConn, err := net.ListenUDP("udp", listenAddr)
if err != nil {
panic(fmt.Sprintf("Failed to initialize UDP connection: %v", err))
}
bfconn := BroflakeConn{
PacketConn: packetConn,

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are not using BroflakeConn.PacketConn directly at all so this should be safe. That said we should probably just not embed PacketConn and just implement net.PacketConn interface.

if httpClient == nil {
httpClient = &http.Client{}
}
res, err := httpClient.Post(netstated, "application/json; charset=UTF-8", bytes.NewBuffer(serialized))
Copy link

Copilot AI Jun 25, 2025

Choose a reason for hiding this comment

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

The Exec helper doesn’t check res.StatusCode and silently treats all responses as success; consider returning an error on non-2xx status codes.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this makes sense but I would ignore this for now as this is from the original code.

Jovis7 added 13 commits June 26, 2025 21:34
This new client type is only used in radiance/sing-box-extensions as an
inbound protocol. It currently can only support CTable/PTable size == 1.
It reads data from WebRTC data tunnel from the "desktop" client, and
bridges the data to a net.PacketConn (BroflakeConn). It does not connect
to the egress server at all.
If we have a custom UDP net.PacketConn in WebRTCOptions, we can force
pion to use this PacketConn to communicate.
We can use our custom http client to send requests to netstate.
In NewListenerFromPacketConn() add a custom datagram handler which will
be called in a separate goroutine whenever the QUIC listener accepts a
new connection.
Add a public API so it can be used in sing-box to close the engine
properly.
…tion

The function now takes a channel which it will then expose the
successfully dialed quic.Connection.
Instead of embedding net.PacketConn in BroflakeConn, implement
net.PacketConn so we have full control.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants