2012年4月17日星期二

DNS 主从同步的NOTIFY机制

DNS的NOTIFY机制是主从同步使用的,master所控制的zone的序列号变动了以后,会主动通知slave更新,详情可见rfc1996 

1 过程
master slave使用 udp 53端口进行通讯,首先 master 向 slave 的udp53发送一个NOTIFY请求包,slave接收后,向master的udp53发送一个NOTIFY响应包,然后 slave 连接到 master 查询SOA信息,根据序列号判断是否请求进行IXFR传输。

2 相关配置
NOTIFY 的对象默认是有变动的zone的所有NS记录。除此之外,在bind中还通过配置also-notify 指定需要将NOTIFY请求发送到哪些服务器,这些服务器被称为 Stealth Server。bind中还有个配置选项notify,取值可以为yes,no,explicit。yes是默认选项,no表示不发送NOTIFY请求,explicit表示仅发送NOTIFY请求给also-notify中的服务器。

master如果配置了多个IP,则可以通过 notify-source 指定源IP地址。否则如果slave配置了其它的IP为自己的master,则会造成slave误以为收到了错误的NOTIFY请求而无法同步。(rfc1996 3.10)为保证安全,还可以配置allow-notify,来限制哪些master可以向本机发送NOTIFY请求。

如果使用udp进行通讯,master为了避免同时并发量太高,会间隔一段时间(60秒)再发送NOTIFY请求,如果发送请求次数超过5次,则不再向slave发送NOTIFY请求。但是在bind中,我未发现配置选项。

如果配置了多个master,这些master数据由于延时原因可能会不一致,因此slave会向发送NOTIFY请求的master进行同步。

slave 收到相同的NOTIFY请求后,在本次更新结束前,将暂缓响应其它的NOTIFY请求。

2012年4月8日星期日

shell 按行读取变量的值或者命令的输出

shell 中可以使用 while 按行读取一个文件,同时也可以使用 while 按行读取一个变量的值,或者一个命令的输出。方法有4种,分别是进程替换,管道,here document 和here string.

进程替换:  

#! /bin/bash
var=$(cat urfile)
echo "Process Substitution"
while read line
do
    echo "$line"
done < <(echo "$var")

管道:

#! /bin/bash
var=$(cat urfile)
echo "Pipe"
echo "$var" | while read line
do
    echo "$line"
done

here document:

#! /bin/bash
var=$(cat urfile)
echo "Here Document"
while read line
do
    echo "$line"
done <<EOF
$var
EOF


here string:

#! /bin/bash
var=$(cat urfile)
echo "Here String"
while read line
do
    echo "$line"
done <<< "$var"

2012年3月18日星期日

Xwindow 的相关概念



X 就像http,ftp一样是个网络协议,目前的版本是11,release号是7。该协议同样具有Server和Client的概念。X Server的作用是接收客户的请求,绘制客户请求的图形,并把客户的消息传递给X Client端。即X Server的用途是绘图,具体该如何绘制,则是由X Client端提供了绘图数据。根据X Server接收请求和绘制图形这两个功能,可以清楚的看出X Server管理的是客户的输入设备(鼠标键盘)和输出设备(显示器)。所以运行在本地机器上的程序是X Server,远程服务器上的程序是X Client。

设想如下情况:用户点击了FireFox的关闭按钮之后的事情:X Server 通知 FireFox(Client端),客户点击关闭按钮了,你不打算做点神马事情?FireFox 于是开始执行退出命令,并告诉X Server,让我消失吧。于是X Server 不再显示FireFox的窗口。

再设想如下情况:用户通过ssh到远程服务器A,启动一个 X Client 程序(比如FireFox),让该程序通过网络连接到本地的X Server绘制图形;然后用户通过ssh到远程服务器B,启动一个X Client程序(比如xterm),也让该程序通过网络连接到本地的X Server绘制图形。这时,用户可以在自己的终端上同时看到A机器的FF和B机器的xterm。

