summaryrefslogtreecommitdiff
blob: 05ef95a37513d74b211e41e941d42a157acb1f03 (plain)
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
#!/bin/bash
# Copyright (c) 2004-2005 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# Contributed by Roy Marples (uberlord@gentoo.org)

# Fix any potential localisation problems
# Note that LC_ALL trumps LC_anything_else according to locale(7)
ifconfig() {
	LC_ALL=C /sbin/ifconfig "$@"
}

ifconfig_tunnel() {
	LC_ALL=C /sbin/iptunnel "$@"
}

route() {
	LC_ALL=C /sbin/route "$@"
}

# void ifconfig_depend(void)
#
# Sets up the dependancies for the module
ifconfig_depend() {
	provide interface
	variables config routes fallback metric ifconfig \
		ifconfig_fallback routes inet6 iface alias broadcast netmask
}

# bool ifconfig_check_installed(void)
#
# Returns 1 if ifconfig is installed, otherwise 0
ifconfig_check_installed() {
	[[ -x /sbin/ifconfig ]] && return 0
	${1:-false} && eerror "For ifconfig support, emerge sys-apps/net-tools"
	return 1
}

# bool ifconfig_exists(char *interface, bool report)
#
# Returns 1 if the interface exists, otherwise 0
ifconfig_exists() {
	local e=$( ifconfig -a | grep -o "^$1" ) report="${2:-false}"
	[[ -n ${e} ]] && return 0

	if ${report} ; then
		eerror "network interface $1 does not exist"
		eerror "Please verify hardware or kernel module (driver)"
	fi

	return 1
}

# void ifconfig_up(char *iface)
#
# provides a generic interface for bringing interfaces up
ifconfig_up() {
	ifconfig "$1" up
}

# void ifconfig_down(char *iface)
#
# provides a generic interface for bringing interfaces down
ifconfig_down() {
	ifconfig "$1" down
}

# bool ifconfig_is_up(char *iface, bool withaddress)
#
# Returns 0 if the interface is up, otherwise 1
# If withaddress is true then the interface has to have an IPv4 address
# assigned as well
ifconfig_is_up() {
	local check="\<UP\>" addr="${2:-false}"
	${addr} && check="\<inet addr:.*${check}"
	ifconfig "$1" | grep -Eq "${check}" && return 0
	return 1
}

# void ifconfig_set_flag(char *iface, char *flag, bool enabled)
#
# Sets or disables the interface flag 
ifconfig_set_flag() {
	local iface="$1" flag="$2" enable="$3"
	${enable} || flag="-${flag}"
	ifconfig "${iface}" "${flag}"
}

# void ifconfig_get_address(char *interface)
#
# Fetch the address retrieved by DHCP.  If successful, echoes the
# address on stdout, otherwise echoes nothing.
ifconfig_get_address() {
	local -a x=( $( ifconfig "$1" \
	| sed -n -e 's/.*inet addr:\([^ ]*\).*Mask:\([^ ]*\).*/\1 \2/p' ) )
	x[1]=$( netmask2cidr "${x[1]}" )
	[[ -n ${x[0]} ]] && echo "${x[0]}/${x[1]}"
}

# void ifconfig_get_mac_address(char *interface)
#
# Fetch the mac address assingned to the network card
ifconfig_get_mac_address() {
	local mac=$( ifconfig "$1" | sed -n -e \
		's/.*HWaddr[ \t]*\<\(..:..:..:..:..:..\)\>.*/\U\1/p' )
	[[ ${mac} != '00:00:00:00:00:00' \
	&& ${mac} != '44:44:44:44:44:44' \
	&& ${mac} != 'FF:FF:FF:FF:FF:FF' ]] \
		&& echo "${mac}"
}

# void ifconfig_set_mac_address(char *interface, char *mac)
#
# Assigned the mac address to the network card
ifconfig_set_mac_address() {
	ifconfig "$1" hw ether "$2"
}

# int ifconfig_set_name(char *interface, char *new_name)
#
# Renames the interface
# This will not work if the interface is setup!
ifconfig_set_name() {
	[[ -z $2 ]] && return 1
	local current="$1" new="$2"

	local mac=$( ifconfig_get_mac_address "${current}" )
	if [[ -z ${mac} ]]; then
		eerror "${iface} does not have a MAC address"
		return 1
	fi

	/sbin/nameif "${new}" "${mac}"
}

# void ifconfig_get_aliases_rev(char *interface)
#
# Fetch the list of aliases for an interface.  
# Outputs a space-separated list on stdout, in reverse order, for
# example "eth0:2 eth0:1"
ifconfig_get_aliases_rev() {
	ifconfig | grep -o "^$1:[0-9]* " | tac
}

