diff --git a/sql/database-create.sql b/sql/database-create.sql index 9e21a1b7ae0af4192241658b07e7a025255c430d..8fafaa231fa9f421555607e1d9123042d50cd7c4 100644 --- a/sql/database-create.sql +++ b/sql/database-create.sql @@ -507,7 +507,7 @@ CREATE TABLE `datapository_databases` ( DROP TABLE IF EXISTS `default_firewall_rules`; CREATE TABLE `default_firewall_rules` ( - `type` enum('ipfw','ipfw2','iptables','ipfw2-vlan','iptables-vlan') NOT NULL default 'ipfw', + `type` enum('ipfw','ipfw2','iptables','ipfw2-vlan','iptables-vlan','iptables-dom0','iptables-domU') NOT NULL default 'ipfw', `style` enum('open','closed','basic','emulab') NOT NULL default 'basic', `enabled` tinyint(4) NOT NULL default '0', `ruleno` int(10) unsigned NOT NULL default '0', @@ -4957,6 +4957,8 @@ CREATE TABLE `virt_nodes` ( `numeric_id` int(11) default NULL, `sharing_mode` varchar(32) default NULL, `role` enum('node','bridge') NOT NULL default 'node', + `firewall_style` tinytext, + `firewall_log` tinytext, PRIMARY KEY (`exptidx`,`vname`), UNIQUE KEY `pideid` (`pid`,`eid`,`vname`), KEY `pid` (`pid`,`eid`,`vname`) diff --git a/sql/database-fill.sql b/sql/database-fill.sql index 522233fb69366d083e26ad64041adb79ea9ff22b..63efe1d25f6811537ee9ebd18ae8723d05941315 100644 --- a/sql/database-fill.sql +++ b/sql/database-fill.sql @@ -1109,6 +1109,8 @@ REPLACE INTO table_regex VALUES ('virt_firewalls','fwname','text','redirect','vi REPLACE INTO table_regex VALUES ('virt_firewalls','type','text','regex','^(ipfw|ipfw2|iptables|ipfw2-vlan|iptables-vlan)$',0,0,NULL); REPLACE INTO table_regex VALUES ('virt_firewalls','style','text','regex','^(open|closed|basic|emulab)$',0,0,NULL); +REPLACE INTO table_regex VALUES ('virt_nodes','firewall_style','text','regex','^(open|closed|basic|emulab)$',0,0,NULL); + REPLACE INTO table_regex VALUES ('mailman_lists','pid_idx','text','redirect','projects:pid_idx',0,0,NULL); REPLACE INTO table_regex VALUES ('mailman_lists','password1','text','redirect','default:tinytext',0,0,NULL); REPLACE INTO table_regex VALUES ('mailman_lists','password2','text','redirect','default:tinytext',0,0,NULL); diff --git a/sql/updates/4/387 b/sql/updates/4/387 new file mode 100644 index 0000000000000000000000000000000000000000..8d7fab9c6f0c676f25d7bdb23a8dc162e83e3aef --- /dev/null +++ b/sql/updates/4/387 @@ -0,0 +1,33 @@ +# +# New firewall type. +# +use strict; +use libdb; + +sub DoUpdate($$$) +{ + my ($dbhandle, $dbname, $version) = @_; + + DBQueryFatal("alter table default_firewall_rules change `type` ". + " `type` enum('ipfw','ipfw2','iptables','ipfw2-vlan',". + " 'iptables-vlan','iptables-dom0', ". + " 'iptables-domU') ". + " NOT NULL default 'ipfw'"); + + if (!DBSlotExists("virt_nodes", "firewall_style")) { + DBQueryFatal("alter table virt_nodes add ". + " `firewall_style` tinytext"); + } + DBQueryFatal("REPLACE INTO table_regex VALUES ". + "('virt_nodes','firewall_style','text','regex',". + "'^(open|closed|basic|emulab)\$',0,0,NULL)"); + + if (!DBSlotExists("virt_nodes", "firewall_log")) { + DBQueryFatal("alter table virt_nodes add ". + " `firewall_log` tinytext"); + } +} + +# Local Variables: +# mode:perl +# End: diff --git a/tbsetup/ns2ir/node.tcl b/tbsetup/ns2ir/node.tcl index 3f5894d800a6998b4cacfdfd7d68ca040c597ca8..441eebfc5ef15eec0f3701a1ec4e213c93482395 100644 --- a/tbsetup/ns2ir/node.tcl +++ b/tbsetup/ns2ir/node.tcl @@ -1,6 +1,6 @@ # -*- tcl -*- # -# Copyright (c) 2000-2013 University of Utah and the Flux Group. +# Copyright (c) 2000-2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -146,6 +146,9 @@ Node instproc init {s} { # This is a blockstore thing. $self set bstore_agent 0 + + # Per node firewall thing. + $self set fw_style "" } Bridge instproc init {s} { @@ -229,6 +232,7 @@ Node instproc updatedb {DB} { $self instvar simulated $self instvar sharing_mode $self instvar topo + $self instvar fw_style $self instvar X_ $self instvar Y_ $self instvar orientation_ @@ -402,6 +406,11 @@ Node instproc updatedb {DB} { lappend values $parent_osid } + if { $fw_style != "" } { + lappend fields "firewall_style" + lappend values $fw_style + } + $sim spitxml_data "virt_nodes" $fields $values if {$topo != "" && ($type == "robot" || $hwtype_class($type) == "robot")} { diff --git a/tbsetup/ns2ir/nstb_compat.tcl b/tbsetup/ns2ir/nstb_compat.tcl index 3f2b0ef60f8bb5eb69a85d1f29f7df25468c2ca8..c2c152e41d47cfd9d7e3c262e6e30a717cf371c9 100644 --- a/tbsetup/ns2ir/nstb_compat.tcl +++ b/tbsetup/ns2ir/nstb_compat.tcl @@ -73,6 +73,7 @@ proc tb-set-endnodeshaping {link onoff} {} proc tb-set-noshaping {link onoff} {} proc tb-set-useveth {link onoff} {} proc tb-set-link-encap {link style} {} +proc tb-set-fw-style {vnode style} {} proc tb-set-allowcolocate {lanlink onoff} {} proc tb-set-colocate-factor {factor} {} proc tb-set-sync-server {node} {} diff --git a/tbsetup/ns2ir/tb_compat.tcl.in b/tbsetup/ns2ir/tb_compat.tcl.in index fc636a1c1dda323b39f10a68d8e10850873dfc34..1e20f5b55ec20fa8da00a6c618adbca5d6e49484 100644 --- a/tbsetup/ns2ir/tb_compat.tcl.in +++ b/tbsetup/ns2ir/tb_compat.tcl.in @@ -2290,6 +2290,20 @@ proc tb-set-elabinelab-fw-type {type} { set elabinelab_fw_type $type } +# +# Set firewall style for an individual node. Really only makes sense +# for linux nodes with iptables. Might need to add an os_feature. +# +proc tb-set-fw-style {vnode style} +{ + if ($style != "basic" && $style != "closed" && + $style != "open" && $style != "elabinelab") { + perror "\[tb-set-fw-style] $style is not a valid type" + return + } + $vnode set fw_style $style +} + # # Set numeric ID (this is a mote thing) # diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c index 0d0ec33a8a70274abbe1a75cd3d03a5eaa23a38e..f541fc7eb43f135e9fef917d9ee4679d970839b8 100644 --- a/tmcd/tmcd.c +++ b/tmcd/tmcd.c @@ -246,6 +246,7 @@ typedef struct { char sfshostid[TBDB_FLEN_SFSHOSTID]; char testdb[TBDB_FLEN_TINYTEXT]; char sharing_mode[TBDB_FLEN_TINYTEXT]; + char erole[TBDB_FLEN_TINYTEXT]; char privkey[PRIVKEY_LEN+1]; char nodeuuid[TBDB_FLEN_UUID]; /* This key is a replacement for privkey, on protogeni resources */ @@ -6795,7 +6796,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) " AS isdedicated_wa, " " r.genisliver_idx,r.tmcd_redirect, " " r.sharing_mode,e.geniflags,n.uuid, " - " n.nonfsmounts,e.nonfsmounts AS enonfs " + " n.nonfsmounts,e.nonfsmounts AS enonfs, " + " r.erole " "FROM nodes AS n " "LEFT JOIN reserved AS r ON " " r.node_id=n.node_id " @@ -6824,7 +6826,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) " (SELECT node_id FROM widearea_nodeinfo " " WHERE privkey='%s') " " AND notmcdinfo_types.attrvalue IS NULL", - 37, nodekey); + 38, nodekey); } else if (reqp->isvnode) { char clause[BUFSIZ]; @@ -6860,7 +6862,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) " u.admin,null, " " r.genisliver_idx,r.tmcd_redirect, " " r.sharing_mode,e.geniflags,nv.uuid, " - " nv.nonfsmounts,e.nonfsmounts AS enonfs " + " nv.nonfsmounts,e.nonfsmounts AS enonfs, " + " r.erole " "from nodes as nv " "left join nodes as np on " " np.node_id=nv.phys_nodeid " @@ -6881,7 +6884,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) "left join users as u on " " u.uid_idx=e.swapper_idx " "where nv.node_id='%s' and (%s)", - 37, reqp->vnodeid, clause); + 38, reqp->vnodeid, clause); } else { char clause[BUFSIZ]; @@ -6910,7 +6913,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) " as isdedicated_wa, " " r.genisliver_idx,r.tmcd_redirect, " " r.sharing_mode,e.geniflags,n.uuid, " - " n.nonfsmounts,e.nonfsmounts AS enonfs " + " n.nonfsmounts,e.nonfsmounts AS enonfs, " + " r.erole " "from interfaces as i " "left join nodes as n on n.node_id=i.node_id " "left join reserved as r on " @@ -6938,7 +6942,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) " on n.type=dedicated_wa_types.type " "where (%s) " " and notmcdinfo_types.attrvalue is NULL", - 37, clause); + 38, clause); } if (!res) { @@ -7048,6 +7052,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) reqp->geniflags = atoi(row[33]); else reqp->geniflags = 0; + if (row[37]) + strcpy(reqp->erole, row[37]); } if (row[9]) @@ -8156,34 +8162,12 @@ COMMAND_PROTOTYPE(doroutelist) */ COMMAND_PROTOTYPE(dorole) { - MYSQL_RES *res; - MYSQL_ROW row; char buf[MYBUFSIZE]; - /* - * Get the erole from the reserved table - */ - res = mydb_query("select erole from reserved where node_id='%s'", - 1, reqp->nodeid); - - if (!res) { - error("ROLE: %s: DB Error getting the role of this node!\n", - reqp->nodeid); - return 1; - } - - if ((int)mysql_num_rows(res) == 0) { - mysql_free_result(res); - return 0; - } - - row = mysql_fetch_row(res); - if (! row[0] || !row[0][0]) { - mysql_free_result(res); + if (! reqp->allocated) { return 0; } - sprintf(buf, "%s\n", row[0]); - mysql_free_result(res); + sprintf(buf, "%s\n", reqp->erole); client_writeback(sock, buf, strlen(buf), tcp); if (verbose) @@ -8572,16 +8556,82 @@ COMMAND_PROTOTYPE(dofwinfo) char fwname[TBDB_FLEN_VNAME+2]; char fwtype[TBDB_FLEN_VNAME+2]; char fwstyle[TBDB_FLEN_VNAME+2]; + char fwlog[TBDB_FLEN_TINYTEXT+1]; int n, nrows; char *vlan; + bzero(fwlog, sizeof(fwlog)); + /* - * See if this node's experiment has an associated firewall - * - * XXX will only work if there is one firewall per experiment. + * Containers and shared hosts can each have specific rules. + * The shared host can protect itself with iptables-dom0 rules, + * and containers themselves can be firewalled with iptables-domU + * rules (in the default_firewall_rules table). The main point + * though, is that this done on the virt host dom0, not with a + * separate firewall node. */ - res = mydb_query("select r.node_id,v.type,v.style,v.log,f.fwname," - " i.IP,i.mac,f.vlan " + if (reqp->isvnode || + strcmp(reqp->erole, "virthost") == 0 || + strcmp(reqp->erole, "sharedhost") == 0) { + /* + * Since we implement the firewall code on the outside of + * the container (dom0), containers themselves know + * nothing about it, nor can containers act *as* firewall + * nodes for an entire experiment (although this is + * something we should implement some day). So just tell + * the container not to worry about it. + */ + if (reqp->asvnode) { + goto nofirewall; + } + res = mydb_query("select firewall_style,firewall_log " + "from virt_nodes " + "where exptidx='%d' and " + " vname='%s' and " + " firewall_style is not null ", + 2, reqp->exptidx, reqp->nickname); + if (!res) { + error("FWINFO: %s: DB Error getting firewall info!\n", + reqp->nodeid); + return 1; + } + if ((int)mysql_num_rows(res) == 0) { + mysql_free_result(res); + goto nofirewall; + } + row = mysql_fetch_row(res); + /* + * Ignore the type, we decide. + */ + if (reqp->isvnode) { + strcpy(fwtype, "iptables-domU"); + } + else { + strcpy(fwtype, "iptables-dom0"); + } + strncpy(fwstyle, row[0], sizeof(fwstyle)); + if (row[1] && row[1][0]) + strncpy(fwlog, row[1], sizeof(fwlog)); + mysql_free_result(res); + + OUTPUT(buf, sizeof(buf), + "TYPE=%s STYLE=%s " + "IN_IF=na OUT_IF=na IN_VLAN=0 OUT_VLAN=0\n", + fwtype, fwstyle); + client_writeback(sock, buf, strlen(buf), tcp); + if (verbose) + info("FWINFO: %s", buf); + + goto vnodefw; + } + else { + /* + * See if this node's experiment has an associated firewall + * + * XXX will only work if there is one firewall per experiment. + */ + res = mydb_query("select r.node_id,v.type,v.style,v.log," + " f.fwname,i.IP,i.mac,f.vlan " "from firewalls as f " "left join reserved as r on" " f.pid=r.pid and f.eid=r.eid and f.fwname=r.vname " @@ -8592,10 +8642,11 @@ COMMAND_PROTOTYPE(dofwinfo) "and i.role='ctrl'", /* XXX */ 8, reqp->pid, reqp->eid); - if (!res) { - error("FWINFO: %s: DB Error getting firewall info!\n", - reqp->nodeid); - return 1; + if (!res) { + error("FWINFO: %s: DB Error getting firewall info!\n", + reqp->nodeid); + return 1; + } } /* @@ -8603,6 +8654,7 @@ COMMAND_PROTOTYPE(dofwinfo) */ if ((int)mysql_num_rows(res) == 0) { mysql_free_result(res); + nofirewall: strncpy(buf, "TYPE=none\n", sizeof(buf)); client_writeback(sock, buf, strlen(buf), tcp); return 0; @@ -8666,21 +8718,24 @@ COMMAND_PROTOTYPE(dofwinfo) if (verbose) info("FWINFO: %s", buf); + strncpy(fwtype, row[1], sizeof(fwtype)); + strncpy(fwstyle, row[2], sizeof(fwstyle)); + strncpy(fwname, row[4], sizeof(fwname)); + if (row[3] && row[3][0]) + strncpy(fwlog, row[3], sizeof(fwlog)); + mysql_free_result(res); + +vnodefw: /* * Put out info about firewall rule logging */ - if (vers > 25 && row[3] && row[3][0]) { - OUTPUT(buf, sizeof(buf), "LOG=%s\n", row[3]); + if (vers > 25 && fwlog[0]) { + OUTPUT(buf, sizeof(buf), "LOG=%s\n", fwlog); client_writeback(sock, buf, strlen(buf), tcp); if (verbose) info("FWINFO: %s", buf); } - strncpy(fwtype, row[1], sizeof(fwtype)); - strncpy(fwstyle, row[2], sizeof(fwstyle)); - strncpy(fwname, row[4], sizeof(fwname)); - mysql_free_result(res); - /* * Return firewall variables */ @@ -8729,13 +8784,41 @@ COMMAND_PROTOTYPE(dofwinfo) info("FWINFO: %d variables\n", nrows); } + if (reqp->isvnode) { + /* + * Write a var for the sshdport number. + */ + res = mydb_query("select n.sshdport from nodes as n " + "where n.node_id='%s'", + 1, reqp->nodeid); + + if (!res) { + error("FWINFO: %s: DB Error getting sshdport!\n", + reqp->nodeid); + return 1; + } + + if ((int)mysql_num_rows(res)) { + row = mysql_fetch_row(res); + + OUTPUT(buf, sizeof(buf), "VAR=%s VALUE=\"%s\"\n", + "SSHDPORT", row[0]); + client_writeback(sock, buf, strlen(buf), tcp); + } + mysql_free_result(res); + } + /* * Get the user firewall rules from the DB and return them. + * Note difference for vnodes/vhosts; these can store rules + # for each vnode/vhost in the topo. */ res = mydb_query("select ruleno,rule from firewall_rules " "where pid='%s' and eid='%s' and fwname='%s' " "order by ruleno", - 2, reqp->pid, reqp->eid, fwname); + 2, reqp->pid, reqp->eid, + ((reqp->isvnode || reqp->sharing_mode[0]) ? + reqp->nickname ? fwname)); if (!res) { error("FWINFO: %s: DB Error getting firewall rules!\n", reqp->nodeid); @@ -8749,10 +8832,9 @@ COMMAND_PROTOTYPE(dofwinfo) row[0], row[1]); client_writeback(sock, buf, strlen(buf), tcp); } - mysql_free_result(res); if (verbose) - info("FWINFO: %d user rules\n", nrows); + info("FWINFO: %d user rules\n", nrows); /* * Get the default firewall rules from the DB and return them. @@ -10253,7 +10335,7 @@ COMMAND_PROTOTYPE(doarpinfo) MYSQL_RES *res; MYSQL_ROW row; int nrows, xenvifrouting = 0; - char buf[MYBUFSIZE], erole[32], arptype[32]; + char buf[MYBUFSIZE], arptype[32]; #ifdef GET_SERVERS_FROM_SITEVARS struct serv { char name[8]; @@ -10331,25 +10413,6 @@ COMMAND_PROTOTYPE(doarpinfo) } mysql_free_result(res); - res = mydb_query("select erole from reserved where node_id='%s'", - 1, reqp->nodeid); - if (!res) { - error("doarpinfo: %s: DB Error checking for reserved.erole\n", - reqp->nodeid); - return 1; - } - - if (mysql_num_rows(res) == 0 || (row = mysql_fetch_row(res)) == NULL || - row[0] == NULL) { - error("doarpinfo: %s: Could not deterimine erole\n", - reqp->nodeid); - mysql_free_result(res); - return 1; - } - - strncpy(erole, row[0], sizeof(erole)); - mysql_free_result(res); - /* * Get the GW and primary server (boss, ops, fs) info. */ @@ -10571,7 +10634,7 @@ COMMAND_PROTOTYPE(doarpinfo) /* * Subbosses get info for all nodes they provide a service for. */ - if (strcmp(erole, "subboss") == 0) { + if (strcmp(reqp->erole, "subboss") == 0) { res = mydb_query("select distinct i.node_id,i.IP,i.mac from " "interfaces as i,subbosses as s where " "s.node_id=i.node_id and "