# The plugin configuration file
###############################
PLUGIN_CONF_FILE="parasitic-net.conf"

# Preinit return value for success
PLUGIN_RET_VAL=0

# Check sanity of environment
parasitic_net_helper_sanity_check()
{
  # Check whether chain exists
  if ! ip4tables -nL PARASITIC_NET_ACL >/dev/null 2>&1; then
    echo "** ERROR: PARASITIC_NET_ACL does not exist! **" >&2
    return 1
  fi

  return 0
}


parasitic_net_helper_do_work()
{
  local RETVAL=0

  # Flush the PARASITIC_NET_ACL
  iptables -F PARASITIC_NET_ACL

  unset IFS
  for rule in $PARASITIC_NET_HOST_DENY_TCP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_DENY_TCP "shosts:ANYHOST-dhosts-ports:ANYPORT"; then
      echo "${INDENT}Denying access from $shosts to $dhosts for TCP port(s): $ports"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping TCP deny rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            for port in $ports; do
              if [ "$PARASITIC_NET_DENY_LOG" = "1" ]; then
                ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p tcp --dport $port -m limit --limit 1/m -j LOG \
                  --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
              fi

              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p tcp --dport $port -j $PARASITIC_NET_DENY_POLICY
            done
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_DENY_UDP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_DENY_UDP "shosts:ANYHOST-dhosts-ports:ANYPORT"; then
      echo "${INDENT}Denying access from $shosts to $dhosts for UDP port(s): $ports"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping UDP deny rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            for port in $ports; do
              if [ "$PARASITIC_NET_DENY_LOG" = "1" ]; then
                ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p udp --dport $port -m limit --limit 1/m -j LOG \
                  --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
              fi

              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p udp --dport $port -j $PARASITIC_NET_DENY_POLICY
            done
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_DENY_ICMP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_DENY_ICMP "shosts:ANYHOST-dhosts"; then
      echo "${INDENT}Denying access from $shosts to $dhosts for ICMP requests"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping ICMP deny rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            if [ "$PARASITIC_NET_DENY_LOG" = "1" ]; then
              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p icmp --icmp-type echo-request -m limit --limit 1/m -j LOG \
                --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
            fi

            ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p icmp --icmp-type echo-request -j $PARASITIC_NET_DENY_POLICY
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_DENY_IP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_DENY_IP "shosts:ANYHOST-dhosts-protos"; then
      echo "${INDENT}Denying access from $shosts to $dhosts for IP protocol(s): $protos"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping IP deny rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            for proto in $protos; do
              if [ "$PARASITIC_NET_DENY_LOG" = "1" ]; then
                ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p $proto -m limit --limit 1/m -j LOG \
                  --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
              fi

              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p $proto -j $PARASITIC_NET_DENY_POLICY
            done
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_OPEN_TCP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_OPEN_TCP "shosts:ANYHOST-dhosts-ports"; then
      echo "${INDENT}Allowing access from $shosts to $dhosts for TCP port(s): $ports"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping TCP allow rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            for port in $ports; do
              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p tcp --dport $port -j ACCEPT
            done
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_OPEN_UDP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_OPEN_UDP "shosts:ANYHOST-dhosts-ports"; then
      echo "${INDENT}Allowing access from $shosts to $dhosts for UDP port(s): $ports"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping UDP allow rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in `ip_range "$shosts"`; do
            for port in $ports; do
              ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p udp --dport $port -j ACCEPT
            done
          done
        done
      done
    fi
  done

  unset IFS

  for rule in $PARASITIC_NET_HOST_OPEN_ICMP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_OPEN_ICMP "shosts:ANYHOST-dhosts"; then
      echo "${INDENT}Allowing access from $shosts to $dhosts for ICMP requests"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping ICMP allow rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in $shosts; do
            ip4tables -A PARASITIC_NET_ACL -s $shost_ip -d $dhost_ip -p icmp --icmp-type echo-request -j ACCEPT
          done
        done
      done
    fi
  done

  unset IFS
  for rule in $PARASITIC_NET_HOST_OPEN_IP; do
    if parse_rule "$rule" PARASITIC_NET_HOST_OPEN_IP "shosts:ANYHOST-dhosts-protos"; then
      echo "${INDENT}Allowing access from $shosts to $dhosts for IP protocol(s): $protos"

      IFS=' ,'
      for dhost in `ip_range "$dhosts"`; do
        if ! get_dynamic_host_cached $dhost || [ -z "$host_ip" ]; then
          echo "** WARNING: Skipping IP allow rule(s) for unresolvable host \"$dhost\"! **" >&2
          RETVAL=1
          continue
        fi

        for dhost_ip in $host_ip; do
          for shost_ip in $shosts; do
            for proto in $protos; do
              ip4tables -A PARASITIC_NET_ACL -d $dhost_ip -p $proto -j ACCEPT
            done
          done
        done
      done
    fi
  done

  # Set default policy
  if [ -z "$PARASITIC_NET_HOST_OPEN_TCP" ]; then
    ip4tables -A PARASITIC_NET_ACL -p tcp -j ACCEPT
  else
    if [ "$PARASITIC_NET_DENY_LOG" != "0" ]; then
      ip4tables -A PARASITIC_NET_ACL -p tcp -m limit --limit 12/m -j LOG \
        --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
    fi

    ip4tables -A PARASITIC_NET_ACL -p tcp -j $PARASITIC_NET_DENY_POLICY
  fi

  if [ -z "$PARASITIC_NET_HOST_OPEN_UDP" ]; then
    ip4tables -A PARASITIC_NET_ACL -p udp -j ACCEPT
  else
    if [ "$PARASITIC_NET_DENY_LOG" != "0" ]; then
      ip4tables -A PARASITIC_NET_ACL -p udp -m limit --limit 12/m -j LOG \
        --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
    fi

    ip4tables -A PARASITIC_NET_ACL -p udp -j $PARASITIC_NET_DENY_POLICY
  fi

  if [ -z "$PARASITIC_NET_HOST_OPEN_ICMP" ]; then
    ip4tables -A PARASITIC_NET_ACL -p icmp --icmp-type echo-request -j ACCEPT
  else
    if [ "$PARASITIC_NET_DENY_LOG" != "0" ]; then
      ip4tables -A PARASITIC_NET_ACL -p icmp --icmp-type echo-request -m limit --limit 12/m -j LOG \
        --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
    fi

    ip4tables -A PARASITIC_NET_ACL -p icmp --icmp-type echo-request -j $PARASITIC_NET_DENY_POLICY
  fi

  # Drop the rest ("Other" IP protocols always need to be specified explicitly)
  if [ "$PARASITIC_NET_DENY_LOG" != "0" ]; then
    ip4tables -A PARASITIC_NET_ACL -m limit --limit 12/m -j LOG \
      --log-level $LOGLEVEL --log-prefix "AIF:Parasitic-net denied: "
  fi
  ip4tables -A PARASITIC_NET_ACL -j $PARASITIC_NET_DENY_POLICY

  return $RETVAL
}


############
# Mainline #
############

# Check where to find the config file
CONF_FILE=""
if [ -n "$PLUGIN_CONF_PATH" ]; then
  CONF_FILE="$PLUGIN_CONF_PATH/$PLUGIN_CONF_FILE"
fi

# Check if the config file exists
if [ ! -f "$CONF_FILE" ]; then
  echo "** ERROR: Config file \"$CONF_FILE\" not found! **" >&2
  PLUGIN_RET_VAL=1
else
  # Source the plugin config file
  . "$CONF_FILE"

  # Only proceed if environment ok
  if ! parasitic_net_helper_sanity_check; then
    PLUGIN_RET_VAL=1
  else
    if ! parasitic_net_helper_do_work; then
      PLUGIN_RET_VAL=1
    fi
  fi
fi
