Wednesday, June 23, 2010

无线网络配置

总是有一种怪感觉: 不能太依赖GUI程序。
在我的记忆中, 还是存在着一种场面:系统无法正常进入X而无法正常使用linux的痛苦记忆。总是感觉GUI是学习使用linux的拦路虎。
所以一般情况下, 我都是CLI程序行先的。这也是防止出现我很不喜欢的感觉。

网络照样是CLI行先。之前我的router是配置成WEP的, 都是使用wireless-tools工具集可以很好处理。 但是慢慢地, 这种加密网络已经被淘汰了。 WEP逐渐出的时, WPA流行起来,同时linux也产生了新的一套wireless配置机制:nl80211.  这是为什么wireless-tools工具集无法使用WPA网络的原因
使用WPA无线现在一般是使用wpa_supplicant工具

使用CLI工具最烦就是需要多手动。 复杂的工具还需要配置文件。

其实这都是一次性的, 因为有脚本的存在。

我也是一个懒人~~~谁都不想每次都搞十几钟才上得了网。命令还是比较好办, 就麻烦的是配置文件, wpa_supplicant的配置文件也不是省油的。

特别是在没网络,不能google的时候更是无奈。 对!这种“无奈”是我最不喜欢看到的! 我很讨厌这种感觉。

相信解决的方法是一定会存在的~~~~

“就地出材”是一条出路, 即:不联网也可配置wpa_supplicant!
copy是方法, How ? 从wpa_supplicant的man里copy出可使用的配置文件来。
在man 5 wpa_supplicant里看到: Catch all example that allows more or less all configuration modes.

这个问题已经解决了, 不存在是否有google。也不存在是否有Networking-manager。 (可以直奔可爱的gentoo世界)
把配置copy出来, 按实现情况修改, 去掉不用的, psk使用wpa_passphrase得到。 一切都是没有问题的
* 如果这一步无法做到, 还是去使用GUI吧, 或者是思考一下问题出在哪里。

============= 华丽的分隔线 ===================

下面是N久在docs里存放的文字, 随便一起放出:

计算机的网络是最常见的配置了。来到北京这边。朋友的宿舍里的网络和广东的不一样:
1. 一个宿舍只有几台计算机上网。
2. 可以上网的机器都被登记MAC地址。
3. 可以上网的机器都分有固定的IP, netmask, DNS, gateway
4. 需要web登陆认证方可使用网络。
5. WEP方式

其实就是MAC的限制 + web登陆认证。

还是很管用的。 至少市场卖的路由没有针对这一系统的web登陆。

为了自己的机器可以上网。只需要满足上面的条件即可。 
针对于有线的情况:

ifconfig eth1 hw ether 00:1e:65:18:e2:a8
ifconfig eth1 10.3.52.132 netmask 255.255.255.0
route add default gw 10.3.52.1

然后使用browser访问web认证即可。

有线的倒很清楚怎么解决它。 无线呢? 也很简单

针对于无线的情况(是WEP网络):
$ sudo ifconfig wlan0 hw ether xxxxxxxx
$ sudo iwlist wlan0 scan
可以得到ssid名~~
$ sudo iwconfig wlan0 ssid 'who' key 'password'
$ sudo route add default gw 10.3.52.1










Monday, June 21, 2010

由setrlimit引发的学习

 
POSIX标准中有这样一个函数: sysconf(3).  自己写了小段代码:

 19 #include <unistd.h>
 20 #include <stdio.h>
 21
 22 int main(int argc, char *argv[]){
 23     int fd_max_number = sysconf(_SC_OPEN_MAX);
 24     printf("%d\n", fd_max_number);
 25
 26 }

使用strace可以知道它其实是调用了getrlimit(2),
什么limit? 全称为 resource limit. 这是kernel分给每个进程独立的一组数据。代表了进程可以使用的最大resource上限。具体有哪些, 可以见getrlimit(2)的manual

kernel也有一堆limit参数, 使用sysctl(2)来修改, kernel的limit应该被称为"limit of limits"。

下面的有关于文件描述符的limit:
 * http://www.karakas-online.de/forum/viewtopic.php?t=9834
 * 其中提到一点很有意义:file descriptor与open file

