|
||||||||||
Here's how I turned my m0n0wall into a filtering bridge.
My hardware is a Soekris 4501. I wanted to use it as a filtering
bridge between my WAN port and some externally visible workstations
and servers, connected to the OPT1 port. The problem of course is
that m0n0wall (pb13) doesn't support firewall rules on bridged
interfaces. This is because the ng_bridge(4) netgraph node doesn't
pass packets through the IPFilter rulesets.
My approach was to switch from ng_bridge(4) bridging to
bridge(4)-style filtering. bridge(4) can be made to do input
filtering using either ipfw or IPFilter.
Here's roughly the steps I did. I'm going to assume you (the reader)
have a little experience at hacking on m0n0wall, updating the
filesystem images, etc.
First, I copied the bridge.ko kernel module from a FreeBSD 4.8-RELEASE
CDROM to /modules on the mfsroot filesystem image.
Then I applied three patches (attached to this email).
1. /etc/rc now loads the bridge.ko kernel module and enables IPFilter
for bridged packets.
2. /etc/inc/interfaces.inc now generates the correct bridge
configuration string to hand to the net.link.ether.bridge_cfg
sysctl variable. Note that after this patch, /etc/inc/bridge.inc
can go away.
3. /etc/inc/filter.inc modifies the filter rules to handle the
concept that the same prefix can be associated with multiple
interfaces (due to the bridging). I might not have gotten this
completely right, in that bridging to the LAN interface probably
won't work. I don't know about bridging between multiple OPTx
interfaces.
After this, I gave the m0n0wall WAN port an IP address out of my
allocation (and the correct subnet mask), and bridged the OPT1 port to
the WAN port.
Other notes:
1. Remember you now need to permit traffic from your OPTx interface.
You also need to write rules for the WAN interface that will
permit traffic going to the machines on the OPTx interface.
2. If you have multicast traffic arriving on your WAN interface,
bridge(4) drops each packet and writes a syslog message announcing
this fact. This is way too chatty.
3. I didn't change the UI pages so they still claim that firewall
rules on bridging interfaces have no effect. This should be
trivial to fix.
4. It'd probably be better just to compile the bridge device into the
kernel. But this worked pretty well for a proof-of-concept.
5. In theory this should be able to handle multiple "bridging groups"
but each bridging group can only contain two interfaces, exactly
one of which must have an IP address associated with it.
Comments/suggestions appreciated!
Bruce. | ||||||||||
--- /scratch0/m0n0wall/rootfs-pb13r443/etc/inc/filter.inc Sun Jun 29 09:24:33 2003
+++ /mnt2/etc/inc/filter.inc Sun Jul 20 21:21:26 2003
@@ -212,12 +212,20 @@
for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
$oc = $config['interfaces']['opt' . $i];
- if (isset($oc['enable']) && $oc['if'] && (!$oc['bridge'])) {
+ if (isset($oc['enable']) && $oc['if']) {
$oic = array();
- $oic['ip'] = $oc['ipaddr'];
$oic['if'] = $oc['if'];
- $oic['sa'] = gen_subnet($oc['ipaddr'], $oc['subnet']);
- $oic['sn'] = $oc['subnet'];
+
+ if ($oc['bridge']) {
+ $oic['ip'] = $config['interfaces'][$oc['bridge']]['ipaddr'];
+ $oic['sn'] = $config['interfaces'][$oc['bridge']]['subnet'];
+ $oic['bridge'] = 1;
+ }
+ else {
+ $oic['ip'] = $oc['ipaddr'];
+ $oic['sn'] = $oc['subnet'];
+ }
+ $oic['sa'] = gen_subnet($oic['ip'], $oic['sn']);
$optcfg['opt' . $i] = $oic;
@@ -253,7 +261,9 @@
EOD;
foreach ($optcfg as $oc) {
- $ipfrules .= "block in log quick on $wanif from {$oc['sa']}/{$oc['sn']} to any\n";
+ if (!$oc['bridge']) {
+ $ipfrules .= "block in log quick on $wanif from {$oc['sa']}/{$oc['sn']} to any\n";
+ }
}
/* allow PPTP traffic if PPTP client is enabled on WAN */ | ||||||||||
--- /scratch0/m0n0wall/rootfs-pb13r443/etc/inc/interfaces.inc Sun Jun 29 09:24:33 2003
+++ /mnt2/etc/inc/interfaces.inc Sun Jul 20 15:42:26 2003
@@ -83,16 +83,23 @@
function interfaces_optional_configure() {
global $config, $g;
+ global $bridgeconfig;
+ /* Reset bridge configuration. Interfaces will add to it. */
+ $bridgeconfig = "";
+
for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
interfaces_optional_configure_if($i);
}
+ /* Set the system bridge configuration. */
+ mwexec("/sbin/sysctl net.link.ether.bridge_cfg=" . $bridgeconfig);
return 0;
}
function interfaces_optional_configure_if($opti) {
global $config, $g;
+ global $bridgeconfig;
$optcfg = $config['interfaces']['opt' . $opti];
@@ -112,11 +119,17 @@
if ($optcfg['bridge']) {
mwexec("/sbin/ifconfig " . escapeshellarg($optcfg['if']) .
" delete up");
- bridge_start("bridge" . $opti, $optcfg['if'],
- (is_array($optcfg['wireless'])) ? false : true,
- $config['interfaces'][$optcfg['bridge']]['if'],
- (is_array($config['interfaces'][$optcfg['bridge']]['wireless']))
- ? false : true);
+# bridge_start("bridge" . $opti, $optcfg['if'],
+# (is_array($optcfg['wireless'])) ? false : true,
+# $config['interfaces'][$optcfg['bridge']]['if'],
+# (is_array($config['interfaces'][$optcfg['bridge']]['wireless']))
+# ? false : true);
+ if ($bridgeconfig != "")
+ $bridgeconfig = $bridgeconfig . ",";
+ $bridgeconfig = $bridgeconfig . $optcfg['if'] .
+ ":" . $opti . "," .
+ $config['interfaces'][$optcfg['bridge']]['if'] .
+ ":" . $opti;
} else {
mwexec("/sbin/ifconfig " . escapeshellarg($optcfg['if']) . " " .
escapeshellarg($optcfg['ipaddr'] . "/" . $optcfg['subnet'])); | ||||||||||
--- /scratch0/m0n0wall/rootfs-pb13r443/etc/rc Wed Jun 25 12:40:42 2003 +++ /mnt2/etc/rc Sun Jul 20 15:42:40 2003 @@ -43,6 +43,11 @@ # Run ldconfig /sbin/ldconfig -elf /usr/lib +# Load bridging module, enable bridging +/sbin/kldload /modules/bridge.ko +/sbin/sysctl net.link.ether.bridge=1 +/sbin/sysctl net.link.ether.bridge_ipf=1 + # let the PHP-based configuration subsystem set up the system now /etc/rc.bootup |