Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] websockets dont add or pass custom headers #426

Open
si458 opened this issue Dec 11, 2024 · 12 comments
Open

[BUG] websockets dont add or pass custom headers #426

si458 opened this issue Dec 11, 2024 · 12 comments
Labels
bug Something isn't working

Comments

@si458
Copy link

si458 commented Dec 11, 2024

Describe the bug
websockets dont add or pass custom headers

To Reproduce
Steps to reproduce the behavior:

  1. run meshcentral
  2. proxy meshcentral
  3. inspect http headers for images, they show custom headers that you set or pass on original request
  4. inspect websocket headers, they DONT contain custom headers that you set or pass on original request

Expected behavior
websocket headers to include your original custom headers AND custom headers you set inside the web ui of zoraxy

Screenshots
If applicable, add screenshots to help explain your problem.

Browser (if it is a bug appears on the UI section of the system):

  • OS: [e.g. iOS] ALL
  • Browser [e.g. chrome, safari] ALL
  • Version [e.g. 22] ALL

Host Environment (please complete the following information):

  • Arch: [e.g. arm64] X64
  • Device: [e.g. Bananapi R2 PRO] VM
  • OS: [e.g. Armbian] Ubuntu
  • Version [e.g. 23.02 Bullseye ] 22.04
  • Docker Version (if you are running Zoraxy in docker): [e.g. 3.0.4] 3.1.4

Additional context
Add any other context about the problem here.

@tobychui
Copy link
Owner

@si458 Thanks for the investigation. Custom headers are currently only applied to HTTP requests (after all, it is a HTTP reverse proxy). I think I can add custom header supports into websocket as well, will take a look at the issue this weekend.

@si458
Copy link
Author

si458 commented Dec 11, 2024

@tobychui thank you! This will explain why our meshcentralrouter app and meshctrl.js app don't work, because we have to send custom headers on the websocket

Would it be possible to just PASS any existing headers then over the websocket, rather than messing around with adding custom headers?

Only issue we have is our custom header x-meshauth contains encoded credentials so it won't be static it will always change

@tobychui
Copy link
Owner

@si458 I need to have a check at the source code though, as I remember current implementation of websocket proxy only copies a limited sets of valid headers (for websocket) from the original request.

requestHeader := http.Header{}
if origin := req.Header.Get("Origin"); origin != "" {
requestHeader.Add("Origin", origin)
}
for _, prot := range req.Header[http.CanonicalHeaderKey("Sec-WebSocket-Protocol")] {
requestHeader.Add("Sec-WebSocket-Protocol", prot)
}
for _, cookie := range req.Header[http.CanonicalHeaderKey("Cookie")] {
requestHeader.Add("Cookie", cookie)
}
if req.Host != "" {
requestHeader.Set("Host", req.Host)
}

Though I understand that some projects might want to sneak in some custom headers like in this case x-meshauth. I think I will handle that case-by-case (or maybe just add a toggle switch for copying all header from src to dest (unsafe))

@si458
Copy link
Author

si458 commented Dec 11, 2024

@tobychui a toggle option would be perfectly fine by me!

One other tiny bug (might be related)
Is the user-agent is still showing as Go-http-client, and again we pass a custom user-agent header to identify application versions and custom applications but again it never sends it :(

tobychui added a commit that referenced this issue Dec 12, 2024
- Optimized types and definitions
- Moved shutdown seq to start.go file
- Moved authelia to auth/sso module
- Added different auth types support (wip)
- Updated proxy config structure
- Added v3.1.4 to v3.1.5 auto upgrade utilities
- Fixed #426
- Optimized status page UI
- Added options to disable uptime montior in config
@tobychui
Copy link
Owner

@si458 I think this should be fixed in the latest commit, but since I don't have anything to test it on, would you mind testing out the v3.1.5 build from the dev branch (build from source and run it on some kind of test bench) to see if it works?

@si458
Copy link
Author

si458 commented Dec 12, 2024

@tobychui do you have a dev docker image at all?
otherwise ill look at trying to building it and testing later 👍

@tobychui
Copy link
Owner

@si458 I guess no. I do not personally maintain the docker build of Zoraxy. You can ping and ask for help from @PassiveLemon if you really need a docker image.

@si458
Copy link
Author

si458 commented Dec 12, 2024

@tobychui no worries leave it with me will do a test for you!

@si458
Copy link
Author

si458 commented Dec 12, 2024

@tobychui ok i got it to build a docker image

  1. git clone https://github.com/tobychui/zoraxy
  2. cd zoraxy && git checkout v3.1.5
  3. cp -R src docker/
  4. cd docker && docker build -t myzoraxy .
  5. use image myzoraxy:latest

so the passing of my custom headers now work!
and also passing of the Custom headers you set in the web ui also work!
even the custom user-agent is being passed too, thank you!

i am seeing an error now tho in our software saying
GENERAL WSERR: RangeError: Invalid WebSocket frame: invalid status code 1006
but i think thats OUR software and not ur proxy as the websocket still opens and replys with data and we can talk over it!

@si458
Copy link
Author

si458 commented Dec 12, 2024

ok the error RangeError: Invalid WebSocket frame: invalid status code 1006 is actually coming from the websocket disconnects

however i tested nginx and traefik and these dont produce these errors?
its only zoraxy that generate these errors?
so im not sure how zoraxy handles the disconnects/closes of the websockets but it seems to think they arent standard

@tobychui
Copy link
Owner

@si458 This snippet shows how websocket close is handled in Zoraxy websocket proxy router.

errClient := make(chan error, 1)
errBackend := make(chan error, 1)
replicateWebsocketConn := func(dst, src *websocket.Conn, errc chan error) {
for {
msgType, msg, err := src.ReadMessage()
if err != nil {
m := websocket.FormatCloseMessage(websocket.CloseNormalClosure, fmt.Sprintf("%v", err))
if e, ok := err.(*websocket.CloseError); ok {
if e.Code != websocket.CloseNoStatusReceived {
m = websocket.FormatCloseMessage(e.Code, e.Text)
}
}
errc <- err
dst.WriteMessage(websocket.CloseMessage, m)
break
}
err = dst.WriteMessage(msgType, msg)
if err != nil {
errc <- err
break
}
}
}
go replicateWebsocketConn(connPub, connBackend, errClient)
go replicateWebsocketConn(connBackend, connPub, errBackend)
var message string
select {
case err = <-errClient:
message = "websocketproxy: Error when copying from backend to client: %v"
case err = <-errBackend:
message = "websocketproxy: Error when copying from client to backend: %v"
}
if e, ok := err.(*websocket.CloseError); !ok || e.Code == websocket.CloseAbnormalClosure {
if w.Verbal {
//Only print message on verbal mode
log.Printf(message, err)
}

If you are getting 1006 error, you can try enable the Verbal Mode by modifying this section in the top of websocketproxy.go and test it again. You should see the error from Zoraxy's STDOUT.

// Create a new websocket proxy
	wsprox := &WebsocketProxy{Backend: backend, Verbal: true, Options: options} <-- Set verbal to true here
	if options.CopyAllHeaders {
		wsprox.Director = DefaultDirector
	}

@si458
Copy link
Author

si458 commented Dec 12, 2024

@tobychui great! I will give that A try tomorrow !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants