Merge branch 'args-and-config'

See CHANGELOG.md for details
This commit is contained in:
Pranav Jerry 2021-08-19 12:49:18 +05:30
commit 1a6dbc4bcb
No known key found for this signature in database
GPG Key ID: F1DCDC4FED0A0C5B
14 changed files with 623 additions and 163 deletions

26
CHANGELOG.md Normal file
View File

@ -0,0 +1,26 @@
# Changelog
## [Unreleased][] - 2021-08-19
- Support for arguments
- Configuration file support with fallback values
- Made messages more readable
- Improved documentation in docstrings
- Changed default name of mesh network. **This will make naxalnet
incompatible with nodes running previous versions.**
- New versioning scheme that conforms to PEP 440
## [v0.2.0][] - 2021-07-26
- rfkill support
- rewrite into python module
## [v0.1.0][] - 2021-06-19
Initial version. At first, this was a shell script. Than it was converted
into a single python file that did just what the shell script used to do.
The shell script was not given a version.
[unreleased]: https://git.disroot.org/pranav/naxalnet/compare/v0.2.0...HEAD
[v0.2.0]: https://git.disroot.org/pranav/naxalnet/compare/v0.1.0...v0.2.0
[v0.1.0]: https://git.disroot.org/pranav/naxalnet/releases/tag/v0.1.0

View File

@ -1,7 +1,6 @@
# Hacking
Everyone <!-- including anti-nationals and urban naxals are -->
is welcome to [hack][] naxalnet. See below for how to hack.
Everyone can [hack][] naxalnet. See below for how to hack.
## Reporting issues and suggesting ideas
@ -9,14 +8,23 @@ To report a bug or suggest an idea, create a new issue at
<https://git.disroot.org/pranav/naxalnet/issues> with a
relevant label.
## Improving documentation
The README and HACKING.md needs to be more beginner friendly.
See section below.
## Contribute code
To push to this repo, you need your username to be in the
contributors list. See issue #8.
contributors list. Add your username to issue #8 to add you
as a contributor. Before each commit, update the CHANGELOG.md
and `__version__` in `naxalnet/__init__.py`
## Packaging
naxalnet needs distro packages in Debian, Fedora, openSUSE,
Currently this program is only packaged for Arch Linux.
naxalnet needs packages in GNU+Linux+systemd
distributions such as Debian, Fedora, openSUSE,
and nixos. If you know/like to package it in your distro,
post to issue #6.

View File

@ -1,4 +1,5 @@
include LICENSE
include README.md
include naxalnet.service
include systemd-networkd/*
include naxalnet.conf.example
recursive-include systemd-networkd *

View File

@ -1,11 +1,27 @@
# This makefile uses setup.py under the hood
# This makefile uses setup.py under the hood.
# In ubuntu, python and pip are symlinks to python2 and pip2, not
# python3. So we have to specify python as python3 by default.
PYTHON := python3
PIP := pip3
DESTDIR:= /
all: build
build:
python3 setup.py build
$(PYTHON) setup.py build
install: build
python3 setup.py install --root="$(DESTDIR)/" --optimize=1 --skip-build
$(PYTHON) setup.py install --root="$(DESTDIR)" --optimize=1 --skip-build
uninstall:
$(PIP) uninstall -y naxalnet
rm -rf /usr/share/naxalnet /usr/lib/systemd/system/naxalnet.service
@-test -d /etc/naxalnet && echo "The directory /etc/naxalnet was not removed." && \
echo "Do 'sudo make purge' to remove it."
# remove config files, like apt purge
purge: uninstall
rm -rf /etc/naxalnet
clean:
rm -rf build naxalnet.egg-info
rm -rf build naxalnet.egg-info **/__pycache__

241
README.md
View File

