blob: 7a31d3816405cb312599b66162889864e03860a5 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.firewall;
2
3import java.io.IOException;
4import java.util.Iterator;
5import java.util.List;
6
7import org.codehaus.jackson.JsonParseException;
8import org.codehaus.jackson.JsonParser;
9import org.codehaus.jackson.JsonToken;
10import org.codehaus.jackson.map.MappingJsonFactory;
11import org.openflow.util.HexString;
12import org.restlet.resource.Delete;
13import org.restlet.resource.Post;
14import org.restlet.resource.Get;
15import org.restlet.resource.ServerResource;
16import org.slf4j.Logger;
17import org.slf4j.LoggerFactory;
18
19import net.floodlightcontroller.packet.Ethernet;
20import net.floodlightcontroller.packet.IPv4;
21
22public class FirewallRulesResource extends ServerResource {
23 protected static Logger log = LoggerFactory.getLogger(FirewallRulesResource.class);
24
25 @Get("json")
26 public Object handleRequest() {
27 IFirewallService firewall =
28 (IFirewallService)getContext().getAttributes().
29 get(IFirewallService.class.getCanonicalName());
30
31 return firewall.getRules();
32 }
33
34 /**
35 * Takes a Firewall Rule string in JSON format and parses it into
36 * our firewall rule data structure, then adds it to the firewall.
37 * @param fmJson The Firewall rule entry in JSON format.
38 * @return A string status message
39 */
40 @Post
41 public String store(String fmJson) {
42 IFirewallService firewall =
43 (IFirewallService)getContext().getAttributes().
44 get(IFirewallService.class.getCanonicalName());
45
46 FirewallRule rule;
47 try {
48 rule = jsonToFirewallRule(fmJson);
49 } catch (IOException e) {
50 log.error("Error parsing firewall rule: " + fmJson, e);
51 e.printStackTrace();
52 return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}";
53 }
54 String status = null;
55 if (checkRuleExists(rule, firewall.getRules())) {
56 status = "Error! A similar firewall rule already exists.";
57 log.error(status);
58 } else {
59 // add rule to firewall
60 firewall.addRule(rule);
61 status = "Rule added";
62 }
63 return ("{\"status\" : \"" + status + "\"}");
64 }
65
66 /**
67 * Takes a Firewall Rule string in JSON format and parses it into
68 * our firewall rule data structure, then deletes it from the firewall.
69 * @param fmJson The Firewall rule entry in JSON format.
70 * @return A string status message
71 */
72
73 @Delete
74 public String remove(String fmJson) {
75 IFirewallService firewall =
76 (IFirewallService)getContext().getAttributes().
77 get(IFirewallService.class.getCanonicalName());
78
79 FirewallRule rule;
80 try {
81 rule = jsonToFirewallRule(fmJson);
82 } catch (IOException e) {
83 log.error("Error parsing firewall rule: " + fmJson, e);
84 e.printStackTrace();
85 return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}";
86 }
87 String status = null;
88 boolean exists = false;
89 Iterator<FirewallRule> iter = firewall.getRules().iterator();
90 while (iter.hasNext()) {
91 FirewallRule r = iter.next();
92 if (r.ruleid == rule.ruleid) {
93 exists = true;
94 break;
95 }
96 }
97 if (!exists) {
98 status = "Error! Can't delete, a rule with this ID doesn't exist.";
99 log.error(status);
100 } else {
101 // delete rule from firewall
102 firewall.deleteRule(rule.ruleid);
103 status = "Rule deleted";
104 }
105 return ("{\"status\" : \"" + status + "\"}");
106 }
107
108 /**
109 * Turns a JSON formatted Firewall Rule string into a FirewallRule instance
110 * @param fmJson The JSON formatted static firewall rule
111 * @return The FirewallRule instance
112 * @throws IOException If there was an error parsing the JSON
113 */
114
115 public static FirewallRule jsonToFirewallRule(String fmJson) throws IOException {
116 FirewallRule rule = new FirewallRule();
117 MappingJsonFactory f = new MappingJsonFactory();
118 JsonParser jp;
119
120 try {
121 jp = f.createJsonParser(fmJson);
122 } catch (JsonParseException e) {
123 throw new IOException(e);
124 }
125
126 jp.nextToken();
127 if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
128 throw new IOException("Expected START_OBJECT");
129 }
130
131 while (jp.nextToken() != JsonToken.END_OBJECT) {
132 if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
133 throw new IOException("Expected FIELD_NAME");
134 }
135
136 String n = jp.getCurrentName();
137 jp.nextToken();
138 if (jp.getText().equals(""))
139 continue;
140
141 String tmp;
142
143 // This is currently only applicable for remove(). In store(), ruleid takes a random number
144 if (n == "ruleid") {
145 rule.ruleid = Integer.parseInt((String)jp.getText());
146 }
147
148 // This assumes user having dpid info for involved switches
149 else if (n == "switchid") {
150 tmp = jp.getText();
151 if (tmp.equalsIgnoreCase("-1") == false) {
152 // user inputs hex format dpid
153 rule.dpid = HexString.toLong(tmp);
154 rule.wildcard_dpid = false;
155 }
156 }
157
158 else if (n == "src-inport") {
159 rule.in_port = Short.parseShort(jp.getText());
160 rule.wildcard_in_port = false;
161 }
162
163 else if (n == "src-mac") {
164 tmp = jp.getText();
165 if (tmp.equalsIgnoreCase("ANY") == false) {
166 rule.wildcard_dl_src = false;
167 rule.dl_src = Ethernet.toLong(Ethernet.toMACAddress(tmp));
168 }
169 }
170
171 else if (n == "dst-mac") {
172 tmp = jp.getText();
173 if (tmp.equalsIgnoreCase("ANY") == false) {
174 rule.wildcard_dl_dst = false;
175 rule.dl_dst = Ethernet.toLong(Ethernet.toMACAddress(tmp));
176 }
177 }
178
179 else if (n == "dl-type") {
180 tmp = jp.getText();
181 if (tmp.equalsIgnoreCase("ARP")) {
182 rule.wildcard_dl_type = false;
183 rule.dl_type = Ethernet.TYPE_ARP;
184 }
185 }
186
187 else if (n == "src-ip") {
188 tmp = jp.getText();
189 if (tmp.equalsIgnoreCase("ANY") == false) {
190 rule.wildcard_nw_src = false;
191 rule.wildcard_dl_type = false;
192 rule.dl_type = Ethernet.TYPE_IPv4;
193 int[] cidr = IPCIDRToPrefixBits(tmp);
194 rule.nw_src_prefix = cidr[0];
195 rule.nw_src_maskbits = cidr[1];
196 }
197 }
198
199 else if (n == "dst-ip") {
200 tmp = jp.getText();
201 if (tmp.equalsIgnoreCase("ANY") == false) {
202 rule.wildcard_nw_dst = false;
203 rule.wildcard_dl_type = false;
204 rule.dl_type = Ethernet.TYPE_IPv4;
205 int[] cidr = IPCIDRToPrefixBits(tmp);
206 rule.nw_dst_prefix = cidr[0];
207 rule.nw_dst_maskbits = cidr[1];
208 }
209 }
210
211 else if (n == "nw-proto") {
212 tmp = jp.getText();
213 if (tmp.equalsIgnoreCase("TCP")) {
214 rule.wildcard_nw_proto = false;
215 rule.nw_proto = IPv4.PROTOCOL_TCP;
216 rule.wildcard_dl_type = false;
217 rule.dl_type = Ethernet.TYPE_IPv4;
218 } else if (tmp.equalsIgnoreCase("UDP")) {
219 rule.wildcard_nw_proto = false;
220 rule.nw_proto = IPv4.PROTOCOL_UDP;
221 rule.wildcard_dl_type = false;
222 rule.dl_type = Ethernet.TYPE_IPv4;
223 } else if (tmp.equalsIgnoreCase("ICMP")) {
224 rule.wildcard_nw_proto = false;
225 rule.nw_proto = IPv4.PROTOCOL_ICMP;
226 rule.wildcard_dl_type = false;
227 rule.dl_type = Ethernet.TYPE_IPv4;
228 }
229 }
230
231 else if (n == "tp-src") {
232 rule.wildcard_tp_src = false;
233 rule.tp_src = Short.parseShort(jp.getText());
234 }
235
236 else if (n == "tp-dst") {
237 rule.wildcard_tp_dst = false;
238 rule.tp_dst = Short.parseShort(jp.getText());
239 }
240
241 else if (n == "priority") {
242 rule.priority = Integer.parseInt(jp.getText());
243 }
244
245 else if (n == "action") {
246 if (jp.getText().equalsIgnoreCase("allow") == true) {
247 rule.action = FirewallRule.FirewallAction.ALLOW;
248 } else if (jp.getText().equalsIgnoreCase("deny") == true) {
249 rule.action = FirewallRule.FirewallAction.DENY;
250 }
251 }
252 }
253
254 return rule;
255 }
256
257 public static int[] IPCIDRToPrefixBits(String cidr) {
258 int ret[] = new int[2];
259
260 // as IP can also be a prefix rather than an absolute address
261 // split it over "/" to get the bit range
262 String[] parts = cidr.split("/");
263 String cidr_prefix = parts[0].trim();
264 int cidr_bits = 0;
265 if (parts.length == 2) {
266 try {
267 cidr_bits = Integer.parseInt(parts[1].trim());
268 } catch (Exception exp) {
269 cidr_bits = 32;
270 }
271 }
272 ret[0] = IPv4.toIPv4Address(cidr_prefix);
273 ret[1] = cidr_bits;
274
275 return ret;
276 }
277
278 public static boolean checkRuleExists(FirewallRule rule, List<FirewallRule> rules) {
279 Iterator<FirewallRule> iter = rules.iterator();
280 while (iter.hasNext()) {
281 FirewallRule r = iter.next();
282
283 // check if we find a similar rule
284 if (rule.isSameAs(r)) {
285 return true;
286 }
287 }
288
289 // no rule matched, so it doesn't exist in the rules
290 return false;
291 }
292}