adoal 的blog

新版 Solaris 10 配 IP Filter 的变化

前些时候上马一台 Sun 小机,装好验收之后,自己想起来要配 IP Filter,实施方工程师给我发了一份文档,是 Sun 培训课程里的材料,于是试图照着做,结果出错,在执行

# autopush -f /etc/ipf/pfil.ap

的时候会出现如下难以理解错误

autopush: ERROR: File /etc/ipf/pfil.ap: could not configure autopush for line ##
autopush: ERROR: Invalid major device number or invalid module name or too many modules

想过各种可能,试试都不对, google 出来的也都是胡说八道。实施方工程师也不知道怎么办,他说没做过,小机一般不在本机配置防火墙,晕。然后突然想到还是看 Sun 官方文档吧,一看之下恍然大悟,原来从 8/07 开始的 Solaris 10 启动 IP Filter 已经不依赖 pfil 了,网卡驱动通过 STREAMS 直接和 IP Filter 起作用,只要用 svcadm 激活 network/ipfilter 服务即可,而 unplumb 之类的操作也不需要做了。

得到的教训是,做配置一定要先看官方文档,网络上的信息人云亦云的太多。另外感慨一下,专职的技术支持工程师毕竟只是靠这个吃饭而已,没教过或者更新了或者用不到的东西不会也是正常的,不能指望他们有激情进行额外的学习和探索。

Debian Volatile

这星期遭遇一件很囧的事情。邮件服务器突然出毛病, SMTP 喂进去的信都塞住不发了。查看一下日志,原来是 ClamAV 罢工,造成邮件入队前的过滤暂时失败,于是堆在那里慢慢等重试。日志里说的主要意思是,最新的病毒特征库里有个无效的字符串。那个字符串的内容是要用户升级到 ClamAV 0.95 版引擎。原因是 ClamAV 开发组停止对老版本的维护,于是在新的特征库里加了这个字符串,这样可以阻止老版本引擎载入特征码,而且文字内容也能让用户得到提示。

又搜索了一下看 Debian 是怎么处理这个问题的。原来在月初已经有人报告过这个 bug / feature 了。在 Squeeze testing 里已经更新到 ClamAV 0.95 版本,但是 Lenny stable 还没有。这时想起还有个叫 Debian volatile 的玩意,其目的就是为了解决在 stable 发行版的更新周期慢和病毒特征码之类数据更新周期快的不河蟹问题。遂找了个源加入,更新,问题解决。

以前用 backports 和现在用 volatile 都是拜 ClamAV 所赐,囧。 Volatie 最大的问题是镜像太少,比以前抱怨的 bakcports 还要少,找个在教育网里速度较快的源太困难。

MBR 签名和 Windows 启动

标准 MBR 从偏移量 0x1b8 开始的 4 个字节是签名,用来标识一个磁盘。这个标记在大多数操作系统里并没有使用,而且很容易被改写掉。 Windows 使用签名来作为识别磁盘的依据,并结合卷的起始偏移量来判定如何分配盘符,如果某个卷的 (签名, 起始偏移量) 组合和盘符的对应关系已保存在注册表里,就给它分配相应的盘符。

直到 Windows 5.x 系列, MBR 签名并不影响 Windows 基本系统的启动过程。 NTLDR 在 boot.ini 里读取的启动配置,磁盘标识是按照 BIOS 约定来编号的。也有资料表明 MBR 签名可以被用于帮助 Windows 在 BIOS 无法处理的情况下完成启动,但并不是强制的。所以操作系统安装程序、磁盘分区管理软件和启动管理软件把 MBR 签名改写之后, Windows 的启动不受影响。也许正是因为如此,这些软件(包括 Windows 自己的安装程序)改 MBR 的时候并不会小心翼翼保留 MBR 签名的值。

