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