]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.ipsec
ipsec: Properly shut down connections when destroyed
[people/stevee/network.git] / src / functions / functions.ipsec
CommitLineData
917a1aa0
JS
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
33944dfb
MT
22IPSEC_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 \
5601f4f5
JS
36 SECURITY_POLICY \
37 ENABLED"
917a1aa0
JS
38
39# Default values
ab589039 40IPSEC_DEFAULT_AUTH_MODE="PSK"
bb9fccaf
JS
41IPSEC_DEFAULT_DPD_ACTION="restart"
42IPSEC_DEFAULT_DPD_DELAY="30"
43IPSEC_DEFAULT_DPD_TIMEOUT="120"
5601f4f5 44IPSEC_DEFAULT_ENABLED="true"
917a1aa0 45IPSEC_DEFAULT_INACTIVITY_TIMEOUT="0"
bb9fccaf 46IPSEC_DEFAULT_MODE="tunnel"
917a1aa0 47IPSEC_DEFAULT_SECURITY_POLICY="system"
bb9fccaf 48IPSEC_DEFAULT_START_ACTION="on-demand"
917a1aa0
JS
49
50IPSEC_VALID_MODES="gre-transport tunnel vti"
ab589039 51IPSEC_VALID_AUTH_MODES="PSK"
917a1aa0 52
2da98f56
MT
53cli_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
68cli_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
5601f4f5 76 authentication|down|disable|dpd|enable|inactivity_timeout|local|mode|peer|remote|security_policy|start_action|up)
2da98f56
MT
77 ipsec_connection_${key} ${connection} $@
78 ;;
c1e76e97
MT
79 show)
80 cli_ipsec_connection_show "${connection}"
81 exit $?
82 ;;
2da98f56
MT
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)
fa33d830 97 cli_ipsec_connection_destroy $@
2da98f56
MT
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
fa33d830
MT
109cli_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
c1e76e97
MT
123cli_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
5601f4f5
JS
217ipsec_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}
c3f31173
MT
226
227 # Configure strongswan autostart
228 ipsec_strongswan_autostart
5601f4f5
JS
229}
230
231ipsec_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}"
c3f31173
MT
240
241 # Configure strongswan autostart
242 ipsec_strongswan_autostart
5601f4f5
JS
243}
244
917a1aa0
JS
245# This function writes all values to a via ${connection} specificated VPN IPsec configuration file
246ipsec_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
cf8685a1 256 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}/settings"
917a1aa0
JS
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
267ipsec_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.
301ipsec_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
cf8685a1 320 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}/settings"
917a1aa0
JS
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
917a1aa0
JS
328# This function checks if a vpn ipsec connection exists
329# Returns True when yes and false when not
330ipsec_connection_exists() {
331 assert [ $# -eq 1 ]
332
333 local connection=${1}
334
cf8685a1 335 local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}"
917a1aa0
JS
336
337 [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
338}
339
c3f31173
MT
340# Determines if strongswan should be automatically started
341# when the system boots up.
342ipsec_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
b863fe52
MT
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
c3f31173
MT
369
370 # Disable strongswan when we do not need it but it is enabled
b863fe52
MT
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
c3f31173
MT
379 fi
380}
381
f0e91d26
JS
382ipsec_strongswan_load() {
383 if ! cmd swanctl --load-all; then
384 log ERROR "Could not reload strongswan config"
385 return ${EXIT_ERROR}
386 fi
387}
388
917a1aa0
JS
389# Reloads the connection after config changes
390ipsec_reload() {
39d87f20
JS
391 local connection=${1}
392
5601f4f5
JS
393 local ENABLED
394
395 if ! ipsec_connection_read_config "${connection}" "ENABLED"; then
396 log ERROR "Could not read configuration for IPsec connection ${connection}"
39d87f20
JS
397 return ${EXIT_ERROR}
398 fi
399
471f16bc 400 if enabled ENABLED; then
5601f4f5
JS
401 if ! ipsec_connection_to_strongswan ${connection}; then
402 log ERROR "Could not generate strongswan config for ${connnection}"
403 return ${EXIT_ERROR}
404 fi
405 else
406 unlink "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
407 fi
408
f0e91d26 409 ipsec_strongswan_load
917a1aa0
JS
410}
411
412# Handle the cli after authentification
413ipsec_connection_authentication() {
414 if [ ! $# -gt 1 ]; then
415 log ERROR "Not enough arguments"
416 return ${EXIT_ERROR}
417 fi
418
419 local connection=${1}
420 local cmd=${2}
421 shift 2
422
423 case ${cmd} in
424 mode)
425 ipsec_connection_authentication_mode "${connection}" $@
426 ;;
427 pre-shared-key)
428 ipsec_connection_authentication_psk "${connection}" $@
429 ;;
430 *)
431 log ERROR "Unrecognized argument: ${cmd}"
432 return ${EXIT_ERROR}
433 ;;
434 esac
435}
436
437# Set the authentification mode
438ipsec_connection_authentication_mode() {
439 if [ ! $# -eq 2 ]; then
440 log ERROR "Not enough arguments"
441 return ${EXIT_ERROR}
442 fi
443 local connection=${1}
444 local mode=${2}
445
446 if ! isoneof mode ${IPSEC_VALID_AUTH_MODES}; then
447 log ERROR "Auth mode '${mode}' is invalid"
448 return ${EXIT_ERROR}
449 fi
450
ab589039 451 if ! ipsec_connection_write_config_key "${connection}" "AUTH_MODE" ${mode^^}; then
917a1aa0
JS
452 log ERROR "Could not write configuration settings"
453 return ${EXIT_ERROR}
454 fi
455}
456
457# Set the psk
458ipsec_connection_authentication_psk() {
db491d1d 459 if [ ! $# -eq 2 ]; then
917a1aa0
JS
460 log ERROR "Not enough arguments"
461 return ${EXIT_ERROR}
462 fi
1bfc4f56 463
917a1aa0
JS
464 local connection=${1}
465 local psk=${2}
466
1bfc4f56
MT
467 local length=${#psk}
468
469 if [ ${length} -lt 4 ]; then
470 error "The PSK must be longer than four characters"
471 return ${EXIT_ERROR}
472 fi
473
474 if [ ${length} -gt 128 ]; then
475 error "The PSK cannot be longer than 128 characters"
476 return ${EXIT_ERROR}
477 fi
917a1aa0 478
1bfc4f56 479 if ! ipsec_connection_write_config_key "${connection}" "PSK" "${psk}"; then
917a1aa0
JS
480 log ERROR "Could not write configuration settings"
481 return ${EXIT_ERROR}
482 fi
483
484 return ${EXIT_OK}
485}
486
3cde31b9
MT
487ipsec_connection_up() {
488 local connection="${1}"
489
490 if ! ipsec_connection_exists "${connection}"; then
491 error "No such VPN IPsec connection: ${connection}"
492 return ${EXIT_ERROR}
493 fi
494
495 cmd swanctl --initiate --child "${connection}"
496}
497
498ipsec_connection_down() {
499 local connection="${1}"
500
501 if ! ipsec_connection_exists "${connection}"; then
502 error "No such VPN IPsec connection: ${connection}"
503 return ${EXIT_ERROR}
504 fi
505
506 cmd swanctl --terminate --ike "${connection}"
507}
bb9fccaf
JS
508
509# Handle the cli after authentification
510ipsec_connection_dpd() {
511 if [ ! $# -gt 1 ]; then
512 log ERROR "Not enough arguments"
513 return ${EXIT_ERROR}
514 fi
515
516 local connection=${1}
517 local cmd=${2}
518 shift 2
519
520 case ${cmd} in
521 action)
522 ipsec_connection_dpd_action "${connection}" $@
523 ;;
524 delay)
525 ipsec_connection_dpd_delay "${connection}" $@
526 ;;
527 timeout)
528 ipsec_connection_dpd_timeout "${connection}" $@
529 ;;
530 *)
531 log ERROR "Unrecognized argument: ${cmd}"
532 return ${EXIT_ERROR}
533 ;;
534 esac
535}
536
537# Set the default dpd action
538ipsec_connection_dpd_action() {
539 if [ ! $# -eq 2 ]; then
540 log ERROR "Not enough arguments"
541 return ${EXIT_ERROR}
542 fi
543 local connection=${1}
544 local action=${2}
545
546 if ! isoneof action "restart" "clear"; then
547 log ERROR "dpd action '${action}' is invalid"
548 return ${EXIT_ERROR}
549 fi
550
551 if ! ipsec_connection_write_config_key "${connection}" "DPD_ACTION" ${action}; then
552 log ERROR "Could not write configuration settings"
553 return ${EXIT_ERROR}
554 fi
555}
556
557# Set the dpd delay
558ipsec_connection_dpd_delay() {
559 if [ ! $# -ge 2 ]; then
560 log ERROR "Not enough arguments"
561 return ${EXIT_ERROR}
562 fi
563
564 local connection=${1}
565 shift 1
566 local value=$@
567
568 if ! isinteger value; then
569 value=$(parse_time $@)
570 if [ ! $? -eq 0 ]; then
571 log ERROR "Parsing the passed time was not sucessful please check the passed values."
572 return ${EXIT_ERROR}
573 fi
574 fi
575
576 if [ ${value} -lt 0 ]; then
577 log ERROR "The passed time value must be in the sum greater or equal zero seconds."
578 return ${EXIT_ERROR}
579 fi
580
581 if ! ipsec_connection_write_config_key "${connection}" "DPD_DELAY" ${value}; then
582 log ERROR "Could not write configuration settings"
583 return ${EXIT_ERROR}
584 fi
585
586 return ${EXIT_OK}
587}
588
589# Set the dpd timeout
590ipsec_connection_dpd_timeout() {
591 if [ ! $# -ge 2 ]; then
592 log ERROR "Not enough arguments"
593 return ${EXIT_ERROR}
594 fi
595
596 local connection=${1}
597 shift 1
598 local value=$@
599
600 if ! isinteger value; then
601 value=$(parse_time $@)
602 if [ ! $? -eq 0 ]; then
603 log ERROR "Parsing the passed time was not sucessful please check the passed values."
604 return ${EXIT_ERROR}
605 fi
606 fi
607
608 if [ ${value} -le 0 ]; then
609 log ERROR "The passed time value must be in the sum greater or equal zero seconds."
610 return ${EXIT_ERROR}
611 fi
612
613 if ! ipsec_connection_write_config_key "${connection}" "DPD_TIMEOUT" ${value}; then
614 log ERROR "Could not write configuration settings"
615 return ${EXIT_ERROR}
616 fi
617
618 return ${EXIT_OK}
619}
620
917a1aa0
JS
621# Handle the cli after local
622ipsec_connection_local() {
623 if [ ! $# -ge 2 ]; then
624 log ERROR "Not enough arguments"
625 return ${EXIT_ERROR}
626 fi
627
628 local connection=${1}
629 local cmd=${2}
630 shift 2
631
632 case ${cmd} in
bb9fccaf
JS
633 address)
634 ipsec_connection_local_address "${connection}" $@
635 ;;
917a1aa0
JS
636 id)
637 ipsec_connection_id "${connection}" "LOCAL" $@
638 ;;
639 prefix)
640 ipsec_connection_prefix "${connection}" "LOCAL" $@
641 ;;
642 *)
643 log ERROR "Unrecognized argument: ${cmd}"
644 return ${EXIT_ERROR}
645 ;;
646 esac
647
648 return ${EXIT_OK}
649}
650
651# Set the connection mode
652ipsec_connection_mode() {
5bdbc2ee 653 if [ ! $# -eq 2 ]; then
917a1aa0
JS
654 log ERROR "Not enough arguments"
655 return ${EXIT_ERROR}
656 fi
657 local connection=${1}
658 local mode=${2}
659
660 if ! isoneof mode ${IPSEC_VALID_MODES}; then
661 log ERROR "Mode '${mode}' is invalid"
662 return ${EXIT_ERROR}
663 fi
664
665 if ! ipsec_connection_write_config_key "${connection}" "MODE" ${mode}; then
666 log ERROR "Could not write configuration settings"
667 return ${EXIT_ERROR}
668 fi
669
670 return ${EXIT_OK}
671}
672
bb9fccaf
JS
673# Set the local address
674ipsec_connection_local_address() {
675 if [ ! $# -eq 2 ]; then
676 log ERROR "Not enough arguments"
677 return ${EXIT_ERROR}
678 fi
679 local connection=${1}
680 local local_address=${2}
681
682 if ! ipsec_connection_check_peer ${local_address}; then
683 log ERROR "Local address '${local_address}' is invalid"
684 return ${EXIT_ERROR}
685 fi
686
687 if ! ipsec_connection_write_config_key "${connection}" "LOCAL_ADDRESS" ${local_address}; then
688 log ERROR "Could not write configuration settings"
689 return ${EXIT_ERROR}
690 fi
691
692 return ${EXIT_OK}
693}
694
917a1aa0
JS
695# Set the peer to connect to
696ipsec_connection_peer() {
0b962a64 697 if [ ! $# -eq 2 ]; then
917a1aa0
JS
698 log ERROR "Not enough arguments"
699 return ${EXIT_ERROR}
700 fi
701 local connection=${1}
702 local peer=${2}
703
704 if ! ipsec_connection_check_peer ${peer}; then
705 log ERROR "Peer '${peer}' is invalid"
706 return ${EXIT_ERROR}
707 fi
708
709 if ! ipsec_connection_write_config_key "${connection}" "PEER" ${peer}; then
710 log ERROR "Could not write configuration settings"
711 return ${EXIT_ERROR}
712 fi
713
714 return ${EXIT_OK}
715}
716
717#Set the local or remote id
718ipsec_connection_id() {
719 if [ ! $# -eq 3 ]; then
720 log ERROR "Not enough arguments"
721 return ${EXIT_ERROR}
722 fi
723 local connection=${1}
724 local type=${2}
725 local id=${3}
726
727 if ! ipsec_connection_check_id ${id}; then
728 log ERROR "Id '${id}' is invalid"
729 return ${EXIT_ERROR}
730 fi
731
732 if ! ipsec_connection_write_config_key "${connection}" "${type}_ID" ${id}; then
733 log ERROR "Could not write configuration settings"
734 return ${EXIT_ERROR}
735 fi
736
737 return ${EXIT_OK}
738}
739
740# Set the local or remote prefix
741ipsec_connection_prefix() {
742 if [ ! $# -ge 3 ]; then
743 log ERROR "Not enough arguments"
744 return ${EXIT_ERROR}
745 fi
746 local connection=${1}
747 local type=${2}
748 shift 2
749
750 local _prefix="${type}_PREFIX"
751 local "${_prefix}"
752 if ! ipsec_connection_read_config "${connection}" "${_prefix}"; then
753 return ${EXIT_ERROR}
754 fi
755
756 # Remove duplicated entries to proceed the list safely
757 assign "${_prefix}" "$(list_unique ${!_prefix} )"
758
759 local prefixes_added
760 local prefixes_removed
761 local prefixes_set
762
763 while [ $# -gt 0 ]; do
764 local arg="${1}"
765
766 case "${arg}" in
767 +*)
768 list_append prefixes_added "${arg:1}"
769 ;;
770 -*)
771 list_append prefixes_removed "${arg:1}"
772 ;;
773 [A-Fa-f0-9]*)
774 list_append prefixes_set "${arg}"
775 ;;
776 *)
777 error "Invalid argument: ${arg}"
778 return ${EXIT_ERROR}
779 ;;
780 esac
781 shift
782 done
783
784 # Check if the user is trying a mixed operation
785 if ! list_is_empty prefixes_set && (! list_is_empty prefixes_added || ! list_is_empty prefixes_removed); then
786 error "You cannot reset the prefix list and add or remove prefixes at the same time"
787 return ${EXIT_ERROR}
788 fi
789
790 # Set new prefix list
791 if ! list_is_empty prefixes_set; then
792 # Check if all prefixes are valid
793 local prefix
794 for prefix in ${prefixes_set}; do
795 if ! ip_net_is_valid ${prefix}; then
796 error "Unsupported prefix: ${prefix}"
797 return ${EXIT_ERROR}
798 fi
799 done
800
801 assign "${_prefix}" "${prefixes_set}"
802
803 # Perform incremental updates
804 else
805 local prefix
806
807 # Perform all removals
808 for prefix in ${prefixes_removed}; do
809 if ! list_remove "${_prefix}" ${prefix}; then
810 warning "${prefix} was not on the list and could not be removed"
811 fi
812 done
813
814
815 for prefix in ${prefixes_added}; do
816 if ip_net_is_valid ${prefix}; then
817 if ! list_append_unique "${_prefix}" ${prefix}; then
818 warning "${prefix} is already on the prefix list"
819 fi
820 else
f03f29b7 821 warning "${prefix} is not a valid IP network and could not be added"
917a1aa0
JS
822 fi
823 done
824 fi
825
826 # Check if the list contain at least one valid prefix
827 if list_is_empty ${_prefix}; then
828 error "Cannot save an empty prefix list"
829 return ${EXIT_ERROR}
830 fi
831
832 # Save everything
833 if ! ipsec_connection_write_config_key "${connection}" "${_prefix}" ${!_prefix}; then
834 log ERROR "Could not write configuration settings"
835 fi
836
837 return ${EXIT_OK}
838}
839
840# Handle the cli after remote
841ipsec_connection_remote() {
842 if [ ! $# -ge 2 ]; then
843 log ERROR "Not enough arguments"
844 return ${EXIT_ERROR}
845 fi
846
847 local connection=${1}
848 local cmd=${2}
849 shift 2
850
851 case ${cmd} in
852 id)
853 ipsec_connection_id "${connection}" "REMOTE" $@
854 ;;
855
856 prefix)
857 ipsec_connection_prefix "${connection}" "REMOTE" $@
858 ;;
859 *)
860 log ERROR "Unrecognized argument: ${cmd}"
861 return ${EXIT_ERROR}
862 ;;
863 esac
864
865 return ${EXIT_OK}
866}
867
868# Set the inactivity timeout
869ipsec_connection_inactivity_timeout() {
870 if [ ! $# -ge 2 ]; then
871 log ERROR "Not enough arguments"
872 return ${EXIT_ERROR}
873 fi
874
875 local connection=${1}
876 shift 1
877 local value=$@
878
879 if ! isinteger value; then
880 value=$(parse_time $@)
881 if [ ! $? -eq 0 ]; then
882 log ERROR "Parsing the passed time was not sucessful please check the passed values."
883 return ${EXIT_ERROR}
884 fi
885 fi
886
887 if [ ${value} -le 0 ]; then
888 log ERROR "The passed time value must be in the sum greater zero seconds."
889 return ${EXIT_ERROR}
890 fi
891
892 if ! ipsec_connection_write_config_key "${connection}" "INACTIVITY_TIMEOUT" ${value}; then
893 log ERROR "Could not write configuration settings"
894 return ${EXIT_ERROR}
895 fi
896
897 return ${EXIT_OK}
898}
899
bb9fccaf
JS
900# Set the default start action
901ipsec_connection_start_action() {
902 if [ ! $# -eq 2 ]; then
903 log ERROR "Not enough arguments"
904 return ${EXIT_ERROR}
905 fi
906 local connection=${1}
907 local action=${2}
908
909 if ! isoneof action "on-demand" "always-on"; then
910 log ERROR "Start action '${action}' is invalid"
911 return ${EXIT_ERROR}
912 fi
913
914 if ! ipsec_connection_write_config_key "${connection}" "START_ACTION" ${action}; then
915 log ERROR "Could not write configuration settings"
916 return ${EXIT_ERROR}
917 fi
918}
917a1aa0
JS
919
920# Set the security policy to use
921ipsec_connection_security_policy() {
922 if [ ! $# -eq 2 ]; then
923 log ERROR "Not enough arguments"
924 return ${EXIT_ERROR}
925 fi
926 local connection=${1}
927 local security_policy=${2}
928
929 if ! vpn_security_policy_exists ${security_policy}; then
930 log ERROR "No such vpn security policy '${security_policy}'"
931 return ${EXIT_ERROR}
932 fi
933
934 if ! ipsec_connection_write_config_key "${connection}" "SECURITY_POLICY" ${security_policy}; then
935 log ERROR "Could not write configuration settings"
936 return ${EXIT_ERROR}
937 fi
938}
939
940# Check if a id is valid
941ipsec_connection_check_id() {
942 assert [ $# -eq 1 ]
943 local id=${1}
944
945 if [[ ${id} =~ ^@[[:alnum:]]+$ ]] || ip_is_valid ${id}; then
946 return ${EXIT_TRUE}
947 else
948 return ${EXIT_FALSE}
949 fi
950}
951
952# Checks if a peer is valid
953ipsec_connection_check_peer() {
954 assert [ $# -eq 1 ]
955 local peer=${1}
956
957 # TODO Accept also FQDNs
958 if ip_is_valid ${peer}; then
959 return ${EXIT_TRUE}
960 else
961 return ${EXIT_FALSE}
962 fi
963}
964
965# This function checks if a VPN IPsec connection name is valid
966# Allowed are only A-Za-z0-9
967ipsec_connection_check_name() {
968 assert [ $# -eq 1 ]
969
970 local connection=${1}
971
972 [[ "${connection}" =~ [^[:alnum:]$] ]]
973}
974
975# Function that creates one VPN IPsec connection
976ipsec_connection_new() {
977 if [ $# -gt 1 ]; then
978 error "Too many arguments"
979 return ${EXIT_ERROR}
980 fi
981
982 local connection="${1}"
983 if ! isset connection; then
984 error "Please provide a connection name"
985 return ${EXIT_ERROR}
986 fi
987
988 # Check for duplicates
989 if ipsec_connection_exists "${connection}"; then
990 error "The VPN IPsec connection ${connection} already exists"
991 return ${EXIT_ERROR}
992 fi
993
994 # Check if the name of the connection is valid
995 if ipsec_connection_check_name "${connection}"; then
996 error "'${connection}' contains illegal characters"
997 return ${EXIT_ERROR}
998 fi
999
1000 log DEBUG "Creating VPN IPsec connection ${connection}"
1001
cf8685a1 1002 if ! mkdir -p "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
917a1aa0
JS
1003 log ERROR "Could not create config directory for ${connection}"
1004 return ${EXIT_ERROR}
1005 fi
1006
1007 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
1008
917a1aa0 1009 AUTH_MODE=${IPSEC_DEFAULT_AUTH_MODE}
bb9fccaf
JS
1010 DPD_ACTION=${IPSEC_DEFAULT_DPD_ACTION}
1011 DPD_DELAY=${IPSEC_DEFAULT_DPD_DELAY}
1012 DPD_TIMEOUT=${IPSEC_DEFAULT_DPD_TIMEOUT}
5601f4f5 1013 ENABLED=${IPSEC_DEFAULT_ENABLED}
bb9fccaf
JS
1014 MODE=${IPSEC_DEFAULT_MODE}
1015 START_ACTION=${IPSEC_DEFAULT_START_ACTION}
1016
917a1aa0
JS
1017 INACTIVITY_TIMEOUT=${IPSEC_DEFAULT_INACTIVITY_TIMEOUT}
1018 SECURITY_POLICY=${IPSEC_DEFAULT_SECURITY_POLICY}
1019
1020 if ! ipsec_connection_write_config "${connection}"; then
1021 log ERROR "Could not write new config file"
1022 return ${EXIT_ERROR}
1023 fi
c3f31173
MT
1024
1025 # Configure strongswan autostart
1026 ipsec_strongswan_autostart
917a1aa0
JS
1027}
1028
1029# Function that deletes based on the passed parameters one ore more vpn security policies
1030ipsec_connection_destroy() {
1031 local connection
1032 for connection in $@; do
1033 if ! ipsec_connection_exists "${connection}"; then
1034 log ERROR "The VPN IPsec connection ${connection} does not exist."
1035 continue
1036 fi
1037
1038 log DEBUG "Deleting VPN IPsec connection ${connection}"
fa33d830
MT
1039
1040 # Delete strongswan configuration file
1041 file_delete "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
1042
cf8685a1 1043 if ! rm -rf "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
917a1aa0
JS
1044 log ERROR "Deleting the VPN IPsec connection ${connection} was not sucessful"
1045 return ${EXIT_ERROR}
1046 fi
c3f31173 1047
fa33d830 1048 done
917a1aa0 1049}
d6c852b8
JS
1050
1051# List all ipsec connections
1052ipsec_list_connections() {
1053 local connection
1054 for connection in ${NETWORK_IPSEC_CONNS_DIR}/*; do
1055 [ -d ${connection} ] || continue
1056 basename ${connection}
1057 done
1058}
67baa452
MT
1059
1060ipsec_connection_to_strongswan() {
1061 local connection="${1}"
1062
1063 # Read the config settings
1064 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
1065 if ! ipsec_connection_read_config "${connection}"; then
1066 error "Could not read the connection ${connection}"
1067 return ${EXIT_ERROR}
1068 fi
1069
1070 local path="${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
1071
1072 (
1073 # Write the connection section
1074 _ipsec_connection_to_strongswan_connection "${connection}"
1075
1076 # Write the secrets section
1077 _ipsec_connection_to_strongswan_secrets "${connection}"
1078
1079 ) > ${path}
1080}
1081
1082_ipsec_connection_to_strongswan_connection() {
1083 local connection="${1}"
1084
1085 # Read the security policy
1086 local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
1087 if ! vpn_security_policies_read_config "${SECURITY_POLICY}"; then
1088 return ${EXIT_ERROR}
1089 fi
1090
4e271faa
MT
1091 # Is DPD enabled?
1092 local dpd="false"
1093 if isset DPD_DELAY && isinteger DPD_DELAY && [ ${DPD_DELAY} -gt 0 ]; then
1094 dpd="true"
1095 fi
1096
b21fb175
MT
1097 # Write configuration header
1098 config_header "strongSwan configuration for ${connection}"
1099
67baa452
MT
1100 print_indent 0 "connections {"
1101 print_indent 1 "${connection} {"
1102
1103 # IKE Version
1104 print_indent 2 "# IKE Version"
1105 case "${KEY_EXCHANGE^^}" in
1106 IKEV1)
1107 print_indent 2 "version = 1"
1108 ;;
1109
1110 # Fall back to IKEv2 for any random values
1111 IKEV2|*)
1112 print_indent 2 "version = 2"
1113 ;;
1114 esac
1115 print # empty line
1116
4609d6b4
MT
1117 # Always only keep one connection open at a time
1118 print_indent 2 "# Unique IDs"
1119 print_indent 2 "unique = replace"
1120 print
1121
3e8ad776
MT
1122 # Local Address
1123 print_indent 2 "# Local Address"
1124 if isset LOCAL_ADDRESS; then
1125 print_indent 2 "local_addrs = ${LOCAL_ADDRESS}"
1126 else
1127 print_indent 2 "local_addrs = %any"
1128 fi
1129 print
67baa452
MT
1130
1131 # Remote Address
1132 print_indent 2 "# Remote Address"
1133 if isset PEER; then
1134 print_indent 2 "remote_addrs = ${PEER}"
1135 else
1136 print_indent 2 "remote_addrs = %any"
1137 fi
1138 print
1139
1140 # IKE Proposals
1141 print_indent 2 "# IKE Proposals"
e3ffacf7 1142 print_indent 2 "proposals = $(vpn_security_policies_make_ike_proposal ${SECURITY_POLICY})"
67baa452
MT
1143 print
1144
117278c3 1145 # DPD Settings
4e271faa 1146 if enabled dpd; then
117278c3 1147 print_indent 2 "# Dead Peer Detection"
117278c3
MT
1148 print_indent 2 "dpd_delay = ${DPD_DELAY}"
1149
1150 if isset DPD_TIMEOUT; then
1151 print_indent 2 "dpd_timeout = ${DPD_TIMEOUT}"
1152 fi
1153
1154 print
1155 fi
67baa452
MT
1156
1157 # Fragmentation
1158 print_indent 2 "# Fragmentation"
1159 print_indent 2 "fragmentation = yes"
1160 print
1161
1162 # Local
1163 print_indent 2 "local {"
1164
1165 # Local ID
1166 if isset LOCAL_ID; then
1167 print_indent 3 "id = ${LOCAL_ID}"
1168 fi
1169
1170 # Authentication
1171 case "${AUTH_MODE}" in
1172 PSK)
1173 print_indent 3 "auth = psk"
1174 ;;
1175 esac
1176
1177 print_indent 2 "}"
1178 print
1179
1180 # Remote
1181 print_indent 2 "remote {"
1182
1183 # Remote ID
1184 if isset REMOTE_ID; then
1185 print_indent 3 "id = ${REMOTE_ID}"
1186 fi
1187
1188 # Authentication
1189 case "${AUTH_MODE}" in
1190 PSK)
1191 print_indent 3 "auth = psk"
1192 ;;
1193 esac
1194
1195 print_indent 2 "}"
1196 print
1197
1198 # Children
1199
1200 print_indent 2 "children {"
1201 print_indent 3 "${connection} {"
1202
1203 print_indent 4 "# ESP Proposals"
e3d8f3f6 1204 print_indent 4 "esp_proposals = $(vpn_security_policies_make_esp_proposal ${SECURITY_POLICY})"
67baa452
MT
1205 print
1206
1207 # Traffic Selectors
1208
95835d23
MT
1209 case "${MODE}" in
1210 gre-*)
1211 print_indent 4 "local_ts = dynamic[gre]"
1212 print_indent 4 "remote_ts = dynamic[gre]"
1213 ;;
1214 *)
1215 # Local Prefixes
1216 if isset LOCAL_PREFIX; then
1217 print_indent 4 "local_ts = $(list_join LOCAL_PREFIX ,)"
1218 else
1219 print_indent 4 "local_ts = dynamic"
1220 fi
67baa452 1221
95835d23
MT
1222 # Remote Prefixes
1223 if isset REMOTE_PREFIX; then
1224 print_indent 4 "remote_ts = $(list_join REMOTE_PREFIX ,)"
1225 else
1226 print_indent 4 "remote_ts = dynamic"
1227 fi
1228 ;;
1229 esac
67baa452
MT
1230 print
1231
82fac748
MT
1232 # Netfilter Marks
1233 print_indent 4 "# Netfilter Marks"
1234 print_indent 4 "mark_in = %unique"
1235 print_indent 4 "mark_out = %unique"
1236 print
1237
4e271faa
MT
1238 # Dead Peer Detection
1239 if enabled dpd; then
1240 print_indent 4 "# Dead Peer Detection"
1241 print_indent 4 "dpd_action = ${DPD_ACTION}"
1242 print
1243 fi
1244
67baa452
MT
1245 # Rekeying
1246 if isset LIFETIME; then
1247 print_indent 4 "# Rekey Time"
1248 print_indent 4 "rekey_time = ${LIFETIME}"
1249 print
1250 fi
1251
1252 # Updown Script
1253 print_indent 4 "updown = ${NETWORK_HELPERS_DIR}/ipsec-updown"
1254 print
1255
1256 # Mode
1257 print_indent 4 "# Mode"
1258 case "${MODE}" in
1259 gre-transport)
1260 print_indent 4 "mode = transport"
1261 ;;
1262 tunnel|vti|*)
1263 print_indent 4 "mode = tunnel"
1264 ;;
1265 esac
1266 print
1267
1268 # Compression
1269 print_indent 4 "# Compression"
1270 if enabled COMPRESSION; then
1271 print_indent 4 "ipcomp = yes"
1272 else
1273 print_indent 4 "ipcomp = no"
1274 fi
1275 print
1276
1277 # Inactivity Timeout
1278 if isset INACTIVITY_TIMEOUT; then
1279 print_indent 4 "# Inactivity Timeout"
1280 print_indent 4 "inactivity = ${INACTIVITY_TIMEOUT}"
1281 print
1282 fi
1283
37317b3e
MT
1284 # Start Action
1285 print_indent 4 "# Start Action"
1286 case "${START_ACTION}" in
1287 on-demand)
1288 print_indent 4 "start_action = trap"
1289 print_indent 4 "close_action = trap"
1290 ;;
1291 wait)
1292 print_indent 4 "start_action = none"
1293 print_indent 4 "close_action = none"
1294 ;;
1295 always-on|*)
1296 print_indent 4 "start_action = start"
1297 print_indent 4 "close_action = start"
1298 ;;
1299 esac
1300 print
67baa452
MT
1301
1302 print_indent 3 "}"
1303 print_indent 2 "}"
1304 print
1305
1306 print_indent 1 "}"
1307 print_indent 0 "}"
1308 print
1309}
1310
1311_ipsec_connection_to_strongswan_secrets() {
1312 local connection="${1}"
1313
1314 print_indent 0 "secrets {"
1315
1316 case "${AUTH_MODE}" in
1317 PSK)
1318 print_indent 1 "ike {"
1319
1320 # Secret
1321 print_indent 2 "secret = ${PSK}"
1322
1323 # ID
1324 if isset REMOTE_ID; then
1325 print_indent 2 "id = ${REMOTE_ID}"
1326 fi
1327
1328 print_indent 1 "}"
1329 ;;
1330 esac
1331
1332 print_indent 0 "}"
1333}