X Client只提供了绘图数据,至于窗口在显示器的什么位置,X Client是完全不知道的。同时启动两个X client后,X Server 该如何排列窗口呢?这就需要Window Manage了。 最简单的Window Manage是twm。

以上是概念,openSUSE 使用的 XServer是 Xorg,配置文件在/etc/X11/xorg.conf.d,使用的WM是Kwin。X client 就很明显了,进行图形输出的程序都是X client。

可以运行 startx 启动 X server。 startx 是个shell脚本,主要用来读取 Xserver 和 X Client 的配置,然后调用 xinit 启动X server 和 X Client。读取参数的顺序:
  • X server 的参数方面:
    1. 使用 startx 后面接的参数;
    2. 若无参数,则找寻使用者HOME目录的文件,亦即 ~/.xserverrc
    3. 若无上述两者,则以 /etc/X11/xinit/xserverrc
    4. 若无上述三者,则运行 /usr/bin/X
  • X client 的参数方面:
    1. 使用 startx 后面接的参数;
    2. 若无参数,则找寻使用者家目录的文件,亦即 ~/.xinitrc
    3. 若无上述两者,则以 /etc/X11/xinit/xinitrc
    4. 若无上述三者,则运行 xterm
分析openSUSE的 /etc/X11/xinit/xserverc 文件,可以看出实际就是调用X命令来启动X Server的,只是在调用命令前,又通过读取一些文件,配置了环境变量。调用 X 启动 X Server 后,Xorg 会去读取 /etc/X11/xorg.conf 这个配置文件。单纯的 X 启动时,会看到画面漆黑,中心有个可以移动的鼠标的光标。

分析openSUSE的 /etc/X11/xinit/xinitrc 文件,可以看出最后实际调用startkde 或者 gnome-session 来启动桌面环境。

直接调用 X 命令自行启动X Server:X :1 &。:1 表示将X Server启动在哪个终端上,调用该命令后,通过切换终端可以看到一个黑色背景加一个光标。
运行 xterm -display :1 &,可以在终端上看到一个xterm,但是这个xterm没有标题栏,无法移动,可以在里面敲几个命令观察一下。
再次运行 xterm -display :1 &,可以在终端上看到一个全新的xterm,这个xterm覆盖了第一次启动的xterm,同样没有标题栏,无法移动,第一次启动的xterm找不到了。
可以通过启动一个窗口管理器(如twm)来解决此问题。运行twm -display :1 &,可以看到xterm有了标题栏,可以关闭,拖动等等。
这就是X Server,X Client 和 WM 之间的关系。

本地的 X Server 和 X Client 通过socket来通讯,因此6000端口默认是看不到开放的。

更详细的可以参考鸟哥:http://vbird.dic.ksu.edu.tw/linux_basic/0590xwindow.php



2012年3月1日星期四

主从dns服务器view中的数据利用Tsig同步

TSIG同步有两个要点,搞清楚这两个要点,就不会配置错了。
1 每个view需要match一个不同的key,并且allow-transfer中也配置此key。
2 slave的ip不能在master的任何一个view中(any这个view例外)。原因:slave在同步的时候会向master查询对应zone的SOA序列号,如果slave的ip在master中的某个view中,将导致每次查询的soa记录都是此view中的记录,而并非对应的key的view中的记录,因此可能造成无法同步数据,或者同步了其它view中的数据。
 
简单的方式可以这么做:master 的 match-clients 只有 key 而没有任何 ip。这种情况下 master 只能用来更新dns记录并传输记录,而不能作为授权 dns 或者 local dns 使用。这样就避免了在master的match-clients中配置多个诸如 !10.0.0.1 这种acl了。

EXAMPLE:

Master 10.20.149.60
Slave 10.20.149.36