然而在 Windows 6.x 时代,这种做法就行不通了。 Windows 6.x 的启动信息放在 BCD 里,不再使用 BIOS 的磁盘编号和 MBR 分区表编号来寻找启动卷,而是 (签名, 起始偏移量) 组合。这样,如果意外改写了 MBR 签名(或者把启动卷移动了位置),就会造成无法启动。然而不幸的是相当多的操作系统(包括 Windows 5.x 在内)的安装程序以及启动管理软件都会去改写 MBR 签名;幸运的是,修复并不麻烦。可以把 MBR 签名改回来,也可以用 Windows 6.x 的安装盘或者 PE 启动盘去修复。

另外网上还有文章说明可以让 Windows 不检查 MBR 签名确定系统盘,从哪个盘引导的就把哪个盘作为系统盘:

BCDEDIT /set {bootmgr} device boot
BCDEDIT /set {default} device boot
BCDEDIT /set {default} osdevice boot

对于引导盘和系统盘一致的情况应该是好用的。

在不远的将来,使用 UEFI boot 和 GPT 分区表的系统将不存在这个问题,因为在 GPT 分区的磁盘里 MBR 只是起防犯旧式软件误操作的作用。操作系统识别卷的依据是 128 位的 GUID,没必要再用 (签名, 起始偏移量) 这种组合了。而移动卷的位置也不会带来什么问题。

用 SPF + Greylisting 给 Postfix 阻挡垃圾邮件

某域名十多年的邮件服务。期间硬件和软件换了好几次。近期将要停止服务。可能这次启用 SPF + greylisting 是我给此域名做的最后一次邮件服务配置了。

安装(Debian下)

$ sudo aptitude install postgrey postfix-policyd-spf-python

配置

  • /etc/postfix/main.cf
[...]
policyd-spf_time_limit = 3600
smtpd_restriction_classes = mfrom_passed_spf
smtpd_recipient_restrictions =
        [...]
        reject_unauth_destination,
        # 一定要放 在reject_unauth_destination 后
        #否则会成为 open relay
        check_policy_service unix:private/policyd-spf,
        check_policy_service inet:127.0.0.1:60000,
        # 后续检查
        [...]
        permit
mfrom_passed_spf =
        # 后续检查
        [...]
        permit

使用 Postfix Restriction Class,只有 SPF 返回值不是 Pass (即 SPF 中性或临时错误)时才检查 greylisting 策略,这样可以减少 greylisting 延迟带来的用户体验变差。

  • /etc/postfix-policyd-spf-python/policyd-spf.conf
[...]
Mail_From_reject = Fail
Mail_From_pass_restriction = mfrom_passed_spf

要注意 policyd-spf.conf 中字段名和值的大小写。

  • /etc/postfix/master.cf
[...]
policyd-spf     unix    -       n       n       -       0       spawn
        user=policyd-spf argv=/usr/bin/policyd-spf

也许用 ppolicy 更合理一点,一个模块化的 policy server 完成多种功能,通过 Python 脚本来配置检查流程。不过看起来比较复杂,也不知道以后有没有机会玩了。

冤枉 Debian 了

前面说的那个在 Lenny domU 里的 PHP 解释器会在访问 Drupal6 的管理页面时停住的问题,其实是误会。问题还是出在 Drupal6 本身,它的更新模块试图直接连 Internet 时如果在内网时连不上,就阻塞在那里了,而且也没法设置代理。之所以我误以为真机上的没这问题,是因为那台真机是通过 NAT 出去的。试了一下把 domU 的 IP 加进 NAT 就好了。为这事还在 Debian bug mailing list 里报告了一下,真丢人。顺便看了一下 Drupal 网站上关于这事的讨论 [DRUPAL7881] ,从 2004 年开始就有,期间也有不少人发过各种简易 patch 但是基本上没啥定论。

[DRUPAL7881]Add support for proxy servers <http://drupal.org/node/7881>

在 Drupal 中使用 reStructuredText - 改进版

