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