{ "info": { "author": "Matthijs Kooijman", "author_email": "matthijs@stdin.nl", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: No Input/Output (Daemon)", "Framework :: AsyncIO", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", "Topic :: Internet :: Proxy Servers", "Topic :: System :: Networking" ], "description": "# TODO: Switch to poetry (or flit) and pyproject.toml? Already made as start\n# with poetry\n\nNuttssh - SSH-based virtual tunnel switchboard server\n=====================================================\nNuttssh is a small Python-based SSH server that internally connects forwarded\nports between different SSH clients. It was designed to work as a way to\nconnect to machines running behind a NAT, by letting them initiate an outgoing\nSSH connection and then piggy-back a reverse SSH connection to access the\nmachine. When used like that, Nuttssh acts somewhat as a very lightweight VPN\nserver.\n\nMore generally, nuttsh can be used to let SSH clients request opening a\nlistening port, which results in an internal virtual port being opened (no\nactual TCP ports on the server are opened). Then another SSH client can request\nto connect to that listening port, using a configurable name to identify the\nclient whose port to connect to.\n\nThis works very similar to using a normal SSH server with port forwarding,\nexcept that when using Nuttssh:\n - Not actual TCP ports are opened on the server.\n - Clients do not need to actually authenticate as a system user, Nuttssh\n handles its own key authentication.\n - When multiple clients request a listening port, they can use the same port\n number, since their hostname will be used to select the right one. This\n removes the need to ensure that each listening client chooses a unique port\n number.\n - When connecting to a listening port, a hostname and the regular port number\n (e.g. 22 for SSH) can be used, rather than having to keep track of which\n port number maps to which client.\n\nTo circumvent the downsides of normal SSH port forwarding (in particular the\nlast two), Nuttssh was created. It replaces the central server, while still\nallowing normal SSH clients to be used.\n\nNuttssh still young, but should be usable already. There is still plenty of\nroom for improvement, especially with regard to configurability.\n\n## Terminology\n - (Nuttssh) server: The central server that accepts connections from various\n clients, and connects them together.\n - Listening client: A client that connects to the Nuttssh server and requests\n listening ports. This is *not* called a \"listener\", to prevent confusing\n with the `SSHListener` class used in AsyncSSH.\n - Initiating client or initiator: A client that connects to the Nuttssh server\n and requests a connection to a listening client.\n - Circuit: the virtual connection between two clients through the Nuttssh\n server. Called a circuit to disambiguate from the normal connection between\n the client and the Nuttssh server.\n\n Note that a client is typically either listening or initiating, but given\n sufficient permissions, a client could also act as both.\n\nThe above terminology is not used everywhere yet, in some cases a listening\nclient is called a slave and an initiating client is called a master (coming\nfrom the original usecase of remote control).\n\n## Installing / running\nThe easiest way to run Nuttsh is to install it using pip. E.g.:\n\n pip3 install nuttsh\n\nOptionally add `--user` to install for your user only (without\nrequiring root), or run inside an activated virtualenv.\n\nThen, to run the nuttsh server:\n\n python3 -m nuttsh\n\nAlternatively, you can also clone this repository, and run `python3 -m nuttsh`\nfrom the root of the repository, without requiring installation.\n\nNote that this uses `pip3` and `python3` to get the Python 3 versions. If this\nis the default on your system (or you are using from a virtualenv containing\nPython 3), you might also be able to just use `pip` and `python` instead.\n\n## Configuration\nCurrently, no configuration file or options is supported. There are some\nconstants in the top of `nuttssh/server.py` that hardcode nuttsh to listen on\nany interface, on port 2222 and set the name of the `ssh_host_key` and\n`authorized_keys` file.\n\n### SSH host key\nTo allow starting `nuttssh`, an ssh host key must be present. This should be\nput into a file called `ssh_host_key` in the current directory. To generate one\nusing OpenSSH's `ssh-keygen`, run:\n\n ssh-keygen -t rsa -b 2048 -P \"\" -f ssh_host_key\n\nThis generates a 2048-bit RSA key without a passphrase.\n\n### Access control\nTo control access to the nuttsh server, an `authorized_keys` file must be\npresent (without it, nuttsh will refuse to start). This file uses the same\nformat as OpenSSH's `authorized_keys` file. Each line must contain a single\npublic key (copied from e.g. the `id_rsa.pub` file). In front of the public\nkey, options can be added.\n\nFor example, a file could look like this (keys are truncated for the example):\n\n access=\"listen\" ssh-rsa AAAAB3NzaC1yc2EAAAADAJnmVYPYe94v user@host\n access=\"listen\",access=\"initiate\",from=\"192.168.1.0/24\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAA+ user@host\n\nThis consists of a comma-separated list of options, a keytype, the actual key\nand a comment.\n\nCurrently, the following options are supported:\n - `access` to specify the permissions for the client. Supported values are\n `listen` (to allow opening listening ports) and `initiate` (to allow\n connecting to listening ports). This option can be specified more than once,\n to give more than one type of permission.\n - `from` to limit connections to specific hosts. The value is a\n comma-separated list of patterns. Each pattern can be a glob pattern (using\n `*` and `?`, e.g. `\"*.mydomain.tld\"`) matched against the address and\n hostname, or a CIDR-style address and mask (e.g. `\"192.168.1.0/24\"`). A\n connection is allowed if it matches at least one of the patterns in the\n list. This option can be specified multiple times, in which case a\n connection must match (one element of) each `from` option separately.\n\n See the OpenSSH `authorized_keys` manpage for more info on this option.\n - `hostname` and `alias` allow configuring the name(s) that can be used to\n connect to this client. See below for details.\n\nNote that when a client has multiple keys, the first one offered by the client\nthat is present in the `authorized_keys` file is used, even when another is\nalso present and has more permissions or other options.\n\n### Slave hostnames and aliases\nEach connected client has a hostname, and an optional list of alias names. The\nhostname is used in various places to refer to a client, while both the\nhostname and the aliases can be used to select a listening client to connect\nto.\n\nBy default, the username specified by the client is used as its hostname (this\nlooks a bit like a hack, but it seems like the cleanest approach). Using the\n`hostname` option in `authorized_keys`, this hostname can be overridden for a\ngiven connection. Using the `alias` option, additional alias names can be\nspecified (the option must be specified multiple times for multiple aliases).\n\nWhen multiple listening clients each claim the same name (hostname or alias),\nthe last client to connect will be reached using that name. To reach the other\nclients, you can add an index to the hostname. E.g. when two listening clients\nboth use `test` as their hostname, you can connect to the most recent one using\n`test` (or `test~0`) and the older one using `test~1`.\n\n### Connecting listening clients\nConnections to the Nuttssh server use the normal SSH protocol, so can use a\nregular SSH client. To open up a listening port, the normal port forwarding\noptions can be used. For example:\n\n ssh myhost@nuttsh.example.org -p 2222 -R 22:localhost:22 -N\n\nThis connects to a Nuttssh server running on `nuttsh.example.org`, port 2222.\nOur hostname (`myhost`) is passed as the username. No shell or other remote\ncommand is run (`-N`), but a (virtual) port 22 is opened in the Nuttssh server.\nAny incoming circuits on that port are forwarded through the SSH connection and\nconnected to localhost:22 (in other words, our local port 22 is exposed through\nNuttssh).\n\nTypically you want a listening client to be continuously connected (and\nreconnect on errors). This is easy using `autossh`, just replace `ssh` with\n`autossh`, and that will take care of autoconnecting.\n\nBy default, `autossh` uses additional port forwards to test connectivity, which\ndo not work with Nuttssh so these should be disabled in favor of letting SSH\nitself do keepalive. Additionally, when running unattended, `autossh` should be\ntold to always keep retrying, even on startup errors.\n\nTODO: Systemd/sh/dropbear/etc.\n\n#### Changing port numbers\nThe above examples all assume that the listening clients requests a listening\nport 22 and forwards any incoming circuits to `localhost:22`, which is probably\nthe common case. However, it is also possible to forward to a different local\nhost or port by specifying them with the `-R` option.\n\nFor example:\n\n ssh myhost@nuttsh.example.org -p 2222 -R 80:localhost:8080 -N\n\nThis requests a virtual port 80 on the Nuttssh server and connects any incoming\ncircuits to port 8080 on localhost. Note that this is completely invisible to\nthe initiating clients, since these only need to specify the hostname\n(`myhost`) and virtual listening port (80).\n\n### Connecting initiating clients\nInitiating clients also use the plain SSH protocol and can use a normal SSH\nclient. For example, to set up an SSH connection to the listening client from\nthe previous example, using a circuit through the NuttSSH server:\n\n ssh -J nuttsh.example.org:2222 myhost\n\nThis instructs ssh to first connect to `nuttssh.example.org`, port 2222 and\nthen inside that connection, ask the Nuttssh server to set up a circuit\n(tunneled connection) to `myhost`, port 22 (not specified explicitly). This\nhostname and port combination is then matched by the Nuttsh server to the\npreviously connected listening client and the circuit is routed to that client.\nFinally, the listening client then completes the circuit by locally connecting\nto its own SSH port, as requested by the `localhost:22` part in its `-R`\noption.\n\nThis makes use of the SSH `-J` option, using the Nuttssh as a *jump host*. This\nis convenient for routing SSH connections through a circuit, but does not work\nfor other kinds of connections. Fortunately, ssh allows other ways to set up\nthese circuit connections as well.\n\nNote that this makes two SSH connections, one to the Nuttsh server and one to\nthe listening client. This also means that authentication must happen twice.\n\n#### Forwarding local ports through a circuit\nYou can also ask SSH to open a local listening port, and create a circuit for\neach incoming connection on that port. For example:\n\n ssh -L 22:myhost:22 nuttsh.example.org -p 2222 -N\n\nOpens up port 22 locally, and forwards any connections through a circuit to\nport 22 on `myhost`. Again `-N` is specified to prevent trying to execute a\nremote shell or command.\n\nNote that more than one circuit can be created in this way, each of which will\nbe routed through the same SSH connection to the Nuttssh server.\n\n#### Forwarding stdin/stdout through a circuit\nSSH can also forward data on its stdin and stdout streams into a circuit. For\nexample:\n\n ssh -W myhost:22 nuttsh.example.org -p 2222\n\nThis opens a circuit to `myhost` on port 22, and connects it to the stdin and\nstdout of the local ssh client. The `-N` option is implied by `-W`, so does\nneed to be separately specified.\n\n#### Routing a SOCKS proxy requests through a circuit\nSSH supports exposing a SOCKS proxy. This proxy is implemented completely in\nthe local SSH client, and allows (local) programs, such as a webbrowser, to\nroute all of their traffic through the proxy. In this case, this means all\nconnections will be made through circuits (and thus connections can be made to\nall listening hosts, but not other hosts).\n\nTo set this up, run:\n\n ssh -D 3128 nuttsh.example.org -p 2222 -N\n\nThis instructs ssh to open up a SOCKS proxy port on local port 3128, which can\nthen be used by other programs.\n\nNote that this setup requires the client to support SOCKS v5 and do name\nresolution through the proxy (e.g. Firefox has a \"Proxy DNS when using SOCKS\nv5\" optoin for this). Without this (and with SOCKS v4), names are locally\nresolved (which will fail) and only the resulting IP address is included in the\nproxy request.\n\n### Using ssh config files\nAll of the above mentioned ssh options (except `-N` it seems) can also be\nconfigured through SSH configuration file options, so you can define some\npresets and apply them by just passing a hostname to ssh. See the `ssh_config`\nmanpage for more info.\n\n# Contributing\nThis is an open project, and contributions are welcomed. For bug reports,\nfeature suggestions and questions, please use the github issue tracker. To\ncontribute patches, use github pull requests.\n\nWhen contributing patches, make sure to provide good quality contributions. In\nparticular, code style should be consistent, commits should be cleanly\nseparated with a single logical change per commit and commit messages should be\nclear. In other words, make sure the code and commit history is easy to read\nand review. Additionally, please explicitly state that you make your\npatch available under the MIT license.\n\nTo check the coding style of the code, the flake8 tool is used. As a\nconvenience, a `Makefile` is provided that allows running `make check` to run\nall checks (currently only flake8). This should not return any errors after any\ncommit, so make sure to run it regularly. To fix import sorting errors, run\n`make sort`.\n\n# License (also setup.py)\nNuttssh was written by Matthijs Kooijman. Its sources, as well as the\naccompanying documentation and other files in this repository are available\nunder the MIT license. See the [`LICENSE`](LICENSE) file for the full license text.\n\n# About Nuttssh\nNuttssh was originally created for the [Meetjestad!](http://www.meetjestad.net)\nproject, to provide lightweight remote control for LoRa gateways spread\nthroughout the city on varying internet connections (usually not publically\nreachable due to NAT). After some initial experiments with a reverse SSH\nconnection and SSH channel multiplexing (which worked, but resulted in fragile\ncode), the current approach of using port forwards was implemented. For this,\nsome inspiration was taking from\n[ssh-proxy](https://github.com/luke-jr/ssh-proxy), which also uses remote port\nforwarding (but uses key fingerprints to identify clients, and probably\npredates the SSH \"jump host\" feature).\n\nSince how Nuttssh works seems a bit similar to the way telephone switchboards\nused to work years ago, Nuttssh is named after Emma & Stella Nutt, which were\nthe first two female telephone switchboard operators. The name \"circuit\" is\nalso taken from telephone jargon.", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/matthijskooijman/nuttssh", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "nuttssh", "package_url": "https://pypi.org/project/nuttssh/", "platform": "", "project_url": "https://pypi.org/project/nuttssh/", "project_urls": { "Homepage": "http://github.com/matthijskooijman/nuttssh" }, "release_url": "https://pypi.org/project/nuttssh/0.2/", "requires_dist": null, "requires_python": ">=3.5", "summary": "SSH switchboard for internally patching forwarded ports", "version": "0.2" }, "last_serial": 4764326, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "83e14755b5d82dc277677faf36dde190", "sha256": "7aeb60ae95ad8b6bebeb919c99d2aa6990586bfe1f6b65ceb246d0592f1467a0" }, "downloads": -1, "filename": "nuttssh-0.1.tar.gz", "has_sig": false, "md5_digest": "83e14755b5d82dc277677faf36dde190", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12532, "upload_time": "2018-07-22T23:13:43", "url": "https://files.pythonhosted.org/packages/60/12/68c3d9c828467ac25ea97c8f3f964e8638b28481ecf52437d4d6ffdf0186/nuttssh-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "dde8994e91d58e4c9593f17b2621df19", "sha256": "aef3c562c046ac7ef2555de3b6ff24c9829b94aee41d22d30dddfd15d56d4292" }, "downloads": -1, "filename": "nuttssh-0.2.tar.gz", "has_sig": false, "md5_digest": "dde8994e91d58e4c9593f17b2621df19", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12993, "upload_time": "2019-01-31T16:28:22", "url": "https://files.pythonhosted.org/packages/ca/e7/6640b1931bfab4b19bdd872d8d9c5b06340449dc6ebdbd9fc5d8989b3238/nuttssh-0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "dde8994e91d58e4c9593f17b2621df19", "sha256": "aef3c562c046ac7ef2555de3b6ff24c9829b94aee41d22d30dddfd15d56d4292" }, "downloads": -1, "filename": "nuttssh-0.2.tar.gz", "has_sig": false, "md5_digest": "dde8994e91d58e4c9593f17b2621df19", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12993, "upload_time": "2019-01-31T16:28:22", "url": "https://files.pythonhosted.org/packages/ca/e7/6640b1931bfab4b19bdd872d8d9c5b06340449dc6ebdbd9fc5d8989b3238/nuttssh-0.2.tar.gz" } ] }