Compare commits
46 Commits
Author | SHA1 | Date |
---|---|---|
B.J. Dweck | 46ab5fea97 | |
B.J. Dweck | 7197e9aa92 | |
B.J. Dweck | 2c6071ea79 | |
B.J. Dweck | 4ac90e7e77 | |
B.J. Dweck | 76e0c6e7a7 | |
B.J. Dweck | d3af567287 | |
B.J. Dweck | 0484e3b484 | |
B.J. Dweck | be4ce4a288 | |
B.J. Dweck | 7d764cb043 | |
B.J. Dweck | cd51f18eab | |
B.J. Dweck | 97f8bdd3ac | |
B.J. Dweck | 64b67b08cb | |
B.J. Dweck | 626c13cde2 | |
B.J. Dweck | 09ff9f6e86 | |
B.J. Dweck | 8bc211d413 | |
B.J. Dweck | 67758f6eb3 | |
B.J. Dweck | 43bece3c57 | |
B.J. Dweck | 16085fd594 | |
B.J. Dweck | 5a2ac0c3dc | |
B.J. Dweck | 26d4444137 | |
B.J. Dweck | 59ddc37cfd | |
B.J. Dweck | fe94fcc204 | |
B.J. Dweck | a8b1029ad2 | |
B.J. Dweck | 32ee0ffe55 | |
B.J. Dweck | f31e9e62d7 | |
B.J. Dweck | 05c9ae8d6e | |
B.J. Dweck | 64b9698010 | |
B.J. Dweck | d9e68d50fe | |
B.J. Dweck | 1c6da7a091 | |
B.J. Dweck | 609ccfbf27 | |
B.J. Dweck | a78cddfdb1 | |
B.J. Dweck | a38b6ee751 | |
B.J. Dweck | f3677ad45e | |
B.J. Dweck | ceb80569cb | |
B.J. Dweck | 72c6af328e | |
B.J. Dweck | 54b1fe79a9 | |
B.J. Dweck | 19df7d2d35 | |
B.J. Dweck | 1a4fceb89e | |
B.J. Dweck | fa3ad27146 | |
B.J. Dweck | 21d8dbe1d1 | |
B.J. Dweck | 4a54459eab | |
B.J. Dweck | 21665f976c | |
B.J. Dweck | a891f9bf51 | |
B.J. Dweck | fa24e56662 | |
B.J. Dweck | c94962e2f1 | |
B.J. Dweck | a9aca4da54 |
|
@ -6,3 +6,4 @@ venv
|
|||
/*.egg-info
|
||||
*.pyc
|
||||
__pycache__
|
||||
.idea
|
26
README.md
26
README.md
|
@ -13,7 +13,21 @@ A TORch solution consists of 3 processes:
|
|||
* MQTT broker - Any MQTT broker, reachable via IPv4 or Tor, through TLS or insecure communications
|
||||
* `torch-subscriber` - Listens for and handles onion hostname publications
|
||||
|
||||
## Build Debian Package
|
||||
Easily launch a TORch Node monitor service using the [`torch-subscriber-docker`](https://git.rudefox.io/bj/torch-subscriber-docker) project
|
||||
|
||||
## Installation
|
||||
|
||||
### Install Package from Rudefox Debian Repo
|
||||
|
||||
1. [Add the Rudefox Repo](https://rudefox.io/repo/) as an `apt` source
|
||||
|
||||
2. Install the `torch-agent` package
|
||||
|
||||
```bash
|
||||
sudo apt install torch-agent
|
||||
```
|
||||
|
||||
### Build Debian Package from Source
|
||||
|
||||
If you don't already have a GPG key, generate one:
|
||||
|
||||
|
@ -21,11 +35,11 @@ If you don't already have a GPG key, generate one:
|
|||
gpg --full-generate-key
|
||||
```
|
||||
|
||||
Using the e-mail address you provided during GPG key generation, run `make-pkg.sh` to build a Debian package and install it
|
||||
Using the e-mail address you provided during GPG key generation, run `build-deb.sh` to build a Debian package and install it
|
||||
|
||||
```bash
|
||||
./make-pkg.sh john@doe.com
|
||||
apt update && apt install build/torch-agent_0.0.1-1_all.deb
|
||||
./build-deb.sh john@doe.com
|
||||
apt update && apt install build/torch-agent_0.0.6-1_all.deb
|
||||
```
|
||||
|
||||
This will:
|
||||
|
@ -45,7 +59,3 @@ The configuation directory can be specified by
|
|||
A fully configured example can be found [here](example)
|
||||
|
||||
See the sample [`torch.conf`](torch.conf) file for additional configuration options and details
|
||||
|
||||
## Roadmap
|
||||
|
||||
[ ] Utilize [dh_python3](https://www.debian.org/doc/manuals/debmake-doc/ch08.en.html#setup-py) in Debian package build
|
43
build-deb.sh
43
build-deb.sh
|
@ -1,33 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ -z "${DEB_EMAIL}" ]]; then
|
||||
DEB_EMAIL="$1"
|
||||
DPKG_BUILD_OPTS=-k"$DEB_EMAIL"
|
||||
fi
|
||||
|
||||
if [[ -z "${DEB_EMAIL}" ]]; then
|
||||
DEB_EMAIL="none@none.com"
|
||||
DPKG_BUILD_OPTS="-us -uc"
|
||||
fi
|
||||
|
||||
TORCH_VERSION=$(git describe --tags --abbrev=0)
|
||||
PROJECT=torch-agent-$TORCH_VERSION
|
||||
|
||||
if [[ -z "${DEBEMAIL}" ]]; then
|
||||
DEBEMAIL="$1"
|
||||
fi
|
||||
|
||||
if [[ -z "${DEBEMAIL}" ]]; then
|
||||
echo "E-mail address required for packaging signing with gpg key!"
|
||||
echo "Usage: ./build-deb.sh EMAIL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_DIR=dist
|
||||
DEB_DIR=$BUILD_DIR/$PROJECT
|
||||
|
||||
rm -rf $BUILD_DIR/*
|
||||
rm -rf "${BUILD_DIR:?}"
|
||||
mkdir -p "$DEB_DIR/src/etc/torch"
|
||||
cp -r debian "$DEB_DIR/"
|
||||
cp torch.conf "$DEB_DIR/src/etc/torch/"
|
||||
|
||||
pip3 install -r requirements.txt
|
||||
python3 setup.py sdist
|
||||
|
||||
mkdir -p $DEB_DIR/src/etc/torch
|
||||
cp -r debian $DEB_DIR/
|
||||
cp torch.conf $DEB_DIR/src/etc/torch/
|
||||
cd $BUILD_DIR || exit
|
||||
tar -xzmf "$PROJECT.tar.gz"
|
||||
|
||||
cd $BUILD_DIR
|
||||
tar -xzmf $PROJECT.tar.gz
|
||||
|
||||
cd $PROJECT
|
||||
export USER=`whoami`
|
||||
dh_make --createorig -e $DEBEMAIL -s -y
|
||||
dpkg-buildpackage -k$DEBEMAIL
|
||||
cd "$PROJECT" || exit
|
||||
export USER
|
||||
USER=$(whoami)
|
||||
dh_make --createorig -e "$DEB_EMAIL" -s -y
|
||||
dpkg-buildpackage $DPKG_BUILD_OPTS
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
torch-agent (0.0.1-1) unstable; urgency=medium
|
||||
torch-agent (0.0.6-1) stable; urgency=medium
|
||||
|
||||
* Initial release
|
||||
* Update
|
||||
|
||||
-- Benjamin Dweck <bjdweck@gmail.com> Tue, 06 Oct 2020 15:53:02 +0200
|
||||
-- Benjamin Dweck <bjdweck@gmail.com> Tue, 08 Oct 2020 19:46:22 +0200
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
torch-agent_0.0.1-1_all.deb net optional
|
||||
torch-agent_0.0.1-1_amd64.buildinfo net optional
|
|
@ -42,7 +42,9 @@ configure_tor_controller() {
|
|||
fi
|
||||
|
||||
if [ $TORRC_CHANGED -eq 1 ]; then
|
||||
systemctl reload tor
|
||||
if [ -d "/run/systemd/system" ]; then
|
||||
systemctl reload tor
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -53,10 +55,12 @@ case "$1" in
|
|||
useradd -r -g $GROUP $USER
|
||||
fi
|
||||
|
||||
chown $USER /etc/torch
|
||||
chown $USER /etc/torch/torch.conf
|
||||
sudo -H pip3 install 'paho-mqtt>=1.5.1'
|
||||
|
||||
configure_tor_controller
|
||||
chown $USER /etc/torch
|
||||
chown $USER /etc/torch/torch.conf
|
||||
|
||||
configure_tor_controller
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
OthermoduleName python-othermodule; PEP386
|
|
@ -0,0 +1,13 @@
|
|||
FROM ubuntu
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y sudo ssh tor curl python3-all
|
||||
|
||||
COPY dist/torch-agent_*_all.deb .
|
||||
RUN apt install -y ./torch-agent_*_all.deb
|
||||
|
||||
COPY docker-tor/torch-agent.wrapper.sh /usr/bin/torch-agent.wrapper.sh
|
||||
|
||||
VOLUME [ "/etc/torch" ]
|
||||
|
||||
ENTRYPOINT [ "torch-agent.wrapper.sh" ]
|
|
@ -0,0 +1,29 @@
|
|||
# Tor Test Harness for TORch Agent
|
||||
|
||||
This is a Docker container for running the current development version of TORch Agent in an environment with a local Tor Proxy (without having to install and configure Tor on the development machine itself)
|
||||
|
||||
## Preparation
|
||||
|
||||
1. Build a Debian package from the current development version of TORch Agent
|
||||
|
||||
```bash
|
||||
python -m venv venv && source venv/bin/activate
|
||||
pip3 install -r requirements.txt
|
||||
./build-deb.sh
|
||||
```
|
||||
|
||||
2. Build the Docker image
|
||||
|
||||
```bash
|
||||
docker build -f docker-tor/Dockerfile -t torch-agent .
|
||||
```
|
||||
|
||||
3. Configure `torch-agent` by editing [`agent-conf/torch.conf`](./agent-conf/torch.conf)
|
||||
|
||||
* Be sure to update the onion hostname of the broker with the one you wish to test with
|
||||
|
||||
4. Launch the Docker container
|
||||
|
||||
```bash
|
||||
docker run -it --rm -v "$(pwd)/docker-tor/agent-conf:/etc/torch" torch-agent
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDhDCCAmwCFFfe134gzLKm3ieNbeoxCvOhwsGxMA0GCSqGSIb3DQEBCwUAMIGE
|
||||
MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxETAPBgNVBAcMCE5ldyBZb3JrMRUw
|
||||
EwYDVQQKDAxFeGFtcGxlIEluYy4xHDAaBgNVBAMME2NhLm1xdHQuZXhhbXBsZS5j
|
||||
b20xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMB4XDTIwMTAwNjEx
|
||||
MDQxMVoXDTMwMTAwNDExMDQxMVoweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5Z
|
||||
MREwDwYDVQQHDAhOZXcgWW9yazEVMBMGA1UECgwMRXhhbXBsZSBJbmMuMRAwDgYD
|
||||
VQQDDAd2YWdyYW50MSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALBR3WYBUoSM9taDBWn8MSU3
|
||||
WW7z9EmutaWRKlNCf8rAVXrEGf3shtBb6MWdRjAKHcBDZaTtmW6o0XoXkKdGeWcm
|
||||
6X0o4TwaROPE7HR8OtKsmPTxQ09gKfkwB+sb8+fIPrKq6VLWiSJqvc6RbZvoKXIa
|
||||
WU/BV4q3HG9MvFB2AMNx9pmzLeeP/m323pAEU28oR/kGvuDJHSLO3cNd1U5ZKFFt
|
||||
J1hHYugKM3uHlyQ44ozu6l2AexGgIYjA5/y1D/RuWaybdpppLS3RerhKDrvTkwWD
|
||||
UALgTdxHnIT90NFCtGsZTzwmbqs/ibq1NtkHGiS0tGhJjftIiPJZfuNArVsoYF0C
|
||||
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAeOEgOA8dJZGo/bT+2vnKm7VnJYrNgAax
|
||||
B/X2kG3vLiayFgPYarQq8AjlqQCr8Dm1EqbUtnAhzSbQTX+v3oQBd7sRdlwfTYKa
|
||||
bFEjhMeXhBgp/bWobq9FcwAL02wsAZh/gcbHAVrIwWmb42sbHTmrWY2jgJbX65jg
|
||||
ameIn9p1j2CSJnC4Ju3B+btaCmksHI6uhuJVef/+pL53hs1z5MfehNvJaBkUzsya
|
||||
nYAiCvrEQIzKlxROdBApZeQs0WFv0ktu6itzA3YsCMct1p3TNGwDUZ+cQqkTPhkB
|
||||
KNT0VcmDNdavD59WsEfrgZe5/DXY+Q1yHzGmaq70y0U6SgTfOsslmQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAsFHdZgFShIz21oMFafwxJTdZbvP0Sa61pZEqU0J/ysBVesQZ
|
||||
/eyG0FvoxZ1GMAodwENlpO2ZbqjReheQp0Z5ZybpfSjhPBpE48TsdHw60qyY9PFD
|
||||
T2Ap+TAH6xvz58g+sqrpUtaJImq9zpFtm+gpchpZT8FXirccb0y8UHYAw3H2mbMt
|
||||
54/+bfbekARTbyhH+Qa+4MkdIs7dw13VTlkoUW0nWEdi6Aoze4eXJDjijO7qXYB7
|
||||
EaAhiMDn/LUP9G5ZrJt2mmktLdF6uEoOu9OTBYNQAuBN3EechP3Q0UK0axlPPCZu
|
||||
qz+JurU22QcaJLS0aEmN+0iI8ll+40CtWyhgXQIDAQABAoIBAQCYYtiHbYMk3jQD
|
||||
p49JT1YmRRT9aMhr2hxR8Ql0lheeYuY9yThxljfZ4mVmTYw4vrWB0n4JsfQWiL8q
|
||||
1y0E9Uq9lQrdSjSH3mhFto9qCWhJZjR4FgBHnOQJ4rIlR65gV1eg0UgAeTxiS4Cq
|
||||
BFSIF3mijRU9ces4DxP7OYXTwHjecLQXWzsENhlcowTCYOfxLM/8YvVRCv2cxPJh
|
||||
/TL3qn1LD5/15lUb58+SqNAOREGACB+YG6rFShvUrxkq3ShtZdPUOzM5z+9xS8yO
|
||||
Uh2aZDmxtMB6GnYbQNhfM274i71aVhf0++7s8VsiVo3C61+qKIYcX0LK8t2PnQ1H
|
||||
cFn20hKhAoGBANfyLB5T+nZUGBysZSe76SoZUFWM0OsLixLq0+CqHvnTmIVMLQpv
|
||||
k8RV2/g7rKCcaKghSENI2gwWy+EDfVGi/nGc+uJ+n4FX92F98MmmzFvuQXOp1AuY
|
||||
Qvqr2XquFu5B6Jz5aOniOMHHSRl9JmZOLc+rs7COH7s/o5OPBT+1OpHJAoGBANEG
|
||||
HBnAuxZ0XJtB7TvA9wW3GCRidCisRH8rG0cN4dE3UuCC+DQq1AV03NwM6pycwz15
|
||||
ljpkb+WtbE6iKG3sfj3vWhwkakcEnJKXGCVbKmMXI0L2sMnQB4bJ4TtXGDRJlLKg
|
||||
XuwBsEmN8pM8IqRmnSpTrVbpCo4vZ/29c8l9+YP1AoGAcgIBGOHtUZuEP18k6J1k
|
||||
tD05FHGLuwwVGJ+xzOMEB5GW7IkTHndZ5EYQJDYdJY5uEpW/uQY1WDyQ1vMornkH
|
||||
LKRcMEf5nif7CxWaklvleIOJOq9mq9hvRDiGUSaoJJHXZUioAxLUNDoqdbKFG24a
|
||||
8ZENBSGDzzACBF11v/TGP0ECgYEAp+WCeOUo4jaBlGx2RIMRaNPTXpZ+u5T0SDm1
|
||||
5XMvKkCIH7LT8ANe3ysppM/zO+1nnl+l3i2C/Dg7QUZbt0A5f0JdXTGa9IStx8n6
|
||||
KTd7arDRMB67jr+86/YJJwMkfAuGl5zd4jDRC6Qrbzzkjq2mHLOuDpuOUPufSl/9
|
||||
O6Im5GkCgYA4zFE3ztSV6nq5EH3A7VmAsLiyRXBJfOlLXIBApv46/t4ivS4C3Esu
|
||||
8LR+Vvx2XLWkpkrm9kR1wIutNx6x1pRkSGDKyRXn5+cU4A2Lw9y2BbwDhj+WiHkM
|
||||
zCuL+8l2px2f3K1YPE3oGWHZZJScDwa03yjVzrSPDr766XBtH7W4vg==
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,23 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID6zCCAtOgAwIBAgIUQJye5MbZVMpOpu87TmmlN/KOBj0wDQYJKoZIhvcNAQEL
|
||||
BQAwgYQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3IFlv
|
||||
cmsxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEcMBoGA1UEAwwTY2EubXF0dC5leGFt
|
||||
cGxlLmNvbTEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wHhcNMjAx
|
||||
MDA2MTA1OTE4WhcNMzAxMDA0MTA1OTE4WjCBhDELMAkGA1UEBhMCVVMxCzAJBgNV
|
||||
BAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9yazEVMBMGA1UECgwMRXhhbXBsZSBJbmMu
|
||||
MRwwGgYDVQQDDBNjYS5tcXR0LmV4YW1wbGUuY29tMSAwHgYJKoZIhvcNAQkBFhFh
|
||||
ZG1pbkBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
ALVndltaj3SX1zuJB0F5woIMUZCHopkgiO027/qE10IgM6SN4lFhR7wR0B/9PXrf
|
||||
zn1xTC63w9xd3GbnlJvcWhWbh/m1t2Qx2mIvOmoELY8wlY6/V6NzjSgju7mZi0u6
|
||||
aitU+LXINNuGS+JhVpc54QQ8M9o0jKlnNGnEmPjv6uhbNXx3f8lw3eqSr1ZqmpGd
|
||||
UQVYKsNYBVzSqsnh/sn/KnGYn/nmpsKRWeLhoslJ3zDjaM/Y4NYol11nWFIPYCk5
|
||||
7rzzxES/WdWLLnZ2W59YCT54YOGFqXE7oYgReD+Og2YwnGVQQpDcvb2HyIZL/2pa
|
||||
oC6avMo/eC8HbSxwUKCnj1cCAwEAAaNTMFEwHQYDVR0OBBYEFEC8a9l0rpIdUqCS
|
||||
i4NJwXlqUoLeMB8GA1UdIwQYMBaAFEC8a9l0rpIdUqCSi4NJwXlqUoLeMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGzxJWZdVozskr5yie2uetpL
|
||||
aAReCaHEdWudRN3wVW1Dpm2sE23x4VFiJ+Uow9k21GgtGUsAIFqRgb3/QO+ipODC
|
||||
GRwZmVopkuOaHfCz+tO8xqjvGHCidhhhNFdR9uVkWHoPKsQsvap0SSk12KMtFBRo
|
||||
3rmeQwPP4qEPFEwc2U0hCUMsIUvMSt3KrA/j+aMRzOXU7QIMFbcYEF1IaGJz1RMh
|
||||
h1VCXaUlL2liVTWU4XgudB8rMOuETec7un9hzoBVOWHxXdRrGPaoN4+zWiLRCDXO
|
||||
6wapOhkmTOXuZY/NcMMwTmdJKTEQBD6XIQamv91Ne2bT89LHpcp1LjbaCz+UAxg=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,16 @@
|
|||
[tor]
|
||||
ControllerPort = 9051
|
||||
|
||||
[ssh]
|
||||
Port = 22
|
||||
|
||||
[mqtt]
|
||||
BrokerHost = wmzin3o2dvd4h2iu4mrf4zqbvgscgi27kd5afzvhgchghjdpqk7cmaqd.onion
|
||||
BrokerPort = 1883
|
||||
ClientID = myagent
|
||||
Topic = torch/myagent/wake
|
||||
RequireCertificate = false
|
||||
CaFile = ca.crt
|
||||
CertFile = agent.crt
|
||||
KeyFile = agent.key
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
tor &
|
||||
|
||||
while ! curl -s --socks5 127.0.0.1:9050 'https://check.torproject.org/' | grep -qm1 Congratulations
|
||||
do
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
torch-agent $1 $2 $3 $4
|
|
@ -35,19 +35,10 @@ In a separate terminal window, run the subscriber:
|
|||
|
||||
#### Run TORch Agent in Vagrant
|
||||
|
||||
[Build](..) the latest source into a Debian package and copy it to `example/`
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
./make-pkg.sh john@doe.com
|
||||
cp -f build/torch-agent_0.0.1-1_all.deb example/
|
||||
cd example
|
||||
```
|
||||
|
||||
Run the Vagrant box in a third terminal window:
|
||||
|
||||
```bash
|
||||
vagrant up
|
||||
```
|
||||
|
||||
You should see that the broker received a connection from the Vagrant box at boot up and the subscriber received the onion hostname. You can use a local `tor` proxy to connect to the vagrant box using SSH and the onion hostname.
|
||||
You should see that the broker received a connection from the Vagrant box at boot up and the subscriber received the onion hostname. You can use a local `tor` proxy to connect to the vagrant box using SSH and the onion hostname.
|
||||
|
|
|
@ -64,17 +64,19 @@ Vagrant.configure("2") do |config|
|
|||
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
|
||||
# documentation for more information about their specific syntax and use.
|
||||
|
||||
config.vm.provision "file", source: "torch-agent_0.0.1-1_all.deb", destination: "~/"
|
||||
config.vm.provision "file", source: "agent-config", destination: "~/torch-conf"
|
||||
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
|
||||
sudo -- sh -c "echo '10.0.2.2 mqtt.example.com' >> /etc/hosts"
|
||||
|
||||
|
||||
sudo -- sh -c "echo '10.0.2.2 mqtt.example.com' >> /etc/hosts"
|
||||
|
||||
sudo apt update
|
||||
sudo apt install -y ./torch-agent_0.0.1-1_all.deb
|
||||
|
||||
sudo cp -f torch-conf/* /etc/torch/
|
||||
wget -qO - https://rudefox.io/repo/gpg | sudo apt-key add
|
||||
sudo add-apt-repository "deb https://repo.rudefox.io/repository/apt-release focal main"
|
||||
sudo apt update
|
||||
sudo apt install -y torch-agent
|
||||
|
||||
sudo cp -f torch-conf/* /etc/torch/
|
||||
sudo chown -R torch /etc/torch
|
||||
|
||||
sudo systemctl enable torch-agent
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
listener 8883
|
||||
websockets_log_level 9
|
||||
connection_messages true
|
||||
log_type all
|
||||
websockets_log_level 9
|
||||
|
||||
listener 1883
|
||||
cafile /mosquitto/config/ca.crt
|
||||
#keyfile /mosquitto/config/mqtt.example.com.key
|
||||
#certfile /mosquitto/config/mqtt.example.com.crt
|
||||
require_certificate true
|
||||
use_identity_as_username true
|
||||
|
||||
listener 8883
|
||||
cafile /mosquitto/config/ca.crt
|
||||
keyfile /mosquitto/config/mqtt.example.com.key
|
||||
certfile /mosquitto/config/mqtt.example.com.crt
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
docker run -it --rm --user $(echo $UID) --name mosquitto -p 8883:8883 -v $(pwd)/broker-config:/mosquitto/config eclipse-mosquitto
|
||||
docker run -it --rm --user $(echo $UID) --name mosquitto -p 8883:8883 -p 1883:1883 -v $(pwd)/broker-config:/mosquitto/config eclipse-mosquitto
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
mosquitto_sub -L mqtts://mqtt.example.com/it/torch/\+/ssh_onion --cafile subscriber-config/ca.crt --key subscriber-config/subscriber.key --cert subscriber-config/subscriber.crt
|
||||
mosquitto_sub -L mqtts://mqtt.example.com/torch/\+/onion_url --cafile subscriber-config/ca.crt --key subscriber-config/subscriber.key --cert subscriber-config/subscriber.crt
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
USERNAME=$1
|
||||
PASSWORD=$2
|
||||
VERSION=$3
|
||||
|
||||
curl -u "$USERNAME:$PASSWORD" -H "Content-Type: multipart/form-data" --data-binary "@dist/torch-agent_${VERSION}-1_all.deb" "https://repo.rudefox.io/repository/apt-release/"
|
|
@ -0,0 +1,3 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
|
@ -1,5 +1,6 @@
|
|||
wheel>=0.35.1
|
||||
setuptools>=44.0.0
|
||||
pip~=20.2.4
|
||||
setuptools~=50.3.2
|
||||
stdeb3~=0.9.0.post2
|
||||
paho-mqtt~=1.5.1
|
||||
stem>=1.8.0
|
||||
paho-mqtt>=1.5.1
|
||||
PySocks>=1.7.1
|
||||
PySocks
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
[metadata]
|
||||
name = torch-agent
|
||||
version = attr: torch_agent.__version__
|
||||
author = Benjamin Dweck
|
||||
author_email = bjdweck@gmail.com
|
||||
description = TORch: Illuminate the Way to your Node
|
||||
url = https://git.rudefox.io/bj/torch-agent
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
License :: OSI Approved :: MIT License
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
install_requires =
|
||||
paho-mqtt~=1.5.1
|
||||
setuptools~=50.3.1
|
||||
pip~=20.2.3
|
||||
stem
|
||||
PySocks
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts = torch-agent=torch_agent.torch_agent:main
|
||||
|
||||
[options.packages.find]
|
||||
exclude=test
|
29
setup.py
29
setup.py
|
@ -1,31 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
import setuptools
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setuptools.setup(
|
||||
name="torch-agent",
|
||||
version="0.0.1",
|
||||
author="B.J. Dweck",
|
||||
author_email="bjdweck@gmail.com",
|
||||
description="TORch: Iluminate the Way to your Node",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://git.rudefox.io/bj/torch-agent",
|
||||
packages=setuptools.find_packages(),
|
||||
install_requires=[
|
||||
'stem',
|
||||
'paho-mqtt',
|
||||
'PySocks',
|
||||
],
|
||||
entry_points = {
|
||||
'console_scripts': ['torch-agent=torch_agent.torch_agent:main'],
|
||||
},
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
],
|
||||
python_requires='>=3.6',
|
||||
)
|
||||
|
||||
setuptools.setup()
|
||||
|
|
34
torch.conf
34
torch.conf
|
@ -1,19 +1,47 @@
|
|||
#################
|
||||
# The `tor` section heading is required
|
||||
[tor]
|
||||
|
||||
# Optional: The Tor onion proxy host and port (default: 127.0.0.1:9050)
|
||||
#ProxyHost 127.0.0.1
|
||||
ProxyPort = 9050
|
||||
|
||||
# Optional: The Tor controller port (default: 9051) for creating new hidden services
|
||||
ControllerPort = 9051
|
||||
|
||||
|
||||
#################
|
||||
# The `ssh` section heading is required
|
||||
[ssh]
|
||||
|
||||
# Optional: Local SSH sevice port (default: 22)
|
||||
Port = 22
|
||||
|
||||
|
||||
#################
|
||||
# The `mqtt` section heading is required
|
||||
[mqtt]
|
||||
BrokerHost = mqtt.example.com # OR example1i3uyrbfoi3fi.onion
|
||||
|
||||
# Optional: The MQTT broker host and port (default: localhost:1883)
|
||||
# Can be either IPv4 or Tor onion hostname
|
||||
BrokerHost = mqtt.example.com
|
||||
#BrokerHost = example1i3uyrbfoi3fi.onion
|
||||
BrokerPort = 1883
|
||||
|
||||
# Optional: ID that will be used as an MQTT client ID when connecting to the broker (defaults to the current host's hostname)
|
||||
ClientID = my-client
|
||||
Topic = example/topic
|
||||
|
||||
### Options for Using TLS
|
||||
# Optional: Topic to be used when publishing connection info (defaults to 'torch/[hostname]/onion_url')
|
||||
#Topic = example/topic
|
||||
|
||||
### Optional: TLS Options
|
||||
#
|
||||
# Note: when CaFile, CertFile and KeyFile are ALL defined, then TLS (MQTTS) is used to connect to the broker. Otherwise MQTT is used.
|
||||
#
|
||||
|
||||
# Optional: Whether or not TORch Agent will verify the hostname of the broker and require it to match the name on the certificate the broker provides. This will be automatically DISABLED for connections to Tor onion hosts
|
||||
#RequireCertificate = true
|
||||
|
||||
#CaFile = ca.crt
|
||||
#CertFile = client.crt
|
||||
#KeyFile = client.key
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "0.0.1"
|
||||
__version__ = "0.0.6"
|
||||
|
|
|
@ -1,97 +1,127 @@
|
|||
from stem.control import Controller
|
||||
import stem.connection
|
||||
import paho.mqtt.client as mqtt
|
||||
import ssl
|
||||
import socks
|
||||
import socket
|
||||
import json
|
||||
import configparser
|
||||
import argparse
|
||||
import configparser
|
||||
import json
|
||||
import socket
|
||||
import ssl
|
||||
from datetime import datetime
|
||||
from os import environ
|
||||
|
||||
import paho.mqtt.publish as publish
|
||||
import socks
|
||||
import stem.connection
|
||||
from stem.control import Controller
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Broadcast SSH hidden service hostname via MQTT')
|
||||
parser = argparse.ArgumentParser(description='Broadcast SSH hidden service hostname via MQTT')
|
||||
|
||||
parser.add_argument('--config-dir', nargs='?', dest='configPath', default='/etc/torch',
|
||||
help='configuration directory (default: /etc/torch)')
|
||||
parser.add_argument('--config-dir', nargs='?', dest='configPath', default='/etc/torch',
|
||||
help='configuration directory (default: /etc/torch)')
|
||||
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
configPath = args.configPath
|
||||
config_path = args.configPath
|
||||
|
||||
if "TORCH_CONFIG_DIR" in environ:
|
||||
configPath = environ.get("TORCH_CONFIG_DIR")
|
||||
if "TORCH_CONFIG_DIR" in environ:
|
||||
config_path = environ.get("TORCH_CONFIG_DIR")
|
||||
|
||||
if not configPath.endswith("/"):
|
||||
configPath = configPath + "/"
|
||||
if not config_path.endswith("/"):
|
||||
config_path = config_path + "/"
|
||||
|
||||
print("Using torch configuration path: " + configPath)
|
||||
print("Using torch configuration path: " + config_path)
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(configPath + "torch.conf")
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
torProxyPort = config['tor'].getint('ProxyPort', fallback = 9050)
|
||||
torControllerPort = config['tor'].getint('ControllerPort', fallback = 9051)
|
||||
configuration_file_path = config_path + "torch.conf"
|
||||
print("Reading configuration file at '%s'" % configuration_file_path)
|
||||
config.read(configuration_file_path)
|
||||
|
||||
sshPort = config['ssh'].getint('Port', fallback = 22)
|
||||
tor_proxy_host = config['tor'].get('ProxyHost', fallback="127.0.0.1")
|
||||
tor_proxy_port = config['tor'].getint('ProxyPort', fallback=9050)
|
||||
tor_controller_port = config['tor'].getint('ControllerPort', fallback=9051)
|
||||
|
||||
mqttConfig = config['mqtt']
|
||||
mqttBrokerHost = mqttConfig.get('BrokerHost', fallback = "localhost")
|
||||
mqttBrokerPort = mqttConfig.getint('BrokerPort', fallback = 1883)
|
||||
clientID = mqttConfig.get('ClientID', fallback = socket.gethostname())
|
||||
mqttTopic = mqttConfig.get('Topic', fallback = "torch/%s/onion_url" % (clientID))
|
||||
ssh_port = config['ssh'].getint('Port', fallback=22)
|
||||
|
||||
mqttRequireCertificate = mqttConfig.getboolean(
|
||||
'RequireCertificate',
|
||||
fallback = False)
|
||||
mqtt_config = config['mqtt']
|
||||
mqtt_broker_host = mqtt_config.get('BrokerHost', fallback="localhost")
|
||||
mqtt_broker_port = mqtt_config.getint('BrokerPort', fallback=1883)
|
||||
mqtt_broker_using_tor = mqtt_broker_host.endswith(".onion")
|
||||
mqtt_client_id = mqtt_config.get('ClientID', fallback=socket.gethostname())
|
||||
mqtt_topic = mqtt_config.get('Topic', fallback="torch/%s/onion_url" % mqtt_client_id)
|
||||
|
||||
mqttCaFile = configPath + mqttConfig.get('CaFile')
|
||||
mqttCertFile = configPath + mqttConfig.get('CertFile')
|
||||
mqttKeyFile = configPath + mqttConfig.get('KeyFile')
|
||||
mqtt_require_certificate = mqtt_config.getboolean(
|
||||
'RequireCertificate',
|
||||
fallback=False)
|
||||
|
||||
with Controller.from_port(port = torControllerPort) as controller:
|
||||
|
||||
protocolInfo = stem.connection.get_protocolinfo(controller)
|
||||
mqtt_ca_file = mqtt_config.get('CaFile', fallback=None)
|
||||
mqtt_ca_file = config_path + mqtt_ca_file
|
||||
mqtt_cert_file = mqtt_config.get('CertFile', fallback=None)
|
||||
mqtt_cert_file = config_path + mqtt_cert_file
|
||||
mqtt_key_file = mqtt_config.get('KeyFile', fallback=None)
|
||||
mqtt_key_file = config_path + mqtt_key_file
|
||||
|
||||
stem.connection.authenticate_safecookie(
|
||||
controller,
|
||||
protocolInfo.cookie_path)
|
||||
|
||||
print("Connected to Tor on port %s" % (torControllerPort))
|
||||
mqtt_use_tls = \
|
||||
mqtt_ca_file is not None and \
|
||||
mqtt_cert_file is not None and \
|
||||
mqtt_key_file is not None
|
||||
|
||||
service = controller.create_ephemeral_hidden_service(sshPort, detached = True)
|
||||
print("Connecting to local TOR controller on port %s" % tor_controller_port)
|
||||
|
||||
onionAddress = "%s.onion" % (service.service_id)
|
||||
with Controller.from_port(port=tor_controller_port) as controller:
|
||||
|
||||
print("Created Tor Hidden Service for local port %s at %s" % (sshPort, onionAddress))
|
||||
protocol_info = stem.connection.get_protocolinfo(controller)
|
||||
|
||||
payload = {
|
||||
'clientId': clientID,
|
||||
'timestamp': datetime.now().strftime("%d-%b-%Y (%H:%M:%S.%f)"),
|
||||
'onionAddress': onionAddress,
|
||||
'sshPort': sshPort
|
||||
}
|
||||
stem.connection.authenticate_safecookie(controller, protocol_info.cookie_path)
|
||||
|
||||
client = mqtt.Client()
|
||||
protocol = "mqtt"
|
||||
print("Creating TOR Hidden Service...")
|
||||
|
||||
if mqttRequireCertificate:
|
||||
client.tls_set(
|
||||
ca_certs = mqttCaFile,
|
||||
certfile = mqttCertFile,
|
||||
keyfile = mqttKeyFile,
|
||||
cert_reqs=ssl.CERT_REQUIRED)
|
||||
protocol = "mqtts"
|
||||
service = controller.create_ephemeral_hidden_service(ssh_port, detached=True)
|
||||
|
||||
if mqttBrokerHost.endswith(".onion"):
|
||||
client.proxy_set(proxy_type=socks.SOCKS5, proxy_addr="localhost", proxy_port=torProxyPort)
|
||||
client.tls_insecure_set(True)
|
||||
onion_address = "%s.onion" % service.service_id
|
||||
|
||||
client.connect(mqttBrokerHost, mqttBrokerPort, 60)
|
||||
client.publish(mqttTopic, json.dumps(payload))
|
||||
print("Connected to MQTT Broker at %s://%s:%s/%s" % (protocol, mqttBrokerHost, mqttBrokerPort, mqttTopic))
|
||||
print("Published payload: " + json.dumps(payload))
|
||||
print("Created Tor Hidden Service for local service on port %s at %s" % (ssh_port, onion_address))
|
||||
|
||||
client.disconnect()
|
||||
print("Disconnected from MQTT Broker")
|
||||
protocol = "mqtt"
|
||||
tls_args = None
|
||||
proxy_args = None
|
||||
|
||||
cert_required = ssl.CERT_OPTIONAL
|
||||
if mqtt_require_certificate:
|
||||
cert_required = ssl.CERT_REQUIRED
|
||||
|
||||
if mqtt_broker_using_tor:
|
||||
cert_required = ssl.CERT_OPTIONAL
|
||||
proxy_args = {
|
||||
'proxy_type': socks.SOCKS5,
|
||||
'proxy_addr': tor_proxy_host,
|
||||
'proxy_port': tor_proxy_port
|
||||
}
|
||||
|
||||
if mqtt_use_tls:
|
||||
protocol = "mqtts"
|
||||
tls_args = {
|
||||
'ca_certs': mqtt_ca_file,
|
||||
'certfile': mqtt_cert_file,
|
||||
'keyfile': mqtt_key_file,
|
||||
'cert_reqs': cert_required
|
||||
}
|
||||
|
||||
print("Publishing to MQTT broker: %s://%s:%s/%s" % (protocol, mqtt_broker_host, mqtt_broker_port, mqtt_topic))
|
||||
if mqtt_broker_using_tor:
|
||||
print("--> Using TOR proxy: %s:%s" % (tor_proxy_host, tor_proxy_port))
|
||||
|
||||
payload = json.dumps({
|
||||
'clientId': mqtt_client_id,
|
||||
'timestamp': datetime.now().strftime("%d-%b-%Y (%H:%M:%S.%f)"),
|
||||
'onionAddress': onion_address,
|
||||
'sshPort': ssh_port
|
||||
})
|
||||
|
||||
publish.single(mqtt_topic,
|
||||
payload,
|
||||
qos=1,
|
||||
hostname=mqtt_broker_host,
|
||||
port=mqtt_broker_port,
|
||||
client_id=mqtt_client_id,
|
||||
tls=tls_args,
|
||||
proxy_args=proxy_args)
|
||||
|
|
Loading…
Reference in New Issue