m0n0中国

怎样开发m0n0wall功能模块 E-mail
Written by m0n0中国   
Tuesday, 22 July 2008 06:00

你需要具备如下的知识背景:

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');
}

        开发已经结束,剩下的工作就是把新的内容重新封装进镜像文件,这样就可以进行分发了。

下图是开发好的截图:

      

Last Updated ( Friday, 22 August 2008 10:20 )
 
You are here  :