iptables-wrapper-installer.sh 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/bin/sh
  2. # Copyright 2020 The Kubernetes Authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. # Usage:
  16. #
  17. # iptables-wrapper-installer.sh [--no-sanity-check]
  18. #
  19. # Installs a wrapper iptables script in a container that will figure out
  20. # whether iptables-legacy or iptables-nft is in use on the host and then
  21. # replaces itself with the correct underlying iptables version.
  22. #
  23. # Unless "--no-sanity-check" is passed, it will first verify that the
  24. # container already contains a suitable version of iptables.
  25. # NOTE: This can only use POSIX /bin/sh features; the build container
  26. # might not contain bash.
  27. set -eu
  28. # Find iptables binary location
  29. if [ -d /usr/sbin -a -e /usr/sbin/iptables ]; then
  30. sbin="/usr/sbin"
  31. elif [ -d /sbin -a -e /sbin/iptables ]; then
  32. sbin="/sbin"
  33. else
  34. echo "ERROR: iptables is not present in either /usr/sbin or /sbin" 1>&2
  35. exit 1
  36. fi
  37. # Determine how the system selects between iptables-legacy and iptables-nft
  38. if [ -x /usr/sbin/alternatives ]; then
  39. # Fedora/SUSE style alternatives
  40. altstyle="fedora"
  41. elif [ -x /usr/sbin/update-alternatives ]; then
  42. # Debian style alternatives
  43. altstyle="debian"
  44. else
  45. # No alternatives system
  46. altstyle="none"
  47. fi
  48. if [ "${1:-}" != "--no-sanity-check" ]; then
  49. # Ensure dependencies are installed
  50. if ! version=$("${sbin}/iptables-nft" --version 2> /dev/null); then
  51. echo "ERROR: iptables-nft is not installed" 1>&2
  52. exit 1
  53. fi
  54. if ! "${sbin}/iptables-legacy" --version > /dev/null 2>&1; then
  55. echo "ERROR: iptables-legacy is not installed" 1>&2
  56. exit 1
  57. fi
  58. case "${version}" in
  59. *v1.8.[012]\ *)
  60. echo "ERROR: iptables 1.8.0 - 1.8.2 have compatibility bugs." 1>&2
  61. echo " Upgrade to 1.8.3 or newer." 1>&2
  62. exit 1
  63. ;;
  64. *v1.8.3\ *)
  65. # 1.8.3 mostly works but can get stuck in an infinite loop if the nft
  66. # kernel modules are unavailable
  67. need_timeout=1
  68. ;;
  69. *)
  70. # 1.8.4+ are OK
  71. ;;
  72. esac
  73. fi
  74. # Start creating the wrapper...
  75. rm -f "${sbin}/iptables-wrapper"
  76. cat > "${sbin}/iptables-wrapper" <<EOF
  77. #!/bin/sh
  78. # Copyright 2020 The Kubernetes Authors.
  79. #
  80. # Licensed under the Apache License, Version 2.0 (the "License");
  81. # you may not use this file except in compliance with the License.
  82. # You may obtain a copy of the License at
  83. #
  84. # http://www.apache.org/licenses/LICENSE-2.0
  85. #
  86. # Unless required by applicable law or agreed to in writing, software
  87. # distributed under the License is distributed on an "AS IS" BASIS,
  88. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  89. # See the License for the specific language governing permissions and
  90. # limitations under the License.
  91. # NOTE: This can only use POSIX /bin/sh features; the container image
  92. # might not contain bash.
  93. set -eu
  94. # Detect whether the base system is using iptables-legacy or
  95. # iptables-nft. This assumes that some non-containerized process (eg
  96. # kubelet) has already created some iptables rules.
  97. EOF
  98. if [ "${need_timeout:-0}" = 0 ]; then
  99. # Write out the simpler version of legacy-vs-nft detection
  100. cat >> "${sbin}/iptables-wrapper" <<EOF
  101. num_legacy_lines=\$( (iptables-legacy-save || true; ip6tables-legacy-save || true) 2>/dev/null | grep '^-' | wc -l)
  102. num_nft_lines=\$( (iptables-nft-save || true; ip6tables-nft-save || true) 2>/dev/null | grep '^-' | wc -l)
  103. if [ "\${num_legacy_lines}" -ge "\${num_nft_lines}" ]; then
  104. mode=legacy
  105. else
  106. mode=nft
  107. fi
  108. EOF
  109. else
  110. # Write out the version of legacy-vs-nft detection with an nft timeout
  111. cat >> "${sbin}/iptables-wrapper" <<EOF
  112. # The iptables-nft binary in this image can get stuck in an infinite
  113. # loop if nft is not available so we need to wrap a timeout around it
  114. # (and to avoid that, we don't even bother calling iptables-nft if it
  115. # looks like iptables-legacy is going to win).
  116. num_legacy_lines=\$( (iptables-legacy-save || true; ip6tables-legacy-save || true) 2>/dev/null | grep '^-' | wc -l)
  117. if [ "\${num_legacy_lines}" -ge 10 ]; then
  118. mode=legacy
  119. else
  120. num_nft_lines=\$( (timeout 5 sh -c "iptables-nft-save; ip6tables-nft-save" || true) 2>/dev/null | grep '^-' | wc -l)
  121. if [ "\${num_legacy_lines}" -ge "\${num_nft_lines}" ]; then
  122. mode=legacy
  123. else
  124. mode=nft
  125. fi
  126. fi
  127. EOF
  128. fi
  129. # Write out the appropriate alternatives-selection commands
  130. case "${altstyle}" in
  131. fedora)
  132. cat >> "${sbin}/iptables-wrapper" <<EOF
  133. # Update links to point to the selected binaries
  134. alternatives --set iptables "/usr/sbin/iptables-\${mode}" > /dev/null || failed=1
  135. EOF
  136. ;;
  137. debian)
  138. cat >> "${sbin}/iptables-wrapper" <<EOF
  139. # Update links to point to the selected binaries
  140. update-alternatives --set iptables "/usr/sbin/iptables-\${mode}" > /dev/null || failed=1
  141. update-alternatives --set ip6tables "/usr/sbin/ip6tables-\${mode}" > /dev/null || failed=1
  142. EOF
  143. ;;
  144. *)
  145. cat >> "${sbin}/iptables-wrapper" <<EOF
  146. # Update links to point to the selected binaries
  147. for cmd in iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore; do
  148. rm -f "${sbin}/\${cmd}"
  149. ln -s "${sbin}/xtables-\${mode}-multi" "${sbin}/\${cmd}"
  150. done 2>/dev/null || failed=1
  151. EOF
  152. ;;
  153. esac
  154. # Write out the post-alternatives-selection error checking and final wrap-up
  155. cat >> "${sbin}/iptables-wrapper" <<EOF
  156. if [ "\${failed:-0}" = 1 ]; then
  157. echo "Unable to redirect iptables binaries. (Are you running in an unprivileged pod?)" 1>&2
  158. # fake it, though this will probably also fail if they aren't root
  159. exec "${sbin}/xtables-\${mode}-multi" "\$0" "\$@"
  160. fi
  161. # Now re-exec the original command with the newly-selected alternative
  162. exec "\$0" "\$@"
  163. EOF
  164. chmod +x "${sbin}/iptables-wrapper"
  165. # Now back in the installer script, point the iptables binaries at our
  166. # wrapper
  167. case "${altstyle}" in
  168. fedora)
  169. alternatives \
  170. --install /usr/sbin/iptables iptables /usr/sbin/iptables-wrapper 100 \
  171. --slave /usr/sbin/iptables-restore iptables-restore /usr/sbin/iptables-wrapper \
  172. --slave /usr/sbin/iptables-save iptables-save /usr/sbin/iptables-wrapper \
  173. --slave /usr/sbin/ip6tables iptables /usr/sbin/iptables-wrapper \
  174. --slave /usr/sbin/ip6tables-restore iptables-restore /usr/sbin/iptables-wrapper \
  175. --slave /usr/sbin/ip6tables-save iptables-save /usr/sbin/iptables-wrapper
  176. ;;
  177. debian)
  178. update-alternatives \
  179. --install /usr/sbin/iptables iptables /usr/sbin/iptables-wrapper 100 \
  180. --slave /usr/sbin/iptables-restore iptables-restore /usr/sbin/iptables-wrapper \
  181. --slave /usr/sbin/iptables-save iptables-save /usr/sbin/iptables-wrapper
  182. update-alternatives \
  183. --install /usr/sbin/ip6tables ip6tables /usr/sbin/iptables-wrapper 100 \
  184. --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/iptables-wrapper \
  185. --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/iptables-wrapper
  186. ;;
  187. *)
  188. for cmd in iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore; do
  189. rm -f "${sbin}/${cmd}"
  190. ln -s "${sbin}/iptables-wrapper" "${sbin}/${cmd}"
  191. done
  192. ;;
  193. esac
  194. # Cleanup
  195. rm -f "$0"