Commit 72fa735e authored by Leigh Stoller's avatar Leigh Stoller

Work on firewall support:

1. Get this working on the NS conversion path.

2. Add support for additional firewall rules along the path,
   the CM never had support for firewall rules.

3. Set the security_level to zapdisk when firewalling is on.
parent c624d741
......@@ -816,6 +816,9 @@ sub new($$$$$)
"routable_control_ip" => undef,
"failure_action" => undef,
"tag" => $tag,
"isexptfirewall" => 0,
"firewall_style" => undef,
"firewall_rules" => [],
};
bless($self, $class);
return $self;
......@@ -829,6 +832,8 @@ sub ifaces($) { return $_[0]->{'ifaces'}; }
sub ifacelist($) { return $_[0]->{'ifacelist'}; }
sub services($) { return $_[0]->{'services'}; }
sub pipes($) { return $_[0]->{'pipes'}; }
sub firewall_style($) { return $_[0]->{'firewall_style'}; }
sub firewall_rules($) { return $_[0]->{'firewall_rules'}; }
sub tag($) { return $_[0]->{'tag'}; }
sub fatal($) { return APT_Rspec::fatal($_[0]); }
sub GetTextOrFail($$) { return APT_Rspec::GetTextOrFail(@_); }
......@@ -908,6 +913,25 @@ sub addNode($$$)
}
}
if ($sliver_type eq "firewall") {
#
# We need the firewall section from sliver_type
#
my $config = GeniXML::GetExperimentFirewallSettings($noderef);
if (!$config) {
fatal("No configuration for firewall node");
}
$node->{'isexptfirewall'} = 1;
$node->{'firewall_style'} = $config->{'style'};
foreach my $rule (@{$config->{'rules'}}) {
# Trim for rtecheck.
$rule =~ s/^\s+//;
$rule =~ s/\s+$//s;
push(@{ $node->{'firewall_rules'}}, $rule);
}
}
#
# Scan all the attributes.
#
......@@ -1039,7 +1063,7 @@ sub addNode($$$)
$node->{"xen_settings"} = $settings;
last SWITCH;
};
/^sliver_type_shaping$/i && do {
/^(sliver_type_shaping|firewall_config)$/i && do {
# We handled this above.
last SWITCH;
};
......@@ -1215,6 +1239,7 @@ sub Compare($$)
(/^(component_id|component_manager_id|disk_image)$/i ||
/^(hardware_type|jacks_site|xen_ptype|instantiate_on)$/i ||
/^(adb_target|failure_action)$/i ||
/^(isexptfirewall|firewall_style)$/i ||
/^(use_type_default_image|routable_control_ip)$/i) && do {
return 1
if (APT_Rspec::CompareValues("Node: $client_id: $key",
......@@ -1236,7 +1261,7 @@ sub Compare($$)
if (APT_Rspec::CompareLists("service", $val1, $val2));
last SWITCH;
};
/^(tag|statements)$/i && do {
/^(tag|statements|firewall_rules)$/i && do {
last SWITCH;
};
print STDERR "Node:Compare: Unknown attribute: $key\n";
......
......@@ -124,7 +124,26 @@ lanifaces = {}
ifacecounts = {}
bridged = {}
programs = {}
firewall = None
#
# Need to know which node is the experiment firewall.
#
for child in tree.getroot():
if child.tag == "virt_firewalls":
row = child.find("row")
fwname = row.find("fwname").text
style = row.find("style").text
if firewall:
Fatal("Only one experiment firewall allowed");
pass
firewall = rspec.ExperimentFirewall(fwname, style);
pass
pass
#
# Now process nodes and a few other things.
#
for child in tree.getroot():
if child.tag == "virt_nodes":
row = child.find("row")
......@@ -150,6 +169,10 @@ for child in tree.getroot():
elif ntype == "blockstore":
node = IG.RemoteBlockstore(vname, "/mnt", "eth0")
node.exclusive = True
elif firewall and firewall.client_id == vname:
# We created the firewall above.
node = firewall;
node.exclusive = True
else:
node = RSpec.RawPC(vname)
node.hardware_type = ntype
......@@ -220,7 +243,9 @@ for child in tree.getroot():
pass
pass
nodes[vname] = node
rspec.addResource(node)
if not (firewall and firewall.client_id == vname):
rspec.addResource(node)
pass
pass
#
# We need to know how many members, so we can create a geni-lib Link or LAN.
......@@ -684,8 +709,9 @@ for child in tree.getroot():
pass
#
# A bunch of things we do not support yet.
# We ignore security_level for now, it gets set for an explicit firewall.
#
for tag in ["jail_osname", "security_level"]:
for tag in ["jail_osname"]:
if row.find(tag) != None:
Fatal("Unsupported use of " + tag)
pass
......@@ -754,6 +780,23 @@ for child in tree.getroot():
raw.attrib["attrvalue"] = val
nodes[vname].addRawElement(raw)
pass
if child.tag == "firewall_rules":
#
# Note that we are ignoring the security level. Not really sure if it
# makes any sense these days. The CM will set it if needed.
#
row = child.find("row")
fwname = row.find("fwname").text
fwrule = row.find("rule").text
ruleno = row.find("ruleno").text
if not fwname in nodes:
Fatal("No such firwall node " + fwname);
pass
if not firewall:
Fatal("Firewall rule for nonexistent firewall " + fwname);
pass
firewall.addRule(fwrule);
pass
if child.tag == "virt_trafgens":
Fatal("Trafgens are not supported anymore")
pass
......@@ -763,7 +806,6 @@ for child in tree.getroot():
if child.tag in ["virt_lan_settings",
"virt_lan_member_settings", "virt_routes",
"virt_node_disks",
"virt_firewalls", "firewall_rules",
"virt_tiptunnels", "elabinelab_attributes",
"virt_paths", "experiment_blobs", "virt_blobs",
"virt_client_service_ctl", "virt_client_service_hooks",
......
......@@ -223,6 +223,16 @@ sub GenerateNodeStatements($)
if (defined($p->lossrate()));
}
}
elsif ($ntype eq "firewall") {
my $fwstyle = $node->firewall_style();
$node->addStatement(
"$ntag = request.ExperimentFirewall('$client_id','$fwstyle')");
foreach my $fwrule (@{$node->firewall_rules()}) {
$node->addTagStatement("addRule('$fwrule')");
}
}
elsif ($ntype eq "emulab-blockstore") {
# attributes.
my $bstore = $node->{'blockstores'}->{$client_id};
......
......@@ -1557,18 +1557,38 @@ sub GetTicketAuxAux($$$$$$$$$$$)
$nodeblob->{'role'} = "bridge";
}
elsif ($isfirewall) {
my $config = GeniXML::GetExperimentFirewallSettings($ref);
if (!defined($config)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Missing firewall configuration");
goto bad;
}
if ($slice->SetFirewallFlag(1) != 0) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
# This is default for all firewalled experiments.
$virtexperiment->security_level(TBDB_SECLEVEL_ZAPDISK());
if (!defined($virtexperiment->NewTableRow("virt_firewalls",
{"fwname" => $node_nickname,
"type" => "iptables-vlan",
"style" => "basic"}))) {
{"fwname" => $node_nickname,
"type" => "iptables-vlan",
"style" => $config->{'style'}}))) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Error creating firewall definition");
goto bad;
}
my $ruleno = 100;
foreach my $rule (@{ $config->{'rules'} }) {
if (!defined($virtexperiment->NewTableRow("firewall_rules",
{"fwname" => $node_nickname,
"ruleno" => $ruleno++,
"rule" => $rule}))) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Error creating firewall rule");
goto bad;
}
}
}
# Program agents.
if (my @progagents = GeniXML::GetProgramAgents($ref)) {
......
......@@ -1116,6 +1116,35 @@ sub GetElabInElabSettings($)
return $result;
}
#
# Experiment firewalls are different then node firewalls
#
sub GetExperimentFirewallSettings($)
{
my ($node) = @_;
my $style = "basic";
my @rules = ();
my $type = FindFirst("n:sliver_type", $node);
return undef
if (!defined($type));
my $settings = FindNodesNS("n:firewall_config", $type, $EMULAB_NS)->pop();
return undef
if (!defined($settings));
my $tmp = GetText("style", $settings);
$style = $tmp
if (defined($tmp));
foreach my $ruleref (FindNodesNS("n:rule", $settings,
$EMULAB_NS)->get_nodelist()) {
my $rule = $ruleref->textContent();
push(@rules, $rule);
}
return { "style" => $style, "rules" => \@rules };
}
sub HasFirewallSettings($)
{
my ($node) = @_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment