Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: CI

on:
"on":
push:
branches:
- master
Expand Down Expand Up @@ -32,15 +33,33 @@ jobs:
run: docker build -t etherjack-ci -f tests/Dockerfile .

# --------------------------------------------------------------------------
# ShellCheck — static analysis on all scripts
# The .shellcheckrc in the repo root suppresses SC1091/SC2154 which are
# false positives caused by inter-script variable sourcing.
# Lint — ShellCheck on all scripts and bats tests, yamllint on workflows,
# shfmt to enforce consistent indentation (catches mixed tabs/spaces).
# .shellcheckrc suppresses SC1091/SC2154 (false positives from sourcing)
# .yamllint.yml holds the shared rule config used locally and here
# --------------------------------------------------------------------------
- name: ShellCheck
run: |
docker run --rm -v "$PWD:/etherjack" etherjack-ci \
bash -c 'find /etherjack -name "*.sh" -not -path "/etherjack/.git/*" \
| xargs shellcheck --severity=error'
docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c '
find /etherjack \( -name "*.sh" -o -name "*.bats" \) \
-not -path "/etherjack/.git/*" \
| xargs shellcheck --severity=warning
'

- name: shfmt
run: |
docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c '
find /etherjack \( -name "*.sh" -o -name "*.bats" \) \
-not -path "/etherjack/.git/*" \
| xargs shfmt -d -i 4
'

- name: yamllint
run: |
docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c '
find /etherjack/.github -name "*.yml" \
| xargs yamllint -c /etherjack/.yamllint.yml
'

# --------------------------------------------------------------------------
# BATS unit / integration tests
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: Release

on:
"on":
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
Expand Down
5 changes: 5 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
extends: default
rules:
line-length:
max: 120
58 changes: 29 additions & 29 deletions EtherJack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@
source EtherJack.conf

case $EJMODE in
lan|LAN)
mkdir $EJPATH/lan/$ENGAGEMENT
cd $EJPATH/lan/$ENGAGEMENT
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in LAN Mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
echo "Starting netfinder.sh" >>$EJLOG
$EJPATH/lan/netfinder.sh
;;
wifi|WIFI|WiFi)
mkdir $EJPATH/wifi/$ENGAGEMENT
cd $EJPATH/wifi/$ENGAGEMENT
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in WiFi Mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
$EJPATH/wifi/wifi.sh
;;
preset|PRESET)
mkdir $EJPATH/preset/$ENGAGEMENT
cd $EJPATH/preset/$ENGAGEMENT
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in preset mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
$EJPATH/preset/preset.sh
;;
*)
echo "Invalid mode defined. Shutting system down!!"
init 0
;;
lan | LAN)
mkdir $EJPATH/lan/$ENGAGEMENT
cd $EJPATH/lan/$ENGAGEMENT || exit
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in LAN Mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
echo "Starting netfinder.sh" >>$EJLOG
$EJPATH/lan/netfinder.sh
;;
wifi | WIFI | WiFi)
mkdir $EJPATH/wifi/$ENGAGEMENT
cd $EJPATH/wifi/$ENGAGEMENT || exit
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in WiFi Mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
$EJPATH/wifi/wifi.sh
;;
preset | PRESET)
mkdir $EJPATH/preset/$ENGAGEMENT
cd $EJPATH/preset/$ENGAGEMENT || exit
cat $EJPATH/files/ejmotd >>$EJLOG
echo "Running EJ in preset mode" >>$EJLOG
echo "Setting up Engagement Folder" >>$EJLOG
$EJPATH/preset/preset.sh
;;
*)
echo "Invalid mode defined. Shutting system down!!"
init 0
;;
esac
29 changes: 29 additions & 0 deletions dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM --platform=linux/arm/v7 kalilinux/kali-rolling

ARG DEBIAN_FRONTEND=noninteractive

# All tools EtherJack scripts call at runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
tshark \
tcpdump \
nmap \
macchanger \
iproute2 \
net-tools \
iptables \
iputils-arping \
hostapd \
dnsmasq \
iw \
rfkill \
openssh-server \
procps \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

WORKDIR /usr/local/EtherJack
ENTRYPOINT ["/entrypoint.sh"]
97 changes: 97 additions & 0 deletions dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# EtherJack ARM Dev Environment

