Added ipfw backend script.
[vsys-scripts.git] / exec / ipfw-be
1 #!/bin/sh
2 #
3 # Marta Carbone
4 # Copyright (C) 2009 UniPi
5 # $Id$
6 #
7 # This script is the backend to be used with
8 # the vsys system.
9 # It allows to configure dummynet pipes and queues.
10 # In detail it:
11 # - read the user's input from the input pipe
12 # - validate the input
13 # - set the firewall
14 # - put results on the output vsys pipe
15 #
16 # This script expect to read from the input vsys
17 # pipe a line formatted as follow:
18 # ${PORT} ${TIMEOUT} <dummynet parameters>
19 # the timeout value is expressed as:
20 # week, day, month or anything else accepted by the date command
21
22 # save the slicename
23 SLICE=$1
24
25 LOG_FILE=/tmp/netconfig.log
26
27 # programs
28 CUT=/usr/bin/cut
29 SED=/bin/sed
30 IPFW=/sbin/ipfw
31
32 # set to 0 to disable debug messages
33 DEBUG=0
34
35 debug() { # $1 message to be displayed
36         [ x"${DEBUG}" != x"0" ] && echo $1 >>{LOG_FILE};
37 }
38
39 abort() { # $1 message to be displayed
40         echo "$1"
41         exit 1
42 }
43
44 user_error() { # $1 message to be displayed
45         echo "1 User error: $1"
46         exit 1
47 }
48
49 filter() { # $* variables to be filtered
50         # allowed chars are: numbers, upcase and lowecase
51         # chars, and the following symbols: . _ - /
52         echo "$*" | ${SED} -r 's/[^0-9a-zA-Z. _\/\-]*//g'
53 }
54
55 # Add ipfw pipe and rules
56 # We use the PORT number to configure the
57 # pipe, and add rules for that port.
58 # The default directory is the slicename root
59 add_rules() { # $1 timeout value
60         local EXPIRE
61
62         debug "Add a new rule"
63         # schedule the rule deletion
64         EXPIRE=`date --date="${TIMEOUT}" +%s`
65         [ x"${EXPIRE}" = x"" ] && abort "Date format $1 not valid"
66
67         # prepend the profile name with the vserver directory
68         echo ${CONFIG_STRING} | ${SED} -e "s/ profile \(.[^ ]\)/ profile \/vservers\/${SLICE}\/\1/g"
69         #
70
71         # check syntax, if ok execute
72         # add rules
73         local IPFW_CHECK="${IPFW} -n "
74         local ERROR=0
75
76         [ $ERROR -eq 0 ] && \
77                 ${IPFW_CHECK} add ${RULE_N} pipe ${PIPE_N} ip from me to any src-port ${PORT} // ${EXPIRE} ${SLICE}
78         let "ERROR += $?"
79         [ $ERROR -eq 0 ] && \
80                 ${IPFW_CHECK} add ${RULE_N} pipe ${PIPE_N} ip from any to me dst-port ${PORT}
81
82         let "ERROR += $?"
83         [ $ERROR -eq 0 ] && \
84                 ${IPFW_CHECK} pipe ${PIPE_N} config ${PARSED_CONFIGURATION}
85
86         if [ ! $ERROR -eq 0 ]; then
87                 echo "Some errors occurred not executing"
88                 user_error "ipfw syntax error"
89         fi
90
91         # add rules
92         ${IPFW} add ${RULE_N} pipe ${PIPE_N} ip from me to any src-port ${PORT} // ${EXPIRE} ${SLICE}
93         ${IPFW} add ${RULE_N} pipe ${PIPE_N} ip from any to me dst-port ${PORT}
94
95         # config pipe
96         ${IPFW} pipe ${PIPE_N} config ${PARSED_CONFIGURATION}
97 }
98
99 # Delete a given link
100 delete_link()
101 {
102         ipfw delete ${RULE_N}
103         ipfw pipe delete ${RULE_N}
104 }
105
106 # The rule we want to configure already exist.
107 # Check for slice owner matching.
108 modify_rule()
109 {
110         local RULE
111
112         RULE=`ipfw list ${PORT} 2>&1 | cut -d ' ' -f 12`;
113         if [ "${RULE}" = "${SLICE}" ] ; then    # replace the link configuration
114                 debug "The rule already exist, the owner match, delete old rule"
115                 echo "Owner match"
116                 delete_link
117                 add_rules ${TIMEOUT}
118         else
119                 user_error "the rule already exist, ant you are not the slice owner, try later"
120         fi
121 }
122
123 # process a single line of input, a request
124 process()
125 {
126         local TMP;              # temporary var
127
128         debug "Received from the input pipe: $1"
129
130         ARGS=`echo $1 | wc -w`
131         if [ $ARGS -le 3 ]; then
132                 abort "One or more input parameter is missing"
133         fi
134
135         # filter input
136         TMP=`echo $1 | cut -d\  -f 1`
137         PORT=`filter $TMP`
138         TMP=`echo $1 | cut -d\  -f 2`
139         TIMEOUT=`filter $TMP`
140         TMP=`echo $1 | cut -d\  -f 3-`
141         CONFIG_STRING=`filter $TMP`
142
143         debug "PORT: $PORT"
144         debug "TIMEOUT: $TIMEOUT"
145         debug "configuration string: $CONFIG_STRING"
146
147         # deny port <= 1024
148         [ ${PORT} -le 1024 ] && user_error "it is not allowed to modify the port range [0-1024]"
149
150         # start to configure pipes and rules
151         PIPE_N=${PORT}
152         RULE_N=${PORT}
153
154         return 0
155         # check if the link is already configured
156         ipfw list ${PORT} 2>&1
157
158         if [ x"$?" != x"0" ]; then      # new rule, add and set owner/timeout
159                 add_rules
160         else                            # the rule already exist, check owner
161                 modify_rule
162         fi
163
164 }
165
166 # main starts here
167
168         requests=[]
169         i=0
170
171         while read request
172         do
173                 # read -a read arguments in array
174                 # XXX skip lines starting with #
175                 requests[$i]=$request;
176                 let i=$i+1
177         done
178
179         # create the lock
180
181         # process requests
182         for i in `/usr/bin/seq 0 $((${#requests[*]} - 1))`
183         do
184                 process "${requests[$i]}"
185                 add_rules
186         done
187
188         # delete the lock
189         exit 0