-
Notifications
You must be signed in to change notification settings - Fork 3.9k
tinyssh: add package #30036
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
base: master
Are you sure you want to change the base?
tinyssh: add package #30036
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # | ||
| # This is free software, licensed under the GNU General Public License v2. | ||
| # See /LICENSE for more information. | ||
| # | ||
|
|
||
| include $(TOPDIR)/rules.mk | ||
|
|
||
| PKG_NAME:=tinyssh | ||
| PKG_RELEASE:=1 | ||
|
|
||
| PKG_SOURCE_PROTO:=git | ||
| PKG_SOURCE_URL:=https://github.com/janmojzis/tinyssh | ||
| PKG_SOURCE_DATE:=2026-06-13 | ||
| PKG_SOURCE_VERSION:=3d93382cde06c109d5d274fa2dddea064e543c85 | ||
| PKG_MIRROR_HASH:=716bc30d70776be6b925fa0454a2597483b694635ee88f855ecbc8d6ac97eb01 | ||
|
|
||
| PKG_MAINTAINER:=Mario Rugiero <mrugiero@gmail.com> | ||
| PKG_LICENSE:=CC0-1.0 OR 0BSD OR MIT-0 OR MIT | ||
| PKG_LICENSE_FILES:=LICENSE.md | ||
|
|
||
| PKG_BUILD_PARALLEL:=1 | ||
|
|
||
| include $(INCLUDE_DIR)/package.mk | ||
|
|
||
| define Package/tinyssh | ||
| SECTION:=net | ||
| CATEGORY:=Network | ||
| TITLE:=Small SSHv2-only server | ||
| URL:=https://tinyssh.org/ | ||
| DEPENDS:= | ||
| endef | ||
|
|
||
| define Package/tinyssh/description | ||
| TinySSH is a minimalistic SSH server which implements only a subset | ||
| of SSHv2 features. | ||
| endef | ||
|
|
||
| comma:=, | ||
| # RELRO bloats tinysshd-listen ~2.7kb -> ~65kb (ld.bfd/mips16 quirk); | ||
| # drop it there only, it parses no untrusted input. | ||
| TINYSSHD_LISTEN_CFLAGS:=$(filter-out -Wl$(comma)-z$(comma)relro,$(TARGET_CFLAGS)) | ||
| TINYSSHD_LISTEN_LDFLAGS:=$(filter-out -zrelro,$(TARGET_LDFLAGS)) | ||
|
|
||
| define Build/Compile | ||
| +$(MAKE) -C $(PKG_BUILD_DIR) \ | ||
| CC="$(TARGET_CC)" \ | ||
| CFLAGS="$(TARGET_CFLAGS) -fwrapv -Icryptoint" \ | ||
| CPPFLAGS="$(TARGET_CPPFLAGS)" \ | ||
| LDFLAGS="$(TARGET_LDFLAGS)" \ | ||
| tinysshd tinysshd-makekey tinysshd-printkey tinysshnoneauthd | ||
| $(TARGET_CC) $(TINYSSHD_LISTEN_CFLAGS) $(TARGET_CPPFLAGS) $(TINYSSHD_LISTEN_LDFLAGS) \ | ||
| -o $(PKG_BUILD_DIR)/tinysshd-listen ./src/tinysshd-listen.c | ||
| endef | ||
|
|
||
| define Package/tinyssh/install | ||
| $(INSTALL_DIR) $(1)/usr/sbin | ||
| $(INSTALL_BIN) $(PKG_BUILD_DIR)/tinysshd $(1)/usr/sbin/tinysshd | ||
| $(LN) tinysshd $(1)/usr/sbin/tinysshd-makekey | ||
| $(LN) tinysshd $(1)/usr/sbin/tinysshd-printkey | ||
| $(LN) tinysshd $(1)/usr/sbin/tinysshnoneauthd | ||
| $(INSTALL_BIN) $(PKG_BUILD_DIR)/tinysshd-listen $(1)/usr/sbin/tinysshd-listen | ||
| $(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config | ||
| $(INSTALL_BIN) ./files/tinyssh.init $(1)/etc/init.d/tinyssh | ||
| $(INSTALL_CONF) ./files/tinyssh.config $(1)/etc/config/tinyssh | ||
| endef | ||
|
|
||
| define Package/tinyssh/conffiles | ||
| /etc/config/tinyssh | ||
| endef | ||
|
|
||
| $(eval $(call BuildPackage,tinyssh)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| config tinyssh 'main' | ||
| option enabled '1' | ||
| option port '22' | ||
| option maxconnections '20' | ||
| option verbose '0' | ||
| # option interface 'lan' | ||
| # option keydir '/etc/tinyssh/sshkeydir' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| #!/bin/sh /etc/rc.common | ||
| # tinyssh | ||
|
|
||
| START=50 | ||
| STOP=10 | ||
|
|
||
| USE_PROCD=1 | ||
|
|
||
| NAME=tinyssh | ||
| LISTEN=/usr/sbin/tinysshd-listen | ||
| TINYSSHD=/usr/sbin/tinysshd | ||
|
|
||
| ensure_keys() { | ||
| local keydir="$1" tmp | ||
|
|
||
| [ -d "$keydir" ] && return 0 | ||
|
|
||
| tmp=$(mktemp -d) || return 1 | ||
| /usr/sbin/tinysshd-makekey -q "$tmp/keys" || { | ||
| rm -rf "$tmp" | ||
| return 1 | ||
| } | ||
| mkdir -p "$(dirname "$keydir")" | ||
| mv "$tmp/keys" "$keydir" | ||
| rmdir "$tmp" | ||
| } | ||
|
|
||
| start_service() { | ||
| local enabled interface port maxconnections verbose keydir bindaddr ipaddr | ||
|
|
||
| . /lib/functions.sh | ||
| . /lib/functions/network.sh | ||
|
|
||
| config_load tinyssh | ||
| config_get_bool enabled main enabled 1 | ||
| [ "$enabled" = 1 ] || return 0 | ||
|
|
||
| config_get interface main interface | ||
| config_get port main port 22 | ||
| config_get maxconnections main maxconnections 20 | ||
| config_get_bool verbose main verbose 0 | ||
| config_get keydir main keydir /etc/tinyssh/sshkeydir | ||
|
|
||
| ensure_keys "$keydir" || { | ||
| logger -s -t "$NAME" -p daemon.err "unable to generate host keys in '$keydir'" | ||
| return 1 | ||
| } | ||
|
|
||
| bindaddr="0.0.0.0" | ||
| if [ -n "$interface" ]; then | ||
| if network_is_up "$interface"; then | ||
| network_get_ipaddr ipaddr "$interface" | ||
| [ -n "$ipaddr" ] && bindaddr="$ipaddr" | ||
| else | ||
| logger -t "$NAME" -p daemon.warn \ | ||
| "interface '$interface' is not up, binding to all interfaces instead" | ||
| fi | ||
| fi | ||
|
|
||
| procd_open_instance | ||
| procd_set_param command "$LISTEN" | ||
| case "$maxconnections" in | ||
| ''|*[!0-9]*|0) ;; | ||
| *) procd_append_param command -c "$maxconnections" ;; | ||
| esac | ||
| procd_append_param command "$bindaddr" "$port" "$TINYSSHD" | ||
| [ "$verbose" = 1 ] && procd_append_param command -v | ||
| procd_append_param command "$keydir" | ||
| procd_set_param respawn | ||
| procd_close_instance | ||
| } | ||
|
|
||
| service_triggers() { | ||
| procd_add_reload_trigger "tinyssh" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /* | ||
| * tinysshd-listen: minimal IPv4/IPv6 accept-and-fork TCP supervisor. | ||
| * usage: tinysshd-listen [-c maxconns] ip port prog [args...] | ||
| */ | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <netinet/in.h> | ||
| #include <signal.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/wait.h> | ||
| #include <unistd.h> | ||
|
|
||
| static volatile sig_atomic_t live = 0; | ||
|
|
||
| static void reap(int sig) { | ||
| (void)sig; | ||
| while (waitpid(-1, NULL, WNOHANG) > 0) live--; | ||
| } | ||
|
|
||
| int main(int argc, char **argv) { | ||
| long maxconns = 0; | ||
|
|
||
| if (argc >= 3 && strcmp(argv[1], "-c") == 0) { | ||
| maxconns = atol(argv[2]); | ||
| argv += 2; | ||
| argc -= 2; | ||
| } | ||
| if (argc < 4) _exit(100); | ||
|
|
||
| struct sockaddr_in a4 = {0}; | ||
| struct sockaddr_in6 a6 = {0}; | ||
| struct sockaddr *addr; | ||
| socklen_t addrlen; | ||
| int family; | ||
|
|
||
| unsigned short port = (unsigned short)atoi(argv[2]); | ||
|
|
||
| if (inet_pton(AF_INET, argv[1], &a4.sin_addr) == 1) { | ||
| family = AF_INET; | ||
| a4.sin_family = AF_INET; | ||
| a4.sin_port = htons(port); | ||
| addr = (struct sockaddr *)&a4; | ||
| addrlen = sizeof(a4); | ||
| } else if (inet_pton(AF_INET6, argv[1], &a6.sin6_addr) == 1) { | ||
| family = AF_INET6; | ||
| a6.sin6_family = AF_INET6; | ||
| a6.sin6_port = htons(port); | ||
| addr = (struct sockaddr *)&a6; | ||
| addrlen = sizeof(a6); | ||
| } else { | ||
| _exit(100); | ||
| } | ||
|
|
||
| int lfd = socket(family, SOCK_STREAM, 0); | ||
| if (lfd < 0) _exit(111); | ||
|
|
||
| int one = 1; | ||
| setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); | ||
|
|
||
| if (bind(lfd, addr, addrlen) < 0) _exit(111); | ||
| if (listen(lfd, 20) < 0) _exit(111); | ||
|
|
||
| signal(SIGCHLD, reap); | ||
|
|
||
| for (;;) { | ||
| int cfd = accept(lfd, NULL, NULL); | ||
| if (cfd < 0) continue; | ||
|
|
||
| if (maxconns > 0 && live >= maxconns) { | ||
| close(cfd); | ||
| continue; | ||
| } | ||
|
|
||
| pid_t pid = fork(); | ||
| if (pid == 0) { | ||
| close(lfd); | ||
| dup2(cfd, 0); | ||
| dup2(cfd, 1); | ||
| close(cfd); | ||
| execvp(argv[3], &argv[3]); | ||
| _exit(111); | ||
| } | ||
| if (pid > 0) live++; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Consider blocking SIGCHLD with Generated by Claude Code |
||
| close(cfd); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
bindaddrdefaults to0.0.0.0and, when an interface is configured, onlynetwork_get_ipaddr(IPv4) is consulted, sotinysshd-listenis only ever handed an IPv4 address — even though it fully supportsAF_INET6. As written IPv6 clients can never reach the daemon, which differs from dropbear (the in-tree SSH server) that listens on both families by default. Is IPv4-only intended, or should the default / interface handling also cover IPv6 (e.g. a second procd instance bound to::or the interface's IPv6 address vianetwork_get_ipaddr6)?Generated by Claude Code