@Override @ActionEvent( eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true) public boolean addSystemFirewallRules(IPAddressVO ip, Account acct) { List<FirewallRuleVO> systemRules = _firewallDao.listSystemRules(); for (FirewallRuleVO rule : systemRules) { try { if (rule.getSourceCidrList() == null && (rule.getPurpose() == Purpose.Firewall || rule.getPurpose() == Purpose.NetworkACL)) { _firewallDao.loadSourceCidrs(rule); } createFirewallRule( ip.getId(), acct, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), rule.getIcmpType(), rule.getRelated(), FirewallRuleType.System, rule.getNetworkId(), rule.getTrafficType()); } catch (Exception e) { s_logger.debug("Failed to add system wide firewall rule, due to:" + e.toString()); } } return true; }
@Override public boolean applyRules( List<? extends FirewallRule> rules, boolean continueOnError, boolean updateRulesInDB) throws ResourceUnavailableException { boolean success = true; if (rules == null || rules.size() == 0) { s_logger.debug("There are no rules to forward to the network elements"); return true; } Purpose purpose = rules.get(0).getPurpose(); if (!_ipAddrMgr.applyRules(rules, purpose, this, continueOnError)) { s_logger.warn("Rules are not completely applied"); return false; } else { if (updateRulesInDB) { for (FirewallRule rule : rules) { if (rule.getState() == FirewallRule.State.Revoke) { FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(rule.getId()); if (relatedRule != null) { s_logger.warn( "Can't remove the firewall rule id=" + rule.getId() + " as it has related firewall rule id=" + relatedRule.getId() + "; leaving it in Revoke state"); success = false; } else { removeRule(rule); if (rule.getSourceIpAddressId() != null) { // if the rule is the last one for the ip address assigned to VPC, unassign it from // the network IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId()); _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), rule.getNetworkId()); } } } else if (rule.getState() == FirewallRule.State.Add) { FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId()); ruleVO.setState(FirewallRule.State.Active); _firewallDao.update(ruleVO.getId(), ruleVO); } } } } return success; }
@Override public boolean applyEgressFirewallRules(FirewallRule rule, Account caller) throws ResourceUnavailableException { List<FirewallRuleVO> rules = _firewallDao.listByNetworkPurposeTrafficType( rule.getNetworkId(), Purpose.Firewall, FirewallRule.TrafficType.Egress); applyDefaultEgressFirewallRule(rule.getNetworkId(), true); return applyFirewallRules(rules, false, caller); }
protected boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, long userId) { FirewallRuleVO rule = _firewallDao.findById(ruleId); if (rule == null || rule.getPurpose() != Purpose.Firewall) { throw new InvalidParameterValueException( "Unable to find " + ruleId + " having purpose " + Purpose.Firewall); } if (rule.getType() == FirewallRuleType.System && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException( "Only root admin can delete the system wide firewall rule"); } _accountMgr.checkAccess(caller, null, true, rule); revokeRule(rule, caller, userId, false); boolean success = false; Long networkId = rule.getNetworkId(); if (apply) { // ingress firewall rule if (rule.getSourceIpAddressId() != null) { // feteches ingress firewall, ingress firewall rules associated with the ip List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurpose(rule.getSourceIpAddressId(), Purpose.Firewall); return applyFirewallRules(rules, false, caller); // egress firewall rule } else if (networkId != null) { List<FirewallRuleVO> rules = _firewallDao.listByNetworkPurposeTrafficType( rule.getNetworkId(), Purpose.Firewall, FirewallRule.TrafficType.Egress); return applyFirewallRules(rules, false, caller); } } else { success = true; } return success; }
@Override @ActionEvent( eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking firewall rule", async = true) public boolean revokeAllFirewallRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException { List<FirewallRule> rules = new ArrayList<FirewallRule>(); List<FirewallRuleVO> fwRules = _firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.Firewall); if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing " + fwRules.size() + " firewall rules for network id=" + networkId); } for (FirewallRuleVO rule : fwRules) { // Mark all Firewall rules as Revoke, but don't revoke them yet - we have to revoke all rules // for ip, no // need to send them one by one revokeFirewallRule(rule.getId(), false, caller, Account.ACCOUNT_ID_SYSTEM); } // now send everything to the backend List<FirewallRuleVO> rulesToApply = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.Firewall); boolean success = applyFirewallRules(rulesToApply, true, caller); // Now we check again in case more rules have been inserted. rules.addAll(_firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.Firewall)); if (s_logger.isDebugEnabled()) { s_logger.debug( "Successfully released firewall rules for network id=" + networkId + " and # of rules now = " + rules.size()); } return success && rules.size() == 0; }
@Override public boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId) { List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.LoadBalancing); if (rules != null) s_logger.debug("Found " + rules.size() + " lb rules to cleanup"); for (FirewallRule rule : rules) { boolean result = deleteLoadBalancerRule(rule.getId(), true, caller, callerUserId); if (result == false) { s_logger.warn("Unable to remove load balancer rule " + rule.getId()); return false; } } return true; }
@Override public boolean revokeRelatedFirewallRule(long ruleId, boolean apply) { FirewallRule fwRule = _firewallDao.findByRelatedId(ruleId); if (fwRule == null) { s_logger.trace( "No related firewall rule exists for rule id=" + ruleId + " so returning true here"); return true; } s_logger.debug( "Revoking Firewall rule id=" + fwRule.getId() + " as a part of rule delete id=" + ruleId + " with apply=" + apply); return revokeFirewallRule(fwRule.getId(), apply); }
@Override @ActionEvent( eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true) public FirewallRule createRuleForAllCidrs( long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType, Long relatedRuleId, long networkId) throws NetworkRuleConflictException { // If firwallRule for this port range already exists, return it List<FirewallRuleVO> rules = _firewallDao.listByIpPurposeAndProtocolAndNotRevoked( ipAddrId, startPort, endPort, protocol, Purpose.Firewall); if (!rules.isEmpty()) { return rules.get(0); } List<String> oneCidr = new ArrayList<String>(); oneCidr.add(NetUtils.ALL_CIDRS); return createFirewallRule( ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, icmpCode, icmpType, relatedRuleId, FirewallRule.FirewallRuleType.User, networkId, FirewallRule.TrafficType.Ingress); }
@Override @DB public void revokeRule(FirewallRuleVO rule, Account caller, long userId, boolean needUsageEvent) { if (caller != null) { _accountMgr.checkAccess(caller, null, true, rule); } Transaction txn = Transaction.currentTxn(); boolean generateUsageEvent = false; txn.start(); if (rule.getState() == State.Staged) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found a rule that is still in stage state so just removing it: " + rule); } removeRule(rule); generateUsageEvent = true; } else if (rule.getState() == State.Add || rule.getState() == State.Active) { rule.setState(State.Revoke); _firewallDao.update(rule.getId(), rule); generateUsageEvent = true; } if (generateUsageEvent && needUsageEvent) { UsageEventUtils.publishUsageEvent( EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), null, rule.getClass().getName(), rule.getUuid()); } txn.commit(); }
@Override @DB @ActionEvent( eventType = EventTypes.EVENT_REMOTE_ACCESS_VPN_DESTROY, eventDescription = "removing remote access vpn", async = true) public boolean destroyRemoteAccessVpnForIp(long ipId, Account caller, final boolean forceCleanup) throws ResourceUnavailableException { final RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findByPublicIpAddress(ipId); if (vpn == null) { s_logger.debug("there are no Remote access vpns for public ip address id=" + ipId); return true; } _accountMgr.checkAccess(caller, AccessType.OperateEntry, true, vpn); RemoteAccessVpn.State prevState = vpn.getState(); vpn.setState(RemoteAccessVpn.State.Removed); _remoteAccessVpnDao.update(vpn.getId(), vpn); boolean success = false; try { for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) { if (element.stopVpn(vpn)) { success = true; break; } } } catch (ResourceUnavailableException ex) { vpn.setState(prevState); _remoteAccessVpnDao.update(vpn.getId(), vpn); s_logger.debug( "Failed to stop the vpn " + vpn.getId() + " , so reverted state to " + RemoteAccessVpn.State.Running); success = false; } finally { if (success || forceCleanup) { // Cleanup corresponding ports final List<? extends FirewallRule> vpnFwRules = _rulesDao.listByIpAndPurpose(ipId, Purpose.Vpn); boolean applyFirewall = false; final List<FirewallRuleVO> fwRules = new ArrayList<FirewallRuleVO>(); // if related firewall rule is created for the first vpn port, it would be created for the 2 // other ports as well, so need to cleanup the backend if (vpnFwRules.size() != 0 && _rulesDao.findByRelatedId(vpnFwRules.get(0).getId()) != null) { applyFirewall = true; } if (applyFirewall) { Transaction.execute( new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { for (FirewallRule vpnFwRule : vpnFwRules) { // don't apply on the backend yet; send all 3 rules in a banch _firewallMgr.revokeRelatedFirewallRule(vpnFwRule.getId(), false); fwRules.add(_rulesDao.findByRelatedId(vpnFwRule.getId())); } s_logger.debug( "Marked " + fwRules.size() + " firewall rules as Revoked as a part of disable remote access vpn"); } }); // now apply vpn rules on the backend s_logger.debug( "Reapplying firewall rules for ip id=" + ipId + " as a part of disable remote access vpn"); success = _firewallMgr.applyIngressFirewallRules(ipId, caller); } if (success || forceCleanup) { try { Transaction.execute( new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { _remoteAccessVpnDao.remove(vpn.getId()); // Stop billing of VPN users when VPN is removed. VPN_User_ADD events will be // generated when VPN is created again List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); for (VpnUserVO user : vpnUsers) { // VPN_USER_REMOVE event is already generated for users in Revoke state if (user.getState() != VpnUser.State.Revoke) { UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } if (vpnFwRules != null) { for (FirewallRule vpnFwRule : vpnFwRules) { _rulesDao.remove(vpnFwRule.getId()); s_logger.debug( "Successfully removed firewall rule with ip id=" + vpnFwRule.getSourceIpAddressId() + " and port " + vpnFwRule.getSourcePortStart().intValue() + " as a part of vpn cleanup"); } } } }); } catch (Exception ex) { s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex); } } } } return success; }
@DB public LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException { long ipId = lb.getSourceIpAddressId(); UserContext caller = UserContext.current(); int srcPortStart = lb.getSourcePortStart(); int defPortStart = lb.getDefaultPortStart(); int srcPortEnd = lb.getSourcePortEnd(); IPAddressVO ipAddr = _ipAddressDao.findById(lb.getSourceIpAddressId()); Long networkId = ipAddr.getSourceNetworkId(); // make sure ip address exists if (ipAddr == null || !ipAddr.readyToUse()) { throw new InvalidParameterValueException( "Unable to create load balancer rule, invalid IP address id" + ipId); } _firewallMgr.validateFirewallRule( caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), Purpose.LoadBalancing); networkId = ipAddr.getAssociatedWithNetworkId(); if (networkId == null) { throw new InvalidParameterValueException( "Unable to create load balancer rule ; ip id=" + ipId + " is not associated with any network"); } NetworkVO network = _networkDao.findById(networkId); _accountMgr.checkAccess(caller.getCaller(), null, ipAddr); // verify that lb service is supported by the network if (!_networkMgr.isServiceSupported(network.getNetworkOfferingId(), Service.Lb)) { throw new InvalidParameterValueException( "LB service is not supported in network id= " + networkId); } Transaction txn = Transaction.currentTxn(); txn.start(); LoadBalancerVO newRule = new LoadBalancerVO( lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), lb.getAlgorithm(), network.getId(), ipAddr.getAccountId(), ipAddr.getDomainId()); newRule = _lbDao.persist(newRule); if (openFirewall) { _firewallMgr.createRuleForAllCidrs( ipId, caller.getCaller(), lb.getSourcePortStart(), lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId()); } boolean success = true; try { _firewallMgr.detectRulesConflict(newRule, ipAddr); if (!_firewallDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } s_logger.debug( "Load balancer " + newRule.getId() + " for Ip address id=" + ipId + ", public port " + srcPortStart + ", private port " + defPortStart + " is added successfully."); UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); UsageEventVO usageEvent = new UsageEventVO( EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null); _usageEventDao.persist(usageEvent); txn.commit(); return newRule; } catch (Exception e) { success = false; if (e instanceof NetworkRuleConflictException) { throw (NetworkRuleConflictException) e; } throw new CloudRuntimeException( "Unable to add rule for ip address id=" + newRule.getSourceIpAddressId(), e); } finally { if (!success && newRule != null) { txn.start(); _firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false); _lbDao.remove(newRule.getId()); txn.commit(); } } }
@DB public boolean deleteLoadBalancerRule( long loadBalancerId, boolean apply, Account caller, long callerUserId) { LoadBalancerVO lb = _lbDao.findById(loadBalancerId); Transaction txn = Transaction.currentTxn(); boolean generateUsageEvent = false; boolean success = true; txn.start(); if (lb.getState() == FirewallRule.State.Staged) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found a rule that is still in stage state so just removing it: " + lb); } generateUsageEvent = true; } else if (lb.getState() == FirewallRule.State.Add || lb.getState() == FirewallRule.State.Active) { lb.setState(FirewallRule.State.Revoke); _lbDao.persist(lb); generateUsageEvent = true; } List<LoadBalancerVMMapVO> maps = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId); if (maps != null) { for (LoadBalancerVMMapVO map : maps) { map.setRevoke(true); _lb2VmMapDao.persist(map); s_logger.debug( "Set load balancer rule for revoke: rule id " + loadBalancerId + ", vmId " + map.getInstanceId()); } } if (generateUsageEvent) { // Generate usage event right after all rules were marked for revoke UsageEventVO usageEvent = new UsageEventVO( EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null); _usageEventDao.persist(usageEvent); } txn.commit(); if (apply) { try { if (!applyLoadBalancerConfig(loadBalancerId)) { s_logger.warn("Unable to apply the load balancer config"); return false; } } catch (ResourceUnavailableException e) { s_logger.warn( "Unable to apply the load balancer config because resource is unavaliable.", e); return false; } } FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(lb.getId()); if (relatedRule != null) { s_logger.warn( "Unable to remove firewall rule id=" + lb.getId() + " as it has related firewall rule id=" + relatedRule.getId() + "; leaving it in Revoke state"); success = false; } else { _firewallDao.remove(lb.getId()); } _elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller); if (success) { s_logger.debug("Load balancer with id " + lb.getId() + " is removed successfully"); } return success; }
@Override @DB public void destroyRemoteAccessVpn(long ipId, Account caller) throws ResourceUnavailableException { RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(ipId); if (vpn == null) { s_logger.debug("vpn id=" + ipId + " does not exists "); return; } _accountMgr.checkAccess(caller, null, true, vpn); Network network = _networkMgr.getNetwork(vpn.getNetworkId()); vpn.setState(RemoteAccessVpn.State.Removed); _remoteAccessVpnDao.update(vpn.getServerAddressId(), vpn); boolean success = false; try { for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) { if (element.stopVpn(network, vpn)) { success = true; break; } } } finally { if (success) { // Cleanup corresponding ports List<? extends FirewallRule> vpnFwRules = _rulesDao.listByIpAndPurpose(ipId, Purpose.Vpn); Transaction txn = Transaction.currentTxn(); boolean applyFirewall = false; List<FirewallRuleVO> fwRules = new ArrayList<FirewallRuleVO>(); // if related firewall rule is created for the first vpn port, it would be created for the 2 // other ports as well, so need to cleanup the backend if (_rulesDao.findByRelatedId(vpnFwRules.get(0).getId()) != null) { applyFirewall = true; } if (applyFirewall) { txn.start(); for (FirewallRule vpnFwRule : vpnFwRules) { // don't apply on the backend yet; send all 3 rules in a banch _firewallMgr.revokeRelatedFirewallRule(vpnFwRule.getId(), false); fwRules.add(_rulesDao.findByRelatedId(vpnFwRule.getId())); } s_logger.debug( "Marked " + fwRules.size() + " firewall rules as Revoked as a part of disable remote access vpn"); txn.commit(); // now apply vpn rules on the backend s_logger.debug( "Reapplying firewall rules for ip id=" + ipId + " as a part of disable remote access vpn"); success = _firewallMgr.applyIngressFirewallRules(ipId, caller); } if (success) { try { txn.start(); _remoteAccessVpnDao.remove(ipId); // Stop billing of VPN users when VPN is removed. VPN_User_ADD events will be generated // when VPN is created again List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); for (VpnUserVO user : vpnUsers) { // VPN_USER_REMOVE event is already generated for users in Revoke state if (user.getState() != VpnUser.State.Revoke) { UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } if (vpnFwRules != null) { for (FirewallRule vpnFwRule : vpnFwRules) { _rulesDao.remove(vpnFwRule.getId()); s_logger.debug( "Successfully removed firewall rule with ip id=" + vpnFwRule.getSourceIpAddressId() + " and port " + vpnFwRule.getSourcePortStart() + " as a part of vpn cleanup"); } } txn.commit(); } catch (Exception ex) { txn.rollback(); s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex); } } } } }
@Override public FirewallRule getFirewallRule(long ruleId) { return _firewallDao.findById(ruleId); }
@Override @ActionEvent( eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking firewall rule", async = true) public boolean revokeFirewallRulesForVm(long vmId) { boolean success = true; UserVmVO vm = _vmDao.findByIdIncludingRemoved(vmId); if (vm == null) { return false; } List<PortForwardingRuleVO> pfRules = _pfRulesDao.listByVm(vmId); List<FirewallRuleVO> staticNatRules = _firewallDao.listStaticNatByVmId(vm.getId()); List<FirewallRuleVO> firewallRules = new ArrayList<FirewallRuleVO>(); // Make a list of firewall rules to reprogram for (PortForwardingRuleVO pfRule : pfRules) { FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(pfRule.getId()); if (relatedRule != null) { firewallRules.add(relatedRule); } } for (FirewallRuleVO staticNatRule : staticNatRules) { FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(staticNatRule.getId()); if (relatedRule != null) { firewallRules.add(relatedRule); } } Set<Long> ipsToReprogram = new HashSet<Long>(); if (firewallRules.isEmpty()) { s_logger.debug("No firewall rules are found for vm id=" + vmId); return true; } else { s_logger.debug("Found " + firewallRules.size() + " to cleanup for vm id=" + vmId); } for (FirewallRuleVO rule : firewallRules) { // Mark firewall rules as Revoked, but don't revoke it yet (apply=false) revokeFirewallRule( rule.getId(), false, _accountMgr.getSystemAccount(), Account.ACCOUNT_ID_SYSTEM); ipsToReprogram.add(rule.getSourceIpAddressId()); } // apply rules for all ip addresses for (Long ipId : ipsToReprogram) { s_logger.debug( "Applying firewall rules for ip address id=" + ipId + " as a part of vm expunge"); try { success = success && applyIngressFirewallRules(ipId, _accountMgr.getSystemAccount()); } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to apply port forwarding rules for ip id=" + ipId); success = false; } } return success; }
@Override public boolean applyIngressFirewallRules(long ipId, Account caller) throws ResourceUnavailableException { List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurpose(ipId, Purpose.Firewall); return applyFirewallRules(rules, false, caller); }
@Override public void removeRule(FirewallRule rule) { // remove the rule _firewallDao.remove(rule.getId()); }
@DB protected FirewallRule createFirewallRule( Long ipAddrId, Account caller, String xId, Integer portStart, Integer portEnd, String protocol, List<String> sourceCidrList, Integer icmpCode, Integer icmpType, Long relatedRuleId, FirewallRule.FirewallRuleType type, Long networkId, FirewallRule.TrafficType trafficType) throws NetworkRuleConflictException { IPAddressVO ipAddress = null; if (ipAddrId != null) { // this for ingress firewall rule, for egress id is null ipAddress = _ipAddressDao.findById(ipAddrId); // Validate ip address if (ipAddress == null && type == FirewallRule.FirewallRuleType.User) { throw new InvalidParameterValueException( "Unable to create firewall rule; " + "couldn't locate IP address by id in the system"); } _networkModel.checkIpForService(ipAddress, Service.Firewall, null); } validateFirewallRule( caller, ipAddress, portStart, portEnd, protocol, Purpose.Firewall, type, networkId, trafficType); // icmp code and icmp type can't be passed in for any other protocol rather than icmp if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) { throw new InvalidParameterValueException( "Can specify icmpCode and icmpType for ICMP protocol only"); } if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart != null || portEnd != null)) { throw new InvalidParameterValueException( "Can't specify start/end port when protocol is ICMP"); } Long accountId = null; Long domainId = null; if (ipAddress != null) { // Ingress firewall rule accountId = ipAddress.getAllocatedToAccountId(); domainId = ipAddress.getAllocatedInDomainId(); } else if (networkId != null) { // egress firewall rule Network network = _networkModel.getNetwork(networkId); accountId = network.getAccountId(); domainId = network.getDomainId(); } Transaction txn = Transaction.currentTxn(); txn.start(); FirewallRuleVO newRule = new FirewallRuleVO( xId, ipAddrId, portStart, portEnd, protocol.toLowerCase(), networkId, accountId, domainId, Purpose.Firewall, sourceCidrList, icmpCode, icmpType, relatedRuleId, trafficType); newRule.setType(type); newRule = _firewallDao.persist(newRule); if (type == FirewallRuleType.User) detectRulesConflict(newRule); if (!_firewallDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } CallContext.current().setEventDetails("Rule Id: " + newRule.getId()); txn.commit(); return newRule; }
@Override public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflictException { List<FirewallRuleVO> rules; if (newRule.getSourceIpAddressId() != null) { rules = _firewallDao.listByIpAndPurposeAndNotRevoked(newRule.getSourceIpAddressId(), null); assert (rules.size() >= 1) : "For network rules, we now always first persist the rule and then check for " + "network conflicts so we should at least have one rule at this point."; } else { // fetches only firewall egress rules. rules = _firewallDao.listByNetworkPurposeTrafficTypeAndNotRevoked( newRule.getNetworkId(), Purpose.Firewall, newRule.getTrafficType()); assert (rules.size() >= 1); } for (FirewallRuleVO rule : rules) { if (rule.getId() == newRule.getId()) { continue; // Skips my own rule. } boolean oneOfRulesIsFirewall = ((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall) && ((newRule.getPurpose() != rule.getPurpose()) || (!newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())))); // if both rules are firewall and their cidrs are different, we can skip port ranges // verification boolean bothRulesFirewall = (rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall); boolean duplicatedCidrs = false; if (bothRulesFirewall) { // Verify that the rules have different cidrs _firewallDao.loadSourceCidrs(rule); _firewallDao.loadSourceCidrs((FirewallRuleVO) newRule); List<String> ruleCidrList = rule.getSourceCidrList(); List<String> newRuleCidrList = newRule.getSourceCidrList(); if (ruleCidrList == null || newRuleCidrList == null) { continue; } Collection<String> similar = new HashSet<String>(ruleCidrList); similar.retainAll(newRuleCidrList); if (similar.size() > 0) { duplicatedCidrs = true; } } if (!oneOfRulesIsFirewall) { if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) { throw new NetworkRuleConflictException( "There is 1 to 1 Nat rule specified for the ip address id=" + newRule.getSourceIpAddressId()); } else if (rule.getPurpose() != Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat) { throw new NetworkRuleConflictException( "There is already firewall rule specified for the ip address id=" + newRule.getSourceIpAddressId()); } } if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) { throw new NetworkRuleConflictException( "New rule is for a different network than what's specified in rule " + rule.getXid()); } if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO) && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue() && newRule.getIcmpType().longValue() == rule.getIcmpType().longValue() && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()) && duplicatedCidrs) { throw new InvalidParameterValueException( "New rule conflicts with existing rule id=" + rule.getId()); } } boolean notNullPorts = (newRule.getSourcePortStart() != null && newRule.getSourcePortEnd() != null && rule.getSourcePortStart() != null && rule.getSourcePortEnd() != null); if (!notNullPorts) { continue; } else if (!oneOfRulesIsFirewall && !(bothRulesFirewall && !duplicatedCidrs) && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) { // we allow port forwarding rules with the same parameters but different protocols boolean allowPf = (rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); boolean allowStaticNat = (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); if (!(allowPf || allowStaticNat || oneOfRulesIsFirewall)) { throw new NetworkRuleConflictException( "The range specified, " + newRule.getSourcePortStart() + "-" + newRule.getSourcePortEnd() + ", conflicts with rule " + rule.getId() + " which has " + rule.getSourcePortStart() + "-" + rule.getSourcePortEnd()); } } } if (s_logger.isDebugEnabled()) { s_logger.debug( "No network rule conflicts detected for " + newRule + " against " + (rules.size() - 1) + " existing rules"); } }
@Override public Pair<List<? extends FirewallRule>, Integer> listFirewallRules(ListFirewallRulesCmd cmd) { Long ipId = cmd.getIpAddressId(); Long id = cmd.getId(); Long networkId = null; Map<String, String> tags = cmd.getTags(); FirewallRule.TrafficType trafficType = cmd.getTrafficType(); Account caller = CallContext.current().getCallingAccount(); List<Long> permittedAccounts = new ArrayList<Long>(); if (ipId != null) { IPAddressVO ipAddressVO = _ipAddressDao.findById(ipId); if (ipAddressVO == null || !ipAddressVO.readyToUse()) { throw new InvalidParameterValueException( "Ip address id=" + ipId + " not ready for firewall rules yet"); } _accountMgr.checkAccess(caller, null, true, ipAddressVO); } Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters( caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); Filter filter = new Filter(FirewallRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchBuilder<FirewallRuleVO> sb = _firewallDao.createSearchBuilder(); _accountMgr.buildACLSearchBuilder( sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); sb.and("id", sb.entity().getId(), Op.EQ); sb.and("trafficType", sb.entity().getTrafficType(), Op.EQ); if (cmd instanceof ListEgressFirewallRulesCmd) { networkId = ((ListEgressFirewallRulesCmd) cmd).getNetworkId(); sb.and("networkId", sb.entity().getNetworkId(), Op.EQ); } else { sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ); } sb.and("purpose", sb.entity().getPurpose(), Op.EQ); if (tags != null && !tags.isEmpty()) { SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder(); for (int count = 0; count < tags.size(); count++) { tagSearch .or() .op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); tagSearch.and( "value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); tagSearch.cp(); } tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); sb.groupBy(sb.entity().getId()); sb.join( "tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); } SearchCriteria<FirewallRuleVO> sc = sb.create(); _accountMgr.buildACLSearchCriteria( sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); if (id != null) { sc.setParameters("id", id); } if (tags != null && !tags.isEmpty()) { int count = 0; sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.FirewallRule.toString()); for (String key : tags.keySet()) { sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); count++; } } if (ipId != null) { sc.setParameters("ip", ipId); } else if (cmd instanceof ListEgressFirewallRulesCmd) { if (networkId != null) { sc.setParameters("networkId", networkId); } } sc.setParameters("purpose", Purpose.Firewall); sc.setParameters("trafficType", trafficType); Pair<List<FirewallRuleVO>, Integer> result = _firewallDao.searchAndCount(sc, filter); return new Pair<List<? extends FirewallRule>, Integer>(result.first(), result.second()); }