|
你需要具备如下的知识背景: 1、熟悉FreeBSD的使用,包括安装、命令、配置等; 2、熟悉PHP的开发,包括基本语法、算法等; 3、会对m0n0wall进行解包和封包,详见本站教程。
一、任务: 1、添加ARP的绑定功能,要求可以自动的获取ARP表; 2、可以自动的进行批量绑定; 3、绑定关系变更后不需要重新启动防火墙; 4、可以对ARP表进行编辑操作; 5、把配置信息写入XML的配置文件中,在每次启动时可以加载。 二、算法分析 在FreeBSD中可以使用arp -an命令获取当前正在跟本机通信的ARP表。作为网关,只要LAN中的机器全部开启,就可以获得全部的IP-MAC地址的对应关系。下表是在FreeBSD中获取的ARP表的例子: ? (192.168.1.7) at 00:0f:ea:09:39:ec on fxp0 [ethernet] ? (192.168.1.52) at 00:50:ba:ed:2d:e5 on fxp0 [ethernet] ? (192.168.1.88) at 00:e2:c6:c0:49:0d on fxp0 [ethernet] ? (192.168.1.89) at 00:e2:c6:c0:49:5f on fxp0 [ethernet] ? (192.168.1.101) at 00:0f:ea:00:90:92 on fxp0 [ethernet] ? (192.168.1.102) at 00:0f:ea:00:98:3b on fxp0 [ethernet] ? (192.168.1.103) at 00:0f:ea:00:90:e5 on fxp0 [ethernet] ? (192.168.1.104) at 00:15:f2:76:2d:bd on fxp0 [ethernet] ? (192.168.1.106) at 00:15:f2:76:2c:6b on fxp0 [ethernet] 从返回结果可以看出来,我们只要获得第2列和第4列的数值就可以了,然后再对第二列进行处理,去掉括号,就获得了ARP表。 获得了ARP表后,使用arp命令进行绑定,命令格式为: arp -s IP MAC。参数s就是告诉系统使用静态ARP对应关系。也可以在静态绑定前使用arp -d -a 把系统的ARP表清空后再绑定。 当获得了ARP表后,就可以利用m0n0wall的函数讲配置写入XML配置文件中,以便下次引导的时候可以自动加载。 三、实现 首先,构造一个函数system_static_arp(),该函数用来在引导的时候从XML配置文件中加载ARP表。 function system_static_arp() { global $config, $g; if (is_array($config['system']['arptable'])) { //使用$config['system']['arptable']读取XML配置文件中的,如果ARP表存在就进行绑定。 foreach ($config['system']['arptable'] as $cmd) { //从数组中逐行读取每一条IP MAC对应关系。 exec("/usr/sbin/arp -s ".$cmd); //执行这些对应关系,进行绑定。 } } }
此段代码被插在/etc/inc/system.inc中。此段代码的逻辑非常简单,就是从XML中读取,然后用命令进行绑定。用来读取XML配置的语句是m0n0wall提供的,开发者只管用就可以了。其中的['system']['arptable']是XML中的节点,读者可以在XML配置文件中轻易明白其对应的关系。 上面的那段代码定义了一个特别的节点“arptable”,这个节点需要在/etc/xmlparse.inc中特别声明,如果不声明m0n0wall的分析器将不会对其进行分析,那么在system_static_arp()中将无法获取ARP表,也就无法绑定了。下面的声明是m0n0wall所有预先定义好的节点名称(arptable被加粗了)。 $listtags = explode(" ", "rule user group key dnsserver winsserver pages " . "encryption-algorithm-option hash-algorithm-option hosts tunnel onetoone " . "staticmap route alias pipe queue arptable arpenable shellcmd cacert earlyshellcmd mobilekey " . "servernat proxyarpnet passthrumac allowedip wolentry vlan domainoverrides element"); 有了读取、执行的代码了,下来就得设计写入配置的代码了。写入代码在m0n0wall中绝大部分都是在PHP页面中完成的,本例中我们专门为ARP绑定功能撰写/usr/local/www/system_static_arp.php。部分代码如下: 提交表单的代码: <form action="?" method="POST"> <div style="color:#999;background:#E7E3E2;border:1px solid #ccc;padding:4px;margin:8px;"> <div align="left">arp表(格式: IP 空格 MAC): <textarea name="arptable" style='display:block;width:90%;height:100px;margin:6px 1px;'><?=htmlentities($arptable)?> </textarea> <BR> <span class="STYLE1">MAC 地址格式: xx:xx:xx:xx:xx:xx. 系统不对格式进行检查,请慎重提交!!! </span> </div> </div> <input type="submit" name="sub" value="保存"/> <label> <input name="cmdCap" type="submit" id="cmdCap" value="获取" /> </label> </form> 这是一个表单代码,其中提交的内容依靠<?=htmlentities($arptable)?>从XML中获取,或者由用户手工填写。当确定ARP表的内容后,点击“保存”就可以向系统进行提交了,下面我们就看看提交后都做了些什么。 if( $_POST['sub'] ){ //判断这是提交动作 $config['lastchange'] = time(); $arptables = preg_split("/\s*[\r\n]\s*/", trim($_POST['arptable'])); //使用正则表达式对提交来的数据进行分割 if(trim($arptables) != "\n"){ foreach($arptables as $IP_MAC){ $Address = preg_split("/\s*[ ]\s*/",trim($IP_MAC)); if(!is_ipaddr($Address[0])){ include("fbegin.inc"); echo $Address[0] . " 不是合法的IP地址!<br>"; include("fend.inc"); exit(0); } if(!is_macaddr($Address[1])){ include("fbegin.inc"); echo $Address[1] . " 不是合法的MAC地址!<br>"; include("fend.inc"); exit(0); } } } $config['system']['arptable'] = $arptables; //把ARP表写入到XML配置文件中。 write_config(); //保存配置文件。 system_static_arp(); //执行绑定。 } $arptable = @join("\n", $config['system']['arptable']); 同时,系统还提供自动获取ARP表的功能: if( $_POST['cmdCap'] ){ //判断这是获取ARP表的动作 exec("/usr/sbin/arp -an",$rawdata); //执行arp -an 命令获取当前的ARP表。 $arptable = ""; foreach ($rawdata as $line) { $elements = explode(' ',$line); //对每一行系统ARP表用空格进行分割,分隔后保存到数组 $elements中。 //以下是对获取的数组内容进行合法性判断。 if ($elements[3] != "(incomplete)") { $arpent = array(); $arpent['ip'] = trim(str_replace(array('(',')'),'',$elements[1])); $arpent['mac'] = trim($elements[3]); $arpent['interface'] = trim($elements[5]); $data[] = $arpent; } $arptable = $arptable.$arpent['ip']." ".$arpent['mac']."\n"; } } 至此,我们就开发完了全部的功能,还需要最后一步,就是把这个功能做到菜单当中去。在/usr/local/www/begin.inc中添加加粗的内容。 $menu['System']['高级'] = array('system_advanced.php'); $menu['System']['静态ARP'] = array('system_static_arp.php'); if ($_SERVER['REMOTE_USER'] === $config['system']['username']) { $menu['System']['用户管理'] = array('system_usermanager.php'); } else { $menu['System']['用户密码'] = array('system_usermanager.php'); } 开发已经结束,剩下的工作就是把新的内容重新封装进镜像文件,这样就可以进行分发了。 下图是开发好的截图:
|