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