主dns配置:
view "view1" {
        match-clients {key idc-key;};
        allow-transfer {key idc-key;};
        allow-update {key idc-key;};
        also-notify {10.20.149.36;};
        server 10.20.149.36 { keys {idc-key;}; };
        zone "example.com" IN {
        type master;
        file "view/idc/hosts.example.com";
    };
};

从dns配置:
view "view1" {
        match-clients {key idc-key; 10.0.0.0/8; };
        allow-transfer {key idc-key;};
        server 10.20.149.60 {keys idc-key;};
        zone "example.com" IN {
        type slave;
        masters { 10.20.149.60; };
        file "view/idc/hosts.example.com";
    };
};

从dns也可以如此配置:
view "view1" {
        match-clients {key idc-key; 10.0.0.0/8; };
        allow-transfer {key idc-key;};
        zone "example.com" IN {
        type slave;
        masters { 10.20.149.60 keys idc-key;};
        file "view/idc/hosts.example.com";
    };
};

2012年2月25日星期六

在linux下创建winpe启动环境


1 配置dhcp服务,下载ris-linux-0.4(略)

2 配置smb服务,配置文件大概如下:
[reminst]
path = /opt/kickstart/tftpboot
public = yes
browsable = true
read only = no
guest ok = yes

3 配置tftp服务,由于linux对大小写敏感,需要将所有以大写字母命名的文件转换成小写字母命名,转换脚本如下:

find ./ -depth |perl -ne 'chomp;m</[^/]*$>;$d=$`;$_=$f=$&;''s/([\x80-\xFF].)|(\w)/$1\l$2/g;system "mv",$d.$f,$d.$_ if $f ne $_'

配置/opt/kickstart/tftpboot/rules文件,对文件名进行映射,内容如下:
[root@linux_install /opt/kickstart/tftpboot]
#cat rules
ri ^[a-z]: # Remove ¡°drive letters¡±
rg \\ / # Convert backslashes to slashes
rg \# @ # Convert hash marks to @ signs
rg /../ /..no../ # Convert /../ to /..no../
rg A a
rg B b
rg C c
rg D d
rg E e
rg F f
rg G g
rg H h
rg I i
rg J j
rg K k
rg L l
rg M m
rg N n
rg O o
rg P p
rg Q q
rg R r
rg S s
rg T t
rg U u
rg V v
rg W w
rg X x
rg Y y
rg Z z
r ^/(.*) \1

启动tftp服务时,需要指定-m参数:
/opt/kickstart/hpa-tftp/sbin/in.tftpd -l -v -s /opt/kickstart/tftpboot/ -m /opt/kickstart/tftpboot/rules

创建winpe的启动环境:
1 找到 STARTROM.N1_ 文件,并重命名为/opt/kickstart/tftpboot/winpe.0
2 运行sed -i -e 's/NTLDR/peldr/gi' /opt/kickstart/tftpboot/winpe.0
3 找到setupldr.exe 文件(i386目录下),并重命名为/opt/kickstart/tftpboot/peldr
4 运行sed -i -e 's/winnt\.sif/winpe\.sif/gi' /opt/kickstart/tftpboot/peldr
5 运行sed -i -e 's/ntdetect\.com/ntdetect\.wpe/gi' /opt/kickstart/tftpboot/peldr
6 找到NTDETECT.COM文件(i386目录下),并重命名为/opt/kickstart/tftpboot/ntdetect.wpe
7 运行 ris-linux-0.4/fixloader.py /opt/kickstart/tftpboot/peldr (此处仅为pxe启动winpe使用,如配置WinXP的安装源则无需这一操作)
8 配置/opt/kickstart/tftpbootwinpe.sif文件如下:

[Intranet root@KickStart /opt/kickstart/tftpboot]
#cat winpe.sif
[SetupData]
OsLoadOptions = "/fastdetect /minint"
SetupSourceDevice = "\Device\LanmanRedirector\10.20.129.9\reminst\windows\winpe"
[UserData]
ComputerName = WindowsPE

