]> git.ipfire.org Git - network.git/blame - src/functions/functions.ipsec
ipsec: add new functions
[network.git] / src / functions / functions.ipsec
CommitLineData
917a1aa0
JS
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
22IPSEC_CONNECTION_CONFIG_SETTINGS="AUTH_MODE INACTIVITY_TIMEOUT LOCAL_ID LOCAL_PREFIX"
23IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} MODE PEER PSK"
24IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} REMOTE_ID REMOTE_PREFIX"
25IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} SECURITY_POLICY"
26
27# Default values
28IPSEC_DEFAULT_MODE="tunnel"
29IPSEC_DEFAULT_AUTH_MODE="psk"
30IPSEC_DEFAULT_INACTIVITY_TIMEOUT="0"
31IPSEC_DEFAULT_SECURITY_POLICY="system"
32
33IPSEC_VALID_MODES="gre-transport tunnel vti"
34IPSEC_VALID_AUTH_MODES="PSK psk"
35
36# This function writes all values to a via ${connection} specificated VPN IPsec configuration file
37ipsec_connection_write_config() {
38 assert [ $# -ge 1 ]
39
40 local connection="${1}"
41
42 if ! ipsec_connection_exists "${connection}"; then
43 log ERROR "No such VPN IPsec connection: ${connection}"
44 return ${EXIT_ERROR}
45 fi
46
47 local path="$(ipsec_connection_path "${connection}")/settings"
48
49 if ! settings_write "${path}" ${IPSEC_CONNECTION_CONFIG_SETTINGS}; then
50 log ERROR "Could not write configuration settings for VPN IPsec connection ${connection}"
51 return ${EXIT_ERROR}
52 fi
53
54 ipsec_reload ${connection}
55}
56
57# This funtion writes the value for one key to a via ${connection} specificated VPN IPsec connection configuration file
58ipsec_connection_write_config_key() {
59 assert [ $# -ge 3 ]
60
61 local connection=${1}
62 local key=${2}
63 shift 2
64
65 local value="$@"
66
67 if ! ipsec_connection_exists "${connection}"; then
68 log ERROR "No such VPN ipsec connection: ${connection}"
69 return ${EXIT_ERROR}
70 fi
71
72 log DEBUG "Set '${key}' to new value '${value}' in VPN ipsec connection '${connection}'"
73
74 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
75
76 # Read the config settings
77 if ! ipsec_connection_read_config "${connection}"; then
78 return ${EXIT_ERROR}
79 fi
80
81 # Set the key to a new value
82 assign "${key}" "${value}"
83
84 if ! ipsec_connection_write_config "${connection}"; then
85 return ${EXIT_ERROR}
86 fi
87
88 return ${EXIT_TRUE}
89}
90
91# Reads one or more keys out of a settings file or all if no key is provided.
92ipsec_connection_read_config() {
93 assert [ $# -ge 1 ]
94
95 local connection="${1}"
96 shift 1
97
98 if ! ipsec_connection_exists "${connection}"; then
99 log ERROR "No such VPN IPsec connection : ${connection}"
100 return ${EXIT_ERROR}
101 fi
102
103
104 local args
105 if [ $# -eq 0 ] && [ -n "${IPSEC_CONNECTION_CONFIG_SETTINGS}" ]; then
106 list_append args ${IPSEC_CONNECTION_CONFIG_SETTINGS}
107 else
108 list_append args $@
109 fi
110
111 local path="$(ipsec_connection_path "${connection}")/settings"
112
113 if ! settings_read "${path}" ${args}; then
114 log ERROR "Could not read settings for VPN IPsec connection ${connection}"
115 return ${EXIT_ERROR}
116 fi
117}
118
119# Returns the path to a the directory for given connection
120ipsec_connection_path() {
121 assert [ $# -eq 1 ]
122
123 local connection=${1}
124
125 echo "${NETWORK_CONFIG_DIR}/vpn/ipsec/connection/${connection}"
126}
127
128# This function checks if a vpn ipsec connection exists
129# Returns True when yes and false when not
130ipsec_connection_exists() {
131 assert [ $# -eq 1 ]
132
133 local connection=${1}
134
135 local path=$(ipsec_connection_path "${connection}")
136
137 [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
138}
139
140# Reloads the connection after config changes
141ipsec_reload() {
142 return ${EXIT_TRUE}
143}
144
145# Handle the cli after authentification
146ipsec_connection_authentication() {
147 if [ ! $# -gt 1 ]; then
148 log ERROR "Not enough arguments"
149 return ${EXIT_ERROR}
150 fi
151
152 local connection=${1}
153 local cmd=${2}
154 shift 2
155
156 case ${cmd} in
157 mode)
158 ipsec_connection_authentication_mode "${connection}" $@
159 ;;
160 pre-shared-key)
161 ipsec_connection_authentication_psk "${connection}" $@
162 ;;
163 *)
164 log ERROR "Unrecognized argument: ${cmd}"
165 return ${EXIT_ERROR}
166 ;;
167 esac
168}
169
170# Set the authentification mode
171ipsec_connection_authentication_mode() {
172 if [ ! $# -eq 2 ]; then
173 log ERROR "Not enough arguments"
174 return ${EXIT_ERROR}
175 fi
176 local connection=${1}
177 local mode=${2}
178
179 if ! isoneof mode ${IPSEC_VALID_AUTH_MODES}; then
180 log ERROR "Auth mode '${mode}' is invalid"
181 return ${EXIT_ERROR}
182 fi
183
184 if ! ipsec_connection_write_config_key "${connection}" "AUTH_MODE" ${mode,,}; then
185 log ERROR "Could not write configuration settings"
186 return ${EXIT_ERROR}
187 fi
188}
189
190# Set the psk
191ipsec_connection_authentication_psk() {
192 if [ ! $# -eq 2]; then
193 log ERROR "Not enough arguments"
194 return ${EXIT_ERROR}
195 fi
196 local connection=${1}
197 local psk=${2}
198
199 # TODO Check if psk is valid
200
201 if ! ipsec_connection_write_config_key "${connection}" "PSK" ${psk}; then
202 log ERROR "Could not write configuration settings"
203 return ${EXIT_ERROR}
204 fi
205
206 return ${EXIT_OK}
207}
208
209# Handle the cli after local
210ipsec_connection_local() {
211 if [ ! $# -ge 2 ]; then
212 log ERROR "Not enough arguments"
213 return ${EXIT_ERROR}
214 fi
215
216 local connection=${1}
217 local cmd=${2}
218 shift 2
219
220 case ${cmd} in
221 id)
222 ipsec_connection_id "${connection}" "LOCAL" $@
223 ;;
224 prefix)
225 ipsec_connection_prefix "${connection}" "LOCAL" $@
226 ;;
227 *)
228 log ERROR "Unrecognized argument: ${cmd}"
229 return ${EXIT_ERROR}
230 ;;
231 esac
232
233 return ${EXIT_OK}
234}
235
236# Set the connection mode
237ipsec_connection_mode() {
238 if [ ! $# -eq 2]; then
239 log ERROR "Not enough arguments"
240 return ${EXIT_ERROR}
241 fi
242 local connection=${1}
243 local mode=${2}
244
245 if ! isoneof mode ${IPSEC_VALID_MODES}; then
246 log ERROR "Mode '${mode}' is invalid"
247 return ${EXIT_ERROR}
248 fi
249
250 if ! ipsec_connection_write_config_key "${connection}" "MODE" ${mode}; then
251 log ERROR "Could not write configuration settings"
252 return ${EXIT_ERROR}
253 fi
254
255 return ${EXIT_OK}
256}
257
258# Set the peer to connect to
259ipsec_connection_peer() {
260 if [ ! $# -eq 2]; then
261 log ERROR "Not enough arguments"
262 return ${EXIT_ERROR}
263 fi
264 local connection=${1}
265 local peer=${2}
266
267 if ! ipsec_connection_check_peer ${peer}; then
268 log ERROR "Peer '${peer}' is invalid"
269 return ${EXIT_ERROR}
270 fi
271
272 if ! ipsec_connection_write_config_key "${connection}" "PEER" ${peer}; then
273 log ERROR "Could not write configuration settings"
274 return ${EXIT_ERROR}
275 fi
276
277 return ${EXIT_OK}
278}
279
280#Set the local or remote id
281ipsec_connection_id() {
282 if [ ! $# -eq 3 ]; then
283 log ERROR "Not enough arguments"
284 return ${EXIT_ERROR}
285 fi
286 local connection=${1}
287 local type=${2}
288 local id=${3}
289
290 if ! ipsec_connection_check_id ${id}; then
291 log ERROR "Id '${id}' is invalid"
292 return ${EXIT_ERROR}
293 fi
294
295 if ! ipsec_connection_write_config_key "${connection}" "${type}_ID" ${id}; then
296 log ERROR "Could not write configuration settings"
297 return ${EXIT_ERROR}
298 fi
299
300 return ${EXIT_OK}
301}
302
303# Set the local or remote prefix
304ipsec_connection_prefix() {
305 if [ ! $# -ge 3 ]; then
306 log ERROR "Not enough arguments"
307 return ${EXIT_ERROR}
308 fi
309 local connection=${1}
310 local type=${2}
311 shift 2
312
313 local _prefix="${type}_PREFIX"
314 local "${_prefix}"
315 if ! ipsec_connection_read_config "${connection}" "${_prefix}"; then
316 return ${EXIT_ERROR}
317 fi
318
319 # Remove duplicated entries to proceed the list safely
320 assign "${_prefix}" "$(list_unique ${!_prefix} )"
321
322 local prefixes_added
323 local prefixes_removed
324 local prefixes_set
325
326 while [ $# -gt 0 ]; do
327 local arg="${1}"
328
329 case "${arg}" in
330 +*)
331 list_append prefixes_added "${arg:1}"
332 ;;
333 -*)
334 list_append prefixes_removed "${arg:1}"
335 ;;
336 [A-Fa-f0-9]*)
337 list_append prefixes_set "${arg}"
338 ;;
339 *)
340 error "Invalid argument: ${arg}"
341 return ${EXIT_ERROR}
342 ;;
343 esac
344 shift
345 done
346
347 # Check if the user is trying a mixed operation
348 if ! list_is_empty prefixes_set && (! list_is_empty prefixes_added || ! list_is_empty prefixes_removed); then
349 error "You cannot reset the prefix list and add or remove prefixes at the same time"
350 return ${EXIT_ERROR}
351 fi
352
353 # Set new prefix list
354 if ! list_is_empty prefixes_set; then
355 # Check if all prefixes are valid
356 local prefix
357 for prefix in ${prefixes_set}; do
358 if ! ip_net_is_valid ${prefix}; then
359 error "Unsupported prefix: ${prefix}"
360 return ${EXIT_ERROR}
361 fi
362 done
363
364 assign "${_prefix}" "${prefixes_set}"
365
366 # Perform incremental updates
367 else
368 local prefix
369
370 # Perform all removals
371 for prefix in ${prefixes_removed}; do
372 if ! list_remove "${_prefix}" ${prefix}; then
373 warning "${prefix} was not on the list and could not be removed"
374 fi
375 done
376
377
378 for prefix in ${prefixes_added}; do
379 if ip_net_is_valid ${prefix}; then
380 if ! list_append_unique "${_prefix}" ${prefix}; then
381 warning "${prefix} is already on the prefix list"
382 fi
383 else
384 warning "${prefix} is not a valiv IP net and could not be added"
385 fi
386 done
387 fi
388
389 # Check if the list contain at least one valid prefix
390 if list_is_empty ${_prefix}; then
391 error "Cannot save an empty prefix list"
392 return ${EXIT_ERROR}
393 fi
394
395 # Save everything
396 if ! ipsec_connection_write_config_key "${connection}" "${_prefix}" ${!_prefix}; then
397 log ERROR "Could not write configuration settings"
398 fi
399
400 return ${EXIT_OK}
401}
402
403# Handle the cli after remote
404ipsec_connection_remote() {
405 if [ ! $# -ge 2 ]; then
406 log ERROR "Not enough arguments"
407 return ${EXIT_ERROR}
408 fi
409
410 local connection=${1}
411 local cmd=${2}
412 shift 2
413
414 case ${cmd} in
415 id)
416 ipsec_connection_id "${connection}" "REMOTE" $@
417 ;;
418
419 prefix)
420 ipsec_connection_prefix "${connection}" "REMOTE" $@
421 ;;
422 *)
423 log ERROR "Unrecognized argument: ${cmd}"
424 return ${EXIT_ERROR}
425 ;;
426 esac
427
428 return ${EXIT_OK}
429}
430
431# Set the inactivity timeout
432ipsec_connection_inactivity_timeout() {
433 if [ ! $# -ge 2 ]; then
434 log ERROR "Not enough arguments"
435 return ${EXIT_ERROR}
436 fi
437
438 local connection=${1}
439 shift 1
440 local value=$@
441
442 if ! isinteger value; then
443 value=$(parse_time $@)
444 if [ ! $? -eq 0 ]; then
445 log ERROR "Parsing the passed time was not sucessful please check the passed values."
446 return ${EXIT_ERROR}
447 fi
448 fi
449
450 if [ ${value} -le 0 ]; then
451 log ERROR "The passed time value must be in the sum greater zero seconds."
452 return ${EXIT_ERROR}
453 fi
454
455 if ! ipsec_connection_write_config_key "${connection}" "INACTIVITY_TIMEOUT" ${value}; then
456 log ERROR "Could not write configuration settings"
457 return ${EXIT_ERROR}
458 fi
459
460 return ${EXIT_OK}
461}
462
463
464# Set the security policy to use
465ipsec_connection_security_policy() {
466 if [ ! $# -eq 2 ]; then
467 log ERROR "Not enough arguments"
468 return ${EXIT_ERROR}
469 fi
470 local connection=${1}
471 local security_policy=${2}
472
473 if ! vpn_security_policy_exists ${security_policy}; then
474 log ERROR "No such vpn security policy '${security_policy}'"
475 return ${EXIT_ERROR}
476 fi
477
478 if ! ipsec_connection_write_config_key "${connection}" "SECURITY_POLICY" ${security_policy}; then
479 log ERROR "Could not write configuration settings"
480 return ${EXIT_ERROR}
481 fi
482}
483
484# Check if a id is valid
485ipsec_connection_check_id() {
486 assert [ $# -eq 1 ]
487 local id=${1}
488
489 if [[ ${id} =~ ^@[[:alnum:]]+$ ]] || ip_is_valid ${id}; then
490 return ${EXIT_TRUE}
491 else
492 return ${EXIT_FALSE}
493 fi
494}
495
496# Checks if a peer is valid
497ipsec_connection_check_peer() {
498 assert [ $# -eq 1 ]
499 local peer=${1}
500
501 # TODO Accept also FQDNs
502 if ip_is_valid ${peer}; then
503 return ${EXIT_TRUE}
504 else
505 return ${EXIT_FALSE}
506 fi
507}
508
509# This function checks if a VPN IPsec connection name is valid
510# Allowed are only A-Za-z0-9
511ipsec_connection_check_name() {
512 assert [ $# -eq 1 ]
513
514 local connection=${1}
515
516 [[ "${connection}" =~ [^[:alnum:]$] ]]
517}
518
519# Function that creates one VPN IPsec connection
520ipsec_connection_new() {
521 if [ $# -gt 1 ]; then
522 error "Too many arguments"
523 return ${EXIT_ERROR}
524 fi
525
526 local connection="${1}"
527 if ! isset connection; then
528 error "Please provide a connection name"
529 return ${EXIT_ERROR}
530 fi
531
532 # Check for duplicates
533 if ipsec_connection_exists "${connection}"; then
534 error "The VPN IPsec connection ${connection} already exists"
535 return ${EXIT_ERROR}
536 fi
537
538 # Check if the name of the connection is valid
539 if ipsec_connection_check_name "${connection}"; then
540 error "'${connection}' contains illegal characters"
541 return ${EXIT_ERROR}
542 fi
543
544 log DEBUG "Creating VPN IPsec connection ${connection}"
545
546 if ! mkdir -p $(ipsec_connection_path "${connection}"); then
547 log ERROR "Could not create config directory for ${connection}"
548 return ${EXIT_ERROR}
549 fi
550
551 local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
552
553 MODE=${IPSEC_DEFAULT_MODE}
554 AUTH_MODE=${IPSEC_DEFAULT_AUTH_MODE}
555 INACTIVITY_TIMEOUT=${IPSEC_DEFAULT_INACTIVITY_TIMEOUT}
556 SECURITY_POLICY=${IPSEC_DEFAULT_SECURITY_POLICY}
557
558 if ! ipsec_connection_write_config "${connection}"; then
559 log ERROR "Could not write new config file"
560 return ${EXIT_ERROR}
561 fi
562}
563
564# Function that deletes based on the passed parameters one ore more vpn security policies
565ipsec_connection_destroy() {
566 local connection
567 for connection in $@; do
568 if ! ipsec_connection_exists "${connection}"; then
569 log ERROR "The VPN IPsec connection ${connection} does not exist."
570 continue
571 fi
572
573 log DEBUG "Deleting VPN IPsec connection ${connection}"
574 if ! rm -rf $(ipsec_connection_path "${connection}"); then
575 log ERROR "Deleting the VPN IPsec connection ${connection} was not sucessful"
576 return ${EXIT_ERROR}
577 fi
578 done
579}