File: IPsrcaddr

package info (click to toggle)
resource-agents 1%3A4.0.0~rc1-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 3,644 kB
  • ctags: 2,191
  • sloc: sh: 47,713; ansic: 4,074; perl: 3,457; makefile: 663; xml: 89
file content (503 lines) | stat: -rwxr-xr-x 12,827 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
#!/bin/sh
#
#	Description:	IPsrcaddr - Preferred source address modification
#
#	Author:			John Sutton <john@scl.co.uk>
#	Support:		users@clusterlabs.org
#	License:		GNU General Public License (GPL)
#	Copyright:		SCL Internet
#
#	Based on the IPaddr script.
#
#	This script manages the preferred source address associated with
#	packets which originate on the localhost and are routed through the
#	default route.  By default, i.e. without the use of this script or
#	similar, these packets will carry the IP of the primary i.e. the
#	non-aliased interface.  This can be a nuisance if you need to ensure
#	that such packets carry the same IP irrespective of which host in
#	a redundant cluster they actually originate from.
#
#	It can add a preferred source address, or remove one.
#
#	usage: IPsrcaddr {start|stop|status|monitor|validate-all|meta-data}
#
#	The "start" arg adds a preferred source address.
#
#	Surprisingly, the "stop" arg removes it.	:-)
#
#	NOTES:
#
#	1) There must be one and not more than 1 default route!  Mainly because
#	I can't see why you should have more than one.  And if there is more
#	than one, we would have to box clever to find out which one is to be
#	modified, or we would have to pass its identity as an argument.
#
#	2) The script depends on Alexey Kuznetsov's ip utility from the
#	iproute aka iproute2 package.
#
#	3) No checking is done to see if the passed in IP address can
#	reasonably be associated with the interface on which the default
#	route exists.  So unless you want to deliberately spoof your source IP,
#	check it!  Normally, I would expect that your haresources looks
#	something like:
#
#		nodename ip1 ip2 ... ipN IPsrcaddr::ipX
#
#	where ipX is one of the ip1 to ipN.
#
#	  OCF parameters are as below:
#		OCF_RESKEY_ipaddress

#######################################################################
# Initialization:

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs

#######################################################################

USAGE="usage: $0 {start|stop|status|monitor|validate-all|meta-data}";

  CMDSHOW="$IP2UTIL route show   to exact 0.0.0.0/0"
CMDCHANGE="$IP2UTIL route change to "

SYSTYPE="`uname -s`"

usage() {
	echo $USAGE >&2
}

meta_data() {
	cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="IPsrcaddr">
<version>1.0</version>

<longdesc lang="en">
Resource script for IPsrcaddr. It manages the preferred source address
modification. 
</longdesc>
<shortdesc lang="en">Manages the preferred source address for outgoing IP packets</shortdesc>

<parameters>
<parameter name="ipaddress" unique="0" required="1">
<longdesc lang="en">
The IP address. 
</longdesc>
<shortdesc lang="en">IP address</shortdesc>
<content type="string" default="" />
</parameter>

<parameter name="cidr_netmask">
<longdesc lang="en">
The netmask for the interface in CIDR format. (ie, 24), or in
dotted quad notation  255.255.255.0).
</longdesc>
<shortdesc lang="en">Netmask</shortdesc>
<content type="string" default=""/>
</parameter>
</parameters>

<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="monitor" depth="0" timeout="20s" interval="10" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
</actions>
</resource-agent>
END
}

errorexit() {
	ocf_exit_reason "$*"
	exit $OCF_ERR_GENERIC
}

#
#	We can distinguish 3 cases: no preferred source address, a
#	preferred source address exists which matches that specified, and one
#	exists but doesn't match that specified.  srca_read() returns 1,0,2
#	respectively.
#
#	The output of route show is something along the lines of:
#
#		default via X.X.X.X dev eth1 src Y.Y.Y.Y
#
#	where the src clause "src Y.Y.Y.Y" may or may not be present

WS="[`echo -en ' \t'`]"
OCTET="[0-9]\{1,3\}"
IPADDR="\($OCTET\.\)\{3\}$OCTET"
SRCCLAUSE="src$WS$WS*\($IPADDR\)"
MATCHROUTE="\(.*${WS}\)\($SRCCLAUSE\)\($WS.*\|$\)"
FINDIF=$HA_BIN/findif

# findif needs that to be set
export OCF_RESKEY_ip=$OCF_RESKEY_ipaddress

srca_read() {
	# Capture the default route - doublequotes prevent word splitting...
	DEFROUTE="`$CMDSHOW`" || errorexit "command '$CMDSHOW' failed"

	# ... so we can make sure there is only 1 default route
	[ 1 -eq `echo "$DEFROUTE" | wc -l` ] || \
		errorexit "more than 1 default route exists"

	# But there might still be no default route
	[ -z "$DEFROUTE" ] && errorexit "no default route exists"

	# Sed out the source ip address if it exists
	SRCIP=`echo $DEFROUTE | sed -n "s/$MATCHROUTE/\3/p"`

	# and what remains after stripping out the source ip address clause
	ROUTE_WO_SRC=`echo $DEFROUTE | sed "s/$MATCHROUTE/\1\5/"`

	[ -z "$SRCIP" ] && return 1
	[ $SRCIP = $1 ] && return 0
	return 2
}

