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