KickStart关于%include的使用方法


我们可以将ks文件中相同的内容独立出来写在同一个文件common当中,然后通过ks中的%include /tmp/ks/common选项包含进来。但是common文件的位置该如何处理呢?
首先解释一下ks文件被安装程序anaconda解析的过程:
1pre脚本运行之前,anacondaks文件进行解析,这个时候anaconda会忽略掉所有它不能找到的文件。
2 运行pre脚本。
3 重新解析那些没有找到的文件。

在第1步中使anaconda访问到include所包含的文件是比较困难的,但是通过运行pre脚本可以使anaconda在第3步中对缺失的文件进行解析。pre脚本可以写成如下的形式:

%pre
#!/bin/bash
###ks服务器的IP192.168.0.1common文件存在于ks服务器上的/kickstart/ks/ 目录下
mount 192.168.0.1:/kickstart /mnt
mkdir –p /tmp/ks
cp /mnt/ks/common /tmp/ks/common

通过以上三个命令anaconda可以直接访问到/tmp/ks/common文件。在第1步对ks配置文件解析时被忽略的%include /tmp/ks/common 顺利的在第3步中被解析了。

可以通过以上方法对系统的分区行为根据需要进行动态设置,方法如下:
1 ks文件中的分区信息独立出来,写进partation文件,然后在ks中添加%include /tmp/ks/partation
2 pre脚本中用fdisk等命令分析硬盘信息
3 pre脚本中运行命令,修改/tmp/ks/partation文件
经过以上三步,anaconda就可以根据硬盘类型,容量的不同对分区信息进行动态调整了

2012年2月23日星期四

qmail对虚拟域用户的处理过程

qmail对域的管理分为两种,一种为本地域,一种为虚拟域。本地域指的是系统用户,虚拟域可以通过手工单独创建,更快捷的方式是通过vpopmail进行管理。如果将信投递给虚拟域用户,qmail处理如下:

假定service.com是一个定义在virtualdomain文件中的虚拟域,该文件包含如下一行
service.com:service.com
qmail收到发给用户user@service.com的信件后首先检查service.com是否存在于locals文件中(service.com是否本地域?),结果不存在,qmail继续检查user@service.com是否在virtualdomains中(user@service.com是否作为一个单独的用户不与service.com域有关?),结果仍然不存在,qmail继续检查service.com是否存在于virtualdomains中,结果是存在的。qmail将user@service.com转化为service.com-user@service.com进行投递。
投递的具体方式定义在assign文件中,assign文件中包含如下的一行:
+service.com-:service.com:89:89:/disk2/vpopmail/domains/service.com:-::
+service.com-定义了匹配service.com-为前缀的邮件,将会以service.com这个用户进行传送,service.com这个用户的uid和gid都是89,/disk2/vpopmail/domains/service.com则定义了用户service.com所在的目录。而最后两个域则定义了.qmail文件实际为.qmail-。
qmail检查service.com-user这个用户是否存在,结果失败,然后qmail继续检查是否存在service.com这个用户,根据对assign文件的说明,可知目前系统存在这个用户,且这个用户的uid和gid都是89,是非0的,用户service.com的家目录/disk2/vpopmail/domains/service.com的uid和gid也都为89。因此把信件交给service.com处理。
service.com用户检查/disk2/vpopmail/domains/service.com是否存在.qmail-user文件,如果失败,那么直接采用.qmail-default文件定义的方式进行处理。

2012年2月20日星期一

加密签名和gpg

为了研究apk的签名,看了下签名和加密的问题,不过本文和apk的签名毫无关系。