在了解setrlimit(2)配置file descriptor时, 有一个文件引起了我的高度注意:
/etc/security/limits.conf

疑问:
1. setrlimit是system call, 为什么会使用这样一个配置文件的?
2. limits.conf是pam_limits module的配置文件, 如果用户不加载此module时,kernel的setrlimit又是处理的?

不解的情况下, 在kernel的源代码堆里纠结时, 发现了一个常常会看到的一个词:SELinux
FAQ了一把, 得知SELinux是在kernel里加入复杂的access control。比如role-based access control

疑问又来了: Linux是一个可高度裁剪(scale)的系统, 如何做到去掉Linux Security Modules可以不影响现有的system call的呢?

这其中的机制比较吸引我。 google了一把, 得到一篇好文, 分享:
 * http://www.ibm.com/developerworks/linux/library/l-selinux/





Wednesday, June 9, 2010

系统里的hostname

1. 修改host name需要reboot吗?
2. host name与/etc/hosts有什么关系呢?
3. gethostname为什么不受/etc/nsswitch.conf的配置?

这三个问题在不了解host name是什么的时候, 比较纠结.

是否要reboot这个问题是最直接让我产生dig这个host name的动力, 还有就是工作中, 碰到一台机器无法使用sudo命令, 于是花时间学习学习.

平时看hostname(3)时, 发现hostname(3)与/etc/nsswitch.conf扯在一起, 这使host name与DNS中的记录纠结在一起. 更是希望了解之间的关系

在找资料的过程中, 本人发现了一个很有意思的方法:
 * Linux kernel与GNU分开.
什么意思呢? 分界是为了把不同时期的产物, 概念之类的分开. 比如: 当你认host name是kernel的一个变量时, 那么它就与DNS中的记录有明显的不同.

gethostname是system call, 它不是glibc的东西, 所以它与glibc中的DNS查询机制(/etc/nsswitch.conf)是扯不上关系的. gethostbyname, gethostbyaddr都是glibc的东西

就算没有glibc的存在, kernel中的host name照样存在!

按上面的方法, 已经可以很清楚地知道host name与/etc/hosts, /etc/nsswitch.conf是没有关系的.

linux kernel提供了实时修改kernel参数的方法, 是无需要reboot内核就可以生效的.  如sysctl(2), 也有CLI的sysctl(3). 也可以修改/proc/sys/kernel下的文件.

在实际中, GNU软件又常常会使用到host name!

在工作中碰到一个这样的问题: 每当运行sudo时shell就hang住!
它被block了吗?
于是使用strace一查, sudo是在等socket的IO. 发现这台机器的DNS請求是发不出去的

为什么sudo需要使用网络呢?
这其实就是程序期望得到FQDN格式的host name的結果.
得到FQDN格式的host name就使得host  name与DNS查询纠结在一起.

通过学习hostname命令的代码, 可以得到hostname -f其实是等同于下面的代码
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>

int main(int argc, char *argv[]){
    char hostname[64];
    if ( gethostname( hostname, sizeof(hostname) ) != 0){
        perror("1");
    }   
    struct hostent * host_struct;
    if ( (host_struct = gethostbyname( hostname )) == NULL ){
        perror("2");
    }   
    printf("%s\n", host_struct->h_name);

}

可以得到这样的信息: 得到FQDN格式的host name, 是需要使用到
1. host name
2. DNS
这就与linux下DNS查询顺序策略有关系(/etc/nsswitch.conf)


python里有一段很明了的代码(来自socket.py):
def getfqdn(name=''):
    """Get fully qualified domain name from name.

    An empty argument is interpreted as meaning the local host.

    First the hostname returned by gethostbyaddr() is checked, then
    possibly existing aliases. In case no FQDN is available, hostname
    from gethostname() is returned.
    """
    name = name.strip()
    if not name or name == '0.0.0.0':
        name = gethostname()
    try:
        hostname, aliases, ipaddrs = gethostbyaddr(name)
    except error:
        pass
    else:
        aliases.insert(0, hostname)
        for name in aliases:
            if '.' in name:
                break
        else:
            name = hostname
    return name

