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

a) Run manually from sys-net terminal

#in sys-net terminal$

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

b) Create Starter Shortcut

#create new starter object with following command
qvm-run sys-net 'xfce4-terminal -e "sudo bash /usr/local/bin/localsend_forward.sh"'

c) Automatic Start

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

In case you want to add a Shortcut to the Starter to run the Forward script in sys-net:

qvm-run sys-net 'xfce4-terminal -e "sudo bash /usr/local/bin/localsend_forward.sh start eth0"'
1 Like

I need some clarification on the setup. I installed this as described and it worked. I was able to send a file to the sys-net qube. Then I setup the alternate setup with the bidirectional discovery however, I can send a file out from the cube to the cell but I can’t send file from cell to the qube (sys-net).

What am I missing? Also are we supposed to be able to run LocalSend on any qube or it has to be sys-net?

I would not recommend running LocalSend in sys-net, but it could be run in the qube of your choice. This guide describes how to set up a dedicated LocalSend qube, then to allow for making connections to another LAN client thru sys-net.

I haven’t tried the bidirectional setup linked above, but in general discovery can be tricky. When sending from the cell to the Qubes machine first manually identify the IP address of the latter, then in the cell select the manual option to identify the Qubes device (arrow/target icon), select IP Address and type it in manually. Occasionally the devices will not recognize each other. I have yet to figure out how to resolve this, but have always managed make a connection. Sometimes stopping and restarting the script in sys-net is sufficient, but iirc I’ve also had to restart sys-net or the devices themselves.

Ok, so with the localsend qube, I’ll fire up LocalSend, then from the cell enter the LAN IP of qube? (e.g. the 192.168.x.x address)? Or the internal 10.x address.

Enter the LAN IP, 192.168.x.x, as the manual choice in your cell. The router will not be able to see your internal 10.x IPs.

I’m getting a timeout unfortunately. To clarify I’m running it from LocalSend qube and not sys-net or any other qube. The config also target=localsend

There are lots of moving parts… I usually default to restarting the sys-net script, since that’s easy and often solves the problem. Next I’d return to the LocalSend qube and try sending to the cell again, to verify that direction is still working.

Ok, I just cleaned up the other implementation and going to restart my machine to clear things up. I’ve solely implemented your solution and will try again if it works. It worked before but as you’ve said wasn’t consistent.
BTW would kdeconnect work with this? That’s what got me on this path.

Sometimes it’s finicky and sometimes it just works. :person_shrugging:

I know others have used kdeconnect with Qubes. I haven’t tried it myself, so cannot verify that it would work with this setup, but might be worth trying

it would be great if you tried! haha. At least I can get the file transfer working with LocalSend then I will be halfway there. I also use the SMS feature with kdeconnect

1 Like

Ok I can confirm this works. Yeah it’s flaky but works. Maybe I’ll try the other solution when someone else confirms it works for them.