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