Bash script to configure static networking on LXC2 container
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
9.5 KiB

  1. #!/usr/bin/env bash
  2. set -euf -o pipefail
  3. function printUsage {
  4. echo "lxc-staticnet: Simple tool to configure lxc container network statically through their respective config files"
  5. echo
  6. echo "Usage: lxc-staticnet {set4|set6|remove4|remove6|ns|man-int|setup|show|overview} [-h|--help] [-n|--name] [-a|--address] [-g|--gateway]"
  7. echo " set4 -n -a -m -g : adds or changes IPv4 address [-a|--address], netmask [-m|--netmask] and gateway [-g|--gateway] to container [-n|--name]"
  8. echo " set6 -n -a -m -g : adds or changes IPv6 address [-a|--address], netmask [-m|--netmask] and gateway [-g|--gateway] to container [-n|--name]"
  9. echo " (use \"radv\" to not set gateway)"
  10. echo " remove4 -n : removes IPv4 configuration from container [-n|--name]"
  11. echo " remove6 -n : removes IPv6 configuration from container [-n|--name]"
  12. echo " ns -n : copys host's /etc/resolv.conf to container [-n|--name]"
  13. echo " man-int -n : sets the network interface of the container to \"manual\" so that dhclient doesn't start"
  14. echo " setup -n : asks one by one for all parameters to set up IPv4, IPv6 and nameserver for given container [-n|--name]"
  15. echo " show -n : shows current network config for given container [-n|--name]"
  16. echo " overview : runs shows command for every container found"
  17. echo
  18. echo "Examples:"
  19. echo " lxc-staticnet set4 -n container01 -a 10.0.0.2 -m 24 -g 10.0.0.1"
  20. echo " lxc-staticnet set6 -n container01 -a 2001:xxxx::1 -m 64 -g radv"
  21. echo " lxc-staticnet ns -n container01"
  22. exit 1
  23. }
  24. # Parameters: $1 = name, $2 = address, $3 = netmask, $4 = gateway, $5 = path
  25. function set4 {
  26. # Check if addresses are valid
  27. regex='^(0*(1?[0-9]{1,2}|2([0-4][0-9]|5[0-5]))\.){3}0*(1?[0-9]{1,2}|2([0-4][0-9]|5[0-5]))$'
  28. for i in 2 4; do
  29. if [[ ! "${!i}" =~ $regex ]]; then
  30. echo "${!i} is not a valid IPv4 address!"
  31. echo
  32. printUsage
  33. fi
  34. done
  35. if [ "$3" -lt 1 ] || [ "$3" -gt 32 ]; then
  36. echo "Netmask must be between 1 and 32"
  37. echo
  38. printUsage
  39. fi
  40. remove4 "$1" "$5"
  41. echo "Setting new IPv4 configuration for container $1"
  42. echo "lxc.network.ipv4 = $2/$3" >> "$5"/"$1"/config
  43. echo "lxc.network.ipv4.gateway = $4" >> "$5"/"$1"/config
  44. }
  45. # Parameters: $1 = name, $2 = address, $3 = netmask, $4 = gateway, $5 = path
  46. function set6 {
  47. # Check if addresses are valid
  48. regex='(^radv$)|(^([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}$)|(^([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}$)|(^([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}$)|(^([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}$)|(^([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}$)|(^([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}$)|(^(([0-9a-f]{1,4}:){1,7}|:):$)|(^:(:[0-9a-f]{1,4}){1,7}$)|(^((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$)|(^(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$)|(^([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|(^:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)'
  49. for i in 2 4; do
  50. if [[ ! "${!i}" =~ $regex ]]; then
  51. echo "${!i} is not a valid IPv6 address!"
  52. echo
  53. printUsage
  54. fi
  55. done
  56. if [ "$3" -lt 1 ] && [ "$3" -gt 128 ]; then
  57. echo "Netmask must be between 1 and 128"
  58. echo
  59. printUsage
  60. fi
  61. remove6 "$1" "$5"
  62. echo "Setting new IPv6 configuration for container $1"
  63. echo "lxc.network.ipv6 = $2/$3" >> "$5"/"$1"/config
  64. if [ "$4" != "radv" ]; then
  65. echo "lxc.network.ipv6.gateway = $4" >> "$5"/"$1"/config
  66. fi
  67. }
  68. # Parameters: $1 = name, $2 = path
  69. function remove4 {
  70. echo "Removing current IPv4 configuration from container $1"
  71. sed -i '/lxc.network.ipv4/d' "$2"/"$1"/config
  72. }
  73. # Parameters: $1 = name, $2 = path
  74. function remove6 {
  75. echo "Removing current IPv6 configuration from container $1"
  76. sed -i '/lxc.network.ipv6/d' "$2"/"$1"/config
  77. }
  78. # Parameters: $1 = name, $2 = path
  79. function ns {
  80. echo "Copying hosts's resolv.conf to container $1"
  81. cat /etc/resolv.conf > "$2"/"$1"/rootfs/etc/resolv.conf
  82. }
  83. # Parameters: $1 = name, $2 = path
  84. function man-int {
  85. echo "Setting eth0 of container $1 to manual"
  86. sed -i 's/^iface eth0 inet dhcp/iface eth0 inet manual/' "$2"/"$1"/rootfs/etc/network/interfaces
  87. }
  88. # Parameters: $1 = name, $2 = path
  89. function setup {
  90. read -p "Enter IPv4 address for $1: " address
  91. read -p "Enter IPv4 gateway for $1: " gateway
  92. read -p "Enter IPv4 netmask for $1: " netmask
  93. set4 "$1" "$address" "$netmask" "$gateway" "$2"
  94. echo
  95. read -p "Enter IPv6 address for $1: " address
  96. read -p "Enter IPv6 gateway for $1 (use \"radv\" to not set): " gateway
  97. read -p "Enter IPv6 netmask for $1: " netmask
  98. set6 "$1" "$address" "$netmask" "$gateway" "$2"
  99. echo
  100. if [[ $EUID -ne 0 ]]; then
  101. echo "You can't change internal container files without root access"
  102. else
  103. read -n 1 -e -p "Set up nameservers for $1? [Y|n] " nameserver
  104. if [[ "$nameserver" == [Yy] || "$nameserver" == "" ]]; then
  105. ns "$1" "$2"
  106. fi
  107. echo
  108. read -n 1 -e -p "Set eth0 to manual for $1? [Y|n] " manual
  109. if [[ "$manual" == [Yy] || "$manual" == "" ]]; then
  110. man-int "$1" "$2"
  111. fi
  112. fi
  113. }
  114. # Parameters: $1 = name, $2 = path
  115. function show {
  116. echo "$1"
  117. cat "$2"/"$1"/config | grep -s -e "lxc.network.ipv4" -e "lxc.network.ipv6" || true | sed 's/^/ /'; echo -n
  118. }
  119. # Parameters: $1 = path
  120. function overview {
  121. lxcArray=($(lxc-ls -P "$1"))
  122. for name in ${lxcArray[@]}; do
  123. show "$name" "$1"
  124. echo
  125. done
  126. }
  127. # Process command line parameters and set them up again afterwards
  128. positional=()
  129. while [[ $# -gt 0 ]]; do
  130. key="$1"
  131. case $key in
  132. -n|--name)
  133. if [ -z "${2:-}" ]; then
  134. echo "Container name can't be empty!"
  135. echo
  136. printUsage
  137. else
  138. name=$2
  139. fi
  140. shift
  141. shift
  142. ;;
  143. -a|--address)
  144. if [ -z "${2:-}" ]; then
  145. echo "IP address can't be empty!"
  146. echo
  147. printUsage
  148. else
  149. address=$2
  150. fi
  151. shift
  152. shift
  153. ;;
  154. -g|--gateway)
  155. if [ -z "${2:-}" ]; then
  156. echo "Gateway can't be empty!"
  157. echo
  158. printUsage
  159. else
  160. gateway=$2
  161. fi
  162. shift
  163. shift
  164. ;;
  165. -m|--netmask)
  166. if [ -z "${2:-}" ]; then
  167. echo "Netmask can't be empty!"
  168. echo
  169. printUsage
  170. else
  171. netmask=$2
  172. fi
  173. shift
  174. shift
  175. ;;
  176. -P|--lxcpath)
  177. if [ -z "${2:-}" ]; then
  178. echo "LXC Path can't be empty!"
  179. echo
  180. printUsage
  181. else
  182. path="$2"
  183. fi
  184. shift
  185. shift
  186. ;;
  187. -h|--help)
  188. printUsage
  189. ;;
  190. *)
  191. positional+=("$1")
  192. shift
  193. ;;
  194. esac
  195. done
  196. set -- "${positional[@]}"
  197. # Check for root or check if user is unprivileged container user
  198. if [[ $EUID -ne 0 ]] && [[ ! -f ~/.config/lxc/default.conf ]]; then
  199. echo "You need to run this tool either as root or as an unprivileged container user to perform any actions!"
  200. echo
  201. printUsage
  202. fi
  203. # Set up path
  204. if [ -z "${path:-}" ]; then
  205. if [[ $EUID -eq 0 ]]; then
  206. if [[ -n "${SUDO_USER:-}" ]]; then
  207. home="$(getent passwd $SUDO_USER | cut -d: -f6)"
  208. if grep -q "lxc.lxcpath" "$home"/.config/lxc/lxc.conf; then
  209. path="$(cat $home/.config/lxc/lxc.conf | grep lxc.lxcpath | sed -e 's/=/ /g' | awk '{print $2}')"
  210. else
  211. path="$home"/.local/share/lxc
  212. fi
  213. else
  214. if grep -q "lxc.lxcpath" /etc/lxc/lxc.conf; then
  215. path="$(cat /etc/lxc/lxc.conf | grep lxc.lxcpath | sed -e 's/=/ /g' | awk '{print $2}')"
  216. else
  217. path=/var/lib/lxc
  218. fi
  219. fi
  220. else
  221. if grep -q "lxc.lxcpath" ~/.config/lxc/lxc.conf; then
  222. path="$(cat ~/.config/lxc/lxc.conf | grep lxc.lxcpath | sed -e 's/=/ /g' | awk '{print $2}')"
  223. else
  224. path=~/.local/share/lxc
  225. fi
  226. fi
  227. fi
  228. path=$(readlink -fn "$path")
  229. # Check if job is given and if it's valid
  230. availablejobs=(set4 set6 remove4 remove6 ns man-int setup show overview)
  231. if [ -z "${1:-}" ] || [[ ! "${availablejobs[@]}" =~ "$1" ]]; then
  232. echo "You need to provide a valid job!"
  233. echo
  234. printUsage
  235. else
  236. job="$1"
  237. fi
  238. # Check if correct paramters are given for the job
  239. if [ -z "${name:-}" ] && [ "$job" != "overview" ]; then
  240. echo "You need to provide a container name!"
  241. echo
  242. printUsage
  243. elif ([ -z "${address:-}" ] || [ -z "${netmask:-}" ] || [ -z "${gateway:-}" ]) && [[ "$job" =~ set[46] ]]; then
  244. echo "You need to provide the static IP address, netmask and gateway address!"
  245. echo
  246. printUsage
  247. fi
  248. if [ "$job" != "overview" ] && [[ ! $(lxc-ls -P "$path") =~ "$name" ]]; then
  249. echo "You need to provide a valid container name"
  250. echo
  251. printUsage
  252. fi
  253. # Run job
  254. case "$job" in
  255. set4) set4 "$name" "$address" "$netmask" "$gateway" "$path";;
  256. set6) set6 "$name" "$address" "$netmask" "$gateway" "$path";;
  257. remove4) remove4 "$name" "$path";;
  258. remove6) remove6 "$name" "$path";;
  259. ns) ns "$name" "$path";;
  260. man-int) man-int "$name" "$path";;
  261. setup) setup "$name" "$path";;
  262. show) show "$name" "$path";;
  263. overview) overview "$path";;
  264. *) printUsage;;
  265. esac