# bool ifconfig_del_addresses(char *interface, bool onlyinet)
#
# Remove addresses from interface.  Returns 0 (true) if there
# were addresses to remove (whether successful or not).  Returns 1
# (false) if there were no addresses to remove.
# If onlyinet is true then we only delete IPv4 / inet addresses
ifconfig_del_addresses() {
	local iface="$1" i onlyinet="${2:-false}"
	# We don't remove addresses from aliases
	[[ ${iface} == *:* ]] && return 0

	# If the interface doesn't exist, don't try and delete
	ifconfig_exists "${iface}" || return 0

	# iproute2 can add many addresses to an iface unlike ifconfig ...
	# iproute2 added addresses cause problems for ifconfig
	# as we delete an address, a new one appears, so we have to
	# keep polling
	while ifconfig "${iface}" | grep -q -m1 -o 'inet addr:[^ ]*' ; do
		ifconfig "${iface}" 0.0.0.0 || break
	done

	# Remove IPv6 addresses
	if ! ${onlyinet} ; then
		for i in $( ifconfig "${iface}" \
			| sed -n -e 's/^.*inet6 addr: \([^ ]*\) Scope:[^L].*/\1/p' ) ; do
			/sbin/ifconfig "${iface}" inet6 del "${i}"
		done
	fi
	return 0
}

