LocalSend - file sharing locally with WiFi

LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection. Basically, a platform neutral “airdrop”.

More about LocalSend

LocalSend is a cross-platform app that enables secure communication between devices using a REST API and HTTPS encryption. Unlike other messaging apps that rely on external servers, LocalSend doesn’t require an internet connection or third-party servers, making it a fast and reliable solution for local communication. The TLS/SSL certificate is generated on the fly on each device, ensuring maximum security. For more info, see the LocalSend protocol documentation.

This guide provides a step-by-step implementation of LocalSend in Qubes r4.2 as provided by @etaz in the following thread. While relatively easy to implement, this method does not enable LocalSend in Qubes to automatically discover other devices on the network. Manual discovery is simple if one knows the ip address of another device, so it’s not a significant barrier to ease of use. An alternative implementation by @WillyJL allows discovery in both directions, but requires a more complicated setup.

General Notes

LocalSend requires devices to be on the same subnet, so will not work if either device is tunneling traffic with a VPN. Use of disposable qubes is assumed below, but is not necessary.

1. Create localsend qube (as named disposable)

LocalSend is available as flatpak or snap packages, but not yet with extrepo. This guide assumes flatpak integration in the template, but any installation method will do.

#in template-with-flatpak terminal$ 

export all_proxy=http://127.0.0.1:8082/
flatpak install flathub org.localsend.localsend_app

Use Qubes Tools to create the named disposable, localsend. Disposability is optional, but should be named.

Application Menu (Q) → Settings (Gear) → Qubes Tools → Create New Qube → Named disposable

Name: localsend
Label: <COLOR>
template: <FLATPAK-DVM-TEMPLATE>
Network: sys-firewall
Applications: + LocalSend + Open File Manager

Optional: Edit Qubes firewall to allow localsend traffic to only local subnet IPs (eg, 192.168.1.0/24). Allow both TCP and UDP protocols.

2. Save script in (the disposable template of) sys-net

For the following, we’ll assume sys-net is a disposable qube. If not, then skip the first part and create the script directly in sys-net.

Edit a file, for example temp_localsend.sh, to include the following script and copy the file from this qube, <FORUM-QUBE>, to the disposable template of sys-net.

#!/bin/sh
# script courtesy of @etaz on forum.qubes-os.org

if_lan=<your LAN network interface>
ip=$(ip -f inet addr show $if_lan | sed -En -e 's/.*inet ([0-9.]+).*/\1/p')
port=53317

case $1 in
  start)
    qvm-connect-tcp ::$port
    nft add rule ip qubes custom-input ip daddr $ip tcp dport $port ct state new accept
    ;;
  stop)
    pkill -f "socat TCP-LISTEN:$port"
    nft flush chain ip qubes custom-input
    ;;
  *)
    >&2 echo "usage: $0 start|stop"
    exit 1
    ;;
esac
Note on nftables

@etaz “You should adjust the line nft flush chain ip qubes custom-input if you have other port forwarding rules you want to keep, when stopping this script.”

The script will require root privileges. Create a file in the sys-net disposable template and read/write the contents of the temporary file.

#in sys-net disposable template as root# 

touch /usr/local/bin/localsend_forward.sh
cat /home/user/QubesIncoming/<FORUM-QUBE>/temp_localsend.sh >> /usr/local/bin/localsend_forward.sh

Finally, tailor the script to your specific LAN interface.

#in sys-net terminal$ 

ip addr show

This will display a numbered list with at least 3 entries. Ignore the lo and vif+ entries. Your LAN interface will be something like eth*, en*, or wl*, and be associated with an ip like 192.168.x.x, 172.16.x.x, or 10.x.x.x, listed after inet. Replace <wl*> below with your specific interface and edit the script.

#in sys-net disposable template as root# 

sed -i 's/<your LAN network interface>/<wl*>/g' /usr/local/bin/localsend_forward.sh

3. Configure qubes policy to allow LocalSend port forwarding

#in dom0 terminal$ 

echo "qubes.ConnectTCP +53317 sys-net @default allow target=localsend" >> /etc/qubes/policy.d/30-user.policy

4. Execute the script

If you share files infrequently, then consider running the script manually as needed.

#in sys-net terminal$

sudo bash /usr/local/bin/localsend_forward.sh start

Otherwise, for automatic starts, make the script executable and modify /rw/config/rc.local in the disposable template.

#in sys-net disposable template as root#

chmod +x /usr/local/bin/localsend_forward.sh
echo "sudo /usr/local/bin/localsend_forward.sh start" >> /rw/config/rc.local

Verify that /usr/local/bin/localsend_forward.sh exists with if_lan properly defined and restart sys-net.

Note on auto start

Running the script automatically can be unreliable (if sys-net does not connect to the network before the script runs?). Manually stopping and starting the script after sys-net has made a connection seems to work fine though.

5. Add favorite devices in LocalSend

Other devices on the subnet should discover your Qubes LocalSend instance, perhaps after a refresh, and identify it with a randomly generated two word name, a number #xxx (the final octet in ipv4 of sys-net), and as a Linux device. Sending to Qubes is straightforward.

With this setup, LocalSend in Qubes will not be able to discover other devices on the subnet. However, with an ip address you can manual send (arrow icon) or you can favorite a device (Send → Heart icon → Add → IP Address) and then send by selecting Favorites and choosing the manually discovered device.

2 Likes

Great Tutorial, just changed this line:

to

if_lan=$2

So you can start the script with:

#in sys-net terminal$

sudo bash /usr/local/bin/localsend_forward.sh start eth0

In my case it is either lan or wifi so I want to start it on the one or the other…

1 Like