]> git.ipfire.org Git - people/jschlag/network.git/blob - src/functions/functions.ipsec
6c2a0df83e154ff4c255778b8b56e43324bb6ad2
[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 local connection
1199 for connection in ${NETWORK_IPSEC_CONNS_DIR}/*; do
1200 [ -d ${connection} ] || continue
1201 basename ${connection}
1202 done
1203 }
1204
1205 ipsec_connection_to_strongswan() {
1206 local connection="${1}"
1207 log DEBUG "Generating IPsec configuration for ${connection}"
1208
1209 # Read the config settings
1210 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
1211 if ! ipsec_connection_read_config "${connection}"; then
1212 error "Could not read the connection ${connection}"
1213 return ${EXIT_ERROR}
1214 fi
1215
1216 local path="${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
1217
1218 (
1219 # Write the connection section
1220 _ipsec_connection_to_strongswan_connection "${connection}"
1221
1222 # Write the secrets section
1223 _ipsec_connection_to_strongswan_secrets "${connection}"
1224
1225 ) > ${path}
1226 }
1227
1228 _ipsec_connection_to_strongswan_connection() {
1229 local connection="${1}"
1230
1231 # Read the security policy
1232 local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
1233 if ! vpn_security_policies_read_config "${SECURITY_POLICY}"; then
1234 return ${EXIT_ERROR}
1235 fi
1236
1237 # Is DPD enabled?
1238 local dpd="false"
1239 if isset DPD_DELAY && isinteger DPD_DELAY && [ ${DPD_DELAY} -gt 0 ]; then
1240 dpd="true"
1241 fi
1242
1243 # Write configuration header
1244 config_header "strongSwan configuration for ${connection}"
1245
1246 print_indent 0 "connections {"
1247 print_indent 1 "${connection} {"
1248
1249 # IKE Version
1250 print_indent 2 "# IKE Version"
1251 case "${KEY_EXCHANGE^^}" in
1252 IKEV1)
1253 print_indent 2 "version = 1"
1254 ;;
1255
1256 # Fall back to IKEv2 for any random values
1257 IKEV2|*)
1258 print_indent 2 "version = 2"
1259 ;;
1260 esac
1261 print # empty line
1262
1263 # Always only keep one connection open at a time
1264 print_indent 2 "# Unique IDs"
1265 print_indent 2 "unique = replace"
1266 print
1267
1268 # Local Address
1269 print_indent 2 "# Local Address"
1270 if isset LOCAL_ADDRESS; then
1271 print_indent 2 "local_addrs = ${LOCAL_ADDRESS}"
1272 else
1273 print_indent 2 "local_addrs = %any"
1274 fi
1275 print
1276
1277 # Remote Address
1278 print_indent 2 "# Remote Address"
1279 if isset PEER; then
1280 print_indent 2 "remote_addrs = ${PEER}"
1281 else
1282 print_indent 2 "remote_addrs = %any"
1283 fi
1284 print
1285
1286 # IKE Proposals
1287 print_indent 2 "# IKE Proposals"
1288 print_indent 2 "proposals = $(vpn_security_policies_make_ike_proposal ${SECURITY_POLICY})"
1289 print
1290
1291 # DPD Settings
1292 if enabled dpd; then
1293 print_indent 2 "# Dead Peer Detection"
1294 print_indent 2 "dpd_delay = ${DPD_DELAY}"
1295
1296 if isset DPD_TIMEOUT; then
1297 print_indent 2 "dpd_timeout = ${DPD_TIMEOUT}"
1298 fi
1299
1300 print
1301 fi
1302
1303 # Fragmentation
1304 print_indent 2 "# Fragmentation"
1305 print_indent 2 "fragmentation = yes"
1306 print
1307
1308
1309 # Host-to-Net specific settings
1310 case "${TYPE}" in
1311 host-to-net)
1312 # Pools
1313 if isset POOLS; then
1314 print_indent 2 "# Pools"
1315 print_indent 2 "pools = $(list_join POOLS ", ")"
1316 print
1317 fi
1318 ;;
1319 esac
1320
1321 # Local
1322 print_indent 2 "local {"
1323
1324 # Local ID
1325 if isset LOCAL_ID; then
1326 print_indent 3 "id = ${LOCAL_ID}"
1327 fi
1328
1329 # Authentication
1330 case "${AUTH_MODE}" in
1331 PSK)
1332 print_indent 3 "auth = psk"
1333 ;;
1334 esac
1335
1336 print_indent 2 "}"
1337 print
1338
1339 # Remote
1340 print_indent 2 "remote {"
1341
1342 # Remote ID
1343 if isset REMOTE_ID; then
1344 print_indent 3 "id = ${REMOTE_ID}"
1345 fi
1346
1347 # Authentication
1348 case "${AUTH_MODE}" in
1349 PSK)
1350 print_indent 3 "auth = psk"
1351 ;;
1352 esac
1353
1354 print_indent 2 "}"
1355 print
1356
1357 # Children
1358
1359 print_indent 2 "children {"
1360 print_indent 3 "${connection} {"
1361
1362 print_indent 4 "# ESP Proposals"
1363 print_indent 4 "esp_proposals = $(vpn_security_policies_make_esp_proposal ${SECURITY_POLICY})"
1364 print
1365
1366 # Traffic Selectors
1367
1368 case "${MODE}" in
1369 gre-*)
1370 print_indent 4 "local_ts = dynamic[gre]"
1371 print_indent 4 "remote_ts = dynamic[gre]"
1372 ;;
1373 *)
1374 # Local Prefixes
1375 if isset LOCAL_PREFIX; then
1376 print_indent 4 "local_ts = $(list_join LOCAL_PREFIX ,)"
1377 else
1378 print_indent 4 "local_ts = dynamic"
1379 fi
1380
1381 # Remote Prefixes
1382 if isset REMOTE_PREFIX; then
1383 print_indent 4 "remote_ts = $(list_join REMOTE_PREFIX ,)"
1384 else
1385 print_indent 4 "remote_ts = dynamic"
1386 fi
1387 ;;
1388 esac
1389 print
1390
1391 # Netfilter Marks
1392 case "${MODE}" in
1393 vti)
1394 print_indent 4 "# Netfilter Marks"
1395 print_indent 4 "mark_in = %unique"
1396 print_indent 4 "mark_out = %unique"
1397 print
1398 ;;
1399 esac
1400
1401 # Dead Peer Detection
1402 if enabled dpd; then
1403 print_indent 4 "# Dead Peer Detection"
1404 print_indent 4 "dpd_action = ${DPD_ACTION}"
1405 print
1406 fi
1407
1408 # Rekeying
1409 if isset LIFETIME; then
1410 print_indent 4 "# Rekey Time"
1411 print_indent 4 "rekey_time = ${LIFETIME}"
1412 print
1413 fi
1414
1415 # Updown Script
1416 print_indent 4 "updown = ${NETWORK_HELPERS_DIR}/ipsec-updown"
1417 print
1418
1419 # Mode
1420 print_indent 4 "# Mode"
1421 case "${MODE}" in
1422 gre-transport)
1423 print_indent 4 "mode = transport"
1424 ;;
1425 tunnel|vti|*)
1426 print_indent 4 "mode = tunnel"
1427 ;;
1428 esac
1429 print
1430
1431 # Compression
1432 print_indent 4 "# Compression"
1433 if enabled COMPRESSION; then
1434 print_indent 4 "ipcomp = yes"
1435 else
1436 print_indent 4 "ipcomp = no"
1437 fi
1438 print
1439
1440 # Inactivity Timeout
1441 if isset INACTIVITY_TIMEOUT; then
1442 print_indent 4 "# Inactivity Timeout"
1443 print_indent 4 "inactivity = ${INACTIVITY_TIMEOUT}"
1444 print
1445 fi
1446
1447 # Net-to-Net specific settings
1448 case "${TYPE}" in
1449 net-to-net)
1450 # Start Action
1451 print_indent 4 "# Start Action"
1452 case "${START_ACTION}" in
1453 on-demand)
1454 print_indent 4 "start_action = trap"
1455 print_indent 4 "close_action = trap"
1456 ;;
1457 wait)
1458 print_indent 4 "start_action = none"
1459 print_indent 4 "close_action = none"
1460 ;;
1461 always-on|*)
1462 print_indent 4 "start_action = start"
1463 print_indent 4 "close_action = start"
1464 ;;
1465 esac
1466 print
1467 ;;
1468 esac
1469
1470 print_indent 3 "}"
1471 print_indent 2 "}"
1472 print
1473
1474 print_indent 1 "}"
1475 print_indent 0 "}"
1476 print
1477 }
1478
1479 _ipsec_connection_to_strongswan_secrets() {
1480 local connection="${1}"
1481
1482 print_indent 0 "secrets {"
1483
1484 case "${AUTH_MODE}" in
1485 PSK)
1486 print_indent 1 "ike {"
1487
1488 # Secret
1489 print_indent 2 "secret = ${PSK}"
1490
1491 # ID
1492 if isset REMOTE_ID; then
1493 print_indent 2 "id = ${REMOTE_ID}"
1494 fi
1495
1496 print_indent 1 "}"
1497 ;;
1498 esac
1499
1500 print_indent 0 "}"
1501 }