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