/* Firewall Builder Copyright (C) 2002-2011 NetCitadel, LLC Author: Vadim Kurland vadim@fwbuilder.org This program is free software which we release under the GNU General Public License. You may redistribute and/or modify this program under the terms of that license as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. To get a copy of the GNU General Public License, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "OSConfigurator_freebsd.h" #include "Configlet.h" #include "interfaceProperties.h" #include "interfacePropertiesObjectFactory.h" #include "fwbuilder/Firewall.h" #include "fwbuilder/FWOptions.h" #include "fwbuilder/Interface.h" #include "fwbuilder/IPv4.h" #include "fwbuilder/FailoverClusterGroup.h" #include "fwbuilder/StateSyncClusterGroup.h" #include #include using namespace libfwbuilder; using namespace fwcompiler; using namespace std; string OSConfigurator_freebsd::myPlatformName() { return "FreeBSD"; } string OSConfigurator_freebsd::printKernelVarsCommands() { FWOptions* options = fw->getOptionsObject(); std::auto_ptr kernel_vars; if (options->getBool("generate_rc_conf_file")) { kernel_vars = std::auto_ptr( new Configlet(fw, "freebsd", "rc_conf_kernel_vars")); } else { kernel_vars = std::auto_ptr( new Configlet(fw, "bsd", "kernel_vars")); } kernel_vars->removeComments(); setKernelVariable(fw, "freebsd_ip_forward", kernel_vars.get()); setKernelVariable(fw, "freebsd_ipv6_forward", kernel_vars.get()); setKernelVariable(fw, "freebsd_ip_sourceroute", kernel_vars.get()); //setKernelVariable(fw, "freebsd_ip_redirect", kernel_vars.get()); return kernel_vars->expand().toStdString(); } void OSConfigurator_freebsd::setKernelVariable(Firewall *fw, const string &var_name, Configlet *configlet) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { string s; s = options->getStr(var_name); if (!s.empty()) { configlet->setVariable(QString("have_") + var_name.c_str(), 1); string yesno = (s=="1" || s=="on" || s=="On") ? "YES" : "NO"; configlet->setVariable(QString(var_name.c_str()), QString(yesno.c_str())); } } else OSConfigurator_bsd::setKernelVariable(fw, var_name, configlet); } int OSConfigurator_freebsd::prolog() { //printPathForAllTools("freebsd"); //printFunctions(); //processFirewallOptions(); //configureInterfaces(); return 0; } void OSConfigurator_freebsd::summaryConfigLineIP(QStringList names, bool ipv6) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file") && !names.isEmpty()) { if (ipv6) { interface_configuration_lines["1_should_sort_before_interfaces_"] << QString("ipv6_network_interfaces=\"%1\"").arg(names.join(" ")); } else { interface_configuration_lines["1_should_sort_before_interfaces_"] << QString("network_interfaces=\"%1\"").arg(names.join(" ")); } } } void OSConfigurator_freebsd::interfaceConfigLineIP( Interface *iface, list > all_addresses) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { /* * lines in rc.conf have the following format: * * network_interfaces="ed0 ed1 lo0" * ifconfig_ed0="inet 192.0.2.1 netmask 0xffffff00" * ipv4_addrs_ed0="192.0.2.129/27 192.0.2.1-5/28" * */ QString interface_name = iface->getName().c_str(); if (iface->isDyn()) { ifconfig_lines[interface_name] << "DHCP"; return; } int ipv4_alias_counter = -2; int ipv6_alias_counter = -2; for (list >::iterator j = all_addresses.begin(); j != all_addresses.end(); ++j) { QString ipv4_conf_line; QString ipv6_conf_line; InetAddr ipaddr = j->first; InetAddr ipnetm = j->second; if (ipaddr.isV6()) { ipv6_conf_line += QString("%1/%2") .arg(ipaddr.toString().c_str()) .arg(ipnetm.getLength()); ipv6_alias_counter++; } else { int nbits = ipnetm.getLength(); uint32_t netm = 0; while (nbits) { netm = netm >> 1; netm |= 1<<31; nbits--; } ipv4_conf_line += QString("%1 netmask 0x%2") .arg(ipaddr.toString().c_str()) .arg(netm, -8, 16); ipv4_alias_counter++; } if (!ipv4_conf_line.isEmpty()) { QString suffix; if (ipv4_alias_counter>=0) suffix = QString("_alias%1").arg(ipv4_alias_counter); ifconfig_lines[interface_name + suffix] << ipv4_conf_line; } if (!ipv6_conf_line.isEmpty()) { QString suffix; if (ipv6_alias_counter>=0) suffix = QString("_alias%1").arg(ipv6_alias_counter); ipv6_ifconfig_lines[interface_name + suffix] << ipv6_conf_line; } } } else OSConfigurator_bsd::interfaceConfigLineIP(iface, all_addresses); } void OSConfigurator_freebsd::interfaceIfconfigLine(Interface *iface) { QString iface_name = iface->getName().c_str(); FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { Configlet configlet(fw, "freebsd", "rc_conf_ifconfig_interface"); QString config_lines = interfaceIfconfigLineInternal(iface, &configlet); if (!config_lines.isEmpty()) ifconfig_lines[iface_name] << config_lines; } else { Configlet configlet(fw, "freebsd", "ifconfig_interface"); QString config_lines = interfaceIfconfigLineInternal(iface, &configlet); if (!config_lines.isEmpty()) interface_configuration_lines[iface_name] << config_lines; } } void OSConfigurator_freebsd::summaryConfigLineVlan(QStringList vlan_names) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { cloned_interfaces += vlan_names; } else interface_configuration_lines["1_should_sort_before_interfaces_"] << QString("sync_vlan_interfaces %1").arg(vlan_names.join(" ")); } /* For rc.conf format: If a vlans_ variable is set, a vlan(4) interface will be created for each item in the list with the vlandev argument set to interface. If a vlan interface's name is a number, then that number is used as the vlan tag and the new vlan interface is named interface.tag. Otherwise, the vlan tag must be specified via a vlan parameter in the create_args_ variable. To create a vlan device named em0.101 on em0 with the vlan tag 101: vlans_em0="101" To create a vlan device named myvlan on em0 with the vlan tag 102: vlans_em0="myvlan" create_args_myvlan="vlan 102" */ void OSConfigurator_freebsd::interfaceConfigLineVlan(Interface *iface, QStringList vlan_names) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { QString iface_name = iface->getName().c_str(); // the "vlans_em2="vlan101 vlan102" will appear next to other lines // intended for interface em2 interface_configuration_lines[iface_name] << QString("vlans_%1=\"%2\"").arg(iface->getName().c_str()) .arg(vlan_names.join(" ")); foreach(QString vlan_intf_name, vlan_names) { std::auto_ptr int_prop( interfacePropertiesObjectFactory::getInterfacePropertiesObject( fw->getStr("host_OS"))); QString parent_name_from_regex; int vlan_id; if (int_prop->parseVlan(vlan_intf_name, &parent_name_from_regex, &vlan_id)) { interface_configuration_lines[iface_name] << QString("create_args_%1=\"vlan %2 vlandev %3\"") .arg(vlan_intf_name).arg(vlan_id).arg(iface->getName().c_str()); } } } else OSConfigurator_bsd::interfaceConfigLineVlan(iface, vlan_names); } void OSConfigurator_freebsd::summaryConfigLineBridge(QStringList bridge_names) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { cloned_interfaces += bridge_names; } else OSConfigurator_bsd::summaryConfigLineBridge(bridge_names); } /* For rc.conf format: Consider a system with two 4-port Ethernet boards. The following will cause a bridge consisting of all 8 ports with Rapid Spanning Tree enabled to be created: ifconfig bridge0 create ifconfig bridge0 \ addm fxp0 stp fxp0 \ addm fxp1 stp fxp1 \ addm fxp2 stp fxp2 \ addm fxp3 stp fxp3 \ addm fxp4 stp fxp4 \ addm fxp5 stp fxp5 \ addm fxp6 stp fxp6 \ addm fxp7 stp fxp7 \ up The bridge can be used as a regular host interface at the same time as bridging between its member ports. In this example, the bridge connects em0 and em1, and will receive its IP address through DHCP: cloned_interfaces="bridge0" ifconfig_bridge0="addm em0 addm em1 DHCP" ifconfig_em0="up" ifconfig_em1="up" Refernce: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/network-bridging.html TODO: STP support should be optional */ void OSConfigurator_freebsd::interfaceConfigLineBridge(Interface *iface, QStringList bridge_port_names) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { FWOptions *ifopt = iface->getOptionsObject(); assert(ifopt != NULL); bool enable_stp = ifopt->getBool("enable_stp"); QStringList outp; QStringList bp; foreach(QString bridge_port, bridge_port_names) { bp << QString("addm %1 %2 %3") .arg(bridge_port).arg((enable_stp)?"stp":"").arg(bridge_port); } bp << "up"; ifconfig_lines[iface->getName().c_str()] << bp.join(" "); foreach(QString bridge_port, bridge_port_names) { ifconfig_lines[bridge_port] << "up"; } interface_configuration_lines[iface->getName().c_str()] << outp.join("\n"); } else OSConfigurator_bsd::interfaceConfigLineBridge(iface, bridge_port_names); } void OSConfigurator_freebsd::summaryConfigLineCARP(QStringList carp_names) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { cloned_interfaces += carp_names; } else OSConfigurator_bsd::summaryConfigLineCARP(carp_names); } void OSConfigurator_freebsd::interfaceConfigLineCARP(Interface *iface, FWObject *failover_group) { FWOptions* options = fw->getOptionsObject(); QString configlet_name = "carp_interface"; if (options->getBool("generate_rc_conf_file")) { configlet_name = "rc_conf_carp_interface"; } Configlet configlet(fw, "freebsd", configlet_name); interfaceConfigLineCARPInternal(iface, failover_group, &configlet); } void OSConfigurator_freebsd::summaryConfigLinePfsync(bool have_pfsync) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { interface_configuration_lines["pfsync0"] << "pfsync_enable=\"YES\""; } else OSConfigurator_bsd::summaryConfigLinePfsync(have_pfsync); } /* in rc.conf format: pfsync_enable (bool) Set to ``NO'' by default. Setting this to ``YES'' enables exposing pf(4) state changes to other hosts over the network by means of pfsync(4). The pfsync_syncdev variable must also be set then. pfsync_syncdev (str) Empty by default. This variable specifies the name of the network interface pfsync(4) should operate through. It must be set accordingly if pfsync_enable is set to ``YES''. pfsync_syncpeer (str) Empty by default. This variable is optional. By default, state change messages are sent out on the synchroni- sation interface using IP multicast packets. The protocol is IP protocol 240, PFSYNC, and the multicast group used is 224.0.0.240. When a peer address is specified using the pfsync_syncpeer option, the peer address is used as a desti- nation for the pfsync traffic, and the traffic can then be protected using ipsec(4). See the pfsync(4) manpage for more details about using ipsec(4) with pfsync(4) interfaces. pfsync_ifconfig (str) Empty by default. This variable can contain additional options to be passed to the ifconfig(8) command used to set up pfsync(4). */ void OSConfigurator_freebsd::interfaceConfigLinePfsync( Interface *iface, StateSyncClusterGroup *state_sync_group) { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { Configlet configlet(fw, "freebsd", "rc_conf_pfsync_interface"); configlet.removeComments(); configlet.collapseEmptyStrings(true); configlet.setVariable("syncdev", iface->getName().c_str()); if (state_sync_group->getOptionsObject()->getBool("syncpeer")) { for (FWObjectTypedChildIterator it = state_sync_group->findByType(FWObjectReference::TYPENAME); it != it.end(); ++it) { Interface *cluster_iface = Interface::cast( FWObjectReference::getObject(*it)); assert(cluster_iface); if (cluster_iface->getId() == iface->getId()) continue; IPv4 *ipv4 = IPv4::cast(cluster_iface->getFirstByType(IPv4::TYPENAME)); const InetAddr *addr = ipv4->getAddressPtr(); configlet.setVariable("have_syncpeer", 1); configlet.setVariable("syncpeer", addr->toString().c_str()); } } interface_configuration_lines[iface->getName().c_str()] << configlet.expand(); } else OSConfigurator_bsd::interfaceConfigLinePfsync(iface, state_sync_group); } QString OSConfigurator_freebsd::printAllInterfaceConfigurationLines() { FWOptions* options = fw->getOptionsObject(); if (options->getBool("generate_rc_conf_file")) { printIfconfigLines(ifconfig_lines); printIfconfigLines(ipv6_ifconfig_lines); if (!cloned_interfaces.isEmpty()) interface_configuration_lines["0_should_be_on_top_"] << QString("cloned_interfaces=\"%1\"") .arg(cloned_interfaces.join(" ")); } return OSConfigurator_bsd::printAllInterfaceConfigurationLines(); } void OSConfigurator_freebsd::printIfconfigLines(const QMap &lines) { if (!lines.isEmpty()) { QStringList keys = lines.keys(); keys.sort(); foreach (QString iface_name, keys) { const QStringList commands = lines[iface_name]; interface_configuration_lines[iface_name] << QString("ifconfig_%1=\"%2\"").arg(iface_name) .arg(commands.join(" ")); } } }