#!/bin/bash ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2010 Michael Tremer & Christian Schmidt # # # # This program 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. # # # # This program 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 this program. If not, see . # # # ############################################################################### IP_SUPPORTED_PROTOCOLS="${IP_SUPPORTED_PROTOCOLS} ipv4" ipv4_is_valid() { local address=${1} local prefix=$(ip_get_prefix ${address}) address=$(ip_split_prefix ${address}) # If prefix is set, we check if it is correct if isset prefix; then # Must be numeric isinteger prefix || return ${EXIT_FALSE} # Must be 32 if present [ ${prefix} -eq 32 ] || return ${EXIT_FALSE} fi inetcalc -4 -c ${address} && return ${EXIT_TRUE} || return ${EXIT_FALSE} } ipv4_prefix_is_valid() { local prefix=${1} # Check if prefix is a number isinteger prefix || return ${EXIT_FALSE} [ ${prefix} -le 0 ] && return ${EXIT_FALSE} [ ${prefix} -gt 32 ] && return ${EXIT_FALSE} return ${EXIT_TRUE} } ipv4_net_is_valid() { local net="${1}" local prefix="$(ip_get_prefix "${net}")" local addr="$(ip_split_prefix "${net}")" ipv4_prefix_is_valid "${prefix}" && ipv4_is_valid "${addr}" } ipv4_netmask_is_valid() { local netmask="${1}" # XXX this check could be much better by checking # if the netmask only contains leading ones ipv4_is_valid "${netmask}" } ipv4_detect_duplicate() { local device=${1} local address=${2} assert isset address assert isset device assert device_exists ${device} # Don't check on PPP devices. device_is_ppp ${device} && return ${EXIT_ERROR} if ! arping -q -c 2 -w 3 -D -I ${device} ${address}; then log DEBUG "Detected duplicate address '${address}' on device '${device}'." return ${EXIT_OK} fi return ${EXIT_ERROR} } ipv4_update_neighbours() { local device=${1} local address=${2} # Don't do anything on PPP devices. device_is_ppp ${device} && return ${EXIT_OK} arping -q -A -c 1 -I ${device} ${address} ( sleep 2; arping -q -U -c 1 -I ${device} ${address} ) >/dev/null 2>&1 /dev/null 2>&1 ip -4 route flush dev ${device} >/dev/null 2>&1 ip -4 neigh flush dev ${device} >/dev/null 2>&1 return 0 } ipv4_prefix2netmask() { local prefix="${1}" case "${prefix}" in 32) echo "255.255.255.255" ;; 31) echo "255.255.255.254" ;; 30) echo "255.255.255.252" ;; 29) echo "255.255.255.248" ;; 28) echo "255.255.255.240" ;; 27) echo "255.255.255.224" ;; 26) echo "255.255.255.192" ;; 25) echo "255.255.255.128" ;; 24) echo "255.255.255.0" ;; 23) echo "255.255.254.0" ;; 22) echo "255.255.252.0" ;; 21) echo "255.255.248.0" ;; 20) echo "255.255.240.0" ;; 19) echo "255.255.224.0" ;; 18) echo "255.255.192.0" ;; 17) echo "255.255.128.0" ;; 16) echo "255.255.0.0" ;; 15) echo "255.254.0.0" ;; 14) echo "255.252.0.0" ;; 13) echo "255.248.0.0" ;; 12) echo "255.240.0.0" ;; 11) echo "255.224.0.0" ;; 10) echo "255.192.0.0" ;; 9) echo "255.128.0.0" ;; 8) echo "255.0.0.0" ;; 7) echo "254.0.0.0" ;; 6) echo "252.0.0.0" ;; 5) echo "248.0.0.0" ;; 4) echo "240.0.0.0" ;; 3) echo "224.0.0.0" ;; 2) echo "192.0.0.0" ;; 1) echo "128.0.0.0" ;; 0) echo "0.0.0.0" ;; *) return ${EXIT_ERROR} ;; esac return ${EXIT_OK} } ipv4_netmask2prefix() { local netmask="${1}" assert isset netmask local mask=0 local field for field in ${netmask//\./ }; do mask=$(( $(( ${mask} << 8 )) | ${field} )) done local cidr=0 local x="$(( 128 << 24 ))" # 0x80000000 while [ $(( ${x} & ${mask} )) -ne 0 ]; do [ ${mask} -eq ${x} ] && mask=0 || mask=$(( ${mask} << 1 )) cidr=$(( ${cidr} + 1 )) done assert [ $(( ${mask} & 2147483647 )) -eq 0 ] print "${cidr}" } ipv4_get_network() { ip_get_network "$@" } ipv4_get_broadcast() { inetcalc -4 -b "$@" && return ${EXIT_OK} || return ${EXIT_ERROR} } ipv4_encode() { local addr=${1} local int=0 local field for field in ${addr//./ }; do int=$(( $(( ${int} << 8 )) | ${field} )) done print "${int}" } ipv4_decode() { local int=${1} local addr=$(( ${int} & 255 )) local i for i in 1 2 3; do int=$(( ${int} >> 8 )) addr="$(( ${int} & 255 )).${addr}" done print "${addr}" } ipv4_addr_eq() { local addr1=${1} assert isset addr1 local addr2=${2} assert isset addr2 [[ "${addr1}" = "${addr2}" ]] \ && return ${EXIT_TRUE} || return ${EXIT_FALSE} } ipv4_addr_gt() { assert [ $# -eq 2 ] local addr1="${1}" local addr2="${2}" inetcalc -4 -g "${addr1}" "${addr2}" \ && return ${EXIT_TRUE} || return ${EXIT_FALSE} } ipv4_addr_ge() { ipv4_addr_eq "$@" || ipv4_addr_gt "$@" } ipv4_addr_lt() { ! ipv4_addr_eq "$@" && ! ipv4_addr_gt "$@" } ipv4_addr_le() { ipv4_addr_eq "$@" || ! ipv4_addr_gt "$@" } ipv4_range() { local range=${1} local first=${1%-*} local last=${1#*-} _ipv4_range "$(ipv4_encode ${first})" "$(ipv4_encode ${last})" } _ipv4_range() { local first=${1} local last=${2} if [ ${first} -gt ${last} ]; then local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})" error "Invalid IPv4 address range: ${range}" return ${EXIT_ERROR} fi last=$(( ${last} + 1 )) local prefix local x y z while [ ${last} -gt ${first} ]; do prefix= x=31 y=2 z=1 while [ $(( ${first} % ${y} )) -eq 0 ] && [ ${last} -gt $(( ${first} + ${y} )) ]; do prefix="/${x}" x=$(( ${x} - 1 )) z=${y} y=$(( ${y} * 2 )) done print "$(ipv4_decode ${first})${prefix}" first=$(( ${first} + ${z} )) done } ipv4_range_explicit() { local range=${1} local first last case "${range}" in *.*.*.*-*.*.*.*) first=${range%-*} last=${range#*-} ;; *.*.*.*/*) first=$(ipv4_get_network ${range}) first="$(ip_split_prefix "${first}")" last=$(ipv4_get_broadcast ${range}) last="$(ip_split_prefix "${last}")" ;; esac _ipv4_range_explicit "$(ipv4_encode ${first})" "$(ipv4_encode ${last})" } _ipv4_range_explicit() { local first=${1} local last=${2} if [ ${first} -gt ${last} ]; then local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})" error "Invalid IPv4 address range: ${range}" return ${EXIT_ERROR} fi while [ ${first} -le ${last} ]; do ipv4_decode ${first} first=$(( ${first} + 1 )) done } ipv4_in_subnet() { local addr=${1} assert isset addr local subnet=${2} assert isset subnet local subnet_first=$(ipv4_get_network_encoded ${subnet}) local subnet_last=$(ipv4_get_broadcast_encoded ${subnet}) addr=$(ipv4_encode ${addr}) if [[ "${addr}" -ge "${subnet_first}" ]] && [[ "${addr}" -le "${subnet_last}" ]]; then return ${EXIT_TRUE} fi return ${EXIT_FALSE} } ipv4_ttl_valid() { local ttl="${1}" isinteger ttl || return ${EXIT_FALSE} # Must be between 10 and 255. [ "${ttl}" -lt 10 ] && return ${EXIT_FALSE} [ "${ttl}" -gt 255 ] && return ${EXIT_FALSE} return ${EXIT_TRUE} }