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