ipv4.sh 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. uint_max=4294967295
  2. d_10_0_0_0=167772160
  3. d_10_255_255_255=184549375
  4. d_172_16_0_0=2886729728
  5. d_172_31_255_255=2887778303
  6. d_192_168_0_0=3232235520
  7. d_192_168_255_255=3232301055
  8. d_169_254_0_0=2851995648
  9. d_169_254_255_255=2852061183
  10. d_127_0_0_0=2130706432
  11. d_127_255_255_255=2147483647
  12. d_224_0_0_0=3758096384
  13. d_239_255_255_255=4026531839
  14. # check that $1 is only base 10 digits, and that it doesn't
  15. # exceed 2^32-1
  16. assert_uint32() {
  17. local __n="$1"
  18. if [ -z "$__n" -o -n "${__n//[0-9]/}" ]; then
  19. printf "Not a decimal integer (%s)\n" "$__n ">&2
  20. return 1
  21. fi
  22. if [ "$__n" -gt $uint_max ]; then
  23. printf "Out of range (%s)\n" "$__n" >&2
  24. return 1
  25. fi
  26. if [ "$((__n + 0))" != "$__n" ]; then
  27. printf "Not normalized notation (%s)\n" "$__n" >&2
  28. return 1
  29. fi
  30. return 0
  31. }
  32. # return a count of the number of bits set in $1
  33. bitcount() {
  34. local __var="$1" __c="$2"
  35. assert_uint32 "$__c" || return 1
  36. __c=$((((__c >> 1) & 0x55555555) + (__c & 0x55555555)))
  37. __c=$((((__c >> 2) & 0x33333333) + (__c & 0x33333333)))
  38. __c=$((((__c >> 4) & 0x0f0f0f0f) + (__c & 0x0f0f0f0f)))
  39. __c=$((((__c >> 8) & 0x00ff00ff) + (__c & 0x00ff00ff)))
  40. __c=$((((__c >> 16) & 0x0000ffff) + (__c & 0x0000ffff)))
  41. export -- "$__var=$__c"
  42. }
  43. # tedious but portable with busybox's limited shell
  44. # we check each octet to be in the range of 0..255,
  45. # and also make sure there's no extaneous characters.
  46. str2ip() {
  47. local __var="$1" __ip="$2" __n __val=0
  48. case "$__ip" in
  49. [0-9].*)
  50. __n="${__ip:0:1}"
  51. __ip="${__ip:2}"
  52. ;;
  53. [1-9][0-9].*)
  54. __n="${__ip:0:2}"
  55. __ip="${__ip:3}"
  56. ;;
  57. 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
  58. __n="${__ip:0:3}"
  59. __ip="${__ip:4}"
  60. ;;
  61. *)
  62. printf "Not a dotted quad (%s)\n" "$2" >&2
  63. return 1
  64. ;;
  65. esac
  66. __val=$((__n << 24))
  67. case "$__ip" in
  68. [0-9].*)
  69. __n="${__ip:0:1}"
  70. __ip="${__ip:2}"
  71. ;;
  72. [1-9][0-9].*)
  73. __n="${__ip:0:2}"
  74. __ip="${__ip:3}"
  75. ;;
  76. 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
  77. __n="${__ip:0:3}"
  78. __ip="${__ip:4}"
  79. ;;
  80. *)
  81. printf "Not a dotted quad (%s)\n" "$2" >&2
  82. return 1
  83. ;;
  84. esac
  85. __val=$((__val + (__n << 16)))
  86. case "$__ip" in
  87. [0-9].*)
  88. __n="${__ip:0:1}"
  89. __ip="${__ip:2}"
  90. ;;
  91. [1-9][0-9].*)
  92. __n="${__ip:0:2}"
  93. __ip="${__ip:3}"
  94. ;;
  95. 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
  96. __n="${__ip:0:3}"
  97. __ip="${__ip:4}"
  98. ;;
  99. *)
  100. printf "Not a dotted quad (%s)\n" "$2" >&2
  101. return 1
  102. ;;
  103. esac
  104. __val=$((__val + (__n << 8)))
  105. case "$__ip" in
  106. [0-9])
  107. __n="${__ip:0:1}"
  108. __ip="${__ip:1}"
  109. ;;
  110. [1-9][0-9])
  111. __n="${__ip:0:2}"
  112. __ip="${__ip:2}"
  113. ;;
  114. 1[0-9][0-9]|2[0-4][0-9]|25[0-5])
  115. __n="${__ip:0:3}"
  116. __ip="${__ip:3}"
  117. ;;
  118. *)
  119. printf "Not a dotted quad (%s)\n" "$2" >&2
  120. return 1
  121. ;;
  122. esac
  123. __val=$((__val + __n))
  124. if [ -n "$__ip" ]; then
  125. printf "Not a dotted quad (%s)\n" "$2" >&2
  126. return 1
  127. fi
  128. export -- "$__var=$__val"
  129. return 0
  130. }
  131. # convert back from an integer to dotted-quad.
  132. ip2str() {
  133. local __var="$1" __n="$2"
  134. assert_uint32 "$__n" || return 1
  135. export -- "$__var=$((__n >> 24)).$(((__n >> 16) & 255)).$(((__n >> 8) & 255)).$((__n & 255))"
  136. }
  137. # convert prefix into an integer bitmask
  138. prefix2netmask() {
  139. local __var="$1" __n="$2"
  140. assert_uint32 "$__n" || return 1
  141. if [ "$__n" -gt 32 ]; then
  142. printf "Prefix out-of-range (%s)" "$__n" >&2
  143. return 1
  144. fi
  145. export -- "$__var=$(((~(uint_max >> __n)) & uint_max))"
  146. }
  147. _is_contiguous() {
  148. local __x="$1" # no checking done
  149. local __y=$((~__x & uint_max))
  150. local __z=$(((__y + 1) & uint_max))
  151. [ $((__z & __y)) -eq 0 ]
  152. }
  153. # check argument as being contiguous upper bits (and yes,
  154. # 0 doesn't have any discontiguous bits).
  155. is_contiguous() {
  156. local __var="$1" __x="$2" __val=0
  157. assert_uint32 "$__x" || return 1
  158. local __y=$((~__x & uint_max))
  159. local __z=$(((__y + 1) & uint_max))
  160. [ $((__z & __y)) -eq 0 ] && __val=1
  161. export -- "$__var=$__val"
  162. }
  163. # convert mask to prefix, validating that it's a conventional
  164. # (contiguous) netmask.
  165. netmask2prefix() {
  166. local __var="$1" __n="$2" __cont __bits
  167. assert_uint32 "$__n" || return 1
  168. is_contiguous __cont "$__n" || return 1
  169. if [ $__cont -eq 0 ]; then
  170. printf "Not a contiguous netmask (%08x)\n" "$__n" >&2
  171. return 1
  172. fi
  173. bitcount __bits "$__n" # already checked
  174. export -- "$__var=$__bits"
  175. }
  176. # check the argument as being an rfc-1918 address
  177. is_rfc1918() {
  178. local __var="$1" __x="$2" __val=0
  179. assert_uint32 "$__x" || return 1
  180. if [ $d_10_0_0_0 -le $__x ] && [ $__x -le $d_10_255_255_255 ]; then
  181. __val=1
  182. elif [ $d_172_16_0_0 -le $__x ] && [ $__x -le $d_172_31_255_255 ]; then
  183. __val=1
  184. elif [ $d_192_168_0_0 -le $__x ] && [ $__x -le $d_192_168_255_255 ]; then
  185. __val=1
  186. fi
  187. export -- "$__var=$__val"
  188. }
  189. # check the argument as being an rfc-3927 address
  190. is_rfc3927() {
  191. local __var="$1" __x="$2" __val=0
  192. assert_uint32 "$__x" || return 1
  193. if [ $d_169_254_0_0 -le $__x ] && [ $__x -le $d_169_254_255_255 ]; then
  194. __val=1
  195. fi
  196. export -- "$__var=$__val"
  197. }
  198. # check the argument as being an rfc-1122 loopback address
  199. is_loopback() {
  200. local __var="$1" __x="$2" __val=0
  201. assert_uint32 "$__x" || return 1
  202. if [ $d_127_0_0_0 -le $__x ] && [ $__x -le $d_127_255_255_255 ]; then
  203. __val=1
  204. fi
  205. export -- "$__var=$__val"
  206. }
  207. # check the argument as being a multicast address
  208. is_multicast() {
  209. local __var="$1" __x="$2" __val=0
  210. assert_uint32 "$__x" || return 1
  211. if [ $d_224_0_0_0 -le $__x ] && [ $__x -le $d_239_255_255_255 ]; then
  212. __val=1
  213. fi
  214. export -- "$__var=$__val"
  215. }