Commit 0527441a authored by Mike Hibler's avatar Mike Hibler

Initial steps toward a hardware-assisted (switch VLAN) firewall implementation.

This checkin adds the necessary NS and client-side changes.

You get such a firewall by creating a firewall object and doing:

	$fw set-type ipfw2-vlan

In addition to the usual firewall setup, it sets the firewall node command
line to boot "/kernel.fw" which is an IPFW2-enabled kernel with a custom
bridge hack.

The client-side setup for firewalled nodes is easy: do nothing.

The client-side setup for the firewall is more involved, using vlan devices
and bridging and all sorts of geeky magic.

Note finally that I don't yet have a decent set of default rules for anything
other than a completely open firewall.  The rules might be slightly different
than for the "software" firewall since they are applied at layer2 (and we want
them just to be applied at layer2 and not multiple times)
parent ed8262c1
......@@ -56,7 +56,7 @@ CREATE TABLE current_reloads (
--
CREATE TABLE default_firewall_rules (
type enum('ipfw','ipfw2','ipchains') NOT NULL default 'ipfw',
type enum('ipfw','ipfw2','ipchains','ipfw2-vlan') NOT NULL default 'ipfw',
style enum('open','closed','basic') NOT NULL default 'basic',
enabled tinyint(4) NOT NULL default '0',
ruleno int(10) unsigned NOT NULL default '0',
......@@ -396,8 +396,9 @@ CREATE TABLE firewalls (
pid varchar(12) NOT NULL default '',
eid varchar(32) NOT NULL default '',
fwname varchar(32) NOT NULL default '',
type enum('ipfw','ipfw2','ipchains') NOT NULL default 'ipfw',
type enum('ipfw','ipfw2','ipchains','ipfw2-vlan') NOT NULL default 'ipfw',
style enum('open','closed','basic') NOT NULL default 'basic',
vlan int(11) default NULL,
PRIMARY KEY (pid,eid,fwname)
) TYPE=MyISAM;
......
......@@ -652,7 +652,7 @@ REPLACE INTO table_regex VALUES ('virt_lan_lans','vname','text','redirect','virt
REPLACE INTO table_regex VALUES ('firewalls','pid','text','redirect','projects:pid',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewalls','eid','text','redirect','experimenets:eid',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewalls','fwname','text','redirect','virt_nodes:vname',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewalls','type','text','regex','^(ipfw|ipfw2|ipchains)$',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewalls','type','text','regex','^(ipfw|ipfw2|ipchains|ipfw2-vlan)$',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewalls','style','text','regex','^(open|closed|basic)$',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewall_rules','pid','text','redirect','projects:pid',0,0,NULL);
REPLACE INTO table_regex VALUES ('firewall_rules','eid','text','redirect','experimenets:eid',0,0,NULL);
......
......@@ -2054,3 +2054,33 @@ last_net_act,last_cpu_act,last_ext_act);
alter table nodes add cd_version varchar(32) default NULL;
1.278: Add partial support for hardware control net vlan implementation of
firewalls. The code to manipulate the control net switch has not
yet been done and will no doubt lead to more DB changes. The hardware
assisted firewall is done at the moment by specifying a different type
'ipfw2-vlan'.
Note that you will need a FBSD410-IPFW2 image which is a standard
image but with an IPFW2 enabled kernel and new versions of ipfw and
libaliases (as mentioned in the ipfw man page).
alter table default_firewall_rules change type type \
enum('ipfw','ipfw2','ipchains','ipfw2-vlan') not null default 'ipfw';
alter table firewalls change type type \
enum('ipfw','ipfw2','ipchains','ipfw2-vlan') not null default 'ipfw';
alter table firewalls add vlan int(11) default NULL;
update table_regex set check='^(ipfw|ipfw2|ipchains|ipfw2-vlan)$' \
where table_name='firewalls' and column_name='type';
INSERT INTO os_info VALUES ('FW-IPFW2','emulab-ops','FW-IPFW2', \
'root',NULL,'IPFW2 Firewall','FreeBSD','',NULL,'FreeBSD','', \
'ping,ssh,ipod,isup,veths,mlinks',0,1,1,'NORMAL', \
'emulab-ops-FBSD410-IPFW2',NULL,0);
INSERT INTO os_info VALUES ('FBSD410-IPFW2','emulab-ops', \
'emulab-ops-FBSD410-IPFW2','root',NULL, \
'FreeBSD 4.10 with IPFW2','FreeBSD','4.10',NULL,NULL,'', \
'ping,ssh,ipod,isup,veths,mlinks',1,1,1,'NORMALv2',NULL,NULL,0);
......@@ -25,4 +25,6 @@ INSERT INTO default_firewall_rules VALUES ('ipfw','basic',1,55400,'allow tcp fro
INSERT INTO default_firewall_rules VALUES ('ipfw','basic',1,55401,'allow tcp from 155.98.36.0/22 to me 16534');
INSERT INTO default_firewall_rules VALUES ('ipfw','basic',1,55500,'allow udp from 224.4.0.0/16 2917 to 224.4.0.0/16 2917');
INSERT INTO default_firewall_rules VALUES ('ipfw','basic',1,65534,'deny ip from any to any');
INSERT INTO default_firewall_rules VALUES ('ipfw2-vlan','open',1,65534,'allow all from any to any');
INSERT INTO default_firewall_rules VALUES ('ipfw2-vlan','closed',1,65534,'deny all from any to any');
......@@ -22,8 +22,11 @@ Firewall instproc init {s} {
$self set sim $s
$self set style "basic"
$self set parent ""
$self set type "ipfw"
$self set style "basic"
$self set osid "FW-IPFW"
$self set cmdline ""
$self set parent ""
$self set next_rule 1
$self instvar rules
......@@ -41,6 +44,34 @@ Firewall instproc rename {old new} {
$sim rename_firewall $old $new
}
#
# Set the type of the firewall
#
Firewall instproc set-type {targ} {
$self instvar type
$self instvar osid
$self instvar cmdline
switch -- $targ {
"ipfw" {
set type $targ
set osid "FW-IPFW"
}
"ipfw2-vlan" {
set type $targ
set osid "FW-IPFW2"
set cmdline "/kernel.fw"
}
"ipfw2" -
"ipchains" {
perror "\[set-type] firewall type $targ not yet implemented"
}
default {
perror "\[set-type] unknown firewall type: $targ"
}
}
}
#
# Set the style of the firewall
#
......@@ -50,7 +81,7 @@ Firewall instproc set-style {starg} {
if {$starg == "open" || $starg == "closed" || $starg == "basic"} {
set style $starg
} else {
punsup "firewall: unsupported style: $starg"
perror "\[set-style] unsupported firewall style: $starg"
}
}
......@@ -106,12 +137,15 @@ Firewall instproc updatedb {DB} {
var_import ::GLOBALS::eid
$self instvar rules
$self instvar sim
$self instvar type
$self instvar style
$self instvar osid
$self instvar cmdline
# XXX add the firewall to the virt_nodes table to avoid assign hacking
$sim spitxml_data "virt_nodes" [list "vname" "type" "ips" "osname" "cmd_line" "rpms" "startupcmd" "tarfiles" "fixed" ] [list "$self" "pc" "" "FW-IPFW" "" "" "" "" "" ]
$sim spitxml_data "virt_nodes" [list "vname" "type" "ips" "osname" "cmd_line" "rpms" "startupcmd" "tarfiles" "fixed" ] [list "$self" "pc" "" $osid $cmdline "" "" "" "" ]
$sim spitxml_data "firewalls" [list "fwname" "type" "style"] [list $self "ipfw" $style]
$sim spitxml_data "firewalls" [list "fwname" "type" "style"] [list $self $type $style]
foreach rule [array names rules] {
set names [list "fwname" "ruleno" "rule"]
set vals [list $self $rule $rules($rule)]
......
......@@ -110,6 +110,15 @@ sub doboot()
exit(0);
}
#
# Common case: no firewall, bug out
#
if ($fwinfo->{TYPE} eq "none") {
print "No firewall\n"
if ($debug);
exit(0);
}
print "Setting up firewall\n";
#
......@@ -121,12 +130,6 @@ sub doboot()
print FWC "# auto-generated by $BINDIR/rc/rc.firewall, DO NOT EDIT\n";
print FWC "if [ x\$1 = x ]; then action=enable; else action=\$1; fi\n";
if ($fwinfo->{TYPE} eq "none") {
print "No firewall\n"
if ($debug);
exit(0);
}
#
# If TYPE is not "remote", we ourselves are a firewall
#
......@@ -136,6 +139,10 @@ sub doboot()
$rc = firewaller();
last SWITCH;
};
/^ipfw2-vlan$/i && do {
$rc = firewaller();
last SWITCH;
};
/^remote$/i && do {
last SWITCH;
};
......@@ -188,7 +195,7 @@ sub firewaller()
#
# Configuration for a firewalled node.
#
# With a transparent firewall, there would be nothing to do here.
# For a "transparent" firewall, there is nothing to do.
#
# However, in our "all volunteer" firewall model, we must replace our
# default route with one leading to the firewall node. Before doing that,
......@@ -197,6 +204,14 @@ sub firewaller()
#
sub firewallee()
{
#
# XXX a firewall IP of 0 implies a transparent firewall
#
if ($fwinfo->{FWIP} eq "0.0.0.0") {
print FWC "true\n";
return 0;
}
my $orouter = `cat $BOOTDIR/routerip`;
chomp($orouter);
......
......@@ -856,11 +856,11 @@ sub getfwconfig($$)
}
my $rempat = q(TYPE=remote FWIP=([0-9\.]*));
my $fwpat = q(TYPE=(\w+) STYLE=(\w+) IN_IF=(\w*) OUT_IF=(\w*));
my $fwpat = q(TYPE=([\w-]+) STYLE=(\w+) IN_IF=(\w*) OUT_IF=(\w*) IN_VLAN=(\d+) OUT_VLAN=(\d+));
my $rpat = q(RULENO=(\d*) RULE="(.*)");
foreach my $line (@tmccresults) {
if ($line =~ /TYPE=(\w+)/) {
if ($line =~ /TYPE=([\w-]+)/) {
my $type = $1;
if ($type eq "none") {
$fwinfo->{"TYPE"} = $type;
......@@ -877,13 +877,20 @@ sub getfwconfig($$)
my $style = $2;
my $inif = $3;
my $outif = $4;
my $invlan = $5;
my $outvlan = $6;
$fwinfo->{"TYPE"} = $type;
$fwinfo->{"STYLE"} = $style;
$fwinfo->{"IN_IF"} = $inif;
$fwinfo->{"OUT_IF"} = $outif;
$fwinfo->{"IN_VLAN"} = $invlan
if ($invlan != 0);
$fwinfo->{"OUT_VLAN"} = $outvlan
if ($outvlan != 0);
} else {
warn("*** WARNING: Bad firewall info line: $line\n");
return 1;
}
} elsif ($line =~ /$rpat/) {
my $ruleno = $1;
......@@ -895,6 +902,7 @@ sub getfwconfig($$)
push(@fwrules, $fw);
} else {
warn("*** WARNING: Bad firewall info line: $line\n");
return 1;
}
}
......
......@@ -521,7 +521,55 @@ sub os_fwconfig_line($@)
my ($fwinfo, @fwrules) = @_;
my ($upline, $downline);
$upline = "kldload ipfw.ko >/dev/null 2>&1\n";
#
# VLAN enforced layer2 firewall with FreeBSD/IPFW2
#
if ($fwinfo->{TYPE} eq "ipfw2-vlan") {
if (!defined($fwinfo->{IN_VLAN})) {
warn "*** WARNING: no VLAN for ipfw2-vlan firewall, NOT SETUP!\n";
return ("false", "false");
}
my $vlandev = "vlan0";
my $vlanno = $fwinfo->{IN_VLAN};
my $pdev = `$BINDIR/findif $fwinfo->{IN_IF}`;
chomp($pdev);
$upline = "ifconfig $vlandev create link vlan $vlanno vlandev $pdev\n";
$upline .= " if [ -z \"`sysctl net.link.ether.bridge 2>/dev/null`\" ]; then\n";
$upline .= " kldload bridge.ko >/dev/null 2>&1\n";
$upline .= " fi\n";
$upline .= " sysctl net.link.ether.bridge_vlan=0\n";
$upline .= " sysctl net.link.ether.bridge_ipfw=1\n";
$upline .= " sysctl net.link.ether.bridge_cfg=$vlandev,$pdev\n";
$upline .= " if [ -z \"`sysctl net.inet.ip.fw.enable 2>/dev/null`\" ]; then\n";
$upline .= " kldload ipfw.ko >/dev/null 2>&1\n";
$upline .= " fi\n";
foreach my $rule (sort { $a->{RULENO} <=> $b->{RULENO}} @fwrules) {
$upline .= " ipfw add $rule->{RULENO} $rule->{RULE} || {\n";
$upline .= " echo 'WARNING: could not load ipfw rule:'\n";
$upline .= " echo ' $rule->{RULE}'\n";
$upline .= " exit 1\n";
$upline .= " }\n";
}
$upline .= " sysctl net.link.ether.bridge=1";
$downline = "sysctl net.link.ether.bridge=0\n";
$downline .= " ipfw -q flush\n";
$downline .= " sysctl net.link.ether.bridge_cfg=\"\"\n";
$downline .= " sysctl net.link.ether.bridge_ipfw=0\n";
$downline .= " sysctl net.link.ether.bridge_vlan=1\n";
$downline .= " ifconfig $vlandev destroy";
return ($upline, $downline);
}
#
# Voluntary IP firewall with FreeBSD/IPFW
#
$upline = "if [ -z \"`sysctl net.inet.ip.fw.enable 2>/dev/null`\" ]; then\n";
$upline .= " kldload ipfw.ko >/dev/null 2>&1\n";
$upline .= " fi\n";
foreach my $rule (sort { $a->{RULENO} <=> $b->{RULENO}} @fwrules) {
$upline .= " ipfw add $rule->{RULENO} $rule->{RULE} || {\n";
$upline .= " echo 'WARNING: could not load ipfw rule:'\n";
......
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