]> git.ipfire.org Git - people/jschlag/network.git/blob - src/functions/functions.ipsec
IPsec: regenerate a swanctl config on connection startup if no config is found
[people/jschlag/network.git] / src / functions / functions.ipsec
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2017 IPFire Network Development Team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 IPSEC_CONNECTION_CONFIG_SETTINGS="\
23 AUTH_MODE \
24 DPD_ACTION \
25 DPD_DELAY \
26 DPD_TIMEOUT \
27 INACTIVITY_TIMEOUT \
28 LOCAL_ADDRESS \
29 LOCAL_ID \
30 LOCAL_PREFIX \
31 MODE \
32 PEER \
33 POOLS \
34 PSK \
35 REMOTE_ID \
36 REMOTE_PREFIX \
37 SECURITY_POLICY \
38 START_ACTION \
39 TYPE \
40 ENABLED"
41
42 # Default values
43 IPSEC_DEFAULT_AUTH_MODE="PSK"
44 IPSEC_DEFAULT_DPD_ACTION="restart"
45 IPSEC_DEFAULT_DPD_DELAY="30"
46 IPSEC_DEFAULT_DPD_TIMEOUT="120"
47 IPSEC_DEFAULT_ENABLED="true"
48 IPSEC_DEFAULT_INACTIVITY_TIMEOUT="0"
49 IPSEC_DEFAULT_MODE="tunnel"
50 IPSEC_DEFAULT_SECURITY_POLICY="system"
51 IPSEC_DEFAULT_START_ACTION="on-demand"
52 IPSEC_DEFAULT_TYPE="net-to-net"
53
54 IPSEC_VALID_MODES="gre-transport tunnel vti"
55 IPSEC_VALID_AUTH_MODES="PSK"
56
57 cli_ipsec() {
58 local action=${1}
59 shift 1
60
61 case "${action}" in
62 connection)
63 cli_ipsec_connection "$@"
64 ;;
65 pool)
66 cli_ipsec_pool "$@"
67 ;;
68 *)
69 error "Unrecognized argument: ${action}"
70 exit ${EXIT_ERROR}
71 ;;
72 esac
73 }
74
75 cli_ipsec_connection() {
76 if ipsec_connection_exists ${1}; then
77 local connection=${1}
78 local key=${2}
79 key=${key//-/_}
80 shift 2
81
82 case "${key}" in
83 authentication|down|disable|dpd|enable|inactivity_timeout|local|mode|peer|pool|remote|security_policy|start_action|up)
84 ipsec_connection_${key} ${connection} "$@"
85 ;;
86 color)
87 color_cli "ipsec-connection" "${connection}" "$@"
88 ;;
89 description)
90 description_cli "ipsec-connection" ${connection} $@
91 ;;
92 show)
93 cli_ipsec_connection_show "${connection}"
94 exit $?
95 ;;
96 *)
97 error "Unrecognized argument: ${key}"
98 exit ${EXIT_ERROR}
99 ;;
100 esac
101 else
102 local action=${1}
103 shift
104
105 case "${action}" in
106 new)
107 ipsec_connection_new "$@"
108 ;;
109 destroy)
110 cli_ipsec_connection_destroy "$@"
111 ;;
112 ""|*)
113 if [ -n "${action}" ]; then
114 error "Unrecognized argument: '${action}'"
115 fi
116 exit ${EXIT_ERROR}
117 ;;
118 esac
119 fi
120 }
121
122 cli_ipsec_connection_destroy() {
123 local connection="${1}"
124
125 if ! ipsec_connection_destroy "${connection}"; then
126 return ${EXIT_ERROR}
127 fi
128
129 # Inform strongswan about the changes
130 ipsec_strongswan_load
131
132 # Configure strongswan autostart
133 ipsec_strongswan_autostart
134 }
135
136 ipsec_connection_get_color() {
137 # This function return the color of a zone
138 assert [ $# -eq 1 ]
139
140 local name=${1}
141 color_read "ipsec-connection" ${name}
142 }
143
144 ipsec_connection_get_description_title() {
145 assert [ $# -eq 1 ]
146
147 local name=${1}
148 description_title_read $(description_format_filename "ipsec-connection" "${name}")
149 }
150
151 cli_ipsec_connection_show() {
152 local connection="${1}"
153
154 # Read the config settings
155 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
156 if ! ipsec_connection_read_config "${connection}"; then
157 error "Could not read the connection configuration"
158 return ${EXIT_ERROR}
159 fi
160
161 cli_headline 0 "IPsec VPN Connection: ${connection}"
162 cli_space
163
164 cli_print_fmt1 1 "Color" "$(cli_color_bar $(ipsec_connection_get_color ${connection}))"
165 cli_print_fmt1 1 "Description" "$(ipsec_connection_get_description_title ${connection})"
166 cli_space
167
168 # Peer
169 if isset PEER; then
170 cli_print_fmt1 1 "Peer" "${PEER}"
171 fi
172
173 # Security Policy
174 cli_print_fmt1 1 "Security Policy" "${SECURITY_POLICY-${IPSEC_DEFAULT_SECURITY_POLICY}}"
175 cli_space
176
177 cli_headline 2 "Authentication"
178 case "${AUTH_MODE^^}" in
179 PSK)
180 cli_print_fmt1 2 "Mode" "Pre-Shared-Key"
181
182 if isset PSK; then
183 cli_print_fmt1 2 "Pre-Shared-Key" "****"
184 else
185 cli_print_fmt1 2 "Pre-Shared-Key" "- is not set -"
186 fi
187 ;;
188 X509)
189 : # TODO
190 ;;
191 esac
192 cli_space
193
194 local i
195 for i in LOCAL REMOTE; do
196 case "${i}" in
197 LOCAL)
198 cli_headline 2 "Local"
199 ;;
200 REMOTE)
201 cli_headline 2 "Remote"
202 ;;
203 esac
204
205 local id_var="${i}_ID"
206 if [ -n "${!id_var}" ]; then
207 cli_print_fmt1 2 "ID" "${!id_var}"
208 fi
209
210 local prefix_var="${i}_PREFIX"
211 if isset ${prefix_var}; then
212 cli_headline 3 "Prefix(es)"
213
214 local prefix
215 for prefix in ${!prefix_var}; do
216 cli_print_fmt1 3 "${prefix}"
217 done
218 fi
219
220 cli_space
221 done
222
223 cli_headline 2 "Misc."
224
225 case "${MODE}" in
226 gre-transport)
227 cli_print_fmt1 2 "Transport Mode" "GRE Transport"
228 ;;
229 tunnel)
230 cli_print_fmt1 2 "Transport Mode" "Tunnel"
231 ;;
232 vti)
233 cli_print_fmt1 2 "Transport Mode" "Virtual Tunnel Interface"
234 ;;
235 *)
236 cli_print_fmt1 2 "Transport Mode" "- Unknown -"
237 ;;
238 esac
239
240 # Inactivity timeout
241 if isset INACTIVITY_TIMEOUT && [ ${INACTIVITY_TIMEOUT} -gt 0 ]; then
242 cli_print_fmt1 2 "Inactivity Timeout" "$(format_time ${INACTIVITY_TIMEOUT})"
243 fi
244 cli_space
245
246 return ${EXIT_OK}
247 }
248
249 ipsec_connection_disable() {
250 local connection=${1}
251
252 if ! ipsec_connection_write_config_key "${connection}" "ENABLED" "false"; then
253 log ERROR "Could not write configuration settings"
254 return ${EXIT_ERROR}
255 fi
256
257 # Configure strongswan autostart
258 ipsec_strongswan_autostart
259 }
260
261 ipsec_connection_enable() {
262 local connection=${1}
263
264 if ! ipsec_connection_write_config_key "${connection}" "ENABLED" "true"; then
265 log ERROR "Could not write configuration settings"
266 return ${EXIT_ERROR}
267 fi
268
269 # Configure strongswan autostart
270 ipsec_strongswan_autostart
271 }
272
273 # This function writes all values to a via ${connection} specificated VPN IPsec configuration file
274 ipsec_connection_write_config() {
275 assert [ $# -ge 1 ]
276
277 local connection="${1}"
278
279 if ! ipsec_connection_exists "${connection}"; then
280 log ERROR "No such VPN IPsec connection: ${connection}"
281 return ${EXIT_ERROR}
282 fi
283
284 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}/settings"
285
286 if ! settings_write "${path}" ${IPSEC_CONNECTION_CONFIG_SETTINGS}; then
287 log ERROR "Could not write configuration settings for VPN IPsec connection ${connection}"
288 return ${EXIT_ERROR}
289 fi
290
291 ipsec_reload ${connection}
292 }
293
294 # This funtion writes the value for one key to a via ${connection} specificated VPN IPsec connection configuration file
295 ipsec_connection_write_config_key() {
296 assert [ $# -ge 3 ]
297
298 local connection=${1}
299 local key=${2}
300 shift 2
301
302 local value="$@"
303
304 if ! ipsec_connection_exists "${connection}"; then
305 log ERROR "No such VPN ipsec connection: ${connection}"
306 return ${EXIT_ERROR}
307 fi
308
309 log DEBUG "Set '${key}' to new value '${value}' in VPN ipsec connection '${connection}'"
310
311 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
312
313 # Read the config settings
314 if ! ipsec_connection_read_config "${connection}"; then
315 return ${EXIT_ERROR}
316 fi
317
318 # Set the key to a new value
319 assign "${key}" "${value}"
320
321 if ! ipsec_connection_write_config "${connection}"; then
322 return ${EXIT_ERROR}
323 fi
324
325 return ${EXIT_TRUE}
326 }
327
328 # Reads one or more keys out of a settings file or all if no key is provided.
329 ipsec_connection_read_config() {
330 assert [ $# -ge 1 ]
331
332 local connection="${1}"
333 shift 1
334
335 if ! ipsec_connection_exists "${connection}"; then
336 log ERROR "No such VPN IPsec connection : ${connection}"
337 return ${EXIT_ERROR}
338 fi
339
340
341 local args
342 if [ $# -eq 0 ] && [ -n "${IPSEC_CONNECTION_CONFIG_SETTINGS}" ]; then
343 list_append args ${IPSEC_CONNECTION_CONFIG_SETTINGS}
344 else
345 list_append args "$@"
346 fi
347
348 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}/settings"
349
350 if ! settings_read "${path}" ${args}; then
351 log ERROR "Could not read settings for VPN IPsec connection ${connection}"
352 return ${EXIT_ERROR}
353 fi
354 }
355
356 # This function checks if a vpn ipsec connection exists
357 # Returns True when yes and false when not
358 ipsec_connection_exists() {
359 assert [ $# -eq 1 ]
360
361 local connection=${1}
362
363 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}"
364
365 [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
366 }
367
368 # Determines if strongswan should be automatically started
369 # when the system boots up.
370 ipsec_strongswan_autostart() {
371 local autostart_needed="false"
372
373 local connection
374 for connection in $(ipsec_list_connections); do
375 local ENABLED
376
377 if ! ipsec_connection_read_config "${connection}" "ENABLED"; then
378 log WARNING "Could not read configuation"
379 continue
380 fi
381
382 if enabled ENABLED; then
383 autostart_needed="true"
384 break
385 fi
386 done
387
388 # Start strongswan when we need it and when it is not yet enabled
389 if ${autostart_needed}; then
390 if ! service_is_enabled "strongswan"; then
391 service_enable "strongswan"
392 fi
393
394 if ! service_is_active "strongswan"; then
395 service_start "strongswan"
396 fi
397
398 # Disable strongswan when we do not need it but it is enabled
399 elif ! ${autostart_needed}; then
400 if service_is_enabled "strongswan"; then
401 service_disable "strongswan"
402 fi
403
404 if service_is_active "strongswan"; then
405 service_stop "strongswan"
406 fi
407 fi
408 }
409
410 ipsec_strongswan_load() {
411 # Do nothing if strongswan is not running
412 if ! service_is_active "strongswan"; then
413 return ${EXIT_OK}
414 fi
415
416 if ! cmd swanctl --load-all; then
417 log ERROR "Could not reload strongswan config"
418 return ${EXIT_ERROR}
419 fi
420 }
421
422 # Reloads the connection after config changes
423 ipsec_reload() {
424 local connection=${1}
425
426 local ENABLED
427
428 if ! ipsec_connection_read_config "${connection}" "ENABLED"; then
429 log ERROR "Could not read configuration for IPsec connection ${connection}"
430 return ${EXIT_ERROR}
431 fi
432
433 if enabled ENABLED; then
434 if ! ipsec_connection_to_strongswan ${connection}; then
435 log ERROR "Could not generate strongswan config for ${connnection}"
436 return ${EXIT_ERROR}
437 fi
438 else
439 log DEBUG "Deleting strongswan config ${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
440 unlink "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
441 fi
442
443 ipsec_strongswan_load
444 }
445
446 # Handle the cli after authentification
447 ipsec_connection_authentication() {
448 if [ ! $# -gt 1 ]; then
449 log ERROR "Not enough arguments"
450 return ${EXIT_ERROR}
451 fi
452
453 local connection=${1}
454 local cmd=${2}
455 shift 2
456
457 case ${cmd} in
458 mode)
459 ipsec_connection_authentication_mode "${connection}" "$@"
460 ;;
461 pre-shared-key)
462 ipsec_connection_authentication_psk "${connection}" "$@"
463 ;;
464 *)
465 log ERROR "Unrecognized argument: ${cmd}"
466 return ${EXIT_ERROR}
467 ;;
468 esac
469 }
470
471 # Set the authentification mode
472 ipsec_connection_authentication_mode() {
473 if [ ! $# -eq 2 ]; then
474 log ERROR "Not enough arguments"
475 return ${EXIT_ERROR}
476 fi
477 local connection=${1}
478 local mode=${2}
479
480 if ! isoneof mode ${IPSEC_VALID_AUTH_MODES}; then
481 log ERROR "Auth mode '${mode}' is invalid"
482 return ${EXIT_ERROR}
483 fi
484
485 if ! ipsec_connection_write_config_key "${connection}" "AUTH_MODE" ${mode^^}; then
486 log ERROR "Could not write configuration settings"
487 return ${EXIT_ERROR}
488 fi
489 }
490
491 # Set the psk
492 ipsec_connection_authentication_psk() {
493 if [ ! $# -eq 2 ]; then
494 log ERROR "Not enough arguments"
495 return ${EXIT_ERROR}
496 fi
497
498 local connection=${1}
499 local psk=${2}
500
501 local length=${#psk}
502
503 if [ ${length} -lt 4 ]; then
504 error "The PSK must be longer than four characters"
505 return ${EXIT_ERROR}
506 fi
507
508 if [ ${length} -gt 128 ]; then
509 error "The PSK cannot be longer than 128 characters"
510 return ${EXIT_ERROR}
511 fi
512
513 if ! ipsec_connection_write_config_key "${connection}" "PSK" "${psk}"; then
514 log ERROR "Could not write configuration settings"
515 return ${EXIT_ERROR}
516 fi
517
518 return ${EXIT_OK}
519 }
520
521 ipsec_connection_up() {
522 local connection="${1}"
523
524 if ! ipsec_connection_exists "${connection}"; then
525 error "No such VPN IPsec connection: ${connection}"
526 return ${EXIT_ERROR}
527 fi
528
529 if ! [ -f "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf" ]; then
530 log DEBUG "Could not find a swanctl config, generating swanctl config"
531 ipsec_connection_to_strongswan "${connection}"
532 ipsec_strongswan_load
533 fi
534
535 cmd swanctl --initiate --child "${connection}"
536 }
537
538 ipsec_connection_down() {
539 local connection="${1}"
540
541 if ! ipsec_connection_exists "${connection}"; then
542 error "No such VPN IPsec connection: ${connection}"
543 return ${EXIT_ERROR}
544 fi
545
546 cmd swanctl --terminate --ike "${connection}"
547 }
548
549 # Handle the cli after authentification
550 ipsec_connection_dpd() {
551 if [ ! $# -gt 1 ]; then
552 log ERROR "Not enough arguments"
553 return ${EXIT_ERROR}
554 fi
555
556 local connection=${1}
557 local cmd=${2}
558 shift 2
559
560 case ${cmd} in
561 action)
562 ipsec_connection_dpd_action "${connection}" "$@"
563 ;;
564 delay)
565 ipsec_connection_dpd_delay "${connection}" "$@"
566 ;;
567 timeout)
568 ipsec_connection_dpd_timeout "${connection}" "$@"
569 ;;
570 *)
571 log ERROR "Unrecognized argument: ${cmd}"
572 return ${EXIT_ERROR}
573 ;;
574 esac
575 }
576
577 # Set the default dpd action
578 ipsec_connection_dpd_action() {
579 if [ ! $# -eq 2 ]; then
580 log ERROR "Not enough arguments"
581 return ${EXIT_ERROR}
582 fi
583 local connection=${1}
584 local action=${2}
585
586 if ! isoneof action "restart" "clear"; then
587 log ERROR "dpd action '${action}' is invalid"
588 return ${EXIT_ERROR}
589 fi
590
591 if ! ipsec_connection_write_config_key "${connection}" "DPD_ACTION" ${action}; then
592 log ERROR "Could not write configuration settings"
593 return ${EXIT_ERROR}
594 fi
595 }
596
597 # Set the dpd delay
598 ipsec_connection_dpd_delay() {
599 if [ ! $# -ge 2 ]; then
600 log ERROR "Not enough arguments"
601 return ${EXIT_ERROR}
602 fi
603
604 local connection=${1}
605 shift 1
606 local value=$@
607
608 if ! isinteger value; then
609 value=$(parse_time "$@")
610 if [ ! $? -eq 0 ]; then
611 log ERROR "Parsing the passed time was not sucessful please check the passed values."
612 return ${EXIT_ERROR}
613 fi
614 fi
615
616 if [ ${value} -lt 0 ]; then
617 log ERROR "The passed time value must be in the sum greater or equal zero seconds."
618 return ${EXIT_ERROR}
619 fi
620
621 if ! ipsec_connection_write_config_key "${connection}" "DPD_DELAY" ${value}; then
622 log ERROR "Could not write configuration settings"
623 return ${EXIT_ERROR}
624 fi
625
626 return ${EXIT_OK}
627 }
628
629 # Set the dpd timeout
630 ipsec_connection_dpd_timeout() {
631 if [ ! $# -ge 2 ]; then
632 log ERROR "Not enough arguments"
633 return ${EXIT_ERROR}
634 fi
635
636 local connection=${1}
637 shift 1
638 local value=$@
639
640 if ! isinteger value; then
641 value=$(parse_time "$@")
642 if [ ! $? -eq 0 ]; then
643 log ERROR "Parsing the passed time was not sucessful please check the passed values."
644 return ${EXIT_ERROR}
645 fi
646 fi
647
648 if [ ${value} -le 0 ]; then
649 log ERROR "The passed time value must be in the sum greater or equal zero seconds."
650 return ${EXIT_ERROR}
651 fi
652
653 if ! ipsec_connection_write_config_key "${connection}" "DPD_TIMEOUT" ${value}; then
654 log ERROR "Could not write configuration settings"
655 return ${EXIT_ERROR}
656 fi
657
658 return ${EXIT_OK}
659 }
660
661 # Handle the cli after local
662 ipsec_connection_local() {
663 if [ ! $# -ge 2 ]; then
664 log ERROR "Not enough arguments"
665 return ${EXIT_ERROR}
666 fi
667
668 local connection=${1}
669 local cmd=${2}
670 shift 2
671
672 case ${cmd} in
673 address)
674 ipsec_connection_local_address "${connection}" "$@"
675 ;;
676 id)
677 ipsec_connection_id "${connection}" "LOCAL" "$@"
678 ;;
679 prefix)
680 ipsec_connection_prefix "${connection}" "LOCAL" "$@"
681 ;;
682 *)
683 log ERROR "Unrecognized argument: ${cmd}"
684 return ${EXIT_ERROR}
685 ;;
686 esac
687
688 return ${EXIT_OK}
689 }
690
691 # Set the connection mode
692 ipsec_connection_mode() {
693 if [ ! $# -eq 2 ]; then
694 log ERROR "Not enough arguments"
695 return ${EXIT_ERROR}
696 fi
697 local connection=${1}
698 local mode=${2}
699
700 if ! isoneof mode ${IPSEC_VALID_MODES}; then
701 log ERROR "Mode '${mode}' is invalid"
702 return ${EXIT_ERROR}
703 fi
704
705 if ! ipsec_connection_write_config_key "${connection}" "MODE" ${mode}; then
706 log ERROR "Could not write configuration settings"
707 return ${EXIT_ERROR}
708 fi
709
710 return ${EXIT_OK}
711 }
712
713 # Set the local address
714 ipsec_connection_local_address() {
715 if [ ! $# -eq 2 ]; then
716 log ERROR "Not enough arguments"
717 return ${EXIT_ERROR}
718 fi
719 local connection=${1}
720 local local_address=${2}
721
722 if ! ipsec_connection_check_peer ${local_address}; then
723 log ERROR "Local address '${local_address}' is invalid"
724 return ${EXIT_ERROR}
725 fi
726
727 if ! ipsec_connection_write_config_key "${connection}" "LOCAL_ADDRESS" ${local_address}; then
728 log ERROR "Could not write configuration settings"
729 return ${EXIT_ERROR}
730 fi
731
732 return ${EXIT_OK}
733 }
734
735 # Set the peer to connect to
736 ipsec_connection_peer() {
737 if [ ! $# -eq 2 ]; then
738 log ERROR "Not enough arguments"
739 return ${EXIT_ERROR}
740 fi
741 local connection=${1}
742 local peer=${2}
743
744 if ! ipsec_connection_check_peer ${peer}; then
745 log ERROR "Peer '${peer}' is invalid"
746 return ${EXIT_ERROR}
747 fi
748
749 if ! ipsec_connection_write_config_key "${connection}" "PEER" ${peer}; then
750 log ERROR "Could not write configuration settings"
751 return ${EXIT_ERROR}
752 fi
753
754 return ${EXIT_OK}
755 }
756
757 #Set the local or remote id
758 ipsec_connection_id() {
759 if [ ! $# -eq 3 ]; then
760 log ERROR "Not enough arguments"
761 return ${EXIT_ERROR}
762 fi
763 local connection=${1}
764 local type=${2}
765 local id=${3}
766
767 if ! ipsec_connection_check_id ${id}; then
768 log ERROR "Id '${id}' is invalid"
769 return ${EXIT_ERROR}
770 fi
771
772 if ! ipsec_connection_write_config_key "${connection}" "${type}_ID" ${id}; then
773 log ERROR "Could not write configuration settings"
774 return ${EXIT_ERROR}
775 fi
776
777 return ${EXIT_OK}
778 }
779
780 # Set the local or remote prefix
781 ipsec_connection_prefix() {
782 if [ ! $# -ge 3 ]; then
783 log ERROR "Not enough arguments"
784 return ${EXIT_ERROR}
785 fi
786 local connection=${1}
787 local type=${2}
788 shift 2
789
790 local _prefix="${type}_PREFIX"
791 local "${_prefix}"
792 if ! ipsec_connection_read_config "${connection}" "${_prefix}"; then
793 return ${EXIT_ERROR}
794 fi
795
796 # Remove duplicated entries to proceed the list safely
797 assign "${_prefix}" "$(list_unique ${!_prefix} )"
798
799 local prefixes_added
800 local prefixes_removed
801 local prefixes_set
802
803 while [ $# -gt 0 ]; do
804 local arg="${1}"
805
806 case "${arg}" in
807 +*)
808 list_append prefixes_added "${arg:1}"
809 ;;
810 -*)
811 list_append prefixes_removed "${arg:1}"
812 ;;
813 [A-Fa-f0-9]*)
814 list_append prefixes_set "${arg}"
815 ;;
816 *)
817 error "Invalid argument: ${arg}"
818 return ${EXIT_ERROR}
819 ;;
820 esac
821 shift
822 done
823
824 # Check if the user is trying a mixed operation
825 if ! list_is_empty prefixes_set && (! list_is_empty prefixes_added || ! list_is_empty prefixes_removed); then
826 error "You cannot reset the prefix list and add or remove prefixes at the same time"
827 return ${EXIT_ERROR}
828 fi
829
830 # Set new prefix list
831 if ! list_is_empty prefixes_set; then
832 # Check if all prefixes are valid
833 local prefix
834 for prefix in ${prefixes_set}; do
835 if ! ip_net_is_valid ${prefix}; then
836 error "Unsupported prefix: ${prefix}"
837 return ${EXIT_ERROR}
838 fi
839 done
840
841 assign "${_prefix}" "${prefixes_set}"
842
843 # Perform incremental updates
844 else
845 local prefix
846
847 # Perform all removals
848 for prefix in ${prefixes_removed}; do
849 if ! list_remove "${_prefix}" ${prefix}; then
850 warning "${prefix} was not on the list and could not be removed"
851 fi
852 done
853
854
855 for prefix in ${prefixes_added}; do
856 if ip_net_is_valid ${prefix}; then
857 if ! list_append_unique "${_prefix}" ${prefix}; then
858 warning "${prefix} is already on the prefix list"
859 fi
860 else
861 warning "${prefix} is not a valid IP network and could not be added"
862 fi
863 done
864 fi
865
866 # Check if the list contain at least one valid prefix
867 if list_is_empty ${_prefix}; then
868 error "Cannot save an empty prefix list"
869 return ${EXIT_ERROR}
870 fi
871
872 # Save everything
873 if ! ipsec_connection_write_config_key "${connection}" "${_prefix}" ${!_prefix}; then
874 log ERROR "Could not write configuration settings"
875 fi
876
877 return ${EXIT_OK}
878 }
879
880 # Set the pools to use
881 ipsec_connection_pool() {
882 if [ ! $# -ge 2 ]; then
883 log ERROR "Not enough arguments"
884 return ${EXIT_ERROR}
885 fi
886 local connection=${1}
887 shift
888
889 local POOLS
890 if ! ipsec_connection_read_config "${connection}" "POOLS"; then
891 return ${EXIT_ERROR}
892 fi
893
894 # Remove duplicated entries to proceed the list safely
895 assign "POOLS" "$(list_unique ${POOLS})"
896
897 local pools_added
898 local pools_removed
899 local pools_set
900
901 while [ $# -gt 0 ]; do
902 local arg="${1}"
903
904 case "${arg}" in
905 +*)
906 list_append pools_added "${arg:1}"
907 ;;
908 -*)
909 list_append pools_removed "${arg:1}"
910 ;;
911 [A-Za-z0-9]*)
912 list_append pools_set "${arg}"
913 ;;
914 *)
915 error "Invalid argument: ${arg}"
916 return ${EXIT_ERROR}
917 ;;
918 esac
919 shift
920 done
921
922 # Check if the user is trying a mixed operation
923 if ! list_is_empty pools_set && (! list_is_empty pools_added || ! list_is_empty pools_removed); then
924 error "You cannot reset the pools list and add or remove pools at the same time"
925 return ${EXIT_ERROR}
926 fi
927
928 # Set new pools list
929 if ! list_is_empty pools_set; then
930 # Check if all pools are valid
931 local pool
932 for pool in ${pools_set}; do
933 if ! ipsec_pool_exists ${pool} || ! ipsec_pool_check_config ${pool}; then
934 error "Pool ${pool} is not valid"
935 return ${EXIT_ERROR}
936 fi
937 done
938
939 assign "POOLS" "${pools_set}"
940
941 # Perform incremental updates
942 else
943 local pool
944
945 # Perform all removals
946 for pool in ${pools_removed}; do
947 if ! list_remove "POOLS" ${pool}; then
948 warning "${pool} was not on the list and could not be removed"
949 fi
950 done
951
952
953 for pool in ${pools_added}; do
954 if ipsec_pool_exists ${pool} && ipsec_pool_check_config ${pool}; then
955 if ! list_append_unique "POOLS" ${pool}; then
956 warning "${pool} is already on the prefix list"
957 fi
958 else
959 warning "${pool} is not a valid pool"
960 fi
961 done
962 fi
963
964 # Check if the list contain at least one valid pool
965 if list_is_empty POOLS; then
966 error "Cannot save an empty pool list"
967 return ${EXIT_ERROR}
968 fi
969
970 # Save everything
971 if ! ipsec_connection_write_config_key "${connection}" "POOLS" ${POOLS}; then
972 log ERROR "Could not write configuration settings"
973 fi
974
975 return ${EXIT_OK}
976 }
977
978 # Handle the cli after remote
979 ipsec_connection_remote() {
980 if [ ! $# -ge 2 ]; then
981 log ERROR "Not enough arguments"
982 return ${EXIT_ERROR}
983 fi
984
985 local connection=${1}
986 local cmd=${2}
987 shift 2
988
989 case ${cmd} in
990 id)
991 ipsec_connection_id "${connection}" "REMOTE" "$@"
992 ;;
993
994 prefix)
995 ipsec_connection_prefix "${connection}" "REMOTE" "$@"
996 ;;
997 *)
998 log ERROR "Unrecognized argument: ${cmd}"
999 return ${EXIT_ERROR}
1000 ;;
1001 esac
1002
1003 return ${EXIT_OK}
1004 }
1005
1006 # Set the inactivity timeout
1007 ipsec_connection_inactivity_timeout() {
1008 if [ ! $# -ge 2 ]; then
1009 log ERROR "Not enough arguments"
1010 return ${EXIT_ERROR}
1011 fi
1012
1013 local connection=${1}
1014 shift 1
1015 local value=$@
1016
1017 if ! isinteger value; then
1018 value=$(parse_time "$@")
1019 if [ ! $? -eq 0 ]; then
1020 log ERROR "Parsing the passed time was not sucessful please check the passed values."
1021 return ${EXIT_ERROR}
1022 fi
1023 fi
1024
1025 if [ ${value} -le 0 ]; then
1026 log ERROR "The passed time value must be in the sum greater zero seconds."
1027 return ${EXIT_ERROR}
1028 fi
1029
1030 if ! ipsec_connection_write_config_key "${connection}" "INACTIVITY_TIMEOUT" ${value}; then
1031 log ERROR "Could not write configuration settings"
1032 return ${EXIT_ERROR}
1033 fi
1034
1035 return ${EXIT_OK}
1036 }
1037
1038 # Set the default start action
1039 ipsec_connection_start_action() {
1040 if [ ! $# -eq 2 ]; then
1041 log ERROR "Not enough arguments"
1042 return ${EXIT_ERROR}
1043 fi
1044 local connection=${1}
1045 local action=${2}
1046
1047 if ! isoneof action "on-demand" "always-on"; then
1048 log ERROR "Start action '${action}' is invalid"
1049 return ${EXIT_ERROR}
1050 fi
1051
1052 if ! ipsec_connection_write_config_key "${connection}" "START_ACTION" ${action}; then
1053 log ERROR "Could not write configuration settings"
1054 return ${EXIT_ERROR}
1055 fi
1056 }
1057
1058 # Set the security policy to use
1059 ipsec_connection_security_policy() {
1060 if [ ! $# -eq 2 ]; then
1061 log ERROR "Not enough arguments"
1062 return ${EXIT_ERROR}
1063 fi
1064 local connection=${1}
1065 local security_policy=${2}
1066
1067 if ! vpn_security_policy_exists ${security_policy}; then
1068 log ERROR "No such vpn security policy '${security_policy}'"
1069 return ${EXIT_ERROR}
1070 fi
1071
1072 if ! ipsec_connection_write_config_key "${connection}" "SECURITY_POLICY" ${security_policy}; then
1073 log ERROR "Could not write configuration settings"
1074 return ${EXIT_ERROR}
1075 fi
1076 }
1077
1078 # Check if a id is valid
1079 ipsec_connection_check_id() {
1080 assert [ $# -eq 1 ]
1081 local id=${1}
1082
1083 if [[ ${id} =~ ^@[[:alnum:]]+$ ]] || ip_is_valid ${id}; then
1084 return ${EXIT_TRUE}
1085 else
1086 return ${EXIT_FALSE}
1087 fi
1088 }
1089
1090 # Checks if a peer is valid
1091 ipsec_connection_check_peer() {
1092 assert [ $# -eq 1 ]
1093 local peer=${1}
1094
1095 # IP addresses are accepted
1096 if ip_is_valid ${peer}; then
1097 return ${EXIT_TRUE}
1098 fi
1099
1100 # FQDNs are okay, too
1101 if fqdn_is_valid "${peer}"; then
1102 return ${EXIT_TRUE}
1103 fi
1104
1105 # We cannot use anything else
1106 return ${EXIT_FALSE}
1107 }
1108
1109 # This function checks if a VPN IPsec connection name is valid
1110 # Allowed are only A-Za-z0-9
1111 ipsec_connection_check_name() {
1112 assert [ $# -eq 1 ]
1113
1114 local connection=${1}
1115
1116 [[ "${connection}" =~ [^[:alnum:]$] ]]
1117 }
1118
1119 # Function that creates one VPN IPsec connection
1120 ipsec_connection_new() {
1121 if [ $# -gt 2 ]; then
1122 error "Too many arguments"
1123 return ${EXIT_ERROR}
1124 fi
1125
1126 local connection="${1}"
1127 local type="${2}"
1128
1129 if ! isset connection; then
1130 error "Please provide a connection name"
1131 return ${EXIT_ERROR}
1132 fi
1133
1134 # Check for duplicates
1135 if ipsec_connection_exists "${connection}"; then
1136 error "The VPN IPsec connection ${connection} already exists"
1137 return ${EXIT_ERROR}
1138 fi
1139
1140 # Check if the name of the connection is valid
1141 if ipsec_connection_check_name "${connection}"; then
1142 error "'${connection}' contains illegal characters"
1143 return ${EXIT_ERROR}
1144 fi
1145
1146 # Set TYPE to default if not set by the user
1147 if ! isset type; then
1148 type="${IPSEC_DEFAULT_TYPE}"
1149 fi
1150
1151 if ! isoneof "type" "net-to-net" "host-to-net"; then
1152 error "Type is invalid"
1153 return ${EXIT_ERROR}
1154 fi
1155
1156 log DEBUG "Creating VPN IPsec connection ${connection}"
1157
1158 if ! mkdir -p "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
1159 log ERROR "Could not create config directory for ${connection}"
1160 return ${EXIT_ERROR}
1161 fi
1162
1163 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
1164
1165 AUTH_MODE=${IPSEC_DEFAULT_AUTH_MODE}
1166 DPD_ACTION=${IPSEC_DEFAULT_DPD_ACTION}
1167 DPD_DELAY=${IPSEC_DEFAULT_DPD_DELAY}
1168 DPD_TIMEOUT=${IPSEC_DEFAULT_DPD_TIMEOUT}
1169 ENABLED=${IPSEC_DEFAULT_ENABLED}
1170 MODE=${IPSEC_DEFAULT_MODE}
1171 START_ACTION=${IPSEC_DEFAULT_START_ACTION}
1172 TYPE="${type}"
1173
1174 INACTIVITY_TIMEOUT=${IPSEC_DEFAULT_INACTIVITY_TIMEOUT}
1175 SECURITY_POLICY=${IPSEC_DEFAULT_SECURITY_POLICY}
1176
1177 if ! ipsec_connection_write_config "${connection}"; then
1178 log ERROR "Could not write new config file"
1179 return ${EXIT_ERROR}
1180 fi
1181
1182 # Configure strongswan autostart
1183 ipsec_strongswan_autostart
1184 }
1185
1186 # Function that deletes based on the passed parameters one ore more vpn security policies
1187 ipsec_connection_destroy() {
1188 local connection
1189 for connection in "$@"; do
1190 if ! ipsec_connection_exists "${connection}"; then
1191 log ERROR "The VPN IPsec connection ${connection} does not exist."
1192 continue
1193 fi
1194
1195 log DEBUG "Deleting VPN IPsec connection ${connection}"
1196
1197 # Delete strongswan configuration file
1198 file_delete "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
1199
1200 if ! rm -rf "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
1201 log ERROR "Deleting the VPN IPsec connection ${connection} was not sucessful"
1202 return ${EXIT_ERROR}
1203 fi
1204
1205 done
1206 }
1207
1208 # List all ipsec connections
1209 ipsec_list_connections() {
1210 list_directory "${NETWORK_IPSEC_CONNS_DIR}"
1211 }
1212
1213 ipsec_connection_to_strongswan() {
1214 local connection="${1}"
1215 log DEBUG "Generating IPsec configuration for ${connection}"
1216
1217 # Read the config settings
1218 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
1219 if ! ipsec_connection_read_config "${connection}"; then
1220 error "Could not read the connection ${connection}"
1221 return ${EXIT_ERROR}
1222 fi
1223
1224 local path="${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
1225
1226 (
1227 # Write the connection section
1228 _ipsec_connection_to_strongswan_connection "${connection}"
1229
1230 # Write the secrets section
1231 _ipsec_connection_to_strongswan_secrets "${connection}"
1232
1233 ) > ${path}
1234 }
1235
1236 _ipsec_connection_to_strongswan_connection() {
1237 local connection="${1}"
1238
1239 # Read the security policy
1240 local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
1241 if ! vpn_security_policies_read_config "${SECURITY_POLICY}"; then
1242 return ${EXIT_ERROR}
1243 fi
1244
1245 # Is DPD enabled?
1246 local dpd="false"
1247 if isset DPD_DELAY && isinteger DPD_DELAY && [ ${DPD_DELAY} -gt 0 ]; then
1248 dpd="true"
1249 fi
1250
1251 # Write configuration header
1252 config_header "strongSwan configuration for ${connection}"
1253
1254 print_indent 0 "connections {"
1255 print_indent 1 "${connection} {"
1256
1257 # IKE Version
1258 print_indent 2 "# IKE Version"
1259 case "${KEY_EXCHANGE^^}" in
1260 IKEV1)
1261 print_indent 2 "version = 1"
1262 ;;
1263
1264 # Fall back to IKEv2 for any random values
1265 IKEV2|*)
1266 print_indent 2 "version = 2"
1267 ;;
1268 esac
1269 print # empty line
1270
1271 # Always only keep one connection open at a time
1272 print_indent 2 "# Unique IDs"
1273 print_indent 2 "unique = replace"
1274 print
1275
1276 # Local Address
1277 print_indent 2 "# Local Address"
1278 if isset LOCAL_ADDRESS; then
1279 print_indent 2 "local_addrs = ${LOCAL_ADDRESS}"
1280 else
1281 print_indent 2 "local_addrs = %any"
1282 fi
1283 print
1284
1285 # Remote Address
1286 print_indent 2 "# Remote Address"
1287 if isset PEER; then
1288 print_indent 2 "remote_addrs = ${PEER}"
1289 else
1290 print_indent 2 "remote_addrs = %any"
1291 fi
1292 print
1293
1294 # IKE Proposals
1295 print_indent 2 "# IKE Proposals"
1296 print_indent 2 "proposals = $(vpn_security_policies_make_ike_proposal ${SECURITY_POLICY})"
1297 print
1298
1299 # DPD Settings
1300 if enabled dpd; then
1301 print_indent 2 "# Dead Peer Detection"
1302 print_indent 2 "dpd_delay = ${DPD_DELAY}"
1303
1304 if isset DPD_TIMEOUT; then
1305 print_indent 2 "dpd_timeout = ${DPD_TIMEOUT}"
1306 fi
1307
1308 print
1309 fi
1310
1311 # Fragmentation
1312 print_indent 2 "# Fragmentation"
1313 print_indent 2 "fragmentation = yes"
1314 print
1315
1316
1317 # Host-to-Net specific settings
1318 case "${TYPE}" in
1319 host-to-net)
1320 # Pools
1321 if isset POOLS; then
1322 print_indent 2 "# Pools"
1323 print_indent 2 "pools = $(list_join POOLS ", ")"
1324 print
1325 fi
1326 ;;
1327 esac
1328
1329 # Local
1330 print_indent 2 "local {"
1331
1332 # Local ID
1333 if isset LOCAL_ID; then
1334 print_indent 3 "id = ${LOCAL_ID}"
1335 fi
1336
1337 # Authentication
1338 case "${AUTH_MODE}" in
1339 PSK)
1340 print_indent 3 "auth = psk"
1341 ;;
1342 esac
1343
1344 print_indent 2 "}"
1345 print
1346
1347 # Remote
1348 print_indent 2 "remote {"
1349
1350 # Remote ID
1351 if isset REMOTE_ID; then
1352 print_indent 3 "id = ${REMOTE_ID}"
1353 fi
1354
1355 # Authentication
1356 case "${AUTH_MODE}" in
1357 PSK)
1358 print_indent 3 "auth = psk"
1359 ;;
1360 esac
1361
1362 print_indent 2 "}"
1363 print
1364
1365 # Children
1366
1367 print_indent 2 "children {"
1368 print_indent 3 "${connection} {"
1369
1370 print_indent 4 "# ESP Proposals"
1371 print_indent 4 "esp_proposals = $(vpn_security_policies_make_esp_proposal ${SECURITY_POLICY})"
1372 print
1373
1374 # Traffic Selectors
1375
1376 case "${MODE}" in
1377 gre-*)
1378 print_indent 4 "local_ts = dynamic[gre]"
1379 print_indent 4 "remote_ts = dynamic[gre]"
1380 ;;
1381 *)
1382 # Local Prefixes
1383 if isset LOCAL_PREFIX; then
1384 print_indent 4 "local_ts = $(list_join LOCAL_PREFIX ,)"
1385 else
1386 print_indent 4 "local_ts = dynamic"
1387 fi
1388
1389 # Remote Prefixes
1390 if isset REMOTE_PREFIX; then
1391 print_indent 4 "remote_ts = $(list_join REMOTE_PREFIX ,)"
1392 else
1393 print_indent 4 "remote_ts = dynamic"
1394 fi
1395 ;;
1396 esac
1397 print
1398
1399 # Netfilter Marks
1400 case "${MODE}" in
1401 vti)
1402 print_indent 4 "# Netfilter Marks"
1403 print_indent 4 "mark_in = %unique"
1404 print_indent 4 "mark_out = %unique"
1405 print
1406 ;;
1407 esac
1408
1409 # Dead Peer Detection
1410 if enabled dpd; then
1411 print_indent 4 "# Dead Peer Detection"
1412 print_indent 4 "dpd_action = ${DPD_ACTION}"
1413 print
1414 fi
1415
1416 # Rekeying
1417 if isset LIFETIME; then
1418 print_indent 4 "# Rekey Time"
1419 print_indent 4 "rekey_time = ${LIFETIME}"
1420 print
1421 fi
1422
1423 # Updown Script
1424 print_indent 4 "updown = ${NETWORK_HELPERS_DIR}/ipsec-updown"
1425 print
1426
1427 # Mode
1428 print_indent 4 "# Mode"
1429 case "${MODE}" in
1430 gre-transport)
1431 print_indent 4 "mode = transport"
1432 ;;
1433 tunnel|vti|*)
1434 print_indent 4 "mode = tunnel"
1435 ;;
1436 esac
1437 print
1438
1439 # Compression
1440 print_indent 4 "# Compression"
1441 if enabled COMPRESSION; then
1442 print_indent 4 "ipcomp = yes"
1443 else
1444 print_indent 4 "ipcomp = no"
1445 fi
1446 print
1447
1448 # Inactivity Timeout
1449 if isset INACTIVITY_TIMEOUT; then
1450 print_indent 4 "# Inactivity Timeout"
1451 print_indent 4 "inactivity = ${INACTIVITY_TIMEOUT}"
1452 print
1453 fi
1454
1455 # Net-to-Net specific settings
1456 case "${TYPE}" in
1457 net-to-net)
1458 # Start Action
1459 print_indent 4 "# Start Action"
1460 case "${START_ACTION}" in
1461 on-demand)
1462 print_indent 4 "start_action = trap"
1463 print_indent 4 "close_action = trap"
1464 ;;
1465 wait)
1466 print_indent 4 "start_action = none"
1467 print_indent 4 "close_action = none"
1468 ;;
1469 always-on|*)
1470 print_indent 4 "start_action = start"
1471 print_indent 4 "close_action = start"
1472 ;;
1473 esac
1474 print
1475 ;;
1476 esac
1477
1478 print_indent 3 "}"
1479 print_indent 2 "}"
1480 print
1481
1482 print_indent 1 "}"
1483 print_indent 0 "}"
1484 print
1485 }
1486
1487 _ipsec_connection_to_strongswan_secrets() {
1488 local connection="${1}"
1489
1490 print_indent 0 "secrets {"
1491
1492 case "${AUTH_MODE}" in
1493 PSK)
1494 print_indent 1 "ike {"
1495
1496 # Secret
1497 print_indent 2 "secret = ${PSK}"
1498
1499 # ID
1500 if isset REMOTE_ID; then
1501 print_indent 2 "id = ${REMOTE_ID}"
1502 fi
1503
1504 print_indent 1 "}"
1505 ;;
1506 esac
1507
1508 print_indent 0 "}"
1509 }