diff --git a/board/common/netbrowse.conf b/board/common/netbrowse.conf new file mode 100644 index 00000000..f6db335a --- /dev/null +++ b/board/common/netbrowse.conf @@ -0,0 +1,5 @@ +proxy_pass http://127.0.0.1:8000; +proxy_set_header Host $host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $scheme; diff --git a/board/common/nginx.conf b/board/common/nginx.conf index 06f1eddd..9946f78e 100644 --- a/board/common/nginx.conf +++ b/board/common/nginx.conf @@ -36,8 +36,7 @@ http { } location /browse { - include fastcgi_params; - fastcgi_pass unix:/tmp/netbrowse.sock; + include netbrowse.conf; } } @@ -46,10 +45,9 @@ http { listen [::]:80; server_name network.local; - location / { - include fastcgi_params; - fastcgi_pass unix:/tmp/netbrowse.sock; - } + location / { + include netbrowse.conf; + } } # diff --git a/board/common/post-build.sh b/board/common/post-build.sh index f8e3be73..31900cf6 100755 --- a/board/common/post-build.sh +++ b/board/common/post-build.sh @@ -86,6 +86,7 @@ grep -qsE '^/bin/clish$$' "$TARGET_DIR/etc/shells" \ || echo "/bin/clish" >> "$TARGET_DIR/etc/shells" if [ -n "$BR2_PACKAGE_NGINX" ]; then + cp "$common/netbrowse.conf" "$TARGET_DIR/etc/nginx/" cp "$common/nginx.conf" "$TARGET_DIR/etc/nginx/" ln -sf ../available/nginx.conf "$TARGET_DIR/etc/finit.d/enabled/nginx.conf" diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig index 87603cf8..b60ca2d8 100644 --- a/configs/aarch64_defconfig +++ b/configs/aarch64_defconfig @@ -54,6 +54,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y BR2_PACKAGE_PYTHON3=y BR2_PACKAGE_PYTHON_CRYPTOGRAPHY=y +BR2_PACKAGE_PYTHON_GUNICORN=y BR2_PACKAGE_LIBSSH_OPENSSL=y BR2_PACKAGE_LIBSSH2=y BR2_PACKAGE_LIBSSH2_OPENSSL=y @@ -141,6 +142,7 @@ BR2_PACKAGE_KEYACK=y BR2_PACKAGE_KLISH_PLUGIN_INFIX=y BR2_PACKAGE_LOWDOWN=y BR2_PACKAGE_MCD=y +BR2_PACKAGE_MDNS_ALIAS=y BR2_PACKAGE_NETBROWSE=y BR2_PACKAGE_PODMAN=y BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y diff --git a/configs/r2s_defconfig b/configs/r2s_defconfig index 9b238ffc..f5ebf9f9 100644 --- a/configs/r2s_defconfig +++ b/configs/r2s_defconfig @@ -64,6 +64,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y BR2_PACKAGE_PYTHON3=y BR2_PACKAGE_PYTHON_CRYPTOGRAPHY=y +BR2_PACKAGE_PYTHON_GUNICORN=y BR2_PACKAGE_CA_CERTIFICATES=y BR2_PACKAGE_LIBSSH_OPENSSL=y BR2_PACKAGE_LIBSSH2=y @@ -170,6 +171,7 @@ BR2_PACKAGE_KEYACK=y BR2_PACKAGE_KLISH_PLUGIN_INFIX=y BR2_PACKAGE_LOWDOWN=y BR2_PACKAGE_MCD=y +BR2_PACKAGE_MDNS_ALIAS=y BR2_PACKAGE_NETBROWSE=y BR2_PACKAGE_PODMAN=y BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y diff --git a/configs/x86_64_defconfig b/configs/x86_64_defconfig index abec241b..a944b94d 100644 --- a/configs/x86_64_defconfig +++ b/configs/x86_64_defconfig @@ -49,6 +49,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y BR2_PACKAGE_PYTHON3=y BR2_PACKAGE_PYTHON_CRYPTOGRAPHY=y +BR2_PACKAGE_PYTHON_GUNICORN=y BR2_PACKAGE_LIBSSH_OPENSSL=y BR2_PACKAGE_LIBSSH2=y BR2_PACKAGE_LIBSSH2_OPENSSL=y @@ -144,6 +145,7 @@ BR2_PACKAGE_KEYACK=y BR2_PACKAGE_KLISH_PLUGIN_INFIX=y BR2_PACKAGE_LOWDOWN=y BR2_PACKAGE_MCD=y +BR2_PACKAGE_MDNS_ALIAS=y BR2_PACKAGE_NETBROWSE=y BR2_PACKAGE_PODMAN=y BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y diff --git a/package/Config.in b/package/Config.in index 6b1db6ba..78417372 100644 --- a/package/Config.in +++ b/package/Config.in @@ -15,6 +15,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/libsrx/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/lowdown/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/mcd/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/mdns-alias/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/netbrowse/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in" diff --git a/package/mdns-alias/Config.in b/package/mdns-alias/Config.in new file mode 100644 index 00000000..25a0f5bf --- /dev/null +++ b/package/mdns-alias/Config.in @@ -0,0 +1,7 @@ +config BR2_PACKAGE_MDNS_ALIAS + bool mdns-alias + select BR2_PACKAGE_DBUS + select BR2_PACKAGE_DBUS_PYTHON + help + Advertises the initial $(HOSTNAME).local and network.local to + Avahi over D-Bus. diff --git a/package/mdns-alias/mdns-alias.mk b/package/mdns-alias/mdns-alias.mk new file mode 100644 index 00000000..3aa0117b --- /dev/null +++ b/package/mdns-alias/mdns-alias.mk @@ -0,0 +1,25 @@ +################################################################################ +# +# mdns-alias +# +################################################################################ + +MDNS_ALIAS_VERSION = 1.0 +MDNS_ALIAS_SITE_METHOD = local +MDNS_ALIAS_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/mdns-alias +MDNS_ALIAS_SETUP_TYPE = setuptools +MDNS_ALIAS_LICENSE = MIT +MDNS_ALIAS_LICENSE_FILES = LICENSE +MDNS_ALIAS_REDISTRIBUTE = NO + +define MDNS_ALIAS_INSTALL_EXTRA + $(INSTALL) -D -m 0644 $(MDNS_ALIAS_PKGDIR)/mdns-alias.svc \ + $(FINIT_D)/available/mdns-alias.conf + ln -sf ../available/mdns-alias.conf $(FINIT_D)/enabled/mdns-alias.conf + $(INSTALL) -d -m 755 $(TARGET_DIR)/etc/default + echo "MDNS_ALIAS_ARGS=\"network.local $(BR2_TARGET_GENERIC_HOSTNAME).local\"" \ + > $(TARGET_DIR)/etc/default/mdns-alias +endef +MDNS_ALIAS_POST_INSTALL_TARGET_HOOKS += MDNS_ALIAS_INSTALL_EXTRA + +$(eval $(python-package)) diff --git a/package/mdns-alias/mdns-alias.svc b/package/mdns-alias/mdns-alias.svc new file mode 100644 index 00000000..dfe65d8f --- /dev/null +++ b/package/mdns-alias/mdns-alias.svc @@ -0,0 +1,2 @@ +service env:-/etc/default/mdns-alias log:prio:daemon.debug,tag:mdns \ + [2345] mdns-alias $MDNS_ALIAS_ARGS -- mDNS alias advertiser diff --git a/package/netbrowse/Config.in b/package/netbrowse/Config.in index 4c5125db..8781fa37 100644 --- a/package/netbrowse/Config.in +++ b/package/netbrowse/Config.in @@ -1,10 +1,6 @@ config BR2_PACKAGE_NETBROWSE bool netbrowse - select BR2_PACKAGE_DBUS - select BR2_PACKAGE_DBUS_PYTHON select BR2_PACKAGE_PYTHON_FLASK help - Advertises the initial $(HOSTNAME).local and network.local to - give your device a http://network.local mDNS/SD browser. + Browse mDNS hosts on your network from http://network.local - UNIX socket available for fastcgi at /tmp/netbrowse.sock diff --git a/package/netbrowse/netbrowse.svc b/package/netbrowse/netbrowse.svc index 002b7f84..789d0ffa 100644 --- a/package/netbrowse/netbrowse.svc +++ b/package/netbrowse/netbrowse.svc @@ -1,3 +1,2 @@ -service env:-/etc/default/netbrowse log:prio:daemon.debug,tag:mdns \ - @www-data:www-data \ - [2345] netbrowse $NETBROWSE_ARGS -- Network browser +service name:netbrowse @www-data:www-data log:prio:daemon.debug,tag:mdns \ + [2345] gunicorn -w 1 -b 127.0.0.1:8000 netbrowse:app -- Network browser diff --git a/src/mdns-alias/LICENSE b/src/mdns-alias/LICENSE new file mode 100644 index 00000000..b67cb375 --- /dev/null +++ b/src/mdns-alias/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Joachim Wiberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/mdns-alias/README.md b/src/mdns-alias/README.md new file mode 100644 index 00000000..1e576b9d --- /dev/null +++ b/src/mdns-alias/README.md @@ -0,0 +1,11 @@ +mDNS Alias +========== + +This Python program both advertises CNAMEs (using D-Bus to Avahi). + +To start the program: + + mdns-alias $hostname.local network.local + +The latter CNAME can be used with nginx and netbrowse to provide +a basic mDNS service browser. diff --git a/src/mdns-alias/mdns_alias/__init__.py b/src/mdns-alias/mdns_alias/__init__.py new file mode 100644 index 00000000..17e78b8d --- /dev/null +++ b/src/mdns-alias/mdns_alias/__init__.py @@ -0,0 +1,24 @@ +""" + Avahi CNAME service over D-Bus advertiser +""" +import sys +import time + +from .mdns_alias import MdnsAlias +__all__ = ['MdnsAlias'] + +def main(): + """Advertises aliases from command line.""" + mdns_aliases = MdnsAlias() + + for arg in sys.argv[1:]: + mdns_aliases.publish_cname(str(arg).encode("utf-8", "strict")) + + while True: + time.sleep(3600) + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print("Exiting") diff --git a/src/netbrowse/netbrowse/avahi_alias/avahi_alias.py b/src/mdns-alias/mdns_alias/mdns_alias.py similarity index 97% rename from src/netbrowse/netbrowse/avahi_alias/avahi_alias.py rename to src/mdns-alias/mdns_alias/mdns_alias.py index c86ec061..f19d9a7c 100644 --- a/src/netbrowse/netbrowse/avahi_alias/avahi_alias.py +++ b/src/mdns-alias/mdns_alias/mdns_alias.py @@ -1,9 +1,9 @@ -"""Avahi CNAME alias class""" +"""Avahi CNAME publisher class""" from encodings.idna import ToASCII import dbus -class AvahiAlias: +class MdnsAlias: """Import to your project and use publish_cname() for each name.""" DBUS_NAME = 'org.freedesktop.Avahi' CLASS_IN = 0x01 diff --git a/src/mdns-alias/pyproject.toml b/src/mdns-alias/pyproject.toml new file mode 100644 index 00000000..4db8cdf5 --- /dev/null +++ b/src/mdns-alias/pyproject.toml @@ -0,0 +1,20 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +#build-backend = "setuptools.build_meta" + +[project] +name = "mdns-alias" +version = "1.0" +description = "Request mDNS-SD CNAME over D-Bus to Avahi." +authors = [{name = "Joachim Wiberg", email = "troglobit@gmail.com"}] +license = {file = "LICENSE"} +readme = "README.md" +dependencies = [ + "dbus", +] + +#[tool.setuptools.packages.find] +#where = ["mdns_alias"] + +[project.scripts] +mdns-alias = "mdns_alias:main" diff --git a/src/netbrowse/README.md b/src/netbrowse/README.md index c15a5233..79b0eecd 100644 --- a/src/netbrowse/README.md +++ b/src/netbrowse/README.md @@ -1,12 +1,8 @@ mDNS Network Browser ==================== -This Python program both advertises CNAMEs (using D-Bus to Avahi) and -provides an mDNS browser over fastcgi for, e.g., Nginx. - -To start the program: - - netbrowse $hostname.local network.local +This program is a Python Flask app that provides an mDNS browser for, +e.g., Nginx. It is intended to answer calls to https://network.local A UNIX socket, for fastcgi, is created in `/tmp/netbrowse.sock` with permissions 0660 as the user and group the program is started as. diff --git a/src/netbrowse/netbrowse/__init__.py b/src/netbrowse/netbrowse/__init__.py index e69de29b..ee498b8e 100644 --- a/src/netbrowse/netbrowse/__init__.py +++ b/src/netbrowse/netbrowse/__init__.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +""" + Very basic mDNS scanner with HTML table renderer +""" +from flask import Flask, render_template +from .mdns_hosts import MdnsHosts + +__all__ = ['MdnsHosts'] + +app = Flask(__name__) + +@app.route('/') +def index(): + """The /browse or network.local application""" + mdns_hosts = MdnsHosts() + hosts_services = mdns_hosts.scan() + + order = { 'HTTPS': 1, 'HTTP': 2, 'SSH': 3, 'SFTP': 4 } + for _, details in hosts_services.items(): + details['services'].sort(key=lambda x: order.get(x['type'], 999)) + + return render_template('browse.html', hosts_services=hosts_services) + +def main(): + """Stand-alone running with Flask development server.""" + try: + app.run(debug=True) + except KeyboardInterrupt: + print("Exiting") + +if __name__ == '__main__': + main() diff --git a/src/netbrowse/netbrowse/avahi_alias/__init__.py b/src/netbrowse/netbrowse/avahi_alias/__init__.py deleted file mode 100644 index 8ba9476b..00000000 --- a/src/netbrowse/netbrowse/avahi_alias/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Avahi CNAME service over D-Bus advertiser -""" - -from .avahi_alias import AvahiAlias -__all__ = ['AvahiAlias'] diff --git a/src/netbrowse/netbrowse/mdns_hosts/mdns_hosts.py b/src/netbrowse/netbrowse/mdns_hosts.py similarity index 100% rename from src/netbrowse/netbrowse/mdns_hosts/mdns_hosts.py rename to src/netbrowse/netbrowse/mdns_hosts.py diff --git a/src/netbrowse/netbrowse/mdns_hosts/__init__.py b/src/netbrowse/netbrowse/mdns_hosts/__init__.py deleted file mode 100644 index d9b98056..00000000 --- a/src/netbrowse/netbrowse/mdns_hosts/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Very basic mDNS scanner with HTML table renderer -""" - -from .mdns_hosts import MdnsHosts -__all__ = ['MdnsHosts'] diff --git a/src/netbrowse/netbrowse/netbrowse.py b/src/netbrowse/netbrowse/netbrowse.py deleted file mode 100755 index a0cc8788..00000000 --- a/src/netbrowse/netbrowse/netbrowse.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -""" - Main server loop. -""" -import sys - -from flask import Flask, render_template -from avahi_alias import AvahiAlias -from mdns_hosts import MdnsHosts - -app = Flask(__name__) - -@app.route('/browse') -def browse(): - """The /browse network.local application""" - mdns_hosts = MdnsHosts() - hosts_services = mdns_hosts.scan() - - order = { 'HTTPS': 1, 'HTTP': 2, 'SSH': 3, 'SFTP': 4 } - for _, details in hosts_services.items(): - details['services'].sort(key=lambda x: order.get(x['type'], 999)) - - return render_template('browse.html', hosts_services=hosts_services) - -def main(): - """Main entrypoint, advertises aliases from command line and starts browser.""" - avahi_aliases = AvahiAlias() - for each in sys.argv[1:]: - avahi_aliases.publish_cname(str(each).encode("utf-8", "strict")) - - try: - app.run(debug=True) - except KeyboardInterrupt: - print("Exiting") - -if __name__ == '__main__': - main() diff --git a/src/netbrowse/pyproject.toml b/src/netbrowse/pyproject.toml index fc502082..7b8f39da 100644 --- a/src/netbrowse/pyproject.toml +++ b/src/netbrowse/pyproject.toml @@ -1,11 +1,11 @@ [build-system] requires = ["setuptools>=42", "wheel"] -build-backend = "setuptools.build_meta" +# build-backend = "setuptools.build_meta" [project] name = "netbrowse" version = "1.0" -description = "mDNS-SD browser" +description = "mDNS Service Browser" authors = [{name = "Joachim Wiberg", email = "troglobit@gmail.com"}] license = {file = "LICENSE"} readme = "README.md" @@ -19,11 +19,11 @@ dev = [ "flake8>=3.8", ] -[tool.setuptools.packages.find] -where = ["netbrowse", "netbrowse.avahi_alias", "netbrowse.mdns_hosts"] +# [tool.setuptools.packages.find] +# where = ["netbrowse"] -[tool.setuptools.package-data] -netbrowse = ["templates/*.html", "static/*"] +# [tool.setuptools.package-data] +# netbrowse = ["templates/*.html", "static/*"] [project.scripts] -netbrowse = "netbrowse.netbrowse:main" +netbrowse = "netbrowse:main"