1
0
Fork 0
mirror of https://github.com/maziggy/bambuddy.git synced 2026-05-09 08:25:54 +02:00

[GH-ISSUE #623] FTP proxy: OrcaSlicer data channel TLS fixes for X1C #405

Closed
opened 2026-05-07 00:09:42 +02:00 by BreizhHardware · 8 comments

Originally created by @begna112 on GitHub (Mar 5, 2026).
Original GitHub issue: https://github.com/maziggy/bambuddy/issues/623

Originally assigned to: @maziggy on GitHub.

Following up on #620 (cipher fix, now merged). After applying the cipher fix, I ran into several more issues getting the virtual printer proxy to work with OrcaSlicer and my X1C. I'm not sure if my setup is unusual or if others are hitting the same things — my network may be different, or OrcaSlicer might behave differently than Bambu Studio in ways that don't come up for everyone. But in case it's helpful, here's what I had to do to get FTP uploads working end-to-end through the proxy.

All changes are in backend/app/services/virtual_printer/tcp_proxy.py. Tested with BambuDdy 0.2.2b2, OrcaSlicer 2.3.1 (as well as 2.3.2-rc and nightly)m Bambu X1C, proxy mode.


1. FTP data channel needs TLS on the slicer side when PROT P is active

The code currently starts the slicer-side data listener as cleartext even after PROT P, with a comment that Bambu Studio doesn't do TLS on data connections. OrcaSlicer does expect TLS on the data channel after PROT P, so the upload fails with an SSL handshake error.

Fix: Pass the server SSL context to asyncio.start_server when use_tls is True:

slicer_data_ssl = self._server_ssl_context if use_tls else None
server = await asyncio.start_server(handle_data, "0.0.0.0", port, ssl=slicer_data_ssl)

This alone wasn't enough though — see fix 2 below.

2. FTP data channel TLS needs session reuse + eager connect

Even with slicer-side TLS, the printer-side data TLS handshake still fails. Two issues:

Session reuse: The printer's vsFTPd requires TLS session reuse on data connections — the data channel must present the same TLS session as the control channel. A fresh handshake is rejected.

Deadlock: The proxy had a deadlock where the slicer waits for 150 Opening before connecting to the data port, but the printer waits for a data connection before sending 150.

Fix: Three parts:

  1. Capture the TLS session from the control connection:

    ctrl_ssl_obj = printer_writer.get_extra_info("ssl_object")
    ctrl_tls_session = ctrl_ssl_obj.session if ctrl_ssl_obj else None
    session_state["_ctrl_tls_session"] = ctrl_tls_session
    
  2. Eagerly connect TCP to the printer data port before the slicer connects, breaking the deadlock:

    printer_reader, printer_writer = await asyncio.open_connection(printer_ip, printer_port)
    
  3. Defer the TLS upgrade until after the slicer connects (STOR/150 have been exchanged by then). Inject the control session via a one-shot wrap_bio monkey-patch:

    def _wrap_bio_once(incoming, outgoing, server_side=False, server_hostname=None):
        ssl_obj = _orig_wrap_bio(incoming, outgoing, server_side=server_side, server_hostname=server_hostname)
        ssl_obj.session = ctrl_session
        return ssl_obj
    _ctx.wrap_bio = _wrap_bio_once
    await printer_writer.start_tls(_ctx)
    

The monkey-patch is ugly but necessary — Python's asyncio.StreamWriter.start_tls() doesn't expose a way to set the session before the handshake, and wrap_bio is the internal hook where the SSL object is created.

3. PROT P/C needs to be forwarded to the printer

The proxy was consuming PROT P/PROT C commands without forwarding them. My printer requires PROT P to be sent or it returns 522 Data connections must be encrypted.

Fix: Forward PROT P/PROT C to the printer while still tracking the state locally for the proxy's own TLS decisions.

4. EPSV→PASV rewrite should be removed

The code rewrites EPSV to PASV, but the printer supports EPSV natively and _maybe_rewrite_pasv already handles both 227 (PASV) and 229 (EPSV) responses. The rewrite was unnecessary and removing it simplified things.


Happy to provide the full diff if that's useful. With all four changes applied, the complete flow works: MQTT, Bind-TLS, FTP control, and FTP data uploads all go through the proxy successfully. Printer control and print sending both work with OrcaSlicer.

Originally created by @begna112 on GitHub (Mar 5, 2026). Original GitHub issue: https://github.com/maziggy/bambuddy/issues/623 Originally assigned to: @maziggy on GitHub. Following up on #620 (cipher fix, now merged). After applying the cipher fix, I ran into several more issues getting the virtual printer proxy to work with OrcaSlicer and my X1C. I'm not sure if my setup is unusual or if others are hitting the same things — my network may be different, or OrcaSlicer might behave differently than Bambu Studio in ways that don't come up for everyone. But in case it's helpful, here's what I had to do to get FTP uploads working end-to-end through the proxy. All changes are in `backend/app/services/virtual_printer/tcp_proxy.py`. Tested with BambuDdy 0.2.2b2, OrcaSlicer 2.3.1 (as well as 2.3.2-rc and nightly)m Bambu X1C, proxy mode. --- ## 1. FTP data channel needs TLS on the slicer side when PROT P is active The code currently starts the slicer-side data listener as cleartext even after `PROT P`, with a comment that Bambu Studio doesn't do TLS on data connections. OrcaSlicer *does* expect TLS on the data channel after `PROT P`, so the upload fails with an SSL handshake error. **Fix:** Pass the server SSL context to `asyncio.start_server` when `use_tls` is True: ```python slicer_data_ssl = self._server_ssl_context if use_tls else None server = await asyncio.start_server(handle_data, "0.0.0.0", port, ssl=slicer_data_ssl) ``` This alone wasn't enough though — see fix 2 below. ## 2. FTP data channel TLS needs session reuse + eager connect Even with slicer-side TLS, the printer-side data TLS handshake still fails. Two issues: **Session reuse:** The printer's vsFTPd requires TLS session reuse on data connections — the data channel must present the same TLS session as the control channel. A fresh handshake is rejected. **Deadlock:** The proxy had a deadlock where the slicer waits for `150 Opening` before connecting to the data port, but the printer waits for a data connection before sending `150`. **Fix:** Three parts: 1. Capture the TLS session from the control connection: ```python ctrl_ssl_obj = printer_writer.get_extra_info("ssl_object") ctrl_tls_session = ctrl_ssl_obj.session if ctrl_ssl_obj else None session_state["_ctrl_tls_session"] = ctrl_tls_session ``` 2. Eagerly connect TCP to the printer data port *before* the slicer connects, breaking the deadlock: ```python printer_reader, printer_writer = await asyncio.open_connection(printer_ip, printer_port) ``` 3. Defer the TLS upgrade until after the slicer connects (STOR/150 have been exchanged by then). Inject the control session via a one-shot `wrap_bio` monkey-patch: ```python def _wrap_bio_once(incoming, outgoing, server_side=False, server_hostname=None): ssl_obj = _orig_wrap_bio(incoming, outgoing, server_side=server_side, server_hostname=server_hostname) ssl_obj.session = ctrl_session return ssl_obj _ctx.wrap_bio = _wrap_bio_once await printer_writer.start_tls(_ctx) ``` The monkey-patch is ugly but necessary — Python's `asyncio.StreamWriter.start_tls()` doesn't expose a way to set the session before the handshake, and `wrap_bio` is the internal hook where the SSL object is created. ## 3. PROT P/C needs to be forwarded to the printer The proxy was consuming `PROT P`/`PROT C` commands without forwarding them. My printer requires `PROT P` to be sent or it returns `522 Data connections must be encrypted`. **Fix:** Forward `PROT P`/`PROT C` to the printer while still tracking the state locally for the proxy's own TLS decisions. ## 4. EPSV→PASV rewrite should be removed The code rewrites `EPSV` to `PASV`, but the printer supports `EPSV` natively and `_maybe_rewrite_pasv` already handles both `227` (PASV) and `229` (EPSV) responses. The rewrite was unnecessary and removing it simplified things. --- Happy to provide the full diff if that's useful. With all four changes applied, the complete flow works: MQTT, Bind-TLS, FTP control, and FTP data uploads all go through the proxy successfully. Printer control and print sending both work with OrcaSlicer.
BreizhHardware 2026-05-07 00:09:42 +02:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@maziggy commented on GitHub (Mar 5, 2026):

Do you have the chance to also test with BambuStudio? That would help a lot!

<!-- gh-comment-id:4004628469 --> @maziggy commented on GitHub (Mar 5, 2026): Do you have the chance to also test with BambuStudio? That would help a lot!
Author
Owner

@begna112 commented on GitHub (Mar 6, 2026):

I can test later tonight

<!-- gh-comment-id:4010103547 --> @begna112 commented on GitHub (Mar 6, 2026): I can test later tonight
Author
Owner

@begna112 commented on GitHub (Mar 6, 2026):

Unfortunately, I'm running into two firmware-related issues that are preventing me from testing:

  1. Unable to connect to the printer — this appears to be tied to the latest firmware and network plugin versions, as reported in
    https://github.com/OrcaSlicer/OrcaSlicer/issues/12537
  2. Print job nozzle type errors — another firmware regression where nozzle types aren't handled correctly, tracked in
    https://github.com/OrcaSlicer/OrcaSlicer/issues/11898
    • able to get by this one by ignoring the popup and clicking the play button on the print.

I don't think either is caused by Bambuddy but It's possible that you may need to account for them at some point, not sure. Haven't looked terribly deep into the code, just troubleshooting exactly what I needed to.

I may need to roll back the firmware to resolve these. Until then, I won't be able to test printing with Bambu Studio.

<!-- gh-comment-id:4011290625 --> @begna112 commented on GitHub (Mar 6, 2026): Unfortunately, I'm running into two firmware-related issues that are preventing me from testing: 1. Unable to connect to the printer — this appears to be tied to the latest firmware and network plugin versions, as reported in https://github.com/OrcaSlicer/OrcaSlicer/issues/12537 2. Print job nozzle type errors — another firmware regression where nozzle types aren't handled correctly, tracked in https://github.com/OrcaSlicer/OrcaSlicer/issues/11898 * able to get by this one by ignoring the popup and clicking the play button on the print. I don't think either is caused by Bambuddy but It's possible that you may need to account for them at some point, not sure. Haven't looked terribly deep into the code, just troubleshooting exactly what I needed to. I may need to roll back the firmware to resolve these. Until then, I won't be able to test printing with Bambu Studio.
Author
Owner

@maziggy commented on GitHub (Mar 6, 2026):

Anyway, thanks!

<!-- gh-comment-id:4011520127 --> @maziggy commented on GitHub (Mar 6, 2026): Anyway, thanks!
Author
Owner

@begna112 commented on GitHub (Mar 6, 2026):

Were any changes made to address the original issue?

I still think the core issue is there, but I can't confirm if on bambu studio.

<!-- gh-comment-id:4011528099 --> @begna112 commented on GitHub (Mar 6, 2026): Were any changes made to address the original issue? I still think the core issue is there, but I can't confirm if on bambu studio.
Author
Owner

@maziggy commented on GitHub (Mar 6, 2026):

Yes, added your fix from https://github.com/maziggy/bambuddy/issues/620

<!-- gh-comment-id:4011539867 --> @maziggy commented on GitHub (Mar 6, 2026): Yes, added your fix from https://github.com/maziggy/bambuddy/issues/620
Author
Owner

@begna112 commented on GitHub (Mar 6, 2026):

Just to be clear, this is a totally different issue than #620.

The first was to be able to auth to the printer, this is to be able to send print jobs to it.

<!-- gh-comment-id:4011554558 --> @begna112 commented on GitHub (Mar 6, 2026): Just to be clear, this is a totally different issue than #620. The first was to be able to auth to the printer, this is to be able to send print jobs to it.
Author
Owner

@maziggy commented on GitHub (Mar 6, 2026):

Yes, but i first need to check that in detail.

<!-- gh-comment-id:4011575158 --> @maziggy commented on GitHub (Mar 6, 2026): Yes, but i first need to check that in detail.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/bambuddy-maziggy-1#405
No description provided.