用于 Drupal6 的版本,加上了 Pygments 对代码做彩色语法显示。还是很简陋而且乱糟糟的,有很多地方要完善。

需要在主题的 style sheet 里设置菜色显示的颜色方案。 Acquia Marina 有个好处是可以把自己修改的设定加在 local.css 里这样升级的时候就安全了。

  • local.css
#content {
    font-size: 133%;
}

#comments h2.comments {
    text-transform: none;
    font-variant: small-caps;
}

h2.title {
    text-transform: none;
    font-variant: small-caps;
}

pre {
    font-family: "Consolas", monospace;
}

.literal {
    text-decoration: none;
    background-color: #fbeddd;
    border-width: 0 0 1px 0;
    border-style: none none dashed none;
}

/* code-block highlight scheme for Pygments output */
.highlight {
    background-color: #ddedfb;
    border-style: solid;
    border-color: #0099cc;
    border-width: 1px 0 1px 0;
    margin: 1em 0;
    padding: 0.5em 1em;
}

/* css genetated from gen_pyg_style.py should be appended here*/

上面是针对自己的喜好改的 local.css 内容,代码彩色语法的 css 可以用下面的脚本生成,加在 local.css 后面。

  • gen_pyg_style.py
#!/usr/bin/python
import sys
from pygments.formatters import HtmlFormatter
style='friendly'
if len(sys.argv) > 1:
    style = sys.argv[1]
print style
f = HtmlFormatter(style=style)
print f.get_style_defs()

另外 settings.php 最好也改一下

  • settings.php
1 <?php
2 $db_url = '<database url...>';
3 $db_prefix = '';
4 $update_free_access = FALSE;
5 $conf = array(
6     'reverse_proxy' => TRUE,
7     'reverse_proxy_addresses' => array('x.y.z.w',),
8     'allow_insecure_uploads' => 1,
9 );

6、7 行是放在反向代理后面而本服务器又没做特别设置时的必要措施。8 行是因为 Drupal 默认会在上传文件时把多段扩展名加个下划线,譬如 .tar.gz 的改成 .tar_.gz 的样子,号称为了安全,但相当丑陋,我不需要这种安全。

忍无可忍启用 postgrey 之后的感觉

冒着来信延迟会被领导骂的危险启用了 postgrey,结果领导还没骂,发现自己先受不了,因为原先习惯了垃圾邮件,现在一天收收不到两三封,于是总担心服务器是不是坏了,嘿嘿。

还是说 Xen,时钟问题

以前 Etch + Etch / Xen-3.0.3 的时候没遇到问题,现在 dom0 升级了之后, domU 里的时间不对了。当时没仔细看,然后遭遇同事投诉邮件时间不对,汗颜。

网上查了一些办法,试了都不行。配置到错得最严重的时候差了 16 个小时,狂晕。

后来重启了一下 dom0 所在的硬件,居然就好了。看来在原来 UTC=no 的机子上改 UTC=yes 之后还是重启可靠,仅仅用 hwclock 在线同步来同步去是不靠谱的。

domU 认为 dom0 发送过来的时间是 UTC,这也是 Linux kenrel 的默认行为。真机上的 dist 往往可以在启动时通过 hwclock 进行时区调整,而 domU 里没有 RTC 设备所以这个办法就不行了,还是老老实实在 dom0 的 RTC 里用 UTC 存储时间吧,反正 dom0 的服务器上不会装 Windows 搞双启动。

设置 domU 使用独立的时间,然后通过 NTP 同步也是个可行的办法,但太重量级了,没必要。

Xen 和 Lenny 的那点事

