ipcalc.sh 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/bin/sh
  2. . /lib/functions/ipv4.sh
  3. PROG="$(basename "$0")"
  4. # wrapper to convert an integer to an address, unless we're using
  5. # decimal output format.
  6. # hook for library function
  7. _ip2str() {
  8. local var="$1" n="$2"
  9. assert_uint32 "$n" || exit 1
  10. if [ "$decimal" -ne 0 ]; then
  11. export -- "$var=$n"
  12. elif [ "$hexadecimal" -ne 0 ]; then
  13. export -- "$var=$(printf "%x" "$n")"
  14. else
  15. ip2str "$@"
  16. fi
  17. }
  18. usage() {
  19. echo "Usage: $PROG [ -d | -x ] address/prefix [ start limit ]" >&2
  20. exit 1
  21. }
  22. decimal=0
  23. hexadecimal=0
  24. if [ "$1" = "-d" ]; then
  25. decimal=1
  26. shift
  27. elif [ "$1" = "-x" ]; then
  28. hexadecimal=1
  29. shift
  30. fi
  31. if [ $# -eq 0 ]; then
  32. usage
  33. fi
  34. case "$1" in
  35. */*.*)
  36. # data is n.n.n.n/m.m.m.m format, like on a Cisco router
  37. str2ip ipaddr "${1%/*}" || exit 1
  38. str2ip netmask "${1#*/}" || exit 1
  39. netmask2prefix prefix "$netmask" || exit 1
  40. shift
  41. ;;
  42. */*)
  43. # more modern prefix notation of n.n.n.n/p
  44. str2ip ipaddr "${1%/*}" || exit 1
  45. prefix="${1#*/}"
  46. assert_uint32 "$prefix" || exit 1
  47. if [ "$prefix" -gt 32 ]; then
  48. printf "Prefix out of range (%s)\n" "$prefix" >&2
  49. exit 1
  50. fi
  51. prefix2netmask netmask "$prefix" || exit 1
  52. shift
  53. ;;
  54. *)
  55. # address and netmask as two separate arguments
  56. str2ip ipaddr "$1" || exit 1
  57. str2ip netmask "$2" || exit 1
  58. netmask2prefix prefix "$netmask" || exit 1
  59. shift 2
  60. ;;
  61. esac
  62. # we either have no arguments left, or we have a range start and length
  63. if [ $# -ne 0 ] && [ $# -ne 2 ]; then
  64. usage
  65. fi
  66. # complement of the netmask, i.e. the hostmask
  67. hostmask=$((netmask ^ 0xffffffff))
  68. network=$((ipaddr & netmask))
  69. broadcast=$((network | hostmask))
  70. count=$((hostmask + 1))
  71. _ip2str IP "$ipaddr"
  72. _ip2str NETMASK "$netmask"
  73. _ip2str NETWORK "$network"
  74. echo "IP=$IP"
  75. echo "NETMASK=$NETMASK"
  76. # don't include this-network or broadcast addresses
  77. if [ "$prefix" -le 30 ]; then
  78. _ip2str BROADCAST "$broadcast"
  79. echo "BROADCAST=$BROADCAST"
  80. fi
  81. echo "NETWORK=$NETWORK"
  82. echo "PREFIX=$prefix"
  83. echo "COUNT=$count"
  84. # if there's no range, we're done
  85. [ $# -eq 0 ] && exit 0
  86. [ -z "$1$2" ] && exit 0
  87. if [ "$prefix" -le 30 ]; then
  88. lower=$((network + 1))
  89. else
  90. lower="$network"
  91. fi
  92. start="$1"
  93. assert_uint32 "$start" || exit 1
  94. start=$((network | (start & hostmask)))
  95. [ "$start" -lt "$lower" ] && start="$lower"
  96. [ "$start" -eq "$ipaddr" ] && start=$((start + 1))
  97. if [ "$prefix" -le 30 ]; then
  98. upper=$(((network | hostmask) - 1))
  99. elif [ "$prefix" -eq 31 ]; then
  100. upper=$((network | hostmask))
  101. else
  102. upper="$network"
  103. fi
  104. range="$2"
  105. assert_uint32 "$range" || exit 1
  106. end=$((start + range - 1))
  107. [ "$end" -gt "$upper" ] && end="$upper"
  108. [ "$end" -eq "$ipaddr" ] && end=$((end - 1))
  109. if [ "$start" -gt "$end" ]; then
  110. echo "network ($NETWORK/$prefix) too small" >&2
  111. exit 1
  112. fi
  113. _ip2str START "$start"
  114. _ip2str END "$end"
  115. if [ "$start" -le "$ipaddr" ] && [ "$ipaddr" -le "$end" ]; then
  116. echo "warning: address $IP inside range $START..$END" >&2
  117. fi
  118. echo "START=$START"
  119. echo "END=$END"
  120. exit 0