这样还可以解开一个疑问: 为什么/etc/hosts里常常会出现hostname和它的FQDN记录
增加这样的信息在这里, 查hostname的FQDN时就无须通过网络得到, 当然, 的确有需求的话, 也是可以的, 如果牛B的话, 就每台机器有一个全球唯一的域名也没有人说


Sunday, May 30, 2010

帐号

1. 问题的来源
一直以来, 都有一种错误的认为: 使用useradd增加帐号和配置好ssh-key就可以使用此帐号登陆 .
实现上不如此. 这是需要usePAM的支持. PAM日后再细细学习, 现在先学习学习一般认证

于是, 把login和su命令的代码翻出来看看. 它们都使用如下的方式:

login(不扯PAM)的代码:
 798     pp = getpass(_("Password: "));
 799
 800 #  ifdef CRYPTOCARD
 801     if (strncmp(pp, "CRYPTO", 6) == 0) {
 802         if (pwd && cryptocard()) break;
 803     }
 804 #  endif /* CRYPTOCARD */
 805
 806     p = crypt(pp, salt);
 807     setpriority(PRIO_PROCESS, 0, 0);
.......
 835     if (pwd && !strcmp(p, pwd->pw_passwd))
 836       break;
 837
 838     printf(_("Login incorrect\n"));

su的代码:
265   unencrypted = getpass (_("Password:"));
266   if (!unencrypted)
267     {
268       error (0, 0, _("getpass: cannot open /dev/tty"));
269       return false;
270     }
271   encrypted = crypt (unencrypted, correct);
272   memset (unencrypted, 0, strlen (unencrypted));
273   return STREQ (encrypted, correct);
274 }

都是:
1. 使用了crypt函数
2. 最后都是字符串比较
3. 需要/etc/shadow里的加密后字符串
* 比红色部分可以看出getpass是在stdin被定重向后会报错(hard wire型的程序), 因为它使用了不回显功能(只有tty才有, pipe没有)

在python官网里看到可爱的python代码是这样的:
crypt.crypt(cleartext, cryptedpasswd) == cryptedpasswd

* 可以知道crypt函数的第二个参数可以是salt, 也可以不是salt, 而是加密后的字符串
* 自来http://docs.python.org/library/crypt.html?highlight=crypt#crypt.crypt



2. Lock 与 Unlock 是怎么一个概念?

在man 5 shadow得到的信息:

If the password field contains some string that is not valid result of crypt(3), for instance ! or *, the user will not be able to use a unix password to log in, subject to pam(7).

从上面的C代码和crypt函数的特性可以猜测: Lock无疑就是让方程两边永远不相等, 代码没有其它测试的必要!

具体到ssh的实例, 当使用一指定用户登陆ssh server时, server并不去分别Lock与不Lock的帐号,
虽然没有看过sshd的代码, 但是从表现上: 不会马上打印: Lock user或者马上disconnect, 如使用全世界都公认的halt默认帐号也是提示输入密码:
$ ssh halt@localhost
halt@localhost's password:

3. 其它
su切换用户
FAIL : 以为切换什么用户都是输入root密码
大概看了一把su的代码, 才知道不是这样的~~~~
知道了下面的真相:
1. 需要输入切换到用户的密码
2. restricted shell : 凡不在/etc/shells里登陆的shell都是受限shell. 为了安全的

nologin
平时nologin默认打印信息是: This account is currently not available.
你也是可以修改的: /etc/nologin.txt, 例如下面的例子:

$ sudo su rpc
我顶~ 乱来~ 去问你妈要密码, 不然见一次骂一次
 * 这个例子有点geek~





Friday, May 28, 2010

虚假终端: pseudo-terminal

之前只听前pseudo terminal, 但是没有理会. 前段时间在写脚本时受点一点限制 

1. 为什么使用subprocess无法与子进程多次通信?
2. 像su这种为什么使用subprocess无法调用? ( 这种软件有一个词来描述: hard wire , 表示需要terminal, 代码中使用了istty函数检测到 )
3. vim这种软件的交互是怎么实现的?

