/** * Copyright 2015, Big Switch Networks, Inc. * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China * Advisers: Keqiu Li, Heng Qi and Haisheng Yu * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.accesscontrollist.web; import java.io.IOException; import java.util.Iterator; import net.floodlightcontroller.accesscontrollist.ACLRule; import net.floodlightcontroller.accesscontrollist.IACLService; import net.floodlightcontroller.accesscontrollist.util.IPAddressUtil; import org.restlet.resource.Delete; import org.restlet.resource.Get; import org.restlet.resource.Post; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.MappingJsonFactory; public class ACLRuleResource extends ServerResource { protected static Logger log = LoggerFactory .getLogger(ACLRuleResource.class); @Get("json") public Object handleRequest() { IACLService acl = (IACLService) getContext().getAttributes().get( IACLService.class.getCanonicalName()); return acl.getRules(); } /** * parse a JSON string into a ACL rule instance, then add it to the ACL * @return A string status message */ @Post public String store(String json) { IACLService aclService = (IACLService) getContext().getAttributes().get( IACLService.class.getCanonicalName()); ACLRule newRule; try { newRule = jsonToRule(json); } catch (Exception e) { log.error("Error parsing ACL rule: " + json, e); return "{\"status\" : \"Failed! " + e.getMessage() + "\"}"; } String status = null; String nw_src = newRule.getNw_src(); String nw_dst = newRule.getNw_dst(); if (nw_src == null && nw_dst == null){ status = "Failed! Either nw_src or nw_dst must be specified."; return ("{\"status\" : \"" + status + "\"}"); } if(aclService.addRule(newRule)){ status = "Success! New rule added."; }else{ status = "Failed! The new ACL rule matches an existing rule."; } return ("{\"status\" : \"" + status + "\"}"); } /** * parse a JSON string into a ACL rule instance, then remove it from the ACL * @return A string status message */ @Delete public String remove(String json) { IACLService ACL = (IACLService) getContext().getAttributes().get( IACLService.class.getCanonicalName()); ACLRule rule; try { rule = jsonToRule(json); } catch (Exception e) { log.error("Error parsing ACL rule: " + json, e); return "{\"status\" : \"Failed! " + e.getMessage() + "\"}"; } // check whether the rule exists boolean exists = false; Iterator<ACLRule> iter = ACL.getRules().iterator(); while (iter.hasNext()) { ACLRule r = iter.next(); if (r.getId() == rule.getId()) { exists = true; break; } } String status = null; if (!exists) { status = "Failed! a rule with this ID doesn't exist."; log.error(status); } else { ACL.removeRule(rule.getId()); status = "Success! Rule deleted"; } return ("{\"status\" : \"" + status + "\"}"); } /** * Turns a JSON string into a ACL rule instance */ public static ACLRule jsonToRule(String json) throws IOException { ACLRule rule = new ACLRule(); MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createParser(json); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String key = jp.getCurrentName(); jp.nextToken(); String value = jp.getText(); if (value.equals("")) continue; // used for removing rule if ("ruleid".equals(key)) { try{ rule.setId(Integer.parseInt(value)); } catch(NumberFormatException e){ throw new NumberFormatException("ruleid must be specified as a number."); } } else if ("src-ip".equals(key)) { rule.setNw_src(value); int[] cidr = IPAddressUtil.parseCIDR(value); rule.setNw_src_prefix(cidr[0]); rule.setNw_src_maskbits(cidr[1]); } else if ("dst-ip".equals(key)) { rule.setNw_dst(value); int[] cidr = IPAddressUtil.parseCIDR(value); rule.setNw_dst_prefix(cidr[0]); rule.setNw_dst_maskbits(cidr[1]); } else if ("nw-proto".equals(key)) { if ("TCP".equalsIgnoreCase(value)) { rule.setNw_proto(6); } else if ("UDP".equalsIgnoreCase(value)) { rule.setNw_proto(17); } else if ("ICMP".equalsIgnoreCase(value)) { rule.setNw_proto(1); } else { throw new IllegalArgumentException("nw-proto must be specified as (TCP || UDP || ICMP)."); } } else if ("tp-dst".equals(key)) { // only when tp-dst == (TCP || UDP), tp-dst can have non-0 value if(rule.getNw_proto() == 6 || rule.getNw_proto() == 17){ try{ rule.setTp_dst(Integer.parseInt(value)); }catch(NumberFormatException e){ throw new NumberFormatException("tp-dst must be specified as a number."); } } } else if (key == "action") { if ("allow".equalsIgnoreCase(value)) { rule.setAction(ACLRule.Action.ALLOW); } else if ("deny".equalsIgnoreCase(value)) { rule.setAction(ACLRule.Action.DENY); } else{ throw new IllegalArgumentException("action must be specidied as (allow || deny)."); } } } return rule; } }