Commit 798f9b6f authored by David Johnson's avatar David Johnson

Add Linux exp firewall support for virt_node_public_addr addresses.

A new tmcd command, publicaddrinfo, just dumps the relevant bits of
virt_node_public_addr to any node in an experiment that has addrs
allocated (we don't want to restrict based on calling node_id or
pool_id).

Then the generic getfwconfig() function calls that, and sets some bits.
I also extended this function to add some dynamic clientside vars
(EMULAB_DOMAIN, EMULAB_EXPDOMAIN, EMULAB_PUBLICADDRS) so that user
firewall rule writers can use them to refer to the control net IPs of
nodes in their experiment (i.e., node-0.EMULAB_EXPDOMAIN); and so that
rules can be written over EMULAB_PUBLICADDRS -- a command-delineated
list of IP addrs).

Finally, I extended the Linux firewalling code to allow any experiment
node to answer ARPs for the public IP addresses; we can't know a priori
which node should answer -- and it could change.

This closes #353 .
parent 754069d2
......@@ -2760,6 +2760,52 @@ sub getfwconfig($$;$)
}
}
@tmccresults = ();
if (tmcc(TMCCCMD_PUBLICADDRINFO, undef, \@tmccresults) < 0) {
warn("*** WARNING: Could not get public addr info from server;".
" ignoring!\n");
}
else {
my @publicaddrs = ();
my $papat = q(IP="([0-9\.]+)" MASK="([0-9\.]*)" NODE_ID="([-\w]*)" POOL_ID="([-\w]*)");
foreach my $line (@tmccresults) {
if ($line =~ /$papat/) {
# Just pass along the IP address for now; it's unclear
# what the node_id and pool_id should mean to the
# firewall. So just treat all publicaddrs as equal.
push(@publicaddrs,$1);
}
else {
warn("*** WARNING: Bad public addr info line: $line\n");
}
}
$fwinfo->{"PUBLICADDRS"} = \@publicaddrs;
$fwvars{"EMULAB_PUBLICADDRS"} = join(",",@publicaddrs);
}
#
# Define the local experiment domain so that people can use
# nickname-based FQDNs to refer to the control net IPs of nodes.
#
my $mydomain = `cat $BOOTDIR/mydomain`;
chomp($mydomain);
if (!defined($fwvars{"EMULAB_EXPDOMAIN"})) {
my $nickname = `cat $BOOTDIR/nickname`;
chomp($nickname);
if ($nickname =~ /[^.]+\.(.+)/) {
$fwvars{"EMULAB_EXPDOMAIN"} = "${1}.${mydomain}";
}
}
#
# Define the local cluster domain so that people can use FQDNs to
# refer to the control net IPs of key servers.
#
if (!defined($fwvars{"EMULAB_DOMAIN"})) {
my $mydomain = `cat $BOOTDIR/mydomain`;
chomp($mydomain);
$fwvars{"EMULAB_DOMAIN"} = $mydomain;
}
#
# XXX inner elab: make sure we have "myops" and "myfs" entries.
#
......
......@@ -54,7 +54,7 @@ use Exporter;
TMCCCMD_TPMBLOB TMCCCMD_TPMPUB TMCCCMD_DHCPDCONF TMCCCMD_MANIFEST
TMCCCMD_NODEUUID TMCCCMD_NODEATTRIBUTES TMCCCMD_DISKS
TMCCCMD_ARPINFO TMCCCMD_STORAGE TMCCCMD_IMAGESIZE
TMCCCMD_PNETNODEATTRS TMCCCMD_SERVINCEINFO
TMCCCMD_PNETNODEATTRS TMCCCMD_SERVINCEINFO TMCCCMD_PUBLICADDRINFO
);
# Must come after package declaration!
......@@ -223,6 +223,7 @@ my %commandset =
"imagesize" => {TAG => "imagesize"},
"pnetnodeattrs" => {TAG => "pnetnodeattrs"},
"serviceinfo" => {TAG => "serviceinfo"},
"publicaddrinfo" => {TAG => "publicaddrinfo"},
);
#
......@@ -301,6 +302,7 @@ sub TMCCCMD_STORAGE() { $commandset{"storageconfig"}->{TAG}; }
sub TMCCCMD_IMAGESIZE() { $commandset{"imagesize"}->{TAG}; }
sub TMCCCMD_PNETNODEATTRS() {$commandset{"pnetnodeattrs"}->{TAG}; }
sub TMCCCMD_SERVINCEINFO() {$commandset{"serviceinfo"}->{TAG}; }
sub TMCCCMD_PUBLICADDRINFO(){ $commandset{"publicaddrinfo"}->{TAG}; }
#
# Caller uses this routine to set configuration of this library
......
......@@ -1546,7 +1546,7 @@ sub os_fwconfig_line($@) {
#
# Setup proxy ARP entries.
#
if (defined($fwinfo->{MACS})) {
if (defined($fwinfo->{MACS}) || defined($fwinfo->{PUBLICADDRS})) {
$upline .= "ebtables -t nat -F PREROUTING\n";
# publish servers (including GW) on inside and for us on outside
if (defined($fwinfo->{SRVMACS})) {
......@@ -1560,6 +1560,7 @@ sub os_fwconfig_line($@) {
}
# provide node MACs to outside
if (defined($fwinfo->{MACS})) {
my $href = $fwinfo->{MACS};
while (my ($node,$mac) = each %$href) {
my $ip = $fwinfo->{IPS}{$node};
......@@ -1568,10 +1569,33 @@ sub os_fwconfig_line($@) {
"--arp-ip-dst $ip -j arpreply " .
"--arpreply-mac $mac\n";
}
}
$upline .= "ebtables -t nat -A PREROUTING -p ARP " .
"--arp-ip-dst $myip -j ACCEPT\n";
#
# Enable proxy arp for PUBLICADDRS, but only
# allow requests/replies for them. This allows
# the PUBLICADDRS to be used by any physical
# node in the expt, which is what we want by
# default.
#
if (defined($fwinfo->{PUBLICADDRS})) {
$upline .= "echo 1 > /proc/sys/net/ipv4/conf/br0/proxy_arp\n";
foreach my $pip (@{$fwinfo->{PUBLICADDRS}}) {
$upline .= "ip ro add $pip/32 dev br0\n";
$upline .= "ebtables -t nat -A PREROUTING " .
"-i $pdev -p ARP --arp-opcode Request " .
"--arp-ip-dst $pip -j ACCEPT\n";
$upline .= "ebtables -t nat -A PREROUTING " .
"-i $vlandev -p ARP --arp-opcode Reply " .
"--arp-ip-src $pip -j ACCEPT\n";
$downline .= "ip ro del $pip/32 dev br0\n";
}
$downline .= "echo 0 > /proc/sys/net/ipv4/conf/br0/proxy_arp\n";
}
$upline .= "ebtables -t nat -A PREROUTING -p ARP -j DROP\n";
if ($dotcpdump) {
......
......@@ -402,6 +402,7 @@ COMMAND_PROTOTYPE(doimagesize);
COMMAND_PROTOTYPE(dopnetnodeattrs);
COMMAND_PROTOTYPE(doserviceinfo);
COMMAND_PROTOTYPE(dosubbossinfo);
COMMAND_PROTOTYPE(dopublicaddrinfo);
#if PROTOGENI_SUPPORT
COMMAND_PROTOTYPE(dogeniclientid);
COMMAND_PROTOTYPE(dogenisliceurn);
......@@ -541,6 +542,7 @@ struct command {
{ "pnetnodeattrs", FULLCONFIG_NONE, F_ALLOCATED, dopnetnodeattrs},
{ "serviceinfo", FULLCONFIG_NONE, 0, doserviceinfo },
{ "subbossinfo", FULLCONFIG_NONE, 0, dosubbossinfo },
{ "publicaddrinfo", FULLCONFIG_NONE, F_ALLOCATED, dopublicaddrinfo },
#if PROTOGENI_SUPPORT
{ "geni_client_id", FULLCONFIG_NONE, 0, dogeniclientid },
{ "geni_slice_urn", FULLCONFIG_NONE, 0, dogenisliceurn },
......@@ -14168,3 +14170,44 @@ COMMAND_PROTOTYPE(dosubbossinfo)
return 0;
}
/*
* Return virt_node_public_addr dump to any node in an experiment.
*/
COMMAND_PROTOTYPE(dopublicaddrinfo)
{
MYSQL_RES *res;
MYSQL_ROW row;
int nrows = 0;
char buf[MYBUFSIZE];
char *bufp = buf, *ebufp = &buf[sizeof(buf)];
res = mydb_query("select IP,mask,node_id,pool_id"
" from virt_node_public_addr"
" where pid='%s' and eid='%s'",
4, reqp->pid, reqp->eid);
if (!res) {
error("dopublicaddrinfo: %s: "
"DB Error checking for experiment public addrs\n",
reqp->nodeid);
return 1;
}
if (mysql_num_rows(res) == 0) {
mysql_free_result(res);
return 0;
}
nrows = (int)mysql_num_rows(res);
while (nrows-- > 0) {
row = mysql_fetch_row(res);
bufp += OUTPUT(bufp, ebufp - buf,
"IP=\"%s\" MASK=\"%s\" NODE_ID=\"%s\""
" POOL_ID=\"%s\"\n",
row[0],row[1] ? row[1] : "",row[2] ? row[2] : "",
row[3] ? row[3] : "");
}
mysql_free_result(res);
client_writeback(sock, buf, strlen(buf), tcp);
return 0;
}
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