#!/bin/sh
# arp-scan is Copyright (C) 2005-2024 Roy Hills
#
# This file is part of arp-scan.
#
# arp-scan 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.
#
# arp-scan is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with arp-scan.  If not, see <http://www.gnu.org/licenses/>.
#
# check-run1 -- Shell script to test arp-scan basic functionality
#
# Author: Roy Hills
# Date: 7 November 2022
#
# This shell script checks various error conditions.
#
ARPSCANOUTPUT=/tmp/arp-scan-output.$$.tmp
SAMPLE01="$srcdir/testdata/pkt-simple-response.pcap"
SAMPLE02="$srcdir/testdata/pkt-too-short.pcap"

# Check invalid option - should have non-zero exit status
echo "Checking arp-scan --xyz (invalid option) ..."
./arp-scan --xyz > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Use "arp-scan --help" for detailed information' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Check no target hosts - should have non-zero exit status
echo "Checking arp-scan without target hosts ..."
./arp-scan > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: No target hosts on command line ' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Try to use a host input file that doesn't exist - should have non-zero exit status
echo "Checking arp-scan with non existent host file ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS -f xxxFUNNYxxx --readpktfromfile="$SAMPLE01" > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Cannot open xxxFUNNYxxx:' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Try to use a non-existent mac/vendor mapping file - should warn and continue
echo "Checking arp-scan with non existent mac/vendor file ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS -O xxxFUNNYxxx --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^WARNING: Cannot open MAC/Vendor file xxxFUNNYxxx:' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Try to specify both --bandwidth and --interval - nonzero exit status.
echo "Checking arp-scan with both --bandwidth and --interval ..."
ARPARGS="--retry=1 --bandwidth=1 --interval=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: You cannot specify both --bandwidth and --interval' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Try to specify targets with the --localnet option - nonzero exit
echo "Checking arp-scan with both targets and --localnet ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" --localnet 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: You can not specify targets with the --localnet option' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Try to specify --file with --localnet option - nonzero exit
echo "Checking arp-scan with --file and --localnet ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" --localnet --file=- > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: You can not specify both --file and --localnet options' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid IP address - warning followed by nonzero exit
echo "Checking arp-scan with invalid IP address ..."
ARPARGS="--retry=1 --numeric"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 333.333.333.333 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^WARNING: "333.333.333.333" is not a valid IPv4 address - target ignored' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid IP network in CIDR notation - nonzero exit
echo "Checking arp-scan with invalid IP network in CIDR notation ..."
ARPARGS="--retry=1 --numeric"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 333.0.0.0/24 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: 333.0.0.0 is not a valid IPv4 network' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid CIDR mask - nonzero exit
echo "Checking arp-scan with invalid CIDR address ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 10.0.0.0/0 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Number of bits in 10.0.0.0/0 must be between 3 and 32' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify CIDR address with non-zero host part: warning
echo "Checking arp-scan with nonzero host in CIDR address ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 10.0.0.1/30 > "$ARPSCANOUTPUT" 2>&1
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^WARNING: host part of 10.0.0.1/30 is non-zero' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid IP network in net:mask notation - nonzero exit
echo "Checking arp-scan with invalid IP network in net:mask notation ..."
ARPARGS="--retry=1 --numeric"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 333.0.0.0:255.255.255.0 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: 333.0.0.0 is not a valid IPv4 network' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid netmask - nonzero exit
echo "Checking arp-scan with invalid netmask ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 10.0.0.0:333.0.0.0 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: 333.0.0.0 is not a valid netmask' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify net:mask address with non-zero host part: warning
echo "Checking arp-scan with nonzero host in net:mask address ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 10.0.0.1:255.255.255.252 > "$ARPSCANOUTPUT" 2>&1
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^WARNING: host part of 10.0.0.1:255.255.255.252 is non-zero' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid starting IP address in range notation - nonzero exit
echo "Checking arp-scan with invalid starting IP network in range notation ..."
ARPARGS="--retry=1 --numeric"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 333.0.0.0-10.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Invalid range specification: 333.0.0.0 is not a valid IPv4 address' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Specify invalid ending IP address in range notation - nonzero exit
echo "Checking arp-scan with invalid ending IP network in range notation ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 10.0.0.1-333.0.0.0 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Invalid range specification: 333.0.0.0 is not a valid IPv4 address' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid signed long int input - nonzero exit
echo "Checking arp-scan with invalid CIDR address ..."
ARPARGS="--retry=1 --retry-send=xyz"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: "xyz" is not a valid numeric value' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid unsigned long int input - nonzero exit
echo "Checking arp-scan with invalid CIDR address ..."
ARPARGS="--retry=1 --snap=xyz"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: "xyz" is not a valid numeric value' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid bandwidth multiplier - nonzero exit
echo "Checking arp-scan with invalid bandwidth multiple ..."
ARPARGS="--retry=1 --bandwidth=1x"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Unknown bandwidth multiplier character: "x"' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid interval multiplier - nonzero exit
echo "Checking arp-scan with invalid interval multiple ..."
ARPARGS="--retry=1 --interval=1x"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Unknown interval multiplier character: "x"' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid --format string: invalid field width
echo "Checking arp-scan with invalid --format field width ..."
ARPARGS="--retry=1 --format=\${ip;X}"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: incorrect format string: invalid character \"X\" in field width' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid --format string: field width out of range
echo "Checking arp-scan with --format field width out of range ..."
ARPARGS="--retry=1 --format=\${ip;5000000000}"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: incorrect format string: field width out of range' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid format string: missing closing brace
echo "Checking arp-scan with --format field missing closing brace ..."
ARPARGS="--retry=1 --format=\${ip"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: incorrect format string: missing closing brace' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid format string: empty string
echo "Checking arp-scan with --format field empty string ..."
ARPARGS="--retry=1 --format="
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: output format may not be empty string' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# --destaddr invalid MAC address
echo "Checking arp-scan with --destaddr invalid MAC address ..."
ARPARGS="--retry=1 --destaddr=XX"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Invalid MAC address: XX' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# --arpsha invalid MAC address
echo "Checking arp-scan with --arpsha invalid MAC address ..."
ARPARGS="--retry=1 --arpsha=XX"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Invalid MAC address: XX' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# --arptha invalid MAC address
echo "Checking arp-scan with --arptha invalid MAC address ..."
ARPARGS="--retry=1 --arptha=XX"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Invalid MAC address: XX' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# --srcaddr invalid MAC address
echo "Checking arp-scan with --srcaddr invalid MAC address ..."
ARPARGS="--retry=1 --srcaddr=XX"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE01" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^Invalid MAC address: XX' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Non-existent pcap file for --readpktfromfile
echo "Checking arp-scan with nonexistent --readpktfromfile file ..."
ARPARGS="--retry=1 --readpktfromfile=xxxFUNNYxxx"
./arp-scan $ARPARGS 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^pcap_open_offline: xxxFUNNYxxx: No such file or directory' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Invalid IP address for --arpspa option
echo "Checking arp-scan with invalid --arpspa option ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --arpspa=333.0.0.1 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Invalid IPv4 address: 333.0.0.1' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Odd --padding length
echo "Checking arp-scan with odd --padding length ..."
ARPARGS="--retry=1"
./arp-scan $ARPARGS --padding=a 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -eq 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^ERROR: Length of --padding argument must be even (multiple of 2).' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"

# Packet too short to decode
echo "Checking arp-scan with packet too short to decode ..."
ARPARGS="--retry=1 --plain --quiet"
./arp-scan $ARPARGS --readpktfromfile="$SAMPLE02" 127.0.0.1 > "$ARPSCANOUTPUT" 2>&1
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
grep '^WARNING: 22 byte packet too short to decode.' "$ARPSCANOUTPUT" >/dev/null
if test $? -ne 0; then
   rm -f "$ARPSCANOUTPUT"
   echo "FAILED"
   exit 1
fi
echo "ok"
rm -f "$ARPSCANOUTPUT"
