一个奇怪的ipfw问题
ipfw是freebsd默认的防火墙,我利用它来进行流量分流,以及做user defined路由,在利用ipfw分流的文章中有描述。
平时用这一套东西的时候没什么问题,诡异的是只要一重启,ipfw就失效了。但是重启一下ipfw,有可以了。这个问题很久以前就出现了,只是因为系统重启次数比较少,所以不太影响业务。
今天南方电网又因为欠费拉闸了,同样的问题再次出现,我远程登陆进去看,以前我一直以为是接口重启导致ipfw转发错误,这次进去看,才发现ipfw没有处理任何报文,所有的ipfw packet counter都为0,问了deepseek后,他建议我检查net.inet.ip.fw.enable是否为0,检查后确实发现是0。
问题的关键在于这个值为什么是0,在初始化ipfw规则的脚本里有service ipfw restart,添加调试代码后,发现确实在这句执行后sysctl里的值变成0,可是内核没有任何错误信息打印。
因为这个enable其实是一个hookcall,所以很有可能在服务重启的过程中,函数执行出错,因此就把它设置成0了。不过我还是很好奇到底为什么会这样,等过两天回家再调试一下。
总结就是,ai总是能以旁人的眼光看到自己没看到的东西,我一直相信ipfw绝对是启用了,问题可能是rule没有完全生效或者因为keep-state。
============
找到原因了,因为是在/etc/rc.local中调用脚本,并且在脚本中service ipfw restart,但是sh的echo会返回2,如果stdout无法输出。这就导致ipfw_start返回2,而后面的ipfw_poststart便不会执行,而sysctl值就是在这里设置的。
stdout无法输出的原因是在rc.local中使用了后台执行,导致rc.local退出后,stdout被关闭,但是后台还在执行,此时echo失败,在运行命令前把stdout重定向到/dev/console就没有这个问题了。
由此可见,软件工程的安全边界,令人难以想象的小,甚至某些测试没有任何问题的东西,稍换一个环境,就会出莫名其妙的问题,让人百思不得其解。日志和debug消息,才是你的傍身利器,即使当下看起来没什么用。