1#!/bin/sh 2 3# Copyright (C) 2014-2021 Internet Systems Consortium, Inc. ("ISC") 4# 5# This Source Code Form is subject to the terms of the Mozilla Public 6# License, v. 2.0. If a copy of the MPL was not distributed with this 7# file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 9# shellcheck disable=SC1091 10# SC1091: Not following: ... was not specified as input (see shellcheck -x). 11 12# shellcheck disable=SC2039 13# SC2039: In POSIX sh, 'local' is undefined. 14 15# Exit with error if commands exit with non-zero and if undefined variables are 16# used. 17set -eu 18 19# Path to the temporary configuration file. 20CFG_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test_config.json" 21# Path to the Kea log file. 22LOG_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test.log" 23# Path to the Kea lease file. 24LEASE_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test_leases.csv" 25# Path to the Kea LFC application 26export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc" 27# Kea configuration to be stored in the configuration file. 28CONFIG="{ 29 \"Dhcp6\": 30 { \"interfaces-config\": { 31 \"interfaces\": [ ] 32 }, 33 \"server-id\": { 34 \"type\": \"LLT\", 35 \"persist\": false 36 }, 37 \"preferred-lifetime\": 3000, 38 \"valid-lifetime\": 4000, 39 \"renew-timer\": 1000, 40 \"rebind-timer\": 2000, 41 \"lease-database\": 42 { 43 \"type\": \"memfile\", 44 \"name\": \"$LEASE_FILE\", 45 \"persist\": false, 46 \"lfc-interval\": 0 47 }, 48 \"subnet6\": [ 49 { 50 \"subnet\": \"2001:db8:1::/64\", 51 \"pools\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ] 52 } ], 53 \"dhcp-ddns\": { 54 \"enable-updates\": true, 55 \"qualifying-suffix\": \"\" 56 }, 57 \"loggers\": [ 58 { 59 \"name\": \"kea-dhcp6\", 60 \"output_options\": [ 61 { 62 \"output\": \"$LOG_FILE\" 63 } 64 ], 65 \"severity\": \"INFO\" 66 } 67 ] 68 } 69}" 70# Invalid configuration (syntax error) to check that Kea can check syntax. 71# This config has following errors: 72# - it should be interfaces-config/interfaces, not interfaces 73# - it should be subnet6/pools, no subnet6/pool 74CONFIG_BAD_SYNTAX="{ 75 \"Dhcp6\": 76 { 77 \"interfaces\": [ ], 78 \"preferred-lifetime\": 3000, 79 \"valid-lifetime\": 4000, 80 \"renew-timer\": 1000, 81 \"rebind-timer\": 2000, 82 \"lease-database\": 83 { 84 \"type\": \"memfile\", 85 \"persist\": false 86 }, 87 \"subnet6\": [ 88 { 89 \"subnet\": \"2001:db8:1::/64\", 90 \"pool\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ] 91 } ], 92 \"loggers\": [ 93 { 94 \"name\": \"kea-dhcp6\", 95 \"output_options\": [ 96 { 97 \"output\": \"$LOG_FILE\" 98 } 99 ], 100 \"severity\": \"INFO\" 101 } 102 ] 103 } 104}" 105# Invalid configuration (negative preferred-lifetime) to check that Kea 106# gracefully handles reconfiguration errors. 107CONFIG_INVALID="{ 108 \"Dhcp6\": 109 { 110 \"interfaces-config\": { 111 \"interfaces\": [ ] 112 }, 113 \"preferred-lifetime\": -3, 114 \"valid-lifetime\": 4000, 115 \"renew-timer\": 1000, 116 \"rebind-timer\": 2000, 117 \"lease-database\": 118 { 119 \"type\": \"memfile\", 120 \"persist\": false 121 }, 122 \"subnet6\": [ 123 { 124 \"subnet\": \"2001:db8:1::/64\", 125 \"pool\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ] 126 } ], 127 \"loggers\": [ 128 { 129 \"name\": \"kea-dhcp6\", 130 \"output_options\": [ 131 { 132 \"output\": \"$LOG_FILE\" 133 } 134 ], 135 \"severity\": \"INFO\" 136 } 137 ] 138 } 139}" 140 141# This config has bad pool values. The pool it out of scope for the subnet 142# it is defined in. Syntactically the config is correct, though. 143CONFIG_BAD_VALUES="{ 144 \"Dhcp6\": 145 { \"interfaces-config\": { 146 \"interfaces\": [ ] 147 }, 148 \"server-id\": { 149 \"type\": \"LLT\", 150 \"persist\": false 151 }, 152 \"preferred-lifetime\": 3000, 153 \"valid-lifetime\": 4000, 154 \"renew-timer\": 1000, 155 \"rebind-timer\": 2000, 156 \"lease-database\": 157 { 158 \"type\": \"memfile\", 159 \"name\": \"$LEASE_FILE\", 160 \"persist\": false, 161 \"lfc-interval\": 0 162 }, 163 \"subnet6\": [ 164 { 165 \"subnet\": \"2001:db8::/64\", 166 \"pools\": [ { \"pool\": \"3000::-3000::ffff\" } ] 167 } ], 168 \"dhcp-ddns\": { 169 \"enable-updates\": true, 170 \"qualifying-suffix\": \"\" 171 } 172 } 173}" 174 175 176# Set the location of the executable. 177bin="kea-dhcp6" 178bin_path="@abs_top_builddir@/src/bin/dhcp6" 179 180# Import common test library. 181. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh" 182 183# This test verifies that syntax checking works properly. This function 184# requires 3 parameters: 185# test_name 186# config - string with a content of the config (will be written to a file) 187# expected_code - expected exit code returned by kea (0 - success, 1 - failure) 188syntax_check_test() { 189 local test_name="${1}" 190 local config="${2}" 191 local expected_code="${3}" 192 193 # Log the start of the test and print test name. 194 test_start "${test_name}" 195 # Create correct configuration file. 196 create_config "${config}" 197 # Check it 198 printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\"" 199 run_command \ 200 "${bin_path}/${bin}" -t "${CFG_FILE}" 201 if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then 202 printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}" 203 clean_exit 1 204 fi 205 206 test_finish 0 207} 208 209# This test verifies that DHCPv6 can be reconfigured with a SIGHUP signal. 210dynamic_reconfiguration_test() { 211 # Log the start of the test and print test name. 212 test_start "dhcpv6_srv.dynamic_reconfiguration" 213 # Create new configuration file. 214 create_config "${CONFIG}" 215 # Instruct Kea to log to the specific file. 216 set_logger 217 # Start Kea. 218 start_kea ${bin_path}/${bin} 219 # Wait up to 20s for Kea to start. 220 wait_for_kea 20 221 if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then 222 printf "ERROR: timeout waiting for Kea to start.\n" 223 clean_exit 1 224 fi 225 226 # Check if it is still running. It could have terminated (e.g. as a result 227 # of configuration failure). 228 get_pid ${bin} 229 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 230 printf "ERROR: expected one Kea process to be started. Found %d processes\ 231 started.\n" "${_GET_PIDS_NUM}" 232 clean_exit 1 233 fi 234 235 # Check in the log file, how many times server has been configured. It should 236 # be just once on startup. 237 get_reconfigs 238 if [ "${_GET_RECONFIGS}" -ne 1 ]; then 239 printf "ERROR: server hasn't been configured.\n" 240 clean_exit 1 241 else 242 printf "Server successfully configured.\n" 243 fi 244 245 # Now use invalid configuration. 246 create_config "${CONFIG_INVALID}" 247 248 # Try to reconfigure by sending SIGHUP 249 send_signal 1 ${bin} 250 251 # The configuration should fail and the error message should be there. 252 wait_for_message 10 "DHCP6_CONFIG_LOAD_FAIL" 1 253 254 # After receiving SIGHUP the server should try to reconfigure itself. 255 # The configuration provided is invalid so it should result in 256 # reconfiguration failure but the server should still be running. 257 get_reconfigs 258 if [ "${_GET_RECONFIGS}" -ne 1 ]; then 259 printf "ERROR: server has been reconfigured despite bogus configuration.\n" 260 clean_exit 1 261 elif [ "${_GET_RECONFIG_ERRORS}" -ne 1 ]; then 262 printf "ERROR: server did not report reconfiguration error despite attempt\ 263 to configure it with invalid configuration.\n" 264 clean_exit 1 265 fi 266 267 # Make sure the server is still operational. 268 get_pid ${bin} 269 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 270 printf "ERROR: Kea process was killed when attempting reconfiguration.\n" 271 clean_exit 1 272 fi 273 274 # Restore the good configuration. 275 create_config "${CONFIG}" 276 277 # Reconfigure the server with SIGHUP. 278 send_signal 1 ${bin} 279 280 # There should be two occurrences of the DHCP6_CONFIG_COMPLETE messages. 281 # Wait for it up to 10s. 282 wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2 283 284 # After receiving SIGHUP the server should get reconfigured and the 285 # reconfiguration should be noted in the log file. We should now 286 # have two configurations logged in the log file. 287 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 288 printf "ERROR: server hasn't been reconfigured.\n" 289 clean_exit 1 290 else 291 printf "Server successfully reconfigured.\n" 292 fi 293 294 # Make sure the server is still operational. 295 get_pid ${bin} 296 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 297 printf "ERROR: Kea process was killed when attempting reconfiguration.\n" 298 clean_exit 1 299 fi 300 301 # When the server receives a signal the call to select() function is 302 # interrupted. This should not be logged as an error. 303 get_log_messages "DHCP6_PACKET_RECEIVE_FAIL" 304 assert_eq 0 "${_GET_LOG_MESSAGES}" \ 305 "Expected get_log_messages DHCP6_PACKET_RECEIVE_FAIL return %d, \ 306returned %d." 307 308 # All ok. Shut down Kea and exit. 309 test_finish 0 310} 311 312# This test verifies that DHCPv6 server is shut down gracefully when it 313# receives a SIGINT or SIGTERM signal. 314shutdown_test() { 315 local test_name="${1}" # Test name 316 local signum="${2}" # Signal number 317 318 # Log the start of the test and print test name. 319 test_start "${test_name}" 320 # Create new configuration file. 321 create_config "${CONFIG}" 322 # Instruct Kea to log to the specific file. 323 set_logger 324 # Start Kea. 325 start_kea ${bin_path}/${bin} 326 # Wait up to 20s for Kea to start. 327 wait_for_kea 20 328 if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then 329 printf "ERROR: timeout waiting for Kea to start.\n" 330 clean_exit 1 331 fi 332 333 # Check if it is still running. It could have terminated (e.g. as a result 334 # of configuration failure). 335 get_pid ${bin} 336 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 337 printf "ERROR: expected one Kea process to be started. Found %d processes\ 338 started.\n" "${_GET_PIDS_NUM}" 339 clean_exit 1 340 fi 341 342 # Check in the log file, how many times server has been configured. It should 343 # be just once on startup. 344 get_reconfigs 345 if [ "${_GET_RECONFIGS}" -ne 1 ]; then 346 printf "ERROR: server hasn't been configured.\n" 347 clean_exit 1 348 else 349 printf "Server successfully configured.\n" 350 fi 351 352 # Send signal to Kea (SIGTERM, SIGINT etc.) 353 send_signal "${signum}" "${bin}" 354 355 # Wait up to 10s for the server's graceful shutdown. The graceful shut down 356 # should be recorded in the log file with the appropriate message. 357 wait_for_message 10 "DHCP6_SHUTDOWN" 1 358 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 359 printf "ERROR: Server did not record shutdown in the log.\n" 360 clean_exit 1 361 fi 362 363 # Make sure the server is down. 364 wait_for_server_down 5 ${bin} 365 assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \ 366 "Expected wait_for_server_down return %d, returned %d" 367 368 # When the server receives a signal the call to select() function is 369 # interrupted. This should not be logged as an error. 370 get_log_messages "DHCP6_PACKET_RECEIVE_FAIL" 371 assert_eq 0 "${_GET_LOG_MESSAGES}" \ 372 "Expected get_log_messages DHCP6_PACKET_RECEIVE_FAIL return %d, \ 373returned %d." 374 375 test_finish 0 376} 377 378# This test verifies that DHCPv6 can be configured to run lease file cleanup 379# periodically. 380lfc_timer_test() { 381 # Log the start of the test and print test name. 382 test_start "dhcpv6_srv.lfc_timer_test" 383 # Create a configuration with the LFC enabled, by replacing the section 384 # with the lfc-interval and persist parameters. 385 LFC_CONFIG=$(printf '%s' "${CONFIG}" | sed -e 's/\"lfc-interval\": 0/\"lfc-interval\": 3/g' \ 386 | sed -e 's/\"persist\": false,/\"persist\": true,/g') 387 # Create new configuration file. 388 create_config "${LFC_CONFIG}" 389 # Instruct Kea to log to the specific file. 390 set_logger 391 # Start Kea. 392 start_kea ${bin_path}/${bin} 393 # Wait up to 20s for Kea to start. 394 wait_for_kea 20 395 if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then 396 printf "ERROR: timeout waiting for Kea to start.\n" 397 clean_exit 1 398 fi 399 400 # Check if it is still running. It could have terminated (e.g. as a result 401 # of configuration failure). 402 get_pid ${bin} 403 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 404 printf "ERROR: expected one Kea process to be started. Found %d processes\ 405 started.\n" "${_GET_PIDS_NUM}" 406 clean_exit 1 407 fi 408 409 # Check if Kea emits the log message indicating that LFC is started. 410 wait_for_message 10 "DHCPSRV_MEMFILE_LFC_EXECUTE" 1 411 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 412 printf "ERROR: Server did not execute LFC.\n" 413 clean_exit 1 414 fi 415 416 # Give it a short time to run. 417 sleep 1 418 419 # Modify the interval. 420 LFC_CONFIG=$(printf '%s' "${LFC_CONFIG}" | sed -e 's/\"lfc-interval\": 3/\"lfc-interval\": 4/g') 421 # Create new configuration file. 422 create_config "${LFC_CONFIG}" 423 424 # Reconfigure the server with SIGHUP. 425 send_signal 1 ${bin} 426 427 # There should be two occurrences of the DHCP4_CONFIG_COMPLETE messages. 428 # Wait for it up to 10s. 429 wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2 430 431 # After receiving SIGHUP the server should get reconfigured and the 432 # reconfiguration should be noted in the log file. We should now 433 # have two configurations logged in the log file. 434 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 435 printf "ERROR: server hasn't been reconfigured.\n" 436 clean_exit 1 437 else 438 printf "Server successfully reconfigured.\n" 439 fi 440 441 # Make sure the server is still operational. 442 get_pid ${bin} 443 if [ "${_GET_PIDS_NUM}" -ne 1 ]; then 444 printf "ERROR: Kea process was killed when attempting reconfiguration.\n" 445 clean_exit 1 446 fi 447 448 # Wait for the LFC to run the second time. 449 wait_for_message 10 "DHCPSRV_MEMFILE_LFC_EXECUTE" 2 450 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 451 printf "ERROR: Server did not execute LFC.\n" 452 clean_exit 1 453 fi 454 455 # Send signal to Kea SIGTERM 456 send_signal 15 ${bin} 457 458 # Wait up to 10s for the server's graceful shutdown. The graceful shut down 459 # should be recorded in the log file with the appropriate message. 460 wait_for_message 10 "DHCP6_SHUTDOWN" 1 461 if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then 462 printf "ERROR: Server did not record shutdown in the log.\n" 463 clean_exit 1 464 fi 465 466 # Make sure the server is down. 467 wait_for_server_down 5 ${bin} 468 assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \ 469 "Expected wait_for_server_down return %d, returned %d" 470 471 # All ok. Shut down Kea and exit. 472 test_finish 0 473} 474 475server_pid_file_test "${CONFIG}" DHCP6_ALREADY_RUNNING 476dynamic_reconfiguration_test 477shutdown_test "dhcpv6.sigterm_test" 15 478shutdown_test "dhcpv6.sigint_test" 2 479version_test "dhcpv6.version" 480logger_vars_test "dhcpv6.variables" 481lfc_timer_test 482syntax_check_test "dhcpv6.syntax_check_success" "${CONFIG}" 0 483syntax_check_test "dhcpv6.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1 484syntax_check_test "dhcpv6.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1 485password_redact_test "dhcpv6.password_redact_test" "$(kea_dhcp_config 6)" 0 486