DynamicRuleActions

package com.spawnlabs.server.dmfs;

import com.spawnlabs.server.dmfs.iptables.DmfsExecuteException;

import com.spawnlabs.server.dmfs.iptables.DmfsExecuteResult;

import com.spawnlabs.server.dmfs.iptables.IptablesStateViolationException;

import com.spawnlabs.server.dmfs.iptables.RuleExecutionException;

import com.spawnlabs.server.dmfs.iptables.RuleExecutor;

import com.spawnlabs.server.dmfs.template.ITemplateMgr;

import com.spawnlabs.server.dmfs.template.MissingTemplateArgumentException;

import com.spawnlabs.server.dmfs.template.TemplateNotFoundException;

import com.spawnlabs.server.dmfs.template.TemplateReadingException;

import com.spawnlabs.server.spawnsvc.ConfigProperties;

import java.net.InetAddress;

import java.util.HashMap;

import java.util.Map;

import java.util.StringTokenizer;

import static com.spawnlabs.server.dmfs.DmfsNames.*;

import static com.spawnlabs.server.dmfs.template.TemplateUtil.CommandType.iptables;

import static com.spawnlabs.server.dmfs.template.TemplateUtil.CommandType.restore;

/**

*

*

*/

public class DynamicRuleActions {

public static final String ruleAlreadyTight = "This rule was already tight: ";

public static final String ruleAlreadyRelaxed = "This rule was already relaxed: ";

private ConfigProperties config;

private RuleExecutor ruleExecutor;

private ITemplateMgr templateMgr;

public DynamicRuleActions(ConfigProperties config, ITemplateMgr templateMgr, RuleExecutor ruleExecutor) {

this.config = config;

this.ruleExecutor = ruleExecutor;

this.templateMgr = templateMgr;

}

public DmfsExecuteResult fullPlaySessionStart(String token, InetAddress rips, InetAddress ripn, int lportn) throws

RuleExecutionException,

TemplateReadingException,

TemplateNotFoundException,

MissingTemplateArgumentException,

IptablesStateViolationException {

// Create map of args

HashMap<String, Object> args = new HashMap<String, Object>();

args.put(TOKEN, token);

args.put(RIPS, rips.getHostAddress());

args.put(RIPN, ripn.getHostAddress());

args.put(LPORTN, lportn);

args.put(LIPN, config.getProperty(LIPN));

args.put(LIPS, config.getProperty(LIPS));

args.put(RPORTS, config.getIntegerProperty(RPORTS));

args.put(LPORTS, config.getIntegerProperty(LPORTS));

String rules = templateMgr.getRulesFor(FULL_PLAY_SESSION, START, restore, args);

return ruleExecutor.applyStartRules(rules);

}

public DmfsExecuteResult fullPlaySessionTighten(String token, int rportn) throws

RuleExecutionException,

TemplateReadingException,

TemplateNotFoundException,

MissingTemplateArgumentException {

// List the existing rules

DmfsExecuteResult listResult = ruleExecutor.listForwardRules(token);

ParsedRuleValues parsedRuleValues = new ParsedRuleValues(listResult.getCommandOutput(), 3, 4);

if (parsedRuleValues.getLines().length == 4) {

// There is a relax rule in place. Re-tighten by deleting it.

return ruleExecutor.deleteForwardRuleForTightening(token);

} // else numLines == 3

// Parse the rules to determine: RIPN, RIPS, and RPORTS

parsedRuleValues.invoke();

if (parsedRuleValues.getRportn() != -1) {

// This rule is already tight. no-op

return new DmfsExecuteResult(listResult.getCommandOutput(), listResult.getCommandLine()).putMessage(ruleAlreadyTight + token);

}

// ==================================================================================================================

// There is no relax rule in place, and the existing rule is relaxed. Replace that rule with a tighter one

// ==================================================================================================================

// Assemble the substitution params for Velocity

// Create map of args

HashMap<String, Object> args = new HashMap<String, Object>();

args.put(TOKEN, token);

args.put(RIPN, parsedRuleValues.getRipn());

args.put(RPORTN, rportn);

args.put(RIPS, parsedRuleValues.getRips());

args.put(RPORTS, parsedRuleValues.getRports());

// Get the template parsed

String tightenRule = templateMgr.getRulesFor(FULL_PLAY_SESSION, TIGHTEN, iptables, args);

// Now execute the command to tighten

return ruleExecutor.replaceForwardRuleForTightening(token, tightenRule);

}

public DmfsExecuteResult fullPlaySessionRelax(String token) throws

TemplateReadingException,

RuleExecutionException,

TemplateNotFoundException,

MissingTemplateArgumentException {

// List the existing rules

DmfsExecuteResult listResult = ruleExecutor.listForwardRules(token);

ParsedRuleValues parsedRuleValues = new ParsedRuleValues(listResult.getCommandOutput(), 3, 4);

if (parsedRuleValues.getLines().length == 4) {

// 2 rules exist: no-op

return new DmfsExecuteResult(listResult.getCommandOutput(), listResult.getCommandLine()).putMessage(ruleAlreadyRelaxed + token);

}// else numLines == 3

// Parse the rules to determine: RIPN, RIPS, and RPORTS (and possibly RPORTN)

parsedRuleValues.invoke();

if (parsedRuleValues.getRportn() == -1) {

// There are 3 lines and 1 rule, but the rule is already relaxed (no "spt:" designated)

return new DmfsExecuteResult(listResult.getCommandOutput(), listResult.getCommandLine()).putMessage(ruleAlreadyRelaxed + token);

}

// ===============================================================================================

// There is no relax rule in place, and the existing rule is tightened. Insert a relax rule

// ===============================================================================================

// Assemble the substitution params for Velocity

// Create map of args

HashMap<String, Object> args = new HashMap<String, Object>();

args.put(TOKEN, token);

args.put(RIPN, parsedRuleValues.getRipn());

args.put(RIPS, parsedRuleValues.getRips());

args.put(RPORTS, parsedRuleValues.getRports());

// Get the template parsed

String relaxRule = templateMgr.getRulesFor(FULL_PLAY_SESSION, RELAX, iptables, args);

// Now execute the command to relax

return ruleExecutor.insertForwardRuleForRelaxing(token, relaxRule);

}

public DmfsExecuteResult fullPlaySessionStop(String token) throws

TemplateReadingException,

TemplateNotFoundException,

MissingTemplateArgumentException,

RuleExecutionException,

IptablesStateViolationException {

// Create map of args

HashMap<String, Object> args = new HashMap<String, Object>();

args.put(TOKEN, token);

String rules = templateMgr.getRulesFor(FULL_PLAY_SESSION, STOP, restore, args);

return ruleExecutor.applyStopRules(rules);

}

public DmfsExecuteResult fullPlaySessionQuery(String token, boolean showRoute) throws

TemplateReadingException,

TemplateNotFoundException,

MissingTemplateArgumentException,

RuleExecutionException,

IptablesStateViolationException {

// Create map of args

HashMap<String, Object> args = new HashMap<String, Object>();

args.put(TOKEN, token);

String rules = templateMgr.getRulesFor(FULL_PLAY_SESSION, QUERY, restore, args);

DmfsExecuteResult result;

try {

result = ruleExecutor.queryPlaySession(rules);

} catch (IptablesStateViolationException e) {

if (e.getCode() == DmfsOperationException.IPTABLES_CONNECTION_DOESNT_EXIST) {

// If we get this exception, throw an exception just like the one we caught, except

// modify the message to include the token (which, at that level in the stack, we didn't know)

throw new IptablesStateViolationException(e.getCode(), (DmfsExecuteException) e.getCause(), "No connection exists for token: [" + token + "]", e.getRules());

}

throw e;

}

/* Sample output:

Chain XYZ (2 references)

num pkts bytes target prot opt in out source destination

1 0 0 DNAT udp -- * * 0.0.0.0/0 10.0.11.75 udp dpt:64600 to:10.0.111.76:64200

2 0 0 DNAT tcp -- * * 0.0.0.0/0 10.0.11.75 tcp dpt:64600 to:10.0.111.76:64200

3 0 0 SNAT udp -- * * 0.0.0.0/0 10.0.111.76 udp dpt:64200 to:10.0.111.75:64400

4 0 0 SNAT tcp -- * * 0.0.0.0/0 10.0.111.76 tcp dpt:64200 to:10.0.111.75:64400

Chain XYZ (1 references)

num pkts bytes target prot opt in out source destination

1 0 0 ACCEPT udp -- * * 10.0.11.75 10.0.111.76 udp dpt:64200

*/

result.setMessage(result.getMessage() + " | " + result.getCommandOutput());

if (showRoute) {

}

return result; // SERVER-569

}

public DmfsExecuteResult queryAllPlaySessions() throws RuleExecutionException {

DmfsExecuteResult result = ruleExecutor.queryAllPlaySessions();

boolean hasConnections = false;

for (String key : result.getExtraValues().keySet()) {

if (key.startsWith(DmfsNames.TOKEN_PREFIX)) {

hasConnections = true;

}

}

if (!hasConnections) {

result.setMessage("No active connections.");

}

return result;

}

public DmfsExecuteResult applyRuleTemplate(String connectionClass, String templateName, Map<String, String> params) {

return null;

}

protected static class ParsedRuleValues {

private String existingRules;

private final int minNumRules;

private final int maxNumRules;

private String sourceIp;

private String destIp;

private int destPort;

private int srcPort = -1;

private String[] lines;

public ParsedRuleValues(String existingRules, int minNumRules, int maxNumRules) throws TemplateReadingException {

this.existingRules = existingRules;

this.minNumRules = minNumRules;

this.maxNumRules = maxNumRules;

lines = getLines();

}

public String getRipn() {

return sourceIp;

}

public String getRips() {

return destIp;

}

public int getRports() {

return destPort;

}

public int getRportn() {

return srcPort;

}

public ParsedRuleValues invoke() throws TemplateReadingException, RuleExecutionException {

try {

return parse();

} catch (NumberFormatException e) {

throw new TemplateReadingException(DmfsProcessException.TEMPLATE_PARSING_EXCEPTION,

e,

"There was a problem parsing out RIPN, RIPS, and RPORTS from the template. This could be a " +

"code problem, or could be that the rule list is incorrectly-formed. Existing Rules: " +

"[" + existingRules + "]");

}

}

public ParsedRuleValues parse() throws RuleExecutionException {

int i;

for (i = 0; i < lines.length; i++) {

String s = lines[i];

if (s.startsWith(RuleExecutor.ARG_RULENUM)) {

break;

}

}

sourceIp = null;

destIp = null;

destPort = -1;

StringTokenizer st = new StringTokenizer(lines[i], SPC, false);

while (st.hasMoreElements()) {

String t = (String) st.nextElement();

if (t.contains(".")) {

if (sourceIp == null) {

sourceIp = t;

}

else {

destIp = t;

}

}

else if (t.startsWith("dpt:")) {

destPort = Integer.parseInt(t.substring("dpt:".length(), t.length()));

}

else if (t.startsWith("spt:")) {

srcPort = Integer.parseInt(t.substring("spt:".length(), t.length()));

}

}

return this;

}

private String[] getLines() throws TemplateReadingException {

if (lines == null) {

lines = existingRules.split(ls);

if (lines.length < minNumRules || lines.length > maxNumRules) {

throw new TemplateReadingException(DmfsProcessException.TEMPLATE_PARSING_EXCEPTION,

"Listed lines were expected to be between: " + minNumRules + " and " + maxNumRules + ". Instead, were " + lines.length + ". Full rules: [" + existingRules + "]",

true);

}

}

return lines;

}

}

}