Skip to content

Conversation

@alejandroliu
Copy link

@alejandroliu alejandroliu commented Dec 18, 2025

This implements proxy_command functionality in the same vein as OpenSSH's
ProxyCommand option. (See example).

It adds a new kwargs to the connect and the async_connect functions:

  • proxy_command : Connect to host using the given proxy command. (If not specified
    a direct connection is used.

Example proxy_command:

ssh -o StrictHostKeyChecking=accept-new -W %h:%p bastion

This allows librouteros to connect devices that are not directly connected to us. This
is a very common scenario where network devices are on a special secure network,
and/or can only be accessed from dedicated security devices. I personally use it for testing
where the test devices are in a virtual network, the proxy command allows librouteros
to tunnel the connection over a virtual interface.

There are two implementations, one uses low-level OS calls, and a generic one based on subprocess.Popen. The later is more portable and should run on Windows, but
I have not tested that.

@alejandroliu
Copy link
Author

Apologies for all the commits. I have never used this lint checker before, nor do I know how to create new unit tests for the new functionality.

@luqasz
Copy link
Owner

luqasz commented Dec 18, 2025

Hi.
Thx for interest and proposal. You can forward remote host 10.1.1.1 port 8728 into localhost with ssh -L 8728:10.1.1.1:8728 user@bastion. All you have to do next is connect via librouteros and point to localhost. No need for ssh -W magic.

@alejandroliu
Copy link
Author

Yes, I realise that using ssh -L is an option. Using the proxy command approach has the following advantages:

  • No need to manage local port mappings.
  • From API perspectively, it makes it look like the connection is managed directly by the
    librouteros connection functions, with all the connectivity being arranged within
    the library.
  • The API is fully self-contained, so connecting to the target host looks as if you
    are connecting directly with the bastion host configuration being isolated as
    a parameter to the connect function.
  • Works naturally with multiple hops (ProxyJump supports chaining).
  • It enhances security as no extra open ports on localhost; traffic is tunneled directly.
  • It is more flexible, as you could use different proxy commands (not just SSH), for example
    you could use netcat or socat to tunnel over http proxies or socks proxies.
    This abstracts the complexities of handling the proxy communications away from
    librouteros and keeps them in the proxy command itself.
  • I find it that for managing hosts via Ansible, the use of ProxyCommand feels more natural.

Of course this has some disadvantages:

  • the current implementation is posix specific. (I commented out the Windows
    compatible code because it did not pass the lint checker).
  • On Linux, if connections are opened and closed multiple times, this may lead to
    zombie processes or you may need to do signal.signal(signal.SIGCHLD,signal.SIG_IGN)
    to automatically reap processes.
  • It adds extra complexity. For instance, I also added ignore_intr boolean option to
    control the child processes handling of Interrupt (Control + C) signals. But this
    may be more than what is needed by most use cases.

@luqasz
Copy link
Owner

luqasz commented Dec 21, 2025

Things I require.

  • proper cleanup. no zombie processes left
  • no assumption on stdio / local ports etc.
  • will it work with SSL/TLS
  • tests, both integration and unit

Which leans me to a rather "pass a socket" param way (which can be already done). I'm not a fan of too many assumptions. Function which will work with eg. netcat but won't work with ssh -W. Distinguish inside what is used and do appropriate. Too much complexity and I'm the one who will maintain it. Finally SSL/TLS connections. Will it work with SSL/TLS ?

I could add some example code in docs though on how to create a simple proxy.

I need some time to think about a good solution. Open for ideas.

- Removing zombie processes
- Adding unit and integration tests
@alejandroliu
Copy link
Author

Hello,

The latest commit brings:

  • Get rids of zombie processes by letting the init processes clean them up.
  • Added unit and integration tests, testing:
    • Using netcat command
    • Using ssh command
    • Using ssl over netcat command
    • Using ssl over ssh command
    • Using netcat with asyncio
    • Using ssh with asyncio

There are no special assumptions being made.
And yes, SSL/TLS was tested and works correctly.

Usage is straight forward:

import librouteros

api = librouteros.connect(
        username = __REMOVED__,
        password = __REMOVED__,
        host = "mikrotik",
        ssl_wrapper = ctx.wrap_socket,
        port = 8729,
       proxy_command = "ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -W %h:%p bastion",
      )

The only difference from normal librouteros usage is the addition of the proxy_command argument.

More examples of proxy_command:

proxy_command ="nc -c %h %p"  # GNU netcat
proxy_command="nc -N %h %p" # OpenBSD netcat
proxy_command="nc -N -xbastion:8080 -Xconnect %h %p" # OpenBSD netcat using HTTP proxy

@luqasz
Copy link
Owner

luqasz commented Jan 7, 2026

Sorry for long delay in reply. Unfortunately I can't accept this PR. I will however accept socket param in connect() and async_connect() and provide some example code on how to do a proxy connection.

@alejandroliu
Copy link
Author

Thanks for the feedback.

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