#
#	Add (or change if it already exists) the preferred source address
#	The exit code should conform to LSB exit codes.
#

srca_start() {
	srca_read $1

	rc=$?
	if [ $rc = 0 ]; then 
		rc=$OCF_SUCCESS
		ocf_log info "The ip route has been already set.($NETWORK, $INTERFACE, $ROUTE_WO_SRC)"
	else
		ip route replace $NETWORK dev $INTERFACE src $1 || \
			errorexit "command 'ip route replace $NETWORK dev $INTERFACE src $1' failed"

		$CMDCHANGE $ROUTE_WO_SRC src $1 || \
			errorexit "command '$CMDCHANGE $ROUTE_WO_SRC src $1' failed"
		rc=$?
	fi

	return $rc
}

#
#	Remove (if it exists) the preferred source address.
#	If one exists but it's not the same as the one specified, that's
#	an error.  Maybe that's the wrong behaviour because if this fails
#	then when IPaddr releases the associated interface (if there is one)
#	your default route will also get dropped ;-(
#	The exit code should conform to LSB exit codes.
#

srca_stop() {
	srca_read $1
	rc=$?

	if [ $rc = 1 ]; then
	# We do not have a preferred source address for now
	  ocf_log info "No preferred source address defined, nothing to stop"
	  exit $OCF_SUCCESS
	fi
	  
	[ $rc = 2 ] && errorexit "The address you specified to stop does not match the preferred source address"

	ip route replace $NETWORK dev $INTERFACE || \
		errorexit "command 'ip route replace $NETWORK dev $INTERFACE' failed"

	$CMDCHANGE $ROUTE_WO_SRC || \
		errorexit "command '$CMDCHANGE $ROUTE_WO_SRC' failed"

	return $?
}

srca_status() {
	srca_read $1

	case $? in
		0)	echo "OK"
			return $OCF_SUCCESS;;

		1)	echo "No preferred source address defined"
			return $OCF_NOT_RUNNING;;

		2)	echo "Preferred source address has incorrect value"
			return $OCF_ERR_GENERIC;;
	esac
}

# A not reliable IP address checking function, which only picks up those _obvious_ violations...
#
# It accepts IPv4 address in dotted quad notation, for example "192.168.1.1"
#
# 100% confidence whenever it reports "negative", 
# but may get false "positive" answer. 
# 
CheckIP() {
  ip="$1"
  case $ip in
    *[!0-9.]*) #got invalid char
	false;;
    .*|*.) #begin or end by ".", which is invalid
	false;;
    *..*) #consecutive ".", which is invalid
	false;;
    *.*.*.*.*) #four decimal dots, which is too many
	false;;
    *.*.*.*) #exactly three decimal dots, candidate, evaluate each field
	local IFS=.
	set -- $ip
	if
	    ( [ $1 -le 254 ] && [ $2 -le 254 ] && [ $3 -le 254 ] && [ $4 -le 254 ] )
	then
	    if [ $1 -eq 127 ]; then
		ocf_exit_reason "IP address [$ip] is a loopback address, thus can not be preferred source address"
		exit $OCF_ERR_CONFIGURED
	    fi
	else
	    true
	fi	   
	;;
    *) #less than three decimal dots
	false;;
  esac
  return $? # This return is unnecessary, this comment too :)
}

#
#       Find out which interface or alias serves the given IP address
#       The argument is an IP address, and its output
#       is an (aliased) interface name (e.g., "eth0" and "eth0:0").
#
find_interface_solaris() {


  $IFCONFIG $IFCONFIG_A_OPT | $AWK '{if ($0 ~ /.*: / && NR > 1) {print "\n"$0} else {print}}' |
  while read ifname linkstuff
  do
    : ifname = $ifname
    read inet addr junk
    : inet = $inet addr = $addr
    while
      read line && [ "X$line" != "X" ]
    do
      : Nothing
    done

    #  This doesn't look right for a box with multiple NICs.
    #  It looks like it always selects the first interface on
    #  a machine.  Yet, we appear to use the results for this case too...
    ifname=`echo "$ifname" | sed s'%:*$%%'`

    case $addr in
      addr:$BASEIP)	echo $ifname; return $OCF_SUCCESS;;
      $BASEIP)	echo $ifname; return $OCF_SUCCESS;;
    esac
  done
  return $OCF_ERR_GENERIC
}


#
#       Find out which interface or alias serves the given IP address
#       The argument is an IP address, and its output
#       is an (aliased) interface name (e.g., "eth0" and "eth0:0").
#
find_interface_generic() {

	local iface=`$IP2UTIL -o -f inet addr show | grep "\ $BASEIP" \
            | cut -d ' ' -f2 | grep -v '^ipsec[0-9][0-9]*$'`
        if [ -z "$iface" ]; then
            return $OCF_ERR_GENERIC
        else 
            echo $iface
            return $OCF_SUCCESS
        fi
}