Runs EtherJack on an emulated ARMv7 (Raspberry Pi Zero W) environment inside Docker using QEMU user-static. Lets you edit scripts on your host and test them instantly without physical hardware.

## Requirements

- Docker
- x86/amd64 host (Linux or Mac with Rosetta)

QEMU ARM support is registered automatically on first run.

## Usage

From the repo root:

```sh
bash dev/run.sh
```

This will:
1. Register QEMU ARM binfmt handlers if not already present
2. Build the `etherjack-dev` Docker image (cached after first build)
3. Drop you into an interactive ARM shell at `/usr/local/EtherJack`

The repo is bind-mounted, so any edits you make on the host are reflected immediately — no rebuild needed.

## Inside the container

```
ARM dev environment — armv7l

Interfaces:
eth0@eth0-peer UP ...
eth0-peer@eth0 UP ...
wlan0 UP ...

Repo mounted at : /usr/local/EtherJack
Current EJMODE : EJMODE=preset
```

### Running EtherJack

```sh
# Edit the mode if needed
nano EtherJack.conf # set EJMODE=lan | wifi | preset

bash EtherJack.sh
```

### Interface layout

| Interface | Purpose |
|------------|---------|
| `eth0` | EtherJack's interface — what the scripts see |
| `eth0-peer`| The veth peer — available if you want to inject traffic manually |
| `wlan0` | Dummy interface for WIFI mode config and iptables rules |

On real Pi hardware, `eth0` would have live LAN traffic as soon as the device is plugged in. In this environment that traffic is absent — see known limitations below.

### Scripted / non-interactive use

Pass a command as an argument to `run.sh` via Docker directly:

```sh
docker run --rm --platform linux/arm/v7 --privileged --network=none \
-v "$PWD:/usr/local/EtherJack" \
etherjack-dev bash -c 'bash EtherJack.sh'
```

## Known limitations

### tshark / tcpdump — live capture does not work

QEMU user-static does not fully emulate `AF_PACKET` socket operations required by libpcap. Both `tshark` and `tcpdump` will fail to open a capture session on `eth0`:

```
setsockopt (PACKET_ADD_MEMBERSHIP): Protocol not available
```

**Impact:** `netfinder.sh` will not collect IP addresses from ARP traffic.
**Workaround:** Use the BATS test suite (`bash dev/run-tests.sh` or CI) to unit-test capture logic with mocked commands.

### hostapd — will not bind to wlan0

`hostapd` requires a real wireless driver with AP mode support. The dummy `wlan0` interface satisfies everything *except* the actual bind. WIFI mode will run through its full setup (IP configuration, iptables rules, dnsmasq) and then print a hostapd error.

### init is intercepted

EtherJack calls `init 0` on an unrecognised `EJMODE`. Inside the container this would kill the shell. A stub `init` in `/dev-bin` intercepts the call and prints a message instead, so the container stays alive.

## Rebuilding the image

Only needed after changing `dev/Dockerfile` or `dev/entrypoint.sh`:

```sh
docker build --platform linux/arm/v7 -t etherjack-dev -f dev/Dockerfile dev/
```
88 changes: 88 additions & 0 deletions dev/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/bin/bash

# ---------------------------------------------------------------------------
# EtherJack dev environment entrypoint
#
# Sets up a virtual eth0 using a veth pair and a dummy wlan0, then drops
# to an interactive bash shell so you can run / edit EtherJack scripts
# without real Pi hardware.
#
# Known limitations (QEMU user-static on x86):
# tshark/tcpdump — AF_PACKET socket operations are not fully emulated;
# live packet capture fails. netfinder.sh will not collect IPs.
# Use the BATS test suite for unit testing capture logic.
# hostapd — needs a real wireless driver; WIFI mode starts but
# hostapd will fail to bind. The rest of wifi.sh runs fine.
# init 0 — intercepted so the container isn't killed on an invalid
# EJMODE value.
# ---------------------------------------------------------------------------