@ -1,32 +1,32 @@
# naxalnet
**naxalnet** is a program to create a wireless mesh network for
communicating with each other. It can be useful during an internet
shutdown, or to join online classes with a group of laptops.
It uses [B.A.T.M.A.N. Advanced][batman-adv],an implementation
communicating with each other. It can be useful during an
[internet shutdown](#internet-shutdown), or to join
[online classes](#online-class-in-remote-areas) with a group
of laptops.
It uses [B.A.T.M.A.N. Advanced][batman-adv], an implementation
of the B.A.T.M.A.N. routing protocol to communicate with peers.
The name naxal comes from Naxalbari, a village in Darjeeling,
West Bengal.
WARNING:
This program uses an unencrypted network. This means,
you do not get any more privacy or security than with an open wifi
This program uses an **unencrypted** network. This means
you do not get any more privacy or security than with an open WiFi
network.
<!-- NOTE TO ACTIVISTS
Running this program in the world's largest partly free democracy
Running this program in the world's largest partly-free democracy
may result in you getting arrested under the UAPA, and not
getting bail because of false evidence planted in your phone by
Pegasus, or by a forensic lab in Gujarat.
The author, not unlike the Government of India, does not wish
The author, much like the Government of India, does not wish
to take responsibility in your well-being if you get arrested under
a draconian national security law, which was once used to arrest
a person involved in the freedom struggle against British Raj.
a draconian national security law.
-->
The name naxal comes from Naxalbari, a village in Darjeeling,
West Bengal.
<!-- UNCOMMENT WHEN NECESSARY
**Disclaimer**:
@ -34,7 +34,7 @@ In case you are either 1) a complete idiot; or 2) a member of the saffron
brigade; or 3) both, please be aware that this project is not affiliated
with any groups designated as "terrorist" groups in India.
Using the name Naxal does not imply any form of connection
Using the name naxal does not imply any form of connection
with anyone currently at risk of death in overcrowded prisons.
-->
@ -44,16 +44,19 @@ with anyone currently at risk of death in overcrowded prisons.
- [systemd v248 or more][batman-systemd]
- Linux kernel with batman-adv module
- [iwd][]
- python3
- python-setuptools (for building)
- [python-dasbus][]
- wifi adapter with ad-hoc support
- two or more computers, or laptops with wifi adapter, called nodes
- systemd-resolved (optional, for DNS)
- python
- python-setuptools (for building and installing)
- [dasbus][]
- WiFi adapter with ad-hoc support
- two or more computers, or laptops with WiFi adapter, called nodes
- batctl (optional, for debugging)
- python pip (optional, for uninstalling)
## Installing
This program is available in the AUR for Arch users. Building
manually for other distributions may not always work.
### Arch Linux
Install [naxalnet][aur] (or [naxalnet-git][aur-devel] for the
@ -64,28 +67,69 @@ yay -S naxalnet
```
Optionally, [setup systemd-resolved][arch-resolved] for DNS if any
of the nodes have internet access.
of the nodes have internet access. [Start naxalnet][startnx] when
you need it.
### Ubuntu
naxalnet is not packaged for Ubuntu, so you will have to build
and install it manually.
Currently, only the [unreleased 21.10][ubuntu-systemd] comes with the
required version of systemd. Therefore, naxalnet won't work on Ubuntu
21.04 or older.
<!-- TODO: remove this message when systemd 248 arrives in 21.04 -->
Install the requirements from the Ubuntu repositories:
```sh
# batctl is optional
sudo apt install systemd python3-pip iwd batctl build-essential
# Now, install dasbus with pip
sudo pip3 install dasbus
```
Now follow the instructions in the
[manual installation section][install-manual]
### Fedora
naxalnet is not packaged for Fedora, so it should be installed
manually. naxalnet requires atleast systemd v248 which is only
available on Fedora 34 and above. Install the dependencies:
```sh
# systemd-resolved may be required for rawhide
sudo dnf install systemd-networkd iwd python3-dasbus python3-setuptools
```
Now head over to the [next section][install-manual] to install naxalnet.
### Manually
Clone the repo and cd into it.
Install the [requirements][requirements].
Clone the naxalnet repo and cd into it.
```sh
git clone https://git.disroot.org/pranav/naxalnet.git
cd naxalnet
```
Or, if you have an [IPFS client][ipfs] running, try:
Or, if you have an [IPFS client][ipfs] running, try this instead:
```sh
git clone http://k51qzi5uqu5dlye74be0n9iihwk6sm54vexo7bf7pdr4w811y6mmrcp25djozv.ipns.localhost:8080/naxalnet.git
```
Run `sudo make install` to install naxalnet. This will install naxalnet in
`/usr/bin/naxalnet`.
Now, install naxalnet:
After installing, reload systemd so that you can enable `naxalnet.service`
without rebooting:
```sh
sudo make install
```
After installing, reload systemd so that it detects the new
service files:
```sh
sudo systemctl daemon-reload
@ -93,53 +137,50 @@ sudo systemctl daemon-reload
## How to use
You need more than one computer running for the connection to work.
You need more than one machine running naxalnet for the connection to work.
### Start naxalnet
Though naxalnet can run from the commandline, it was designed to be
run as a systemd service.
To start naxalnet, do the command on all the nodes:
```sh
sudo systemctl start naxalnet.service
```
To test if it works, run `ip -c addr` to find out your address.
Note the `inet` address of `bridge0`. If there isn't one, try again
after a few seconds. If the address starts with 169.254, it has
got a link-local address. Otherwise, it has got an IP address
from DHCP.
This will start a mesh network and connect to all nodes.
To test if it works, run `sudo batctl n -w` and check for
nodes. If there are any nodes, your network is up.
### Getting internet access
Connect an ethernet cable to any of the peers and
[start naxalnet][startnx]. Now all the peers should
be able to connect after renewing their DHCP connection
(`sudo networkctl renew bridge0`).
Connect an ethernet cable from a router to any of the peers and
[start naxalnet][startnx]. If it was already started, you should
renew the DHCP connection of all peers. To do this, type
`sudo networkctl renew bridge0` on all peers.
### Tethering via WiFi AP
If there are two adapters in a peer, naxalnet will start a
wifi ap (wifi hotspot) on one of them.
WiFi ap (also called WiFi hotspot) on one of them.
Connect two WiFi adapters on a device and [start naxalnet][startnx].
Now an ap will be started on one of the adapters.
Type `naxalnet --print-WiFi` to get the WiFi SSID and password.
Connect two wifi adapters on a device and [start naxalnet][startnx].
Now an ap will be created on one of the adapters with
SSID `NaxalNet` and password `naxalnet256`.
If you had set up internet access on one of the peers, internet
can be accessed from the AP.
### Running at boot
Starting the service will stop `NetworkManager.service` and
`wpa_supplicant.service` if it is running. If you start either of these
services after naxalnet was started, systemd will stop naxalnet.
To run naxalnet at boot, enable the service on all the nodes:
```sh
sudo systemctl enable naxalnet.service
```
Now naxalnet will configure a batman interface on every boot.
Now naxalnet will start a mesh on every boot.
Disable the service to stop running at boot:
```sh
@ -149,10 +190,7 @@ sudo systemctl disable naxalnet.service
### Stopping the service
```sh
# Stop the services
sudo systemctl stop naxalnet systemd-networkd systemd-resolved iwd
# Delete the virtual interfaces created by naxalnet
sudo networkctl delete bat0 bridge0
sudo systemctl stop naxalnet iwd systemd-networkd systemd-resolved
```
If your distribution uses NetworkManager, starting `naxalnet.service`
@ -162,61 +200,112 @@ will have stopped it. Start NetworkManager again:
sudo systemctl start NetworkManager.service
```
### Configuration
naxalnet comes with a sample configuration file
`/etc/naxalnet/naxalnet.conf.example`. To change how the program
behaves, copy it to /etc/naxalnet/naxalnet.conf and edit it:
```sh
sudo cp /etc/naxalnet/naxalnet.conf{.example,}
# Now edit the file with your favourite editor as root
gedit admin:/etc/naxalnet/naxalnet.conf
```
Also, you can change its behaviour every time you run it using
arguments:
```sh
naxalnet --help
```
## How it works
The program naxalnet copies some `systemd-networkd` configuration files
into networkd's runtime configuration directory. It uses iwd to start
an ad-hoc network named "HelloWorld". See the
[systemd-networkd](systemd-networkd) directory
to see how systemd-networkd configures the network. You can use
services like [IPFS][], [Jami][], [Secure Scuttlebutt][ssb]
There are three modes commonly supported by WiFi adapters -
`ap` (WiFi hotspot), `station` (for joining WiFi networks) and `ad-hoc`
(for decentralised networks). There are some other modes too,
like `p2p` (WiFi direct), but we won't go into the details.
naxalnet uses two modes - `ad-hoc` and `ap`, for connecting to the
mesh. naxalnet uses iwd to start an `ad-hoc` network and configures
systemd-networkd to setup a BATMAN Advanced network.
If there are two WiFi adapters connected to the machine,
naxalnet starts an ad-hoc on one of them and an ap on the other.
You can use the ap for connecting mobile phones and other devices
to the mesh network.
Read the code to learn the details.
See [systemd-networkd](systemd-networkd) to see how
systemd-networkd configures the network.
## Use cases
### Online class in remote areas
naxalnet can be used to share connections in remote areas.
You need at least one device with internet access.
### Internet shutdown
You can communicate with neighbouring devices running naxalnet,
using services like [IPFS][], [Jami][], [Secure Scuttlebutt][ssb]
and others which can work on an intranet.
They should be installed on your machine _before_ your friendly
democratic government announces an [internet shutdown][], since you
cannot download and install them during a shutdown.
When a shutdown occurs, [enable naxalnet][enablenx]
## Uninstalling
If you installed naxalnet manually, there is no way to uninstall
than manually removing the files:
If you installed naxalnet manually, use make uninstall to remove
naxalnet and its data files. This requires python pip to be installed.
```sh
sudo pip uninstall naxalnet
sudo rm -rf /usr/share/naxalnet* /usr/lib/systemd/system/naxalnet.service
# Uninstall the program, keeping the config files
sudo make uninstall
# Or, to uninstall and remove config files
sudo make purge
```
## Contributing
## Contributing or reporting bugs
See [HACKING.md](HACKING.md)
## Similar projects
The following projects are similar to naxalnet, but are not designed
to be used in a laptop or computer with wifi adapter. If you live in
to be used in a machine with WiFi adapter. If you live in
an area where the materials required for any of them are easily
available, consider using them instead of naxalnet.
- [LibreMesh][libremesh]: framework for OpenWrt-based
firmwares
- [LibreMesh][]: framework for OpenWrt-based firmwares
- [disaster.radio][]: solar-powered communications network
## License
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
naxalnet is [free/libre/swatantra][free-sw] and open source software;
you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation,
eitherversion 3 of the License, or (at your option) any later version.
See [LICENSE](LICENSE) for the complete version of the
license.
See [LICENSE](LICENSE) for the complete version of the license.
[batman-adv]: https://www.open-mesh.org/projects/batman-adv/wiki
[ipfs]: https://ipfs.io
[internet shutdown]: https://internetshutdowns.in
[ipfs]: https://ipfs.io "InterPlanetary File System"
[jami]: https://jami.net "Peer to peer video calls"
[ssb]: https://scuttlebutt.nz "Secure Scuttlebutt"
[python-dasbus]: https://github.com/rhinstaller/dasbus "Python D-Bus library"
[dasbus]: https://github.com/rhinstaller/dasbus "A python D-Bus library"
[aur]: https://aur.archlinux.org/packages/naxalnet
[aur-devel]: https://aur.archlinux.org/packages/naxalnet-git
[arch-resolved]: https://wiki.archlinux.org/title/Systemd-resolved#DNS
[batman-systemd]: https://www.open-mesh.org/news/101
[arch-resolved]: https://wiki.archlinux.org/title/Systemd-resolved#DNS "systemd-resolved on ArchWiki"
[batman-systemd]: https://www.open-mesh.org/news/101 "systemd v248 brings support for batman advanced"
[libremesh]: https://libremesh.org
[disaster.radio]: https://disaster.radio/
[disaster.radio]: https://disaster.radio
[startnx]: #start-naxalnet
[iwd]: https://iwd.wiki.kernel.org "wifi daemon"
[iwd]: https://iwd.wiki.kernel.org "WiFi daemon"
[free-sw]: https://gnu.org/philosophy/free-sw.html "What is free software?"
[enablenx]: #running-at-boot
[ubuntu-systemd]: https://packages.ubuntu.com/impish/systemd
[requirements]: #requirements
[install-manual]: #manually

22
naxalnet.conf.example Normal file
View File

@ -0,0 +1,22 @@
# This configuration file is part of naxalnet.
# To configure this program, rename this file
# to naxalnet.conf and edit it.
# The values given here are defaults.
[networkd]
# systemd-networkd configuration files bundled with naxalnet.
# THese will be copied to runtimedir at runtime.
confdir = /usr/share/naxalnet/networkd
# systemd-networkd runtime configuration directory.
# See man:systemd.network(5)
runtimedir = /run/systemd/network
[adhoc]
# All your nodes should have the same name
name = NxMesh
[ap]
# An AP is started if your machine has more than one WiFi adapter.
ssid = MeshWiFi
passwd = naxalnet256

View File

@ -1,18 +1,16 @@
# naxalnet systemd service
# The naxalnet systemd service
# See man:systemd.service(5) and man:systemd.unit(5)
# before editing this file.
[Unit]
Description=Naxalnet
Description=Setup mesh networks
Requires=systemd-networkd.service
Requires=iwd.service
Wants=systemd-resolved.service
# naxalnet does not reload networkd, so networkd
# should be started only afer naxalnet exits
Before=systemd-networkd.service
After=iwd.service
# Stops NetworkManager and wpa_supplicant if already running
Conflicts=NetworkManager.service
Conflicts=wpa_supplicant.service
# This stops networkmanager and wpa_supplicant when naxalnet is enabled
After=NetworkManager.service
After=wpa_supplicant.service
@ -20,13 +18,30 @@ After=wpa_supplicant.service
Type=oneshot
RemainAfterExit=yes
Restart=on-failure
# Probably not needed now
RestartSec=2sec
# IWD takes some time to find devices.
# Without the delay, naxalnet could not detect the second
# device while testing.
# If naxalnet is run before iwd finds devices,
# naxalnet cannot start a mesh network but exits without errors.
# So, we give a 2s delay.
ExecStartPre=/usr/bin/sleep 2
ExecStart=/usr/bin/naxalnet
# Reload systemd-networkd after naxalnet exits
ExecStartPost=/usr/bin/networkctl reload
# Delete all files in /run/systemd/network
ExecStop=/usr/bin/find /run/systemd/network -type f -delete
# Delete the interfaces created...
ExecStopPost=/usr/bin/networkctl delete bridge0 bat0
# ... and reload the configuration files.
ExecStopPost=/usr/bin/networkctl reload
# Make python flush messages instead of buffering.
# When reading the systemd journal, we need to see the messages
# in the exact order. There will suddenly be a lot of messages
# from naxalnet, networkd, iwd and resolved. When buffering is on,
# we won't see the messages from naxalnet in the order they were
# printed. This, among other problems, make it hard while debugging.
# This will no longer be needed when naxalnet sends its messages
# directly to the systtemd journal instead of stdout.
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target

View File

@ -15,5 +15,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
naxalnet
========
__version__ = "0.2.0a"
Create mesh networks with batman-adv, systemd-networkd and iwd.
See README.md for documentation.
"""
# GUIDE FOR CHANGING __version__
#
# All commits in master should have the version as
# {last published version tag}.a{1,2,3,...}
# example: 0.2.0a3 should mean 3 commits after tag v0.2.0
#
# All commits in other branches should
# have {version in master}.dev{1,2,...}
# example: 0.2.0a3.dev1 should mean 1 commit in the new
# branch after the commit in master.
#
# In case you forgot to change the version, skip the number
# and put the next number in the next commit.
__version__ = "0.2.0a4"

View File

@ -15,6 +15,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
If called as python -m naxalnet, this file makes naxalnet run like
it was called from the commandline. Try:
python -m naxalnet --help
"""
from naxalnet.scripts import here_be_dragons

144
naxalnet/config.py Normal file
View File

@ -0,0 +1,144 @@
#!/usr/bin/env python3
"""
config.py
---------
This file contains functions to parse configuration files
and arguments. Most of these functions are meant to be used
by parse_args() internally, so only parse_args() should
be imported outside this file.
Some parts of naxalnet can be configured by configuration
files and arguments. First, the default values from
default.py is taken. Then, key-value pairs from the
configuration files are read, if they exist, in the
following order:
- First it reads /usr/share/naxalnet/naxalnet.conf
and then from /usr/share/naxalnet/naxalnet.conf.d/*.conf
where *.conf means any file with the name ending with
".conf". The files in this directory are intended
to be used by distribution and package maintainers.
- Next, it does the same with /usr/local/share/naxalnet
- Then, it looks for the files naxalnet.conf and
naxalnet.conf.d/*.conf from the directory
/etc/naxalnet, like it did up above. This directory is where
the user creates and stores the config file.
- Then it parses the arguments from the commandline,
storing the values in the files parsed until now
as fallback. Finally you get an argpase.Namespace object
from parse_args().
Because of the way this is implemented, all key-value
pairs in the configuration should have an argument
too, or they won't be parsed.
All the key-value pairs are replaced successively if they exist
by each new configuration file parsed, similar
to how systemd parses configuration and service files.
If any of the files checked does not exist, then they are
ignored and the next combination is checked. If none of
the config files exist and no arguments are given, the
fallback data from default.py is used.
"""
from pathlib import Path
from configparser import ConfigParser
from argparse import ArgumentParser, Namespace
from naxalnet.default import CONFIG, CONFIG_FILES, CONFIG_DIRS
def get_config_files():
"""
Read list of configuration files and return a list
of files that exists as pathlib.Path objects
"""
config_files = []
for directory in CONFIG_DIRS:
path = Path(directory)
if path.exists():
for i in CONFIG_FILES:
glob = path.glob(i)
config_files.extend(glob)
return config_files
def parse_config():
"""
Parse all configuration files, with the values in
default.py as fallback
"""
parser = ConfigParser()
# encoded defaults
parser.read_dict(CONFIG)
# read config files
files = get_config_files()
for i in files:
parser.read_file(i.open())
return parser
def parse_args() -> Namespace:
"""
Parse all arguments and return ArgumentParser.parse_args(),
with values in config files as fallback. Ideally, only this
function should be used by naxalnet to get arguments and
configuration.
"""
config = parse_config()
parser = ArgumentParser(
description="setup batman-adv networks with systemd and iwd"
)
parser.add_argument(
"--ap-ssid",
"-n",
type=str,
help="SSID of the WiFi AP",
default=config["ap"]["ssid"],
)
parser.add_argument(
"--ap-passwd",
"-p",
"--ap-password",
type=str,
help="password of the WiFi AP",
default=config["ap"]["passwd"],
)
parser.add_argument(
"--adhoc-name",
"-a",
type=str,
default=config["adhoc"]["name"],
help="name of adhoc network",
)
parser.add_argument(
"--print-wifi",
action="store_true",
default=False,
help="prints the ssid and password of the WiFi network and exit",
)
parser.add_argument(
"--networkd-config-dir",
type=str,
default=config["networkd"]["confdir"],
help="the directory where systemd-networkd configuration files are stored",
)
parser.add_argument(
"--networkd-runtime-dir",
type=str,
default=config["networkd"]["runtimedir"],
help="volatile directory where configuration files of systemd-networkd should be copied",
)
parser.add_argument(
"--version",
default=False,
action="store_true",
help="prints the version and exit",
)
return parser.parse_args()

26
naxalnet/default.py Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
"""
default.py
----------
This file contains default values for configuration.
This is taken as fallback data by config.py if no
configuration files were found, or if a key-value pair
was not present in the config file. The data will be
further changed by arguments if naxalnet is called
from the commandline. See config.py for more info.
"""
CONFIG = {
"networkd": {
"confdir": "/usr/share/naxalnet/networkd",
"runtimedir": "/run/systemd/network",
},
"adhoc": {"name": "NxMesh"},
"ap": {"ssid": "MeshWiFi", "passwd": "naxalnet256"},
}
# glob
CONFIG_FILES = ["naxalnet.conf", "naxalnet.conf.d/*.conf"]
CONFIG_DIRS = ["/usr/share/naxalnet", "/usr/local/share/naxalnet", "/etc/naxalnet"]

View File

@ -16,7 +16,48 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Manage wifi adapter via iwd D-Bus api"""
"""
iwd.py
------
This file contains methods to communicate with iwd via
its D-Bus API and control WiFi adapters.
Some terms used here, such as device and adapter might
confuse you if you haven't used iwctl before.
Just as a quick reference, here is a list of terms
and what they mean:
- ad-hoc: a mode supported by some WiFi adapters to
start a decentralised network, where there
is no central point of failure.
- ap: a mode used to start a central access point
so that other machines without naxalnet can
connect to the mesh. AP is also known as
WiFi hotspot.
- station: this is the mode most WiFi adapters use
by default. This mode is used to connect to
an ap. naxalnet DOES NOT use this mode.
- adapter: a physical WiFi chip or something similar
that is present inside most laptops and phones
or can be connected via USB to a machine.
- device: an interface provided by the kernel to control
an adapter. Some adapters can have multiple
devices so that you can start an ap on one device
and an ad-hoc on the other. By default, iwd starts
only one device each for one adapter.
- machine: Since iwd uses the term device for a
WiFi interface, we use the word machine to
refer to a computer, or a laptop, or a phone.
- node: a machine that runs naxalnet and is therefore
connected to the mesh.
"""
from dasbus.connection import SystemMessageBus
@ -27,7 +68,7 @@ IWD_ADAPTER_INTERFACE = "net.connman.iwd.Adapter"
# If you are new to D-Bus, you might want to use a program
# such as D-Feet (https://wiki.gnome.org/Apps/DFeet) for reference.
# And try out iwctl to understand iwd's bus objects
# And try out iwctl to understand iwd's bus objects.
class IWD:
@ -155,23 +196,24 @@ class Device:
# name of adapter ('phy0' for example)
self.adapter = self._iwd.get_name_from_path(adapter_path)
def is_adhoc_started(self):
def is_adhoc_started(self) -> bool:
"""
Returns True if an adhoc network is started on this device.
Returns None if device is not powered on or not in ad-hoc mode.
Returns False if the network is in staring stage, device
is not powered on or not in ad-hoc mode.
"""
if self.is_powered_on() and self.get_mode() == "ad-hoc":
return self._proxy.Started
# If above condition is not true, return None
return None
# If above condition is not true, return False
return False
def is_ap_started(self):
def is_ap_started(self) -> bool:
"""
Same as is_adhoc_started(), but for ap
"""
if self.is_powered_on() and self.get_mode() == "ap":
return self._proxy.Started
return None
return False
def get_mode(self) -> str:
"""
@ -250,8 +292,6 @@ class Adapter:
self._proxy = self._bus.get_proxy(IWD_BUS, self._path)
self.name = self._proxy.Name
self.supported_modes = self._proxy.SupportedModes
self.model = self._proxy.Model
self.vendor = self._proxy.Vendor
def is_powered_on(self) -> bool:
"""returns True if adapter is powered on, False otherwise"""

View File

@ -16,24 +16,27 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Setup a working BATMAN Advanced network
with systemd-networkd and iwd
scripts.py
----------
The functions in this file is used for reading configs, args
and doing the things this program is supposed to do.
This file is named scripts.py because the original developer
of this program could not think of a better name that suits this file.
If you want to hack naxalnet, this is the right place to start.
When run from the commandline, the function here_be_dragons() is called.
"""
import sys
from pathlib import Path
from shutil import copy
from dasbus.error import DBusError
from naxalnet.iwd import IWD, Device, Adapter
NETWORKD_CONFIGS = "/usr/share/naxalnet/networkd"
NETWORKD_VOLATILE_DIR = "/run/systemd/network"
ADHOC_SSID = "HelloWorld"
AP_SSID = "NaxalNet"
AP_PASSWD = "naxalnet256"
from naxalnet import __version__
from naxalnet.iwd import Adapter, Device, IWD
from naxalnet.config import parse_args
def copy_files():
def copy_files(args):
"""
Copy networkd configs to volatile dir.
The D-Bus API does not support creating new interfaces
@ -42,8 +45,8 @@ def copy_files():
"""
print("Copying network config files")
dest = Path(NETWORKD_VOLATILE_DIR)
src = Path(NETWORKD_CONFIGS)
dest = Path(args.networkd_runtime_dir)
src = Path(args.networkd_config_dir)
# Create the volatile directory if it doesn't exist
dest.mkdir(parents=True, exist_ok=True)
@ -53,60 +56,99 @@ def copy_files():
copy(i, dest)
def setup_devices(args):
"""
Setup wifi interfaces using iwd
This function should be called every time an interface
is connected or removed.
args should be what parse_args() returns
"""
iwd = IWD()
devices = iwd.get_devices()
adhoc_devices = []
ap_devices = []
# Find devices supporting ad-hoc and ap
for i in devices:
# For each device, check if its adapter supports
# ad-hoc or ap. Many adapters will support both,
# so we will prioritise ad-hoc over ap.
device = Device(i)
adapter = Adapter(device.adapter)
if adapter.supports_mode("ad-hoc"):
adhoc_devices.append(i)
if adapter.supports_mode("ap"):
ap_devices.append(i)
if len(adhoc_devices) != 0:
# Start ad-hoc on first device supporting ad-hoc
adhoc_device = Device(adhoc_devices.pop())
# The same device is likely to have ap support too.
# But we can't start ad-hoc and ap on the same interface.
# So we will remove adhoc_device from ap_devices if it exists there
if adhoc_device.name in ap_devices:
ap_devices.remove(adhoc_device.name)
print("Starting mesh on", adhoc_device.name)
# Turn on adapter if it is off
# See issue #9
adhoc_adapter = Adapter(adhoc_device.adapter)
if not adhoc_adapter.is_powered_on():
adhoc_adapter.power_on()
adhoc_device.reload()
adhoc_device.start_adhoc_open(args.adhoc_name)
# Start Access point if ap_device is not empty,
# ie, we have more devices
if len(ap_devices) != 0:
ap_device = Device(ap_devices.pop())
print("Starting WiFi Access point on", ap_device.name)
print('Use "naxalnet --print-wifi" to get password')
# Turn on adapter if it is off
# See issue #9
ap_adapter = Adapter(ap_device.adapter)
if not ap_adapter.is_powered_on():
ap_adapter.power_on()
ap_adapter.reload()
ap_device.start_ap(args.ap_ssid, args.ap_passwd)
def print_wifi(args):
"""
Prints the name and password of the adhoc, and ap
from the arguments
"""
print("Mesh name:", args.adhoc_name)
print("SSID:", args.ap_ssid)
print("Password:", args.ap_passwd)
def print_version():
"""Just does what the name suggests"""
print(__version__)
def here_be_dragons():
"""
This is where the magic happens!
This function is run every time you
execute naxalnet from commandline
execute naxalnet from the commandline
"""
args = parse_args()
if args.print_wifi:
print_wifi(args)
sys.exit(0)
elif args.version:
print_version()
sys.exit(0)
try:
copy_files()
copy_files(args)
except PermissionError as error:
print(error)
sys.exit("Make sure you are root")
# Now, the iwd part
try:
iwd = IWD()
devices = iwd.get_devices()
adhoc_devices = []
ap_devices = []
for i in devices:
device = Device(i)
adapter = Adapter(device.adapter)
if adapter.supports_mode("ad-hoc"):
adhoc_devices.append(i)
if adapter.supports_mode("ap"):
ap_devices.append(i)
if len(adhoc_devices) != 0:
# Start ad-hoc on first device supporting ad-hoc
adhoc_device = Device(adhoc_devices.pop())
# The same device is likely to have ap support too.
# But we can't start ad-hoc and ap on the same interface.
# Remove adhoc_device from ap_devices if it exists there
if adhoc_device.name in ap_devices:
ap_devices.remove(adhoc_device.name)
print("Working on ad-hoc")
# Turn on adapter if it is off
# See issue #9
adhoc_adapter = Adapter(adhoc_device.adapter)
if not adhoc_adapter.is_powered_on():
adhoc_adapter.power_on()
adhoc_device.reload()
adhoc_device.start_adhoc_open(ADHOC_SSID)
# Start Access point if ap_device is not empty,
# ie, we have more devices
if len(ap_devices) != 0:
print("Working on AP")
ap_device = Device(ap_devices.pop())
# Turn on adapter if it is off
# See issue #9
ap_adapter = Adapter(ap_device.adapter)
if not ap_adapter.is_powered_on():
ap_adapter.power_on()
ap_adapter.reload()
ap_device.start_ap(AP_SSID, AP_PASSWD)
setup_devices(args)
except DBusError as error:
print(error)
sys.exit("An error occured while communicating with iwd")

View File

@ -2,11 +2,12 @@
name = naxalnet
version = attr: naxalnet.__version__
description = create mesh networks with batman-adv and systemd
long_description = file: README.md, LICENSE
long_description = file: README.md
url = https://git.disroot.org/pranav/naxalnet
author = Pranav Jerry
author_email = libreinator@disroot.org
license = GPLv3
license_files = LICENSE
classifiers =
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Operating System :: POSIX :: Linux
@ -18,15 +19,20 @@ packages = find:
python_requires = >=3.6
install_requires =
dasbus
configparser
pathlib
argparse
[options.entry_points]
console_scripts =
naxalnet = naxalnet.scripts:here_be_dragons
[options.data_files]
/usr/lib/systemd/system =
lib/systemd/system =
naxalnet.service
/usr/share/naxalnet/networkd =
/etc/naxalnet =
naxalnet.conf.example
share/naxalnet/networkd =
systemd-networkd/01-batman.netdev
systemd-networkd/02-bridge.netdev
systemd-networkd/03-wireless-ad-hoc.network