File: //usr/libexec/knock_helper_ipt.sh
#!/bin/sh
# Original version to add non-duplicated rules by Greg Kuchyt (greg.kuchyt@gmail.com)
# Updated to handle deletes and be generic by Paul Rogers (paul.rogers@flumps.org)
SCRIPT_NAME=$(basename $0)
AWK="/bin/awk"
GREP="/bin/grep"
IPTABLES="/sbin/iptables"
SORT="/bin/sort"
COMMENT_APP="Append "
COMMENT_DEL="Delete "
COMMENT_INS="Insert "
COMMENT_DEFAULT="by knockd"
IPT_CHAIN="INPUT"
IPT_METHOD=""
IPT_COMMENT=""
IPT_SRC_IP=""
IPT_DST_PORT=""
IPT_PROTO="tcp"
IPT_RULE_TARGET="ACCEPT"
DRY_RUN=0
SEEN=0
VERBOSE=0
usage() {
echo "Usage: $SCRIPT_NAME -a|-i|-x -f SRC_IP_ADDR -d DST_PORT [-p|-c|-m|-t|-h|-v]"
echo "Options:"
echo "-a|--append Action: append a rule to NetFilter"
echo "-i|--insert Action: insert a rule to NetFiler"
echo "-x|--delete Action: delete a rule from NetFilter"
echo "-f|--srcaddr The source IP address to be used"
echo "-d|--dstport The destination port to be used in the rule"
echo "-p|--proto The protocol that the rule applies to; default: $IPT_PROTO"
echo "-c|--chain The NetFilter chain to apply the change to; default: $IPT_CHAIN"
echo "-m|--comment Overide default comment text: '$COMMENT_DEFAULT'"
echo "-t|--test Test run - don't actually perform an update to NetFilter"
echo "-h|--help Print this informational screen and exit"
echo "-v|--verbose Print verbose information about actions"
}
ARGS=$(getopt -o aixf:d:p:c:m::thv -l "append,insert,delete,srcaddr:,dstport:,proto:,chain:,comment::,test,help,verbose" -n $SCRIPT_NAME -- "$@")
if [ $? -ne 0 ];
then
echo "$SCRIPT_NAME - Error! Invalid arguments"
usage
exit 1
fi
eval set -- "$ARGS"
while true; do
case "$1" in
-a|--append)
IPT_METHOD="-A"
shift;
;;
-x|--delete)
IPT_METHOD="-D"
shift;
;;
-i|--insert)
IPT_METHOD="-I"
shift;
;;
-f|--srcaddr)
IPT_SRC_IP=$2
shift 2;
;;
-d|--dstport)
IPT_DST_PORT=$2
shift 2;
;;
-p|--proto)
IPT_PROTO=$2
shift 2;
;;
-c|--chain)
IPT_CHAIN=$2
shift 2;
;;
-m|--comment)
case "$2" in
"")
IPT_COMMENT=$COMMENT_DEFAULT;
shift 2;;
*)
IPT_COMMENT=$2;
shift 2 ;;
esac
;;
-t|--test)
DRY_RUN=1
shift;
;;
-h|--help)
usage
shift;
exit
;;
-v|--verbose)
VERBOSE=1
shift;
;;
--)
shift;
break;
;;
esac
done
# Begin sanity checks
if [ -z "$IPT_SRC_IP" ]; then
echo "$SCRIPT_NAME - Error! Source IP address required"
usage
exit 1
fi
if [ -z "$IPT_DST_PORT" ]; then
echo "$SCRIPT_NAME - Error! Destination port required"
usage
exit 1
fi
if [ -z "$IPT_METHOD" ]; then
echo "$SCRIPT_NAME - Error! Valid action option not specified"
fi
case "$IPT_METHOD" in
-A)
IPT_COMMENT="$COMMENT_APP $IPT_COMMENT"
;;
-I)
IPT_COMMENT="$COMMENT_INS $IPT_COMMENT"
;;
-D)
IPT_COMMENT="$COMMENT_DEL $IPT_COMMENT"
;;
esac
if [ "$VERBOSE" -eq 1 ]; then
echo "$SCRIPT_NAME - Testing rule"
echo "$SCRIPT_NAME - action: $IPT_METHOD _ src: $IPT_SRC_IP _ dstport: $IPT_DST_PORT _ proto: $IPT_PROTO _ chain: $IPT_CHAIN _ comment: $IPT_COMMENT"
fi
COMMENT=""
if [ -n "$IPT_COMMENT" ]; then
COMMENT="-m comment --comment '$IPT_COMMENT'"
fi
$IPTABLES -L $IPT_CHAIN &> /dev/null
if [ 0 -ne "$?" ]; then
echo "$SCRIPT_NAME - Error: $IPT_CHAIN is not a valid NetFilter chain"
exit
fi
# End sanity checks
# Dupe checking
for IP in `$IPTABLES -n -L $IPT_CHAIN | $GREP $IPT_RULE_TARGET | $AWK '{print $4}' | $SORT -u`;
do
if [ "$VERBOSE" -eq 1 ]; then
echo "$SCRIPT_NAME - $IP"
fi
if [ "$IPT_SRC_IP" == "$IP" ]; then
SEEN=1
fi
done
if [ "$VERBOSE" -eq 1 ]; then
echo "$SCRIPT_NAME - Seen: $SEEN"
fi
if [ "$SEEN" -eq 0 ]; then
if [ "$VERBOSE" -eq 1 ]; then
echo "$SCRIPT_NAME - $IPT_COMMENT"
echo $IPTABLES $IPT_METHOD $IPT_CHAIN -s $IPT_SRC_IP -p $IPT_PROTO --dport $IPT_DST_PORT -j $IPT_RULE_TARGET $COMMENT
fi
if [ "$DRY_RUN" -eq 0 ]; then
eval $IPTABLES $IPT_METHOD $IPT_CHAIN -s $IPT_SRC_IP -p $IPT_PROTO --dport $IPT_DST_PORT -j $IPT_RULE_TARGET $COMMENT
fi
fi