Skip to content

feat: add UDP in HTTP#10

Open
imgk wants to merge 6 commits intoklzgrad:naivefrom
imgk:udpinhttp
Open

feat: add UDP in HTTP#10
imgk wants to merge 6 commits intoklzgrad:naivefrom
imgk:udpinhttp

Conversation

@imgk
Copy link

@imgk imgk commented Feb 13, 2025

1. What does this change do, exactly?

Add UDP in HTTP support

2. Please link to the relevant issues.

klzgrad/naiveproxy#617

3. Which documentation changes (if any) need to be made because of this PR?

4. Checklist

  • I have written tests and verified that they fail without my change
  • I have squashed any insignificant commits
  • This change has comments for package types, values, functions, and non-obvious lines of code

@imgk imgk force-pushed the udpinhttp branch 2 times, most recently from 4d46ff7 to 02e512b Compare February 14, 2025 11:51
forwardproxy.go Outdated
h.udpProxyServer = &udpProxyServer{}
// parse http2/http3 uri template
if h.URITemplate == "" {
h.uriTemplate = uritemplate.MustNew("https://{host}/.well-known/masque/udp/{target_host}/{target_port}/")
Copy link
Owner

Choose a reason for hiding this comment

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

Is it necessary to introduce a library for this? Can you use simpler functions?

Copy link
Author

Choose a reason for hiding this comment

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

Removed

return Request(net.JoinHostPort(targetHost, strconv.Itoa(targetPort))), nil
}

func (h *Handler) checkACL(hostPort string) (bool, error) {
Copy link
Owner

@klzgrad klzgrad Feb 14, 2025

Choose a reason for hiding this comment

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

Seems to have duplicated forwardproxy.go.

I think much of this should be embedded along side the logic of tcp/http.

Copy link
Author

Choose a reason for hiding this comment

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

Done

@imgk imgk force-pushed the udpinhttp branch 13 times, most recently from 0aa5ca1 to 95737ac Compare February 18, 2025 12:52
@imgk imgk force-pushed the udpinhttp branch 2 times, most recently from 30eb2ff to 6b9937e Compare February 28, 2025 13:26
@imgk imgk force-pushed the udpinhttp branch 6 times, most recently from e7abc00 to c3819b0 Compare March 5, 2025 11:28
@naiba
Copy link

naiba commented Apr 2, 2025

any update?

@klzgrad
Copy link
Owner

klzgrad commented Apr 4, 2025

Review comments are not addressed yet.

@naiba
Copy link

naiba commented Apr 19, 2025

How is it now? This PR looks very interesting, does the naiveproxy client need to be modified?

@klzgrad
Copy link
Owner

klzgrad commented Apr 20, 2025

I asked for not duplicating forwardproxy.go into a udp version, and there was no answer for that.

@imgk
Copy link
Author

imgk commented Apr 22, 2025

I asked for not duplicating forwardproxy.go into a udp version, and there was no answer for that.

Hi, I misunderstood your request there. I believe this is done now.

@naiba
Copy link

naiba commented May 18, 2025

Hi @imgk, Does this feature require any changes to the client? Or does it already support the client that complies with the RFC definition?

@imgk
Copy link
Author

imgk commented May 18, 2025

Hi @imgk, Does this feature require any changes to the client? Or does it already support the client that complies with the RFC definition?

Hi, this modified forwardproxy should be compatible with any client which supports RFC 9298. However, this module is not well tested yet. The function is not guaranteed. Feedbacks are welcomed.

PrintNow and others added 3 commits June 17, 2025 22:09
Fixes caddyserver#170

- Update `dial_timeout` example to use duration unit (30s)
- Change parameter type from [integer] to [Duration] to match Go type
- Update description to clarify duration unit requirement

This change makes the documentation more accurate and consistent
with Go's time.Duration type usage.
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.0 to 1.2.4.
- [Release notes](https://github.com/golang/glog/releases)
- [Commits](golang/glog@v1.2.0...v1.2.4)

---
updated-dependencies:
- dependency-name: github.com/golang/glog
  dependency-version: 1.2.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](actions/setup-go@v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@aaravrav
Copy link

How is the status of the PR now?

Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.44.0 to 0.49.1.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Commits](quic-go/quic-go@v0.44.0...v0.49.1)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-version: 0.49.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Copy link

@naiba naiba left a comment

Choose a reason for hiding this comment

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

Code Review (AI-assisted review by Claude)

Thanks for the implementation! Reviewed against RFC 9298/9297 and the existing codebase. A few issues found:

Blocking

1. HTTP/2 path uses Hijack() — breaks HTTP/2 multiplexing

case 2:
    conn, _, err := rc.Hijack()

Hijack() drops down to the raw TCP connection, bypassing HTTP/2 framing entirely. This destroys all other streams on the same connection. The existing TCP CONNECT handler uses dualStream() for HTTP/2 (reading from r.Body + writing to ResponseWriter). The UDP handler should follow the same pattern.

2. ReceiveBuffer — remote crash via malicious Length

data.Length, err = quicvarint.Read(rr)  // up to 2^62-1
bb := b[:data.Length]                    // panic if Length > len(b)

A malicious client sending a large Length value will panic the server. Needs bounds check:

if data.Length > uint64(len(b)) {
    return fmt.Errorf("datagram too large: %d > %d", data.Length, len(b))
}

3. HTTP/1.1 Upgrade header typo

w.Header().Set("Upgrade:", RequestProtocol)  // extra colon in header name

Should be "Upgrade", not "Upgrade:".

Should Fix

4. ACL logic duplicated — The anonymous function in tryUDPoverHTTP duplicates dialContextCheckACL. Should extract a shared helper to avoid divergence.

5. target_port range not validatedstrconv.Atoi succeeds for 0, negative, or >65535 values. RFC 9298 requires 1-65535.

6. ReadPacket lacks bounds checking — Parsing bb[1], bb[2]...bb[19] without checking len(bb) first. Short payloads will panic.

7. Non-standard extensions not documentedCompressionAssignValue (0x1C0FE323) / CompressionCloseValue (0x1C0FE324) don't match current draft-ietf-masque-connect-udp-listen values (0x11/0x12/0x13), and COMPRESSION_ACK is missing. Connect-UDP-Bind is also draft-only. These should be clearly documented as experimental.

8. HandlePacketBind returns error at runtime — HTTP/3 + bind mode should be rejected at request parsing time with a proper HTTP status code, not deep in the handler.

Minor

  • All types (Payload, Datagram, BytePayload, etc.) and vars (CapsuleProtocolHeaderValue, etc.) are exported but are internal implementation details — should be unexported.
  • HandlePacket relies on b[0] being zero-initialized for Context ID 0 — should explicitly set b[0] = 0.
  • RequestMatcher uses (.+) which matches across path segments — consider ([^/]+).

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.

5 participants