subprocess的communicate函数是代码是这样的:

            if self.stdin:
                if input:
                    self.stdin.write(input)
                self.stdin.close()

这里为什么需要self.stdin.close()呢? 这就是subprocess无法与子进程多次通信的地方.
在不明白为什么需要close的情况下, 自己写的一段fork功能的代码, 結果: 当父进程在读子进程的stdout时被block了. 其实, 这时父进程和子进程都是block的, 这被称为"死锁". 这就是为什么subprocess里需要close

那么, 我的需求:
1. 在调用外部进程的情况下, 如何多次父-子进程通信?
2. 如何调用hard wire的程序?

种种问题的浮现让sysadmin岗位的本人不爽. 至少不方便工作....

例子:
1. passwd的调用
passwd是一典型的hard wire程序, 下面的方式调用是不行的:
$ echo "new password" | passwd
比较有意思的是passwd在不同的系统或者是distro下都是不同的.
 * freeBSD下有参数控制(具体的忘了, 也没有环境回顾), 成为batch mode
 * redhat系使用"--stdin"控制
 * ubuntu下没有batch mode参数

2. su -c "my command"的调用
使用在系统上使用su ( 我不得不说, 没有sudo使用~~~), 这将是一个很大的麻烦~~

后知后觉, 发现了pseudo terminal这一概念. 它的应用很广泛, 比如提供network login的sshd就使用到此概念