加密算法有两种,对称密钥算法和非对称密钥算法。对称密钥算法包括DES,AES等,非对称密钥算法包括RSA,DSA等。对称密钥算法在加密和解密的时候使用同一个密钥。加密解密速度快,如果同时和多方通信,密钥管理成本高;非对称密钥算法则有私钥和公钥之分。私钥保留在用户手中,不对外透漏,公钥公布在互联网上,比如可以放在keys.gnupg.net。公钥和私钥都可以用来加密数据。密钥管理成本低,但是加密解密速度慢。Gnupg简称gpg,是生成和管理密钥的工具。Gnome用seahorse做前端,KDE用Kgpg做前端。

签名是指身份认证,即证明和B通讯的另一方就是A,而不是C冒充的。即A使用私钥签名,B使用A的公钥进行解密。解密成功,则证明对方就是A。
加密是指将信息加密,即使其他用户获得加密后的信息,也无法获得信息正确内容。即B使用A的公钥进行加密,再将加密数据传给A,A收到数据后,利用私钥解密,C即使获得了加密数据,但是由于C没有A的私钥,因此信息依然是安全的。

gpg 命令:
生成key: gpg --gen-key
修改key信息: gpg --edit-key ilout
查看当前的公钥: gpg --list-keys
查看当前的私钥: gpg --list-secret-keys
删除私钥:gpg --delete-secret-keys ilout
删除公钥:gpg --delete-keys ilout
加密信息:gpg -e -r ilout file
解密信息:gpg -d file.asc  >file
导出公钥:gpg --export -a ilout >ilout.pk
将公钥上传到网站: gpg --import --keyserver keys.gnupg.net --send-key E7201101
从文件导入公钥:gpg --import -a ilout.pk
从网站导入公钥:gpg --import --keyserver keys.gnupg.net --recv-keys E7201101
导入公钥后需要对公钥签名,以表示信任该公钥: gpg --sign-key E7201101

上述的签名过程有个漏洞:如果C谎称自己是A,然后将自己的公钥发送给B,B直接导入假冒的公钥,也可以顺利的完成签名认证的过程。为了解决此问题,就产生了数字证书来保证A的公钥无法被任何人冒充。

2012年1月18日星期三

linux利用无线网卡做热点

这是一篇失败的文档,只留作记录,无太大参考价值。

操作系统:opensuse12.1 i586
内核:3.1.0-1.2-desktop
硬件: thinkpad x201i
网卡:Intel Corporation Centrino Advanced-N 6200
软件:hostapd-0.7.3

参考:http://linuxwireless.org/en/users/Documentation/hostapd
过程:

1 创建了最简单的一个配置文件 /tmp/hostapd.min.conf:
interface=wlan0
driver=nl80211
ssid=test
channel=1

2 启动hostapd,hostapd -dd /tmp/hostapd.min.conf,报错:
nl80211: Register Action command failed: ret=-114 (Operation already in progress)
nl80211: Register Action match - hexdump(len=1): 06
nl80211: Failed to register Action frame processing - ignore for now
nl80211: Add own interface ifindex 3
nl80211: Failed to set interface 3 to mode 3: -95 (Operation not supported)
nl80211: Failed to set interface 3 to mode 3: -95 (Operation not supported)
nl80211: Interface mode change to 3 from 0 failed
nl80211: Failed to set interface wlan0 into AP mode
nl80211 driver initialization failed.
ELOOP: remaining socket: sock=4 eloop_data=0x80c5958 user_data=0x80c5e38 handler=0x80751f0
ELOOP: remaining socket: sock=6 eloop_data=0x80c7ae0 user_data=(nil) handler=0x807f2f0

经 google 有人解答是linux驱动不支持AP,不清楚该如何验证这种说法。(理论依据?)基本死翘翘了,不再折腾了。

2012年1月13日星期五

android手机利用Linux主机的网络上网

PC利用android手机的网络联网,英语称为usb tethering;如果反过来,手机利用PC的网络上网,则称为reverse-tethering。如果PC为windows或者MAC,则在安装htc sync后,可以直接进行reverse-tethering;如果PC的操作系统为Linux,则有两种方案:
1 将Linux配置为路由器,利用NAT联网。
2 在Linux上启动bridge,然后联网。
本文简述利用NAT上网的办法,bridge方式与此大同小异。

思路:
1 利用usb线将root过的手机连接到PC上,并在PC上创建虚拟设备usb0
2 在android手机上设定usb0设备的IP地址,dns,路由信息
3 在PC上设定新创建的网卡usb0的IP地址(该地址即为android设备的网关地址)
4 在PC上打开ip_forward,并配置NAT

软硬件要求:
1 root过的android手机
2 Gscript(只为方便,非必须)

配置过程:
1 修改/sys/devices/platform/msm_hsusb/usb_function_switch 的值:
经测试,该文件中值的含义如下:

==== 1 ==== usb_mass_storage:enable
==== 2 ==== adb:enable
==== 4 ==== ether:enable
==== 8 ==== diag:enable
==== 16 ==== serial:enable
==== 32 ==== projector:enable
==== 128 ==== adb:enable
==== 256 ==== modem:enable
==== 512 ==== cdc_ethernet:enable
比如echo 1 >usb_function_switch,表示将android设备作为存储;echo 6>usb_function_switch,表示在PC上创建网卡usb0,并打开adb调试开关。为方便调试,最好将值修改为6,否则直接设定为4也可以。

2 利用setprop配置android的网络信息
dnsserver="8.8.8.8"
setprop net.usb0.ps.ip 192.168.99.1
setprop net.usb0.ps.mask 255.255.255.0
setprop net.usb0.ps.gw 192.168.99.254
setprop net.usb0.ps.dns $dnsserver
setprop net.dns1 $dnsserver
ifconfig usb0 192.168.99.1 netmask 255.255.255.0
ip route add default via 192.168.99.254 dev usb0

3 在Linux主机上,设置usb0的IP地址为192.168.99.254,掩码为24位。可利用ifconfig,或者直接在NetworkManager中设置,不再详述。

4 在Linux主机上设定NAT以及ip_forward
iptables -t nat -A POSTROUTING -j MASQUERADE
echo 1>/proc/sys/net/ipv4/ip_forward

经过以上操作后,android手机理论上就可以上网了。但经过测试,发现不是所有应用程序都可以连接网络,原因见该链接,但是没有解决方案 http://android.stackexchange.com/questions/14046/android-usb-reverse-tethering-how-to-fool-the-apps 。 可以连接网络的程序有:支付宝,电子市场,uc浏览器;无法连接网络的程序有:gtalk,新浪微博,安全隧道。

为方便输入以上命令,最好安装Gscript,创建一个脚本net.sh,内容如下:

#!/bin/sh
dnsserver="8.8.8.8"
echo 6 >/sys/devices/platform/msm_hsusb/usb_function_switch
sleep 3
setprop net.usb0.ps.ip 192.168.99.1
setprop net.usb0.ps.mask 255.255.255.0
setprop net.usb0.ps.gw 192.168.99.254
setprop net.usb0.ps.dns $dnsserver
setprop net.dns1 $dnsserver
ifconfig usb0 192.168.99.1 netmask 255.255.255.0
ip route add default via 192.168.99.254 dev usb0

附录:
如果需要将android手机设置成为硬盘,除了需要
echo 3  >/sys/devices/platform/msm_hsusb/usb_function_switch 以外,还需要设定存储设备的路径,对于我的手机,需要:
echo "/dev/block/vold/179:64" >/sys/devices/platform/usb_mass_storage/lun0/file
具体的值,可以先将手机挂载为硬盘设备,然后记录下 /sys/devices/platform/usb_mass_storage/lun0/file的内容,最后写个disk.sh 文件利用Gscript运行:

#!/bin/sh
echo 3  >/sys/devices/platform/msm_hsusb/usb_function_switch
echo "/dev/block/vold/179:64" >/sys/devices/platform/usb_mass_storage/lun0/file