diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..5b479aa --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,48 @@ +--- +name: CI + +on: + pull_request: + branches: + - main + types: [opened, synchronize, edited] + +permissions: {} + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + + permissions: + contents: read + packages: read + statuses: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Super-linter + uses: super-linter/super-linter/slim@v7.1.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + test: + needs: lint + name: Test + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run tests + shell: bash + run: | + chmod +x bidir-traffic-check.sh \ + test-bidir-traffic-check.sh + + sudo ./test-bidir-traffic-check.sh diff --git a/README.md b/README.md index 99f8f6b..9907689 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,85 @@ -# bidir-traffic-check -This repo contains a health script that looks for bi-directional TCP communications using tcpdump. +# Bi-Directional Traffic Check + +This project provides a script to check for bi-directional network traffic on specified interfaces. + +## Table of Contents + +- [Description](#description) +- [Features](#features) +- [Installation](#installation) +- [Usage](#usage) +- [Configuration](#configuration) +- [Testing](#testing) +- [Contributing](#contributing) +- [License](#license) + +## Description + +The Bi-Directional Traffic Check script is designed to monitor network interfaces for bi-directional TCP traffic. It's useful for network administrators and security professionals who need to verify active two-way communications on their networks. + +## Features + +- Automatic detection of active network interfaces +- Configurable interface ignore list +- Customizable packet capture count + +## Installation + +1. Clone this repository: + ```bash + git clone https://github.com/yourusername/bidir-traffic-check.git + ``` +2. Navigate to the project directory: + ```bash + cd bidir-traffic-check + ``` +3. Ensure the script has execute permissions: + ```bash + chmod +x bidir-traffic-check.sh + ``` + +## Usage + +Run the script with root privileges: + +```bash +sudo ./bidir-traffic-check.sh +``` + +The script will output whether bi-directional communication was found on each active interface. + +## Configuration + +You can configure the script by editing the following variables: + +- `TCPDUMP_PATH`: Set the path to tcpdump if it's not in your system PATH +- `INTERFACES`: Specify network interfaces to check (empty array checks all interfaces) +- `IGNORE_INTERFACES`: List interfaces to ignore +- `PACKETS`: Number of packets to capture when checking for bi-directional traffic + +## Testing + +To run the test suite: + +1. Ensure the test script has execute permissions: + ```bash + chmod +x test-bidir-traffic-check.sh + ``` +2. Run the test script with root privileges: + ```bash + sudo ./test-bidir-traffic-check.sh + ``` + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/AmazingFeature`) +3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +## License + +This project is licensed under the GNU General Public License v3.0. See the [LICENSE](LICENSE) file for details. diff --git a/bidir-traffic-check.sh b/bidir-traffic-check.sh index 8b5d18f..b230499 100755 --- a/bidir-traffic-check.sh +++ b/bidir-traffic-check.sh @@ -1,73 +1,87 @@ #!/usr/bin/env bash -set -x - # Path to tcpdump (defaults to $PATH if empty) -TCPDUMP_PATH= +TCPDUMP_PATH=${TCPDUMP_PATH:-tcpdump} + # Automatically found network interfaces in 'up' status AUTO_INTERFACES=() + # Network interfaces to check (defaults to all interfaces if empty) INTERFACES=() + # Network interface ignore list (useful when defaulting to all interfaces) IGNORE_INTERFACES=("lo" "docker0" "virbr0") + +# Number of packets to capture when checking for bi-directional traffic +PACKETS=50 + # Return codes OK=0 ERROR=1 WARNING=2 -UNKNOWN=3 + # Check for root privileges function checkSudo() { - if (( $(id -u) != 0 )); then - echo "ERROR - This script must be run with root privileges!" - return $ERROR - fi + if (($(id -u) != 0)); then + echo "ERROR - This script must be run with root privileges!" + return $ERROR + fi } + # Populate the network interfaces array function getInterfaces() { - if (( ${#INTERFACES[@]} == 0 )); then - for iface in /sys/class/net/*; do - INTERFACES+=("${iface}") - done - fi + if ((${#INTERFACES[@]} == 0)); then + for iface in /sys/class/net/*; do + INTERFACES+=("${iface}") + done + fi } + # Remove ignored interfaces from the interfaces array function ignoreInterfaces() { - for ignored_iface in "${IGNORE_INTERFACES[@]}"; do - INTERFACES=("${INTERFACES[@]/$ignored_iface}") - done + for ignored_iface in "${IGNORE_INTERFACES[@]}"; do + INTERFACES=("${INTERFACES[@]/$ignored_iface/}") + done } + # Remove interfaces marked as 'down' function removeDownInterfaces() { - for iface in "${INTERFACES[@]}"; do - if [[ -n "$iface" && -f "/sys/class/net/$iface/operstate" ]]; then - if grep -q 'up' "/sys/class/net/$iface/operstate"; then - AUTO_INTERFACES+=("$iface") - fi - fi - done + for iface in "${INTERFACES[@]}"; do + if [[ -n "$iface" && -f "/sys/class/net/$iface/operstate" ]]; then + if grep -q 'up' "/sys/class/net/$iface/operstate"; then + AUTO_INTERFACES+=("$iface") + fi + fi + done } + # Check for bi-directional traffic on interfaces function checkTraffic() { - for iface in "${AUTO_INTERFACES[@]}"; do - tcpdump -n -i "$iface" tcp -c 50 2> /dev/null | awk '{ - src[NR]=$3; - dst[NR]=substr($5, 1, length($5)-1) + for iface in "${AUTO_INTERFACES[@]}"; do + tcpdump -n -i "$iface" tcp -c "$PACKETS" 2>/dev/null | awk ' + { + src[NR] = $3 + dst[NR] = substr($5, 1, length($5) - 1) } END { - for (i=1; i<=NR; i++) { - for (j=1; j<=NR; j++) { + for (i = 1; i <= NR; i++) { + for (j = 1; j <= NR; j++) { if (src[i] == dst[j] && src[i] != "") { if (dst[i] == src[j]) { - print "Bi-Directional communication found on '"$iface"'\n" src[i]" -> "dst[i]"\n"src[j]" -> "dst[j]; - exit + print "Bi-Directional communication found on '"$iface"'" + print src[i] " -> " dst[i] + print src[j] " -> " dst[j] + return '"$OK"' } } } } print "Bi-Directional communication not found on '"$iface"'" + return '"$WARNING"' }' - done + done } + # Main script execution checkSudo getInterfaces diff --git a/test-bidir-traffic-check.sh b/test-bidir-traffic-check.sh new file mode 100755 index 0000000..a1fb177 --- /dev/null +++ b/test-bidir-traffic-check.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# Set up test environment +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_TO_TEST="$SCRIPT_DIR/bidir-traffic-check.sh" +FAILED_TESTS=0 + +# Function to run the script and capture output +run_test() { + local description="$1" + local expected_exit_code="$2" + local expected_output="$3" + + echo "Running test: $description" + output=$(sudo "$SCRIPT_TO_TEST" 2>&1) + exit_code=$? + + if [ $exit_code -eq "$expected_exit_code" ]; then + echo "Exit code test passed" + else + echo "Exit code test failed. Expected: $expected_exit_code, Got: $exit_code" + FAILED_TESTS=$((FAILED_TESTS + 1)) + fi + + if echo "$output" | grep -q "$expected_output"; then + echo "Output test passed" + else + echo "Output test failed. Expected to contain: $expected_output" + echo "Got: $output" + FAILED_TESTS=$((FAILED_TESTS + 1)) + fi + + echo "---" +} + +# Test 1: Check if script runs without errors +run_test "Basic execution" 0 "Bi-Directional communication" + +# Test 2: Check if script detects lack of root privileges +if [ "$EUID" -eq 0 ]; then + echo "Skipping root privilege test (already running as root)" +else + run_test "Non-root execution" 3 "This script must be run with root privileges" +fi + +# Test 3: Check if script handles non-existent interface +NONEXISTENT_INTERFACE="eth999" +sudo sed -i "s/^INTERFACES=(.*)/INTERFACES=($NONEXISTENT_INTERFACE)/" "$SCRIPT_TO_TEST" +run_test "Non-existent interface" 1 "Bi-Directional communication not found" + +# Restore original INTERFACES setting +sudo sed -i "s/^INTERFACES=(.*)/INTERFACES=()/" "$SCRIPT_TO_TEST" + +echo "All tests completed." + +if [ $FAILED_TESTS -gt 0 ]; then + echo "Test suite failed with $FAILED_TESTS error(s)." + exit 1 +else + echo "All tests passed successfully." + exit 0 +fi