在朋友(mrluanma (AT) gmail.com)的帮忙下, 找到pexpect程序(http://www.noah.org/wiki/Pexpect). 提供了一个很好的学习模板.

刚接触pseudo terminal很头大的, 还好APUE一书中有这部分和关于terminal I/O的资料, 下面是一个很清晰的图:


本人写了两个简单的例子:
1. 使用pty.fork()函数产生子进程, 子进程与父进程的controlling terminal是不同的.
帐号与密码都是svn

2. 使用pty实现调用passwd这种hard wire外部程序
帐号与密码都是svn





Monday, May 24, 2010

记一次开源软件原理追查

有这种dig行为, 主要是本人想写完一篇笔记, 是关于xxx.pid文件与锁的文章。
在实际和自己了解的情况中, 掌握的东西不够多, 所以就dig下去了。

在shell中, 如果要得到文件锁,在debian系的distro下可以使用这个包:  lockfile-progs

ubuntu下已经预装
http://packages.qa.debian.org/l/lockfile-progs.html

因为一直对lock file 和 file lock这两个名词纠结不清, 所以就下载源代码(还好, 很简短)来看

发现使用了liblockfile库, 视线被转到这一个library上, 首先想到的是找这个库的文档

dpkg -l|grep lockfile
得到:
liblockfile1

dpkg -L liblockfile1
只有一份man手册,是关于随liblockfile1包发布的dotlockfile程序的说明。

嗯, 至少比没有好吧.....man之

不过很有意思的是从这份手册里看到一点线索:
The above mentioned lockfile_create(3) manpage is present in the liblockfile-dev package.

呵呵, lockfile_create 这个API的手册在dev包里, 马上apt-get安装

lockfile_create API手册里有一节叫ALGORITHM的。 其实这一节已经说明了原理和流程了(从man手册里的文字转成流程还是需要很细心地阅读)
我对其它的 "A check is made to see if the existing lockfile is a valid one" 不是很明白, 所以找了lockfile_check函数的代码看, 这里就不贴代码了(还是wordpress写blog好呀~~)
代码可以出下面的地址得到:
 * http://liblockfile.sourcearchive.com/documentation/1.06.1/lockfile_8c-source.html

lockfile_check函数的判断有两个:
1. lock file中保存PID号代表的进程是否还存在, 通过kill函数得到。 (用法与xxx.pid文件类似, 关于xxx.pid用法, 本人别起笔记)
2. 如果lock file 中保存的pid号为0, 则与5分钟为lock file生命期。


xxx.pid文件与lock file

linux下, xxx.pid这类文件还是很常见的, 特别是在/var/run目录下, APUE一书都是推介在这里创建pid文件。
pid文件到底有什么作用呢? 用法是如何的呢?种种疑问让我产生了dig的冲动。

先看看实现生活中碰到的:

1. init.d脚本使用到pid文件

/etc/init.d目录下存放了众多daemon程序的控制脚本,这类脚本一般有几个参数:
  1. start
  2. retstart
  3. stop
  4. 强大的专业服务端还有gracestop之类的参数
这类脚本的这些参数功能的实现是使用到了linux的signal机制, 无疑需要daemon进程的pid

2. lock

lock主要是协调, 操作atomic时使用的一种方式。
举个实际中的例子:
系统需要一个定时任务, 要求每分钟对系统N多状态收集(如硬盘,CPU, 网络等等), 收集过程中不断有日志产生。

这个例子会有两个问题:
  1. 运行间隔为每分钟, 可能会定时任务某次运行时长长于1分钟。
  2. 如果出现1的情况会对日志产生影响
lock主要是用于证实有进程在处理。

linux系统本身有锁的机制, 如flock和fcntl函数。 这种锁称为file lock, 文件锁
linux下的文件锁可以对一个文件的一个区域进行锁定。

现在, 本笔记不想扯上这种强大功能, 只是谈论上面举的例子: 怎么让进程得到一个結果:能否处理

完成这需求, 只需要一个标志, 这个标志需要进程在得到时是atomic性的。

可以通过两种方法得这种标志:
  1. 指定文件已经存在, 表示有进程在处理. 这种方式称为lock file
  2. 使用系统本身的file lock机制, 如果open的file descriptor有锁, 表示有进程在处理

使用linux的flock函数得到file lock, 这里有一个python的例子:
http://svn.lvscar.info/jessinio_repos/flock_example.py
  * 帐号与密码都是svn

lock file 和 file lock 的区别

lock file是利用系统本身的open, link, stat这样的函数, 实现文件创建的atomic性. 成功被创建的文件作为atomic的标志

file lock是利用系统本身的fcntl或者flock函数对某一的文件进行锁定, 将能否成功锁定文件作为atomic的标志

无论是lock file 还是 file lock都是需要文件这一角色的. 但是这一文件起的作用不同.

本文主要是想扯lock file与xxx.pid文件的关系. 不想扯file locklock file

仅仅需要可以标志行为的atomic性的话, lock file是最好的方法:
1. NFS上可以使用(flock函数在旧版本的NFS上不起作用)
2. shell脚本可用. 因为是shell脚本是CLI, 时刻都是新的进程在处理, 不方便使用flock(这样需要一个daemon在保持file lock的存在
 * 关于 lock file可以移步: http://en.wikipedia.org/wiki/File_locking#Lock_files

使用lock file需要解决的问题

当使用lock file作为atomic的标志时, 有一种情况是需要解决的: 持锁者是否还存在, 例如:

当一个进程成功创建了lock file后, 在不明异常的情况终止了, 后面的进程怎么判断刚才被创建的lock file是被进程使用的? ( 使用file lock就没有这种问题, 得到锁的进程终止后锁会被释放, 新的进程可以得到)

具体处理方式可以参考liblockfile的原代码:
 * http://liblockfile.sourcearchive.com/documentation/1.06.1/lockfile_8c-source.html

在它的lockfile_check函数里, 使用到了kill函数. 这个kill函数需要的pid就是xxx.pid文件的pid

因此:

xxx.pid有两种作用:
1. 方便daemon被控制(通过signal)
2. 可以用于实现lock file

利用了1不一定利用2, 但是作用了2一定需要利用1

另外

除了利用kill给指定的pid发signal的方式去判断某进程是否存在的方式后, 还可以使用如下URL提到的方法:
http://stackoverflow.com/questions/2735926/how-to-capture-pid-of-a-linux-daemon-run-from-init-d

利用/proc/NamePID/exe得到的字符串是否为先前在进行的进程名. 这种方法需要知道进程的名称.

疑问

是否会出现pid号的进程存在, 但不是自己期望的进程呢?
查阅了APUE也没有明确, 只知道是有一定的算法去reuse 进程号的.

在这方面, 还是flock方便, 不过此函数不是所有地方都可以使用的, 纠结`~~