mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-02 05:43:02 +02:00
package/netbrowse: new package
- Advertises the build-time $hostname.local as a CNAME to the A and AAAA records already advertised by Avahi - Advertises a special network.local CNAME and provides a fastcgi service on unix:/tmp/netbrowse.sock for browsing mDNS services This commit also activates netbrowse by default with nginx listeing to port 80 on IPv4 and IPv6 /browse by default but also / if called with server name network.local. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
root html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root html;
|
||||
}
|
||||
|
||||
location /browse {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/tmp/netbrowse.sock;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name network.local;
|
||||
|
||||
location / {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/tmp/netbrowse.sock;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# HTTPS server
|
||||
#
|
||||
# server {
|
||||
# listen 443 ssl;
|
||||
# server_name localhost;
|
||||
|
||||
# ssl_certificate cert.pem;
|
||||
# ssl_certificate_key cert.key;
|
||||
|
||||
# ssl_session_cache shared:SSL:1m;
|
||||
# ssl_session_timeout 5m;
|
||||
|
||||
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
# ssl_prefer_server_ciphers on;
|
||||
|
||||
# location / {
|
||||
# root html;
|
||||
# index index.html index.htm;
|
||||
# }
|
||||
# }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
common=$(dirname "$(readlink -f "$0")")
|
||||
. "$BR2_CONFIG" 2>/dev/null
|
||||
. "$TARGET_DIR/usr/lib/os-release"
|
||||
|
||||
@@ -79,6 +80,37 @@ grep -qsE '^/bin/true$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/true" >> "$TARGET_DIR/etc/shells"
|
||||
grep -qsE '^/bin/false$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/false" >> "$TARGET_DIR/etc/shells"
|
||||
|
||||
# Allow clish (symlink to /usr/bin/klish) to be a login shell
|
||||
grep -qsE '^/bin/clish$$' "$TARGET_DIR/etc/shells" \
|
||||
|| echo "/bin/clish" >> "$TARGET_DIR/etc/shells"
|
||||
|
||||
if [ -n "$BR2_PACKAGE_NGINX" ]; then
|
||||
cp "$common/nginx.conf" "$TARGET_DIR/etc/nginx/"
|
||||
ln -sf ../available/nginx.conf "$TARGET_DIR/etc/finit.d/enabled/nginx.conf"
|
||||
|
||||
cat <<EOF > "$TARGET_DIR/etc/avahi/services/http.service"
|
||||
<?xml version="1.0" standalone='no'?>
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
<service-group>
|
||||
<name replace-wildcards="yes">%h</name>
|
||||
<service>
|
||||
<type>_http._tcp</type>
|
||||
<port>80</port>
|
||||
<txt-record value-format="text">product=$INFIX_NAME</txt-record>
|
||||
</service>
|
||||
</service-group>
|
||||
EOF
|
||||
cat <<EOF > "$TARGET_DIR/etc/avahi/services/https.service"
|
||||
<?xml version="1.0" standalone='no'?>
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
<service-group>
|
||||
<name replace-wildcards="yes">%h</name>
|
||||
<service>
|
||||
<type>_https._tcp</type>
|
||||
<port>443</port>
|
||||
<txt-record value-format="text">product=$INFIX_NAME</txt-record>
|
||||
</service>
|
||||
</service-group>
|
||||
EOF
|
||||
fi
|
||||
|
||||
@@ -80,6 +80,9 @@ BR2_PACKAGE_NETCALC=y
|
||||
BR2_PACKAGE_NETCAT_OPENBSD=y
|
||||
BR2_PACKAGE_NETSNMP=y
|
||||
BR2_PACKAGE_NFTABLES=y
|
||||
BR2_PACKAGE_NGINX=y
|
||||
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
|
||||
BR2_PACKAGE_NMAP=y
|
||||
BR2_PACKAGE_NMAP_NCAT=y
|
||||
BR2_PACKAGE_NMAP_NMAP=y
|
||||
@@ -137,12 +140,13 @@ BR2_PACKAGE_K8S_LOGGER=y
|
||||
BR2_PACKAGE_KEYACK=y
|
||||
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
|
||||
BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_NETBROWSE=y
|
||||
BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_LIBINPUT=y
|
||||
DISK_IMAGE_BOOT_BIN=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
|
||||
@@ -63,6 +63,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
|
||||
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_CA_CERTIFICATES=y
|
||||
BR2_PACKAGE_LIBSSH_OPENSSL=y
|
||||
BR2_PACKAGE_LIBSSH2=y
|
||||
@@ -91,6 +92,9 @@ BR2_PACKAGE_NETCALC=y
|
||||
BR2_PACKAGE_NETCAT_OPENBSD=y
|
||||
BR2_PACKAGE_NETSNMP=y
|
||||
BR2_PACKAGE_NFTABLES=y
|
||||
BR2_PACKAGE_NGINX=y
|
||||
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
|
||||
BR2_PACKAGE_NMAP=y
|
||||
BR2_PACKAGE_NMAP_NCAT=y
|
||||
BR2_PACKAGE_NMAP_NMAP=y
|
||||
@@ -165,12 +169,13 @@ BR2_PACKAGE_K8S_LOGGER=y
|
||||
BR2_PACKAGE_KEYACK=y
|
||||
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
|
||||
BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_NETBROWSE=y
|
||||
BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_LIBINPUT=y
|
||||
# SIGN_ENABLED is not set
|
||||
# GNS3_APPLIANCE is not set
|
||||
|
||||
@@ -75,6 +75,9 @@ BR2_PACKAGE_NETCALC=y
|
||||
BR2_PACKAGE_NETCAT_OPENBSD=y
|
||||
BR2_PACKAGE_NETSNMP=y
|
||||
BR2_PACKAGE_NFTABLES=y
|
||||
BR2_PACKAGE_NGINX=y
|
||||
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
|
||||
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
|
||||
BR2_PACKAGE_NMAP=y
|
||||
BR2_PACKAGE_NMAP_NCAT=y
|
||||
BR2_PACKAGE_NMAP_NMAP=y
|
||||
@@ -140,11 +143,12 @@ BR2_PACKAGE_K8S_LOGGER=y
|
||||
BR2_PACKAGE_KEYACK=y
|
||||
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
|
||||
BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_NETBROWSE=y
|
||||
BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
GNS3_APPLIANCE_RAM=512
|
||||
GNS3_APPLIANCE_IFNUM=10
|
||||
|
||||
@@ -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/netbrowse/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
config BR2_PACKAGE_NETBROWSE
|
||||
bool netbrowse
|
||||
select BR2_PACKAGE_DBUS
|
||||
select BR2_PACKAGE_DBUS_PYTHON
|
||||
select BR2_PACKAGE_PYTHON_FLUP
|
||||
help
|
||||
Advertises the initial $(HOSTNAME).local and network.local to
|
||||
give your device a http://network.local mDNS/SD browser.
|
||||
|
||||
UNIX socket available for fastcgi at /tmp/netbrowse.sock
|
||||
@@ -0,0 +1,25 @@
|
||||
################################################################################
|
||||
#
|
||||
# netbrowse
|
||||
#
|
||||
################################################################################
|
||||
|
||||
NETBROWSE_VERSION = 1.0
|
||||
NETBROWSE_SITE_METHOD = local
|
||||
NETBROWSE_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/netbrowse
|
||||
NETBROWSE_SETUP_TYPE = setuptools
|
||||
NETBROWSE_LICENSE = MIT
|
||||
NETBROWSE_LICENSE_FILES = LICENSE
|
||||
NETBROWSE_REDISTRIBUTE = NO
|
||||
|
||||
define NETBROWSE_INSTALL_EXTRA
|
||||
$(INSTALL) -D -m 0644 $(NETBROWSE_PKGDIR)/netbrowse.svc \
|
||||
$(FINIT_D)/available/netbrowse.conf
|
||||
ln -sf ../available/netbrowse.conf $(FINIT_D)/enabled/netbrowse.conf
|
||||
$(INSTALL) -d -m 755 $(TARGET_DIR)/etc/default
|
||||
echo "NETBROWSE_ARGS=\"network.local $(BR2_TARGET_GENERIC_HOSTNAME).local\"" \
|
||||
> $(TARGET_DIR)/etc/default/netbrowse
|
||||
endef
|
||||
NETBROWSE_POST_INSTALL_TARGET_HOOKS += NETBROWSE_INSTALL_EXTRA
|
||||
|
||||
$(eval $(python-package))
|
||||
@@ -0,0 +1,3 @@
|
||||
service env:-/etc/default/netbrowse log:prio:daemon.debug,tag:mdns \
|
||||
<!service/mdns/running> @www-data:www-data \
|
||||
[2345] netbrowse $NETBROWSE_ARGS -- Network browser
|
||||
@@ -0,0 +1 @@
|
||||
__pycache__/
|
||||
@@ -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.
|
||||
@@ -0,0 +1,38 @@
|
||||
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
|
||||
|
||||
A UNIX socket, for fastcgi, is created in `/tmp/netbrowse.sock` with
|
||||
permissions 0660 as the user and group the program is started as.
|
||||
|
||||
When using Finit this can be achieved with
|
||||
|
||||
service @www-data:www-data netbrowse network.local
|
||||
|
||||
In your Nginx server configuration, add:
|
||||
|
||||
location /browse {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/tmp/netbrowse.sock;
|
||||
}
|
||||
|
||||
For more a elaborate setup, you can have another server block:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name network.local;
|
||||
|
||||
location / {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/tmp/netbrowse.sock;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Avahi CNAME service over D-Bus advertiser
|
||||
"""
|
||||
|
||||
from .avahi_alias import AvahiAlias
|
||||
__all__ = ['AvahiAlias']
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Avahi CNAME alias class"""
|
||||
|
||||
from encodings.idna import ToASCII
|
||||
import dbus
|
||||
|
||||
class AvahiAlias:
|
||||
"""Import to your project and use publish_cname() for each name."""
|
||||
DBUS_NAME = 'org.freedesktop.Avahi'
|
||||
CLASS_IN = 0x01
|
||||
TYPE_CNAME = 0x05
|
||||
TTL = 60
|
||||
DBUS_PATH_SERVER = '/'
|
||||
DBUS_INTERFACE_SERVER = DBUS_NAME + '.Server'
|
||||
DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + '.EntryGroup'
|
||||
IF_UNSPEC = -1
|
||||
PROTO_UNSPEC = -1
|
||||
|
||||
def publish_cname(self, cname):
|
||||
"""Call this method for each alias to publish as a CNAME record."""
|
||||
bus = dbus.SystemBus()
|
||||
server = dbus.Interface(bus.get_object(self.DBUS_NAME, self.DBUS_PATH_SERVER),
|
||||
self.DBUS_INTERFACE_SERVER)
|
||||
group = dbus.Interface(bus.get_object(self.DBUS_NAME, server.EntryGroupNew()),
|
||||
self.DBUS_INTERFACE_ENTRY_GROUP)
|
||||
|
||||
rdata = self.create_rr(server.GetHostNameFqdn())
|
||||
cname = self.encode_dns(cname)
|
||||
|
||||
group.AddRecord(self.IF_UNSPEC, self.PROTO_UNSPEC, dbus.UInt32(0),
|
||||
cname, self.CLASS_IN, self.TYPE_CNAME, self.TTL, rdata)
|
||||
group.Commit()
|
||||
print("Published " + cname.decode())
|
||||
|
||||
@staticmethod
|
||||
def encode_dns(name):
|
||||
"""Internal"""
|
||||
out = []
|
||||
name = name.decode()
|
||||
for part in str(name).split('.'):
|
||||
if len(part) == 0:
|
||||
continue
|
||||
out.append(ToASCII(part))
|
||||
return b'.'.join(out)
|
||||
|
||||
@staticmethod
|
||||
def create_rr(name):
|
||||
"""Internal"""
|
||||
out = []
|
||||
for part in name.split('.'):
|
||||
if len(part) == 0:
|
||||
continue
|
||||
out.append(chr(len(part)).encode())
|
||||
out.append(ToASCII(part))
|
||||
out.append(b'\0')
|
||||
|
||||
return b''.join(out)
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Very basic mDNS scanner with HTML table renderer
|
||||
"""
|
||||
|
||||
from .mdns_hosts import MdnsHosts
|
||||
__all__ = ['MdnsHosts']
|
||||
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
Very basic mDNS scanner with HTML table renderer
|
||||
"""
|
||||
import subprocess
|
||||
|
||||
class MdnsHosts:
|
||||
"""mDNS scanner class using avahi-browse"""
|
||||
def hask(self):
|
||||
"""Check if avahi-browse has -k option"""
|
||||
try:
|
||||
result = subprocess.run(['avahi-browse', '--help'], check=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
return '-k' in result.stdout
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
def scan(self):
|
||||
"""Perform mDNS scan and return list of hosts."""
|
||||
services = {
|
||||
'_daap._tcp': ('iTunes Server', None),
|
||||
'_device-info._tcp': ('Device info', None),
|
||||
'_http._tcp': ('HTTP', 'http://{address}'),
|
||||
'_https._tcp': ('HTTPS', 'https://{address}'),
|
||||
'_ipp._tcp': ('Printer', None),
|
||||
'_ipps._tcp': ('Printer', None),
|
||||
'_netconf-ssh._tcp': ('NETCONF', None),
|
||||
'_raop._tcp': ('AirPlay ', None),
|
||||
'_ssh._tcp': ('SSH', None),
|
||||
'_sftp-ssh._tcp': ('SFTP', None),
|
||||
'_workstation._tcp': ('Workstation', None),
|
||||
}
|
||||
|
||||
result = subprocess.run(['avahi-browse', '-tarpk' if self.hask() else '-tarp'],
|
||||
stdout=subprocess.PIPE, text=True)
|
||||
lines = result.stdout.strip().split('\n')
|
||||
hosts_services = {} # Key: address, Value: list of dicts with service details
|
||||
|
||||
for line in lines:
|
||||
print(f"{line}")
|
||||
parts = line.split(';')
|
||||
if len(parts) <= 8 or parts[0] != '=':
|
||||
continue
|
||||
if (parts[2] != 'IPv4' and parts[2] != 'IPv6'):
|
||||
continue
|
||||
|
||||
service_type = parts[4]
|
||||
if service_type not in services:
|
||||
continue
|
||||
|
||||
service_name = parts[3]
|
||||
address = parts[7]
|
||||
identifier, url_template = services[service_type]
|
||||
url = url_template.format(address=address) if url_template else None
|
||||
|
||||
service_details = {
|
||||
'name': self.decode(service_name),
|
||||
'type': identifier,
|
||||
'link': parts[6],
|
||||
'url': url
|
||||
}
|
||||
if address not in hosts_services:
|
||||
hosts_services[address] = {'services': [service_details], 'type': parts[2]}
|
||||
else:
|
||||
hosts_services[address]['services'].append(service_details)
|
||||
|
||||
return hosts_services
|
||||
|
||||
def decode(self, name):
|
||||
"""Decode escape sequences like \032 and \040 in service names"""
|
||||
name = name.replace('\\032', ' ')
|
||||
name = name.replace('\\040', '(')
|
||||
name = name.replace('\\041', ')')
|
||||
return bytes(name, "utf-8").decode("unicode_escape")
|
||||
|
||||
def html(self):
|
||||
"""Generate a HTML table of the mDNS scan results"""
|
||||
hosts_services = self.scan()
|
||||
html_content = """
|
||||
<html>
|
||||
<head>
|
||||
<title>mDNS Hosts - Services</title>
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1024px;
|
||||
margin: auto;
|
||||
padding: 0 10px;
|
||||
}
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
|
||||
th { background-color: #f2f2f2; }
|
||||
tr:hover {background-color: #e8e8e8;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<input type="text" id="search" onkeyup="filter()" placeholder="Filter column ...">
|
||||
<table id="main">
|
||||
<tr><th>IP Address</th><th>Service Name</th><th>Link</th><th>Service Type</th></tr>
|
||||
"""
|
||||
|
||||
for address, info in hosts_services.items():
|
||||
for service in info['services']:
|
||||
service_name = service['name']
|
||||
service_type = service['type']
|
||||
link = service['link']
|
||||
url = service['url']
|
||||
if url:
|
||||
url = url.replace("127.0.0.1", link)
|
||||
link_html = f'<a href="{url}">{link}</a>'
|
||||
else:
|
||||
link_html = f'{link}'
|
||||
|
||||
html_content += f"<tr><td>{address}</td><td>{service_name}</td>"
|
||||
html_content += f"<td>{link_html}</td><td>{service_type}</td></tr>\n"
|
||||
|
||||
html_content += """
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
function filter() {
|
||||
var input, filter, table, tr, tdaddr, tdserv, i, addr, serv;
|
||||
input = document.getElementById("search");
|
||||
filter = input.value.toUpperCase();
|
||||
table = document.getElementById("main");
|
||||
tr = table.getElementsByTagName("tr");
|
||||
|
||||
for (i = 1; i < tr.length; i++) {
|
||||
tdaddr = tr[i].getElementsByTagName("td")[0];
|
||||
tdserv = tr[i].getElementsByTagName("td")[1];
|
||||
tdlink = tr[i].getElementsByTagName("td")[2];
|
||||
tdtype = tr[i].getElementsByTagName("td")[3];
|
||||
addr = tdaddr ? tdaddr.textContent || tdaddr.innerText : "";
|
||||
serv = tdserv ? tdserv.textContent || tdserv.innerText : "";
|
||||
link = tdlink ? tdlink.textContent || tdlink.innerText : "";
|
||||
type = tdtype ? tdtype.textContent || tdtype.innerText : "";
|
||||
|
||||
if (addr.toUpperCase().indexOf(filter) > -1 ||
|
||||
serv.toUpperCase().indexOf(filter) > -1 ||
|
||||
link.toUpperCase().indexOf(filter) > -1 ||
|
||||
type.toUpperCase().indexOf(filter) > -1) {
|
||||
tr[i].style.display = "";
|
||||
} else {
|
||||
tr[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return html_content
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Main server loop.
|
||||
"""
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
from flup.server.fcgi import WSGIServer
|
||||
|
||||
from avahi_alias import AvahiAlias
|
||||
from mdns_hosts import MdnsHosts
|
||||
|
||||
SOCK_FILE='/tmp/netbrowse.sock'
|
||||
|
||||
def app(_, start_response):
|
||||
"""The /browse network.local application"""
|
||||
mdns_hosts = MdnsHosts()
|
||||
content = mdns_hosts.html().encode('utf-8')
|
||||
|
||||
start_response('200 OK', [('Content-Type', 'text/html'), ('Content-Length', str(len(content)))])
|
||||
return [content]
|
||||
|
||||
def cleanup():
|
||||
"""Clean up on server shutdown"""
|
||||
try:
|
||||
os.remove(SOCK_FILE)
|
||||
except OSError:
|
||||
pass
|
||||
sys.exit(0)
|
||||
|
||||
def __sigcb(_, __):
|
||||
cleanup()
|
||||
|
||||
if __name__ == '__main__':
|
||||
avahi_aliases = AvahiAlias()
|
||||
for each in sys.argv[1:]:
|
||||
avahi_aliases.publish_cname(str(each).encode("utf-8", "strict"))
|
||||
|
||||
signal.signal(signal.SIGINT, __sigcb)
|
||||
signal.signal(signal.SIGTERM, __sigcb)
|
||||
|
||||
try:
|
||||
# For testing on PC as $USER, add: , umask=0
|
||||
WSGIServer(app, bindAddress=SOCK_FILE).run()
|
||||
except KeyboardInterrupt:
|
||||
cleanup()
|
||||
print("Exiting")
|
||||
@@ -0,0 +1,5 @@
|
||||
[metadata]
|
||||
name = Network Browser
|
||||
description = An mDNS CNAME advertiser over D-Bus and mDNS Browser (fcgi)
|
||||
version = 1.0
|
||||
license_files = LICENSE
|
||||
@@ -0,0 +1,10 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
packages=find_packages(),
|
||||
scripts=['netbrowse'],
|
||||
install_requires=[
|
||||
'dbus-python',
|
||||
'flup'
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user