#
#       Find out which interface or alias serves the given IP address
#       The argument is an IP address, and its output
#       is an (aliased) interface name (e.g., "eth0" and "eth0:0").
#
find_interface() {
    case "$SYSTYPE" in
	SunOS)
	 	IF=`find_interface_solaris $BASEIP`
        ;;
      *)
	 	IF=`find_interface_generic $BASEIP`
       ;;
       esac

  echo $IF
  return $OCF_SUCCESS;
}


ip_status() {

  BASEIP="$1"
  case "$SYSTYPE" in
    Darwin)
	# Treat Darwin the same as the other BSD variants (matched as *BSD)
	SYSTYPE="${SYSTYPE}BSD"
	;;
    *)
        ;;
  esac


  case "$SYSTYPE" in
      *BSD)
	  $IFCONFIG $IFCONFIG_A_OPT | grep "inet.*[: ]$BASEIP " >/dev/null 2>&1
	  if [ $? = 0 ]; then
	      return $OCF_SUCCESS
	  else
	      return $OCF_NOT_RUNNING
	  fi;;
      
      Linux|SunOS)		
	  IF=`find_interface "$BASEIP"`
	  if [ -z "$IF" ]; then
	      return $OCF_NOT_RUNNING
	  fi

	  case $IF in
	  	lo*)  
		    ocf_exit_reason "IP address [$BASEIP] is served by loopback, thus can not be preferred source address"
		    exit $OCF_ERR_CONFIGURED
		    ;;
		*)return $OCF_SUCCESS;;
	  esac
	  ;;
	  
      *)		
	  if [ -z "$IF" ]; then
	      return $OCF_NOT_RUNNING
	  else
	      return $OCF_SUCCESS
	  fi;;
  esac
}


srca_validate_all() {

	if [ -z "$OCF_RESKEY_ipaddress" ]; then
		#  usage
		ocf_exit_reason "Please set OCF_RESKEY_ipaddress to the preferred source IP address!"
		return $OCF_ERR_CONFIGURED
	fi


	if ! [ "x$SYSTYPE" = "xLinux" ]; then
		# checks after this point are only relevant for linux.
		return $OCF_SUCCESS
	fi

	check_binary $AWK
	check_binary $IFCONFIG

#	The IP address should be in good shape
	if CheckIP "$ipaddress"; then
	  : 
	else
	  ocf_exit_reason "Invalid IP address [$ipaddress]"
	  return $OCF_ERR_CONFIGURED
	fi

	if ocf_is_probe; then
	  return $OCF_SUCCESS
	fi

#	We should serve this IP address of course
	if ip_status "$ipaddress"; then
	  :
	else
	  ocf_exit_reason "We are not serving [$ipaddress], hence can not make it a preferred source address"
	  return $OCF_ERR_INSTALLED
	fi
	return $OCF_SUCCESS
}

if
  ( [ $# -ne 1 ] )
then
  usage
  exit $OCF_ERR_ARGS
fi

# These operations do not require the OCF instance parameters to be set
case $1 in
	meta-data)	meta_data 
			exit $OCF_SUCCESS
			;;
	usage)		usage
			exit $OCF_SUCCESS
			;;
	*)	
			;;
esac

ipaddress="$OCF_RESKEY_ipaddress"

srca_validate_all
rc=$?
if [ $rc -ne $OCF_SUCCESS ]; then
	case $1 in
		# if we can't validate the configuration during a stop, that
		# means the resources isn't configured correctly. There's no way
		# to actually stop the resource in this situation because there's
		# no way it could have even started. Return success here
		# to indicate that the resource is not running, otherwise the
		# stop action will fail causing the node to be fenced just because
		# of a mis configuration.
		stop) exit $OCF_SUCCESS;;
		*)    exit $rc;;
	esac
fi

findif_out=`$FINDIF -C`
rc=$?
[ $rc -ne 0 ] && {
    ocf_exit_reason "[$FINDIF -C] failed"
    exit $rc
}

INTERFACE=`echo $findif_out | awk '{print $1}'`
NETWORK=`ip route list dev $INTERFACE scope link match $ipaddress|grep -o '^[^ ]*'`

case $1 in
	start)		srca_start $ipaddress
			;;
	stop)		srca_stop $ipaddress
			;;
	status)		srca_status $ipaddress
			;;
	monitor)	srca_status $ipaddress
			;;
	validate-all)	srca_validate_all
			;;
	*)		usage
			exit $OCF_ERR_UNIMPLEMENTED
			;;
esac

exit $?

#
# Version 0.3  2002/11/04 17:00:00 John Sutton <john@scl.co.uk>
# Name changed from IPsrcroute to IPsrcaddr and now reports errors
# using ha_log rather than on stderr.
#
# Version 0.2  2002/11/02 17:00:00 John Sutton <john@scl.co.uk>
# Changed status output to "OK" to satisfy ResourceManager's
# we_own_resource() function.
#
# Version 0.1  2002/11/01 17:00:00 John Sutton <john@scl.co.uk>
# First effort but does the job?
#