Lenny 正式发布之前终于解决了 dom0 的问题,好像是从蜥蜴那里抄来的 backport 吧,反正不是 pv_ops 的方案。于是最近忍不住把一个运行很好的 dom0 从 Etch 升到 Lenny 了,不为别的就为了 PyGrub,没出息。还好对原来的 Etch/domU 没啥影响而且牠能在 domU 内自己升自己的 kernel 也确实挺方便的。然后又装了个 Lenny/domU,折腾得晕。主要问题及解决办法:

  • 启动 Lenny/domU 过了 crond 之后就失去反应了,但网络是通的,想不明白问题在哪里,干掉重装了几次都不行。而 Etch/domU 就没这毛病。后来谷歌得知新版的 Xen domU 更改了处理 console 的方式(而 Etch 里用的还是 Xen 3.0.3 的),其实系统启动好了只是 tty 没跟 console 挂在一起而已。遂在 domU 的内核参数里加上 xencons=tty ,或者把 /etc/inittab 里的 getty 项改成
1:2345:respawn:/sbin/getty 38400 hvc0

这种样子即可。前一种方法比较传统而后一种比较现代。回头想想, debootstrap 安装的时候没装 ssh server 是个失误,如果启动之前补装了就可以远程登录了。

  • Lenny 里的 update-grub 非常之脑残一定要去找根分区所在的硬盘,问题是我用 LVS 装的,把 dom0 的 LV 导入 domU 当文件系统(没用整个 xvd),这样是不可能找到硬盘的,于是 update-grub 出错,于是一直 broken…… 最后的解决办法是在 rc.local 里加了这么一句:
XVDADEV=/dev/xvda
if test ! -e $XVDADEV; then mknod $XVDADEV b 202 0; fi

并且在 grub 的 device.map 里建立映射,相当无语啊。后来想了想,其实可以在 /etc/kernel-img.cong 里去掉 update-grub 的那两项。在 domU 里装一大堆 kernel 把 grub 启动菜单搞复杂根本没必要,只要有一项就够用。而且即使 testing 的 kernel 版本号也不会经常变,需要的时候手工改一下即可。

另外,把这个 Drupal 站移到 Lenny guest 里会出问题,访问管理页面时 php5 锁住不动了,不论用 FastCGI 方式还是 Apache module 方式都如此,很不解。还是放在外面吧。

近期改动,从5到6,从MySQL到PostgreSQL

最近对本站动了两次手脚。

稍远的一次是从 5.X 升级到了 6.X,按照 Drupal 的升级指南一步一步来就行。中间有个意外, 自己写的 5.X 山寨版 reStructured Filter 在升级之后挂了。于是找了个Markdown Filter 的例子把框架扒出来套用了一下搞定。中途不小心破坏了一个 node 的内容,修复之。今天才发现写东西的时候用不了这个 filter 了,遂修正了一下被剥夺的权限。似乎还有些不太对,留着慢慢修吧。

稍近的一次是把后台数据库从 MySQL 迁移到了 PostgreSQL,用写迁移指南 [DRUPAL15793] 那位老兄的话来说“I'm not a MySQL fun” :D 话说我觉得这里 fun 应该是 fan 才说得通。

指南里的三个问题,第一个不管,因为我数据库是 UTF-8 的;第二个要打上补丁,其实就是添了一个字母 E;第三个先不管,反正现在用到的模块不存在这问题。

但是按照指南的步骤搞好以后,站点统计会报错。根据提示信息并搜索并思考得知,PostgreSQL 是没有 CONCAT 函数的,于是 Drupal 自己写了个 SP 加进来,但不幸的是调用的时候参数类型不匹配。真是相当莫名其妙,不知道以前的版本它是怎么搞的。于是手工写了个重载的 CONCAT 搞定之。期间反反复复 DROP 库重建好几次,因为忘了在新库里开启非默认模块,而这东西在迁完库之后再开启是无效的。

以后的子版本升级得小心 E 的问题,至于 重载的CONCAT 应该不会被干掉的。。

瞎折腾啊。

[DRUPAL15793]Drupal 6.x. site Migration from MySQL to PostgreSQL (howto) <http://groups.drupal.org/node/15793>
同步内容