# bool ifconfig_get_old_config(char *iface)
#
# Returns config and config_fallback for the given interface
ifconfig_get_old_config() {
	local iface="$1" ifvar=$( bash_variable "$1" ) i inet6

	config="ifconfig_${ifvar}[@]"
	config=( "${!config}" )
	config_fallback="ifconfig_fallback_${ifvar}[@]"
	config_fallback=( "${!config_fallback}" )
	inet6="inet6_${ifvar}[@]"
	inet6=( "${!inet6}" )

	# BACKWARD COMPATIBILITY: populate the config_IFACE array
	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
	i="iface_${ifvar}"
	if [[ -n ${!i} && -z ${config} ]]; then
		# Make sure these get evaluated as arrays
		local -a aliases broadcasts netmasks

		# Start with the primary interface
		config=( ${!i} )

		# ..then add aliases
		aliases="alias_${ifvars}"
		aliases=( ${!aliases} )
		broadcasts="broadcast_${ifvar}"
		broadcasts=( ${!broadcasts} )
		netmasks="netmask_${ifvar}"
		netmasks=( ${!netmasks} )
		for (( i=0; i<${#aliases[@]}; i++ )); do
			config[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
		done
	fi

	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
	[[ ${#inet6[@]} == 1 && ${inet6} == *' '* ]] &&  inet6=( ${inet6} )

	# Add inet6 addresses to our config if required
	[[ -n ${inet6} ]] && config=( "${config[@]}" "${inet6[@]}" )

	return 0
}

# bool ifconfig_iface_stop(char *interface)
#
# Do final shutdown for an interface or alias.
#
# Returns 0 (true) when successful, non-zero (false) on failure
ifconfig_iface_stop() {
	# If an alias is already down, then "ifconfig eth0:1 down"
	# will try to bring it up with an address of "down" which
	# fails.  Do some double-checking before returning error
	# status
	ifconfig_is_up "$1" || return 0
	ifconfig_down "$1" && return 0

	# It is sometimes impossible to transition an alias from the
	# UP state... particularly if the alias has no address.  So
	# ignore the failure, which should be okay since the entire
	# interface will be shut down eventually.
	[[ $1 == *:* ]] && return 0
	return 1
}

# bool ifconfig_pre_start(char *interface)
#
# Runs any pre_start stuff on our interface - just the MTU atm
# We set MTU twice as it may be needed for DHCP - a dhcp client could
# change it in error, so we set MTU in post start too
ifconfig_pre_start() {
	local iface="$1"

	interface_exists "${iface}" || return 0

	local ifvar=$( bash_variable "$1" ) mtu

	# MTU support
	mtu="mtu_${ifvar}"
	[[ -n ${!mtu} ]] && ifconfig "${iface}" mtu "${!mtu}"

	return 0
}


# bool ifconfig_post_start(char *iface)
#
# Bring up iface using ifconfig utilities, called from iface_start
#
# Returns 0 (true) when successful on the primary interface, non-zero
# (false) when the primary interface fails.  Aliases are allowed to
# fail, the routine should still return success to indicate that
# net.eth0 was successful
ifconfig_post_start() {
	local iface="$1" ifvar=$( bash_variable "$1" ) routes x metric mtu cidr
	metric="metric_${ifvar}"

	ifconfig_exists "${iface}" || return 0
	
	# Make sure interface is marked UP
	ifconfig_up "${iface}"

	# MTU support
	mtu="mtu_${ifvar}"
	[[ -n ${!mtu} ]] && ifconfig "${iface}" mtu "${!mtu}"

	routes="routes_${ifvar}[@]"
	routes=( "${!routes}" )

	# BACKWARD COMPATIBILITY: set the default gateway
	if [[ ${gateway} == "${iface}/"* ]]; then
		# We don't add the old gateway if one has been set in routes_IFACE
		local gw=true
		for x in "${routes[@]}"; do
			[[ ${x} != *"default gw"* ]] && continue
			gw=false
			break
		done
		${gw} && routes=( "${routes[@]}" "default gw ${gateway#*/}" )
	fi

	[[ -z ${routes} ]] && return 0

	# Add routes for this interface, might even include default gw
	einfo "Adding routes"
	eindent
	for x in "${routes[@]}"; do
		ebegin "${x}"

		# Support iproute2 style routes
		x="${x//via/gw} "
		x="${x//scope * / }"

		# Assume we're a net device unless told otherwise
		[[ " ${x} " != *" -net "* && " ${x} " != *" -host "* ]] && x="-net ${x}"

		# Support adding IPv6 addresses easily
		if [[ ${x} == *:* ]]; then
			[[ ${x} != *"-A inet6"* ]] && x="-A inet6 ${x}"
			x="${x// -net / }"
		fi

		# Add a metric if we don't have one
		[[ ${x} != *" metric "* ]] && x="${x} metric ${!metric}"

		route add ${x} dev "${iface}"
		eend $?
	done
	eoutdent

	return 0
}

# bool ifconfig_add_address(char *iface, char *options ...)
#
# Adds the given address to the interface
ifconfig_add_address() {
	local iface="$1" i=0 r e real_iface=$(interface_device "$1")

	ifconfig_exists "${real_iface}" true || return 1
	
	# Extract the config
	local -a config=( "$@" )
	config=( ${config[@]:1} )

	if [[ ${config[0]} == *:* ]]; then
		# Support IPv6 - nice and simple
		config[0]="inet6 add ${config[0]}"
	else
		# IPv4 is tricky - ifconfig requires an aliased device
		# for multiple addresses
		if ifconfig "${iface}" | grep -Eq "\<inet addr:.*" ; then
			# Get the last alias made for the interface and add 1 to it
			i=$( ifconfig | tac | grep -m 1 -o "^${iface}:[0-9]*" \
			| sed -n -e 's/'"${iface}"'://p' )
			i="${i:-0}"
			(( i++ ))
			iface="${iface}:${i}"
		fi

		# ifconfig doesn't like CIDR addresses
		local ip="${config[0]%%/*}" cidr="${config[0]##*/}" netmask
		if [[ -n ${cidr} && ${cidr} != "${ip}" ]]; then
			netmask=$( cidr2netmask "${cidr}" )
			config[0]="${ip} netmask ${netmask}"
		fi	

		# Support iproute2 style config where possible
		r="${config[@]}"
		config=( ${r//brd +/} )
		config=( "${config[@]//brd/broadcast}" )
		config=( "${config[@]//peer/pointopoint}" )
	fi

	# Ensure that the interface is up so we can add IPv6 addresses
	interface_up "${real_iface}"

	# Some kernels like to apply lo with an address when they are brought up
	if [[ ${iface} == "lo" && ${config[@]} == "127.0.0.1 netmask 255.0.0.0 broadcast 127.255.255.255" ]]; then
		ifconfig "${iface}" 0.0.0.0
	fi

	ifconfig "${iface}" ${config[@]}
	r="$?"
	[[ ${r} != "0" ]] && return ${r}

	local metric ifvar=$(bash_variable "${real_iface}")
	# Remove the newly added route and replace with our metric
	metric="metric_${ifvar}"
	[[ ${!metric} == "0" || ${RC_AUTO_INTERFACE} != "yes" ]] && return ${r}

	if [[ -z ${netmask} ]]; then
		for (( i=1; i<${#config[@]}-1; i++ )); do
			if [[ ${config[i]} == "netmask" ]]; then
				netmask="${config[i+1]}"
				cidr=$( netmask2cidr "${netmask}" )
				break
			fi
		done
		[[ -z ${netmask} ]] && return ${r}
	fi

	local network=$( ip_network "${ip}" "${netmask}" )

	if route del -net "${network}/${cidr}" metric 0 dev "${iface}" \
		2>/dev/null ; then
		route add -net "${network}/${cidr}" metric "${!metric}" dev "${iface}"
	fi

	return ${r}
}

# void ifconfig_route_metric(char* interface, int metric)
#
# Change all routes for an interface to a given metric
ifconfig_route_metric() {
	local dest gateway mask flags metric ref use
	route -n | grep " $1$" | {
		while read dest gateway mask flags metric ref use ; do
			if [[ ${gateway} != "0.0.0.0" ]]; then
				gateway="gw ${gateway}"
			else
				unset gateway
			fi
			route del ${dest}
			route add -net ${dest} netmask ${mask} ${gateway} metric "$2" dev "$1"
		done
	}
}

# void ifconfig_default_route(char* interface, char* gateway_ip, int metric)
#
# Force default route to the specified gateway
ifconfig_default_route() {
	local metric="${3:-0}"

	# Delete any existing default routes
	while true ; do
		route del default metric "${metric}" dev "$1" 2>/dev/null || break
	done

	# Then we add our route
	route add default gw "$2" metric "${metric}" dev "$1"
}

# vim:ts=4