echo ""
echo " ███████╗████████╗██╗ ██╗███████╗██████╗ ██╗ █████╗ ██████╗██╗ ██╗"
echo " ██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗ ██║██╔══██╗██╔════╝██║ ██╔╝"
echo " █████╗ ██║ ███████║█████╗ ██████╔╝ ██║███████║██║ █████╔╝ "
echo " ██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗██ ██║██╔══██║██║ ██╔═██╗ "
echo " ███████╗ ██║ ██║ ██║███████╗██║ ██║╚█████╔╝██║ ██║╚██████╗██║ ██╗"
echo " ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝"
echo ""
echo " ARM dev environment — $(uname -m)"
echo ""

# ---------------------------------------------------------------------------
# Intercept init so invalid/empty EJMODE doesn't kill the container
# ---------------------------------------------------------------------------
mkdir -p /dev-bin
cat >/dev-bin/init <<'EOF'
#!/bin/bash
echo "[dev] init $* called — ignoring shutdown in dev environment"
EOF
chmod +x /dev-bin/init
export PATH="/dev-bin:$PATH"

# ---------------------------------------------------------------------------
# Virtual eth0 via veth pair
# eth0 — EtherJack's interface (what the scripts see)
# eth0-peer — available if you want to inject traffic manually
# ---------------------------------------------------------------------------
ip link add eth0 type veth peer name eth0-peer 2>/dev/null || true
ip link set eth0 up 2>/dev/null || true
ip link set eth0-peer up 2>/dev/null || true

# ---------------------------------------------------------------------------
# Dummy wlan0 (enough for wifi.sh to configure IP / iptables rules;
# hostapd will fail to bind — that's a known dev limitation)
# ---------------------------------------------------------------------------
ip link add wlan0 type dummy 2>/dev/null || true
ip link set wlan0 up 2>/dev/null || true

echo " ##############################################################"
echo " # KNOWN DEV LIMITATIONS #"
echo " ##############################################################"
echo " tshark/tcpdump — live capture fails (QEMU AF_PACKET limitation)."
echo " On real hardware eth0 would have live LAN traffic."
echo " hostapd — needs a real wireless driver; won't bind to wlan0."
echo " ##############################################################"
echo ""
echo " ##############################################################"
echo " # INTERFACES #"
echo " ##############################################################"
ip -brief link 2>/dev/null || true
echo ""
echo " ##############################################################"
echo " # ENVIRONMENT INFO #"
echo " ##############################################################"
echo " Repo mounted at : /usr/local/EtherJack"
echo " Current EJMODE : $(grep '^EJMODE=' /usr/local/EtherJack/EtherJack.conf 2>/dev/null || echo 'not set')"
echo ""
echo " To run EtherJack (on real hardware this starts automatically on boot):"
echo " cd /usr/local/EtherJack && bash EtherJack.sh"
echo ""

# Pass through any arguments (e.g. bash -c '...' for scripted use);
# default to an interactive shell (not --login; avoids Kali profile scripts
# that can hang or suppress the prompt in the ARM QEMU environment)
if [ $# -gt 0 ]; then
exec "$@"
else
exec bash -i
fi
40 changes: 40 additions & 0 deletions dev/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# ---------------------------------------------------------------------------
# Ensure QEMU ARM binfmt handlers are registered so Docker can run arm/v7
# images on this x86 host. This is a one-time no-op after first run.
# ---------------------------------------------------------------------------
if ! grep -rq "arm" /proc/sys/fs/binfmt_misc/ 2>/dev/null; then
echo "[run] Registering QEMU ARM binfmt handlers..."
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
else
echo "[run] QEMU ARM binfmt already registered."
fi

# ---------------------------------------------------------------------------
# Build the dev image (cached after first build)
# ---------------------------------------------------------------------------
echo "[run] Building ARM dev image..."
docker build \
--platform linux/arm/v7 \
-t etherjack-dev \
-f "$SCRIPT_DIR/Dockerfile" \
"$SCRIPT_DIR"

# ---------------------------------------------------------------------------
# Launch the container
# --privileged needed for ip link / iptables inside the container
# -v mount the live repo so edits on the host take effect
# immediately — no rebuild required
# ---------------------------------------------------------------------------
echo "[run] Launching EtherJack ARM dev environment..."
docker run --rm -it \
--platform linux/arm/v7 \
--privileged \
--network=none \
-v "$REPO_ROOT:/usr/local/EtherJack" \
etherjack-dev
Loading
Loading