1#! /bin/bash
2
3CheckForwarding () {
4  local sbase fwd
5  sbase=/proc/sys/net/ipv4/conf
6  fwd=0
7  if [ -d $sbase ]; then
8    for dir in $sbase/*/forwarding; do
9      fwd=$[$fwd + `cat $dir`]
10    done
11  else
12    fwd=2
13  fi
14  return $fwd
15}
16
17RestartRDISC () {
18  killall -HUP rdisc || rdisc -fs
19}
20
21ABCMaskLen () {
22  local class;
23
24  class=${1%%.*}
25  if [ "$1" = "" -o $class -eq 0 -o $class -ge 224 ]; then return 0
26  elif [ $class -ge 224 ]; then return 0
27  elif [ $class -ge 192 ]; then return 24
28  elif [ $class -ge 128 ]; then return 16
29  else return 8; fi
30}
31
32label="label $1"
33ldev="$1"
34dev=${1%:*}
35if [ "$dev" = "" -o "$1" = "help" ]; then
36  echo "Usage: ifcfg DEV [[add|del [ADDR[/LEN]] [PEER] | stop]" 1>&2
37  echo "       add - add new address" 1>&2
38  echo "       del - delete address" 1>&2
39  echo "       stop - completely disable IP" 1>&2
40  exit 1
41fi
42shift
43
44CheckForwarding
45fwd=$?
46if [ $fwd -ne 0 ]; then
47  echo "Forwarding is ON or its state is unknown ($fwd). OK, No RDISC." 1>&2
48fi
49
50
51deleting=0
52case "$1" in
53add) shift ;;
54stop)
55  if [ "$ldev" != "$dev" ]; then
56    echo "Cannot stop alias $ldev" 1>&2
57    exit 1;
58  fi
59  ip -4 addr flush dev $dev $label || exit 1
60  if [ $fwd -eq 0 ]; then RestartRDISC; fi
61  exit 0 ;;
62del*)
63  deleting=1; shift ;;
64*)
65esac
66
67ipaddr=
68pfxlen=
69if [ "$1" != "" ]; then
70  ipaddr=${1%/*}
71  if [ "$1" != "$ipaddr" ]; then
72    pfxlen=${1#*/}
73  fi
74  if [ "$ipaddr" = "" ]; then
75    echo "$1 is bad IP address." 1>&2
76    exit 1
77  fi
78fi
79shift
80
81peer=$1
82if [ "$peer" != "" ]; then
83  if [ "$pfxlen" != "" -a "$pfxlen" != "32" ]; then
84    echo "Peer address with non-trivial netmask." 1>&2
85    exit 1
86  fi
87  pfx="$ipaddr peer $peer"
88else
89  if [ "$pfxlen" = "" ]; then
90    ABCMaskLen $ipaddr
91    pfxlen=$?
92  fi
93  pfx="$ipaddr/$pfxlen"
94fi
95
96if [ "$ldev" = "$dev" -a "$ipaddr" != "" ]; then
97  label=
98fi
99
100if [ $deleting -ne 0 ]; then
101  ip addr del $pfx dev $dev $label || exit 1
102  if [ $fwd -eq 0 ]; then RestartRDISC; fi
103  exit 0
104fi
105
106
107if ! ip link set up dev $dev ; then
108  echo "Error: cannot enable interface $dev." 1>&2
109  exit 1
110fi
111if [ "$ipaddr" = "" ]; then exit 0; fi
112
113if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
114  echo "Error: some host already uses address $ipaddr on $dev." 1>&2
115  exit 1
116fi
117
118if ! ip address add $pfx brd + dev $dev $label; then
119  echo "Error: failed to add $pfx on $dev." 1>&2
120  exit 1
121fi
122
123arping -q -A -c 1 -I $dev $ipaddr
124noarp=$?
125( sleep 2 ;
126  arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
127
128ip route add unreachable 224.0.0.0/24 >& /dev/null 
129ip route add unreachable 255.255.255.255 >& /dev/null
130if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
131  ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
132fi
133
134if [ $fwd -eq 0 ]; then
135  if [ $noarp -eq 0 ]; then
136    ip ro append default dev $dev metric 30000 scope global
137  elif [ "$peer" != "" ]; then
138    if ping -q -c 2 -w 4 $peer ; then
139      ip ro append default via $peer dev $dev metric 30001
140    fi
141  fi
142  RestartRDISC
143fi
144
145exit 0
146