Archive for 二月, 2012

昨天试用了一下同学的microsoft arc鼠标,被自动安装了Intellipoint驱动。

今天换回我的小罗技,虽然可以使用。但是进入“鼠标”管理,发现无法切换左右键了(我是悲催的左手鼠标),显示的是“无法找到microsoft鼠标”,界面不同于默认的鼠标管理界面,且全部灰显。

进入程序管理里,卸载掉Intellipoint驱动即可。

立此备忘。

本文参考了:http://www.grepmymind.com/2008/01/11/memcached-php-semaphore-cache-expiration-handling/

问题描述

memcached作为互联网经常使用的缓存工具,大大减少了数据库的压力。但是当并发度较高时,可能会有多个请求都检测到expire,从而发起数据库请求,于是会对数据库造成冲击。

问题重现

当采用传统的设置expire time时,使用httpload工具并发100,在数据库请求函数里sleep 1秒钟。memcache封装里打印是从mc读取还是db读取。expire time设置为2秒。可以看到有重复的数据库请求:

[2012-02-21 10:17:13] NOTICE [1]: mc(127.0.0.1,/test.php)
[2012-02-21 10:17:14] NOTICE [1]: mc(127.0.0.1,/test.php)
[2012-02-21 10:17:14] NOTICE [1]: db(127.0.0.1,/test.php)
[2012-02-21 10:17:14] NOTICE [1]: db(127.0.0.1,/test.php)
[2012-02-21 10:17:15] NOTICE [1]: mc(127.0.0.1,/test.php)
[2012-02-21 10:17:15] NOTICE [1]: mc(127.0.0.1,/test.php)

解决方法

                function call_high($func, $args, $expire=60){/*{{{*/
                        // Calulate key
                        $key = md5(json_encode($func).json_encode($args));

                        // Get from memcached
                        return $this->get_high($key, $func, $args, $expire);

                }/*}}}*/

                // lock_expire should longer than db_func running time
                function get_high($key/* string or array*/, $db_func/*mixed*/, $db_args/*mixed*/, $expire, $lock_expire=10){/*{{{*/
                        if (!$this->mem){
                                return false;
                        }

                        $val = $this->get($key);

                        // if(!$val){ // Maybe empty when FIRST get, otherwise, must something wrong, like the lock&work thread haven't refresh item before expire time. So we use a short lock expire time to allow more thread trying to refresh. }   

                        if ( $val && (!isset($val['t']) || !isset($val['i'])) ){ // don't have expire index? must be wrong. For logic layer to process.
                                #Core_Log::get_instance()->notice("mc, no expire index");
                                return $val;
                        }

                        if ($val && ($val['t'] - $this->get_high_cal_time($expire) > time())){ // not expired
                                #Core_Log::get_instance()->notice("mc");
                                return $val['i'];
                        }

                        // expired, allowed one process to refresh it
                        if (!($this->get_high_lock($key, $lock_expire))){ // other process has refreshing it, so we quit with old data(or may be empty)
                                #Core_Log::get_instance()->notice("other lock, we quit");
                                return $val?$val['i']:false;
                        }

                        #Core_Log::get_instance()->notice("db");
                        // get from user func, and set into memcache
                        $db_info = call_user_func_array($db_func, $db_args); // may be empty, we also set into mc
                        $this->set_high($key, $db_info, MEMCACHE_COMPRESSED, $expire, $this->get_more_expire_time($expire));

                        $this->free_high_lock($key);
                        #Core_Log::get_instance()->notice("save and free lock");

                        return $db_info;
                }

                // These two functions should guarantee the refresh thread can do all work before realy expired.
                // So the work_time < cal_time + more_time                 
                protected function get_high_cal_time($expire){                         
                        return intval(min(10, max(0, $expire/5))); // [0, 10]                 
                }                 
                protected function get_more_expire_time($expire){                          
                        return intval(max(100, $expire*0.1)); // [100, ...)                 
                }                 

                function get_high_lock($key, $expire=100){                         
                        return $this->mem->add($key.self::HIGH_MC_LOCK_TAIL, 1, 0, $expire); // return true when not exists already, otherwise return false, use as mutex
                        //return $this->mem->increment($key.self::HIGH_MC_LOCK_TAIL, 1); //can't, because increment will return false, if elem not exists already
                }

                function free_high_lock($key){
                        return $this->del($key.self::HIGH_MC_LOCK_TAIL);
                        //return $this->mem->decrement ($key.self::HIGH_MC_LOCK_TAIL, 1);
                }

                function set_high($key, $val, $flag, $expire/*second*/, $more_expire=100){
                        if (!$this->mem){
                                return false;
                        }

                        // save expire time
                        $expire_time = time()+$expire;
                        $val = array('t'=>$expire_time, 'i'=>$val);

                        $expire += $more_expire; // need more expire time, because we don't want return null when get_high
                        return $this->set($key, $val, $flag, $expire);
                }/*}}}*/

基本思想就是利用mutex锁,保证仅有一个进程更新该item。

有几个点说明一下:

  • 首次请求时,非refresh线程会返回为空,在业务逻辑上是否可接受?解决方法可以是等待一定时间后再次获取
  • 如果refresh线程工作太久,导致memcached中相应item已经expire了,那么其他线程get from mc即为空,则也会尝试获取lock后从db读取。这里通过设置lock time、cal time和more expire time已解决,允许其他线程也请求db,这种情况一般是数据库阻塞导致的,允许重复读取可能会加大数据库压力,所以存疑。
  • 如果memcached内存不足,导致item expire,则正常情况下也只有一个refresh线程从db读取
  • 如果memcached内存不足,导致lock expire,则会有多个refresh线程从db读取(一般不会设置这么小的memcached吧?)

作为程序员,肯定都加过班,也有晚上或者周末自己写代码、学习技术的经验。为什么做这些事情,有时很快乐,而有时却很痛苦呢?

我自己认为,关键点在于是否自愿。而是否自愿,又受到很多种因素的影响,比如兴趣、公司氛围、合作者等。

记得还在实习期,经常半夜写SIP协议代码,抛却被老板压榨的感觉,单纯评论coding的过程那是非常快乐的,因为做的事情在那时看来是有挑战的、有意义的。

刚去MySpace的时候,有一次迫于项目的压力,加班到晚上10点左右,心情是焦虑的,但是却认为理所当然,因为上线的时间是我们承诺的,而且是team里的同事一起在抗这件事。这种团队的感觉、责任,使得加班也不是那么难熬。

而某些情况下,加班就很无聊。比如明明今天的工作已经完成,时针指向6点半,窗外已经天黑,预计到要堵车了,而leader还一点放人走路的意思也没有,周围的同事还装作很忙碌的样子。或者,就是工作时间里,都在扯皮、磨洋工,非要把活拖到晚上加班才能完成。这样的公司,打死我都不去!

我觉得,用真诚对待同事和上下级。

  • 坚决杜绝加班文化
  • 必要的时候,该加班就加班,仅相关人加班,但leader可以陪着,完事之后请客吃饭是必须的
  • 关心同事生活、家庭的突发情况,该体贴的时候就体贴
  • 平等、公平待人

至少对我而言,只有对公司有感情、认可所做的事情,才会有动力付出更多。

ios、andriod平台上,开发app有3种模式。

  1. native app模式,即使用object C或者java之类的语言,经过app store等销售,被用户安装,可以调用到一切允许的底层接口,如拍照等。
  2. web app模式,基于浏览器,使用html5、js、css等,不需要经过app store,用户直接通过URI访问,不可以访问底层接口
  3. 混合模式,基于第三方框架如phonegap,相当于开发一个属于自己的小浏览器,基于该浏览器使用html5等进行页面展示,通过网络访问后端服务器接口进行数据交互,逻辑部分可以完全放置的服务器端。需要通过app store销售,但是业务升级等可以不依赖于app store。

从开发速度来说,web app 快于混合模式。但是目前我倾向于native app。

php的foreach与引用(&)一起,如果使用不当,会引起相当隐蔽的bug。

  $arr = array(1,2,3);
  foreach($arr as &$a){
      echo $a."\t";
  }
  echo "\n";

  foreach($arr as $a){
      echo $a."\t";
  }

输出为:

:!./test.php
1       2       3
1       2       2
而期望输出为:
:!./test.php
1       2       3
1       2       3

可以看到,数组的最后一个元素被修改了!

实际上,是数组的最后一个元素,被N次改写了。具体过程为:

  1. 第一次foreach结束之后,$a与$arr[last]指向同一块地址
  2. 第二次foreach里,每次,$a的内容都被改写!
    1. $arr[2] = $a = $arr[0] = 1
    2. $arr[2] =  $a = $arr[1] = 2
    3. $arr[2] =  $a = $arr[2] = 2

这样就很明显了!通过以下代码可以看出具体过程:

 $arr = array(1,2,3);
  foreach($arr as &$a){
      echo $a."\t";
  }
  echo "\n";

  foreach($arr as $a){
      echo "$a( $arr[2] )\t";
  }

输出为:

:!./test.php
1       2       3
1( 1 )  2( 2 )  2( 2 )

结论

如果你用lighttpd1.5(以下lighttpd均指1.5)做静态文件服务器,或者你虽然用lighttpd处理php请求,但是用到$PHYSICAL作为mod_proxy_core的条件, 且某个时候你的单机流量很低(几个/s), 或许你也有类似的问题,但是影响程度或许不会引起你的注意!
1.Lighttpd的mod_proxy_core不建议用$PHYSICAL作为条件;
2.Lighttpd的stat cache机制没有节省任何开销;
3.Lighttpd子线程和主线程通过管道+epoll的通信机制,存在event丢失问题;

现象

用户反馈凌晨的时候访问百度某页面,某些模块的数据出不来;

其它依赖于我们的前端接口的产品线反馈访问时间有时候超过1s;

我们自己的QA环境偶尔也会出现请求超过1s的问题;

因此我们打开lighttpd的日志的%D配置,打印ms级别的处理时间,发现晚上1点到凌晨8点有很多处理时间超过1s的请求,500ms以上的也有很多,并且流量越低, 比例越大;

1点-8点是流量低峰时期,流量越低,性能越差

这个现象每到高峰时期就正常了,因为是流量低峰才会出现这样的慢请求,占总比例非常之少,对整体的性能和稳定性影响极小,所以性能和稳定性监控报表中没有发现这个问题。

追查过程

由于这个页面对性能要求相对比较严格,虽然性能和稳定性衡量数据已经非常好, 但是这个问题一直是一个阴影,不解决终归不爽,所以开始了下面的追查过程:

由于处理路径是lighttpd->php-cgi->框架+逻辑, 首先的怀疑是框架+逻辑问题,但是通过查看php的处理时间,流量低峰高峰都非常正常,极少超过100ms,所以排除是框架+逻辑问题;那究竟是php-cgi的问题还是lighttpd本身的问题呢?为了排除php-cgi的问题,我们尝试了从线下复现这个问题,看访问静态文件是否也有类似的问题。但是悲剧的是线下就是复现不了这个问题。那再对比和线上环境的不同,会不会是先要经过一段时间的大流量,然后再小流量才会出现这个问题呢?于是用ab 30qps压了2个小时后停止,然后再手动访问试了一下,果然如此!通过访问静态文件,发现静态文件也是如此,处理时间超过1s, 因此基本排除php-cgi本身的原因,问题应该是出在lighttpd本身

通过这个线下实验,我们还发现了如下规律:

1.前期用ab压的时间不定,有时候压2个小时后然后低流量访问还不会出现这个问题,有一定的随机性;

2.手动低流量访问的时候,并不是每次都慢,对同一个url, 紧接着的两次访问(访问第一次后马上访问第二次),第一次会慢,但第二次会很快,然后再过个1-2s钟再访问第三次,又会很慢;

3.手动请求的时候,如果慢,总是慢1s, 但是线上有慢1s的,也有不是慢1s的,最多1s;

4.重启lighttpd后,所有请求会恢复正常,需要重新压;

于是产生两个最大的疑问, lighttpd在公司使用这么广,处理静态资源和php请求的都有用到, 别的产品线为什么不报? 为什么是1s? 对于第一个疑问,觉得可能是因为这种情况影响的平均性能非常少,可能其他产品线不会这么敏感,或者是流量低峰的单机请求量也很高,没有频繁的触发这个问题,这个时候还对比了其它产品线的lighttpd.conf, 这个时候是没有发现有什么问题的。于是就从第二个问题开始着手追查:为什么是1s?

带着问题,开始读lighttpd的源代码了。。。

该页面lighttpd event-handler用的是linux-sysepoll;

首先发现lighttpd代码中有各个地方和1s有关的代码:

源文件server.c

第一个1000ms是lighttpd的epoll的超时时间,也就是如果没有任何句柄有事件发生,epoll最多等待1000ms后即会返回,如果有事件发生,epoll会马上返回有事件发生的所有句柄,然后lighttpd会处理joblist中已经准备好的connection,重新进入状态机;第二个1s是lighttpd有个一个trigger机制,每隔1s会触发一次SIGALRM, 然后lighttpd处理超时的请求,清理stat_cache等;因此,通过修改这两个1s, 发现当改成fdevent_poll(srv->ev, 500);  后,慢请求都变成500了, 所以慢请求是因为的那个connection已经放在joblist, 但是没有成功触发epoll返回, epoll只有等待超时后返回,该connection才会被处理,这也就解释了为什么流量高峰的时候没有这个问题,因为高峰的时候epoll返回得相当频繁,也可以解释为什么线上的慢请求慢100,200ms的都有,但是最多不超过1s了,线下手工访问的时候总是慢1s, 这也是因为每秒的请求量的原因, 这其实也是类似epoll这种异步事件处理模型所带来的通病,用延迟换吞吐量;

问题进一步,那为什么重启lighttpd后,就算流量低也没问题呢,所以进一步看代码,通过把lighttpd所有debug日志打开,发现这个问题和lighttpd­的stat cache机制有关, 为了避免反复的调用stat来获取文件信息,lighttpd用了一个全局的hash表保存了每个物理路径的所对应文件的stat结果,这个机制和server. stat-cache-engine这个配置有关,我们用的默认配置“simple”, cache结果会缓存1s, 如果没有命中或者失效,lighttpd会把这个stat任务放在一个队列里面, 然后告诉状态机HANDLER_WAIT_FOR_EVENT, 暂时退出状态机,由另外几个线程来异步处理这个stat任务,处理完这个任务后,会重新把这个任务关联的connection加到joblist_queue中,然后通过管道通知主线程,让epoll返回, 相关代码如下:

源文件joblist.c

上面的代码可以看出, lighttpd是通过判断一个全局的变量srv->did_wakeup,如果是0,就把它改成1,然后往这个管道发生一个空格字符串,触发主线程的epoll返回,如果这个变量不是0,就不会通知主进程。

下面的代码是主线程epoll返回后,和这个管道句柄对于的处理函数,可以看出主线程又把srv->did_wakeup初始化成0了, 这样下次还会wakeup主线程;

源文件server.c

这就引发一个思考,如果因为某种原因srv->did_wakeup被修改成1了,但是主线程由于某种原因没有收到这个write事件,导致srv->did_wakeup没有被改成0,那不是后面都不会通过管道通知主线程了,为了证明这个假设,我加了下trace代码,发现确实是这样的,设置srv->did_wakeup =1 做了2456次,但是设置srv->did_wakeup = 0只做了2455次,只差一次,并且后续都没有做这个操作了,另外还发现子线程每次write管道都是成功的,但是最后一次主线程没有收到这个事件,至于为什么没有收到,就没有继续查了。

但是,还是有个疑问,我访问的php请求,lighttpd应该把请求路径发给php-fpm,自己应该不关心物理路径的啊,就不用搞什么stat cache吧,这个时候想起了当时为了解决某扩展能够正确获取到PATH_INFO的问题,把mod_proxy_core的条件配置从$HTTP[“url”] =~ “\.php$”改成了$PHYSICAL[“existing-path”] =~ “\.php$”。马上修改配置,再测试,问题果然没有了, 通过查看lighttpd代码,发现如果配置成$PHYSICAL这种形式,会导致lighttpd去stat这个物理文件,这个操作在mod_proxy_core之前执行,如果用$HTTP[“url”]就不会引发这个问题,到此,一切都清楚了,我看到的其它老的产品线都是配的$HTTP[“url”], 只有少数的几个产品线不是用的$HTTP[“url”],也只是单机流量非常低的情况才会出现这个问题,很难会让人觉察到!

另外,在追查问题的过程中还发现lighttpd stat_cache机制的两个问题,第一个问题就是处理stat任务的子线程,在stat之后,并没有更新这个stat cache的状态为FINISHED, 下次来查的时候还是没有命中cache, 等于是白干了。如下代码所示:

源文件stat_cache.c

第二个问题是就是命中了stat cache, 其实还是需要调用stat判断改cache有没有过期, 所以觉得stat cache本身这个机制也是白搞了,比较没有节省stat的开销,还多搞了,如下代码所示:

源文件stat_cache.c

遗留问题

子线程和主线程通过管道+epoll的机制来通信,为什么会有一定的概率失败呢?write管道其实是成功的,由于精力有限,这个问题没有继续追查;

管道其实是成功的,由于精力有限,这个问题没有继续追查;

对lighttpd配置的建议

如果利用mod_proxy_core做php处理,还是用$HTTP[“url”]做条件吧,例如:

$HTTP[“url”] =~ “\.php” {

proxy-core.balancer = “static”

proxy-core.protocol = “fastcgi”

proxy-core.allow-x-sendfile = “enable”

proxy-core.backends = ( “unix:/home/super/php/var/php-cgi.sock” )

proxy-core.rewrite-request = (

“_pathinfo” => ( “(/[^\?]*)/index\.php(/[^\?]*)” => “$2″ ),

“_scriptname” => ( “(.*\.php)” => “$1″ )

)

注意,为了让php-cgi取到正确的PATH_IFNO, 请注意添加“_pathinfo” rewrite规则!

对lighttpd代码优化的建议

1.在每隔1s的trigger操作中,新增一个操作:将srv->did_wakeup重置为0,防止这个变量变成1以后永远便不会0的情况发生;
2.stat_cache_thread处理完stat_job之后,要更新源stat_cache_entry的状态为FINISHED, 否则就白搞了;
3.命中stat cache后,不用再通过stat判断该cache是不是最新的,因为最多缓存1s钟;

zz from: http://stblog.baidu-tech.com/?p=1444

显示Linux系统信息

arch 显示机器的处理器架构(1)

uname -m 显示机器的处理器架构(2)

uname -r 显示正在使用的内核版本

dmidecode -q 显示硬件系统部件 – (SMBIOS / DMI)

hdparm -i /dev/hda 罗列一个磁盘的架构特性

hdparm -tT /dev/sda 在磁盘上执行测试性读取操作

cat /proc/cpuinfo 显示CPU info的信息

cat /proc/interrupts 显示中断

cat /proc/meminfo 校验内存使用

cat /proc/swaps 显示哪些swap被使用

cat /proc/version 显示内核的版本

cat /proc/net/dev 显示网络适配器及统计

cat /proc/mounts 显示已加载的文件系统

lspci -tv 罗列 PCI 设备

lsusb -tv 显示 USB 设备

date 显示系统日期

cal 2007 显示2007年的日历表

date 041217002007.00 设置日期和时间 – 月日时分年.秒

clock -w 将时间修改保存到 BIOS

Linux关机 (系统的关机、重启以及登出 )

shutdown -h now 关闭系统(1)

init 0 关闭系统(2)

telinit 0 关闭系统(3)

shutdown -h hours:minutes 按预定时间关闭系统

shutdown -c 取消按预定时间关闭系统

shutdown -r now 重启(1)

reboot 重启(2)

logout 注销

文件和目录操作

cd /home 进入 ‘/ home’ 目录’

cd .. 返回上一级目录

cd ../.. 返回上两级目录

cd 进入个人的主目录

cd ~user1 进入个人的主目录

cd – 返回上次所在的目录

pwd 显示工作路径

ls 查看目录中的文件

ls -F 查看目录中的文件

ls -l 显示文件和目录的详细资料

ls -a 显示隐藏文件

ls *[0-9]* 显示包含数字的文件名和目录名

tree 显示文件和目录由根目录开始的树形结构(1)

lstree 显示文件和目录由根目录开始的树形结构(2)

mkdir dir1 创建一个叫做 ‘dir1′ 的目录’

mkdir dir1 dir2 同时创建两个目录

mkdir -p /tmp/dir1/dir2 创建一个目录树

rm -f file1 删除一个叫做 ‘file1′ 的文件’

rmdir dir1 删除一个叫做 ‘dir1′ 的目录’

rm -rf dir1 删除一个叫做 ‘dir1′ 的目录并同时删除其内容

rm -rf dir1 dir2 同时删除两个目录及它们的内容

mv dir1 new_dir 重命名/移动 一个目录

cp file1 file2 复制一个文件

cp dir/* . 复制一个目录下的所有文件到当前工作目录

cp -a /tmp/dir1 . 复制一个目录到当前工作目录

cp -a dir1 dir2 复制一个目录

ln -s file1 lnk1 创建一个指向文件或目录的软链接

ln file1 lnk1 创建一个指向文件或目录的物理链接

touch -t 0712250000 file1 修改一个文件或目录的时间戳 – (YYMMDDhhmm)

file file1 outputs the mime type of the file as text

iconv -l 列出已知的编码

iconv -f fromEncoding -t toEncoding inputFile > outputFile creates a new from the given input file by assuming it is encoded in fromEncoding and converting it to toEncoding.

find . -maxdepth 1 -name *.jpg -print -exec convert “{}” -resize 80×60 “thumbs/{}” \; batch resize files in the current directory and send them to a thumbnails directory (requires convert from Imagemagick)

文件搜索

find / -name file1 从 ‘/’ 开始进入根文件系统搜索文件和目录

find / -user user1 搜索属于用户 ‘user1′ 的文件和目录

find /home/user1 -name \*.bin 在目录 ‘/ home/user1′ 中搜索带有’.bin’ 结尾的文件

find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件

find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件

find / -name \*.rpm -exec chmod 755 ‘{}’ \; 搜索以 ‘.rpm’ 结尾的文件并定义其权限

find / -xdev -name \*.rpm 搜索以 ‘.rpm’ 结尾的文件,忽略光驱、捷盘等可移动设备

locate \*.ps 寻找以 ‘.ps’ 结尾的文件 – 先运行 ‘updatedb’ 命令

whereis halt 显示一个二进制文件、源码或man的位置

which halt 显示一个二进制文件或可执行文件的完整路径

Linux挂载文件系统

mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 – 确定目录 ‘/ mnt/hda2′ 已经存在

umount /dev/hda2 卸载一个叫做hda2的盘 – 先从挂载点 ‘/ mnt/hda2′ 退出

fuser -km /mnt/hda2 当设备繁忙时强制卸载

umount -n /mnt/hda2 运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用

mount /dev/fd0 /mnt/floppy 挂载一个软盘

mount /dev/cdrom /mnt/cdrom 挂载一个cdrom或dvdrom

mount /dev/hdc /mnt/cdrecorder 挂载一个cdrw或dvdrom

mount /dev/hdb /mnt/cdrecorder 挂载一个cdrw或dvdrom

mount -o loop file.iso /mnt/cdrom 挂载一个文件或ISO镜像文件

mount -t vfat /dev/hda5 /mnt/hda5 挂载一个Windows FAT32文件系统

mount /dev/sda1 /mnt/usbdisk 挂载一个usb 捷盘或闪存设备

mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share 挂载一个windows网络共享

Linux磁盘空间管理

df -h 显示已经挂载的分区列表

ls -lSr |more 以尺寸大小排列文件和目录

du -sh dir1 估算目录 ‘dir1′ 已经使用的磁盘空间’

du -sk * | sort -rn 以容量大小为依据依次显示文件和目录的大小

rpm -q -a –qf ‘%10{SIZE}t%{NAME}n’ | sort -k1,1n 以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统)

dpkg-query -W -f=’${Installed-Size;10}t${Package}n’ | sort -k1,1n 以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统)

Linux用户和群组

groupadd group_name 创建一个新用户组

groupdel group_name 删除一个用户组

groupmod -n new_group_name old_group_name 重命名一个用户组

useradd -c “Name Surname ” -g admin -d /home/user1 -s /bin/bash user1 创建一个属于 “admin” 用户组的用户

useradd user1 创建一个新用户

userdel -r user1 删除一个用户 ( ‘-r’ 排除主目录)

usermod -c “User FTP” -g system -d /ftp/user1 -s /bin/nologin user1 修改用户属性

passwd 修改口令

passwd user1 修改一个用户的口令 (只允许root执行)

chage -E 2010-12-31 user1 设置用户口令的失效期限

pwck 检查 ‘/etc/passwd’ 的文件格式和语法修正以及存在的用户

grpck 检查 ‘/etc/passwd’ 的文件格式和语法修正以及存在的群组

newgrp group_name 登陆进一个新的群组以改变新创建文件的预设群组

Linux文件的权限

–- 使用 “+” 设置权限,使用 “-” 用于取消

ls -lh 显示权限

ls /tmp | pr -T5 -W$COLUMNS 将终端划分成5栏显示

chmod ugo+rwx directory1 设置目录的所有人(u)、群组(g)以及其他人(o)以读(r )、写(w)和执行(x)的权限

chmod go-rwx directory1 删除群组(g)与其他人(o)对目录的读写执行权限

chown user1 file1 改变一个文件的所有人属性

chown -R user1 directory1 改变一个目录的所有人属性并同时改变改目录下所有文件的属性

chgrp group1 file1 改变文件的群组

chown user1:group1 file1 改变一个文件的所有人和群组属性

find / -perm -u+s 罗列一个系统中所有使用了SUID控制的文件

chmod u+s /bin/file1 设置一个二进制文件的 SUID 位 – 运行该文件的用户也被赋予和所有者同样的权限

chmod u-s /bin/file1 禁用一个二进制文件的 SUID位

chmod g+s /home/public 设置一个目录的SGID 位 – 类似SUID ,不过这是针对目录的

chmod g-s /home/public 禁用一个目录的 SGID 位

chmod o+t /home/public 设置一个文件的 STIKY 位 – 只允许合法所有人删除文件

chmod o-t /home/public 禁用一个目录的 STIKY 位

Linux文件的属性

–- 使用 “+” 设置权限,使用 “-” 用于取消

chattr +a file1 只允许以追加方式读写文件

chattr +c file1 允许这个文件能被内核自动压缩/解压

chattr +d file1 在进行文件系统备份时,dump程序将忽略这个文件

chattr +i file1 设置成不可变的文件,不能被删除、修改、重命名或者链接

chattr +s file1 允许一个文件被安全地删除

chattr +S file1 一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘

chattr +u file1 若文件被删除,系统会允许你在以后恢复这个被删除的文件

lsattr 显示特殊的属性

Linux打包和压缩文件

bunzip2 file1.bz2 解压一个叫做 ‘file1.bz2′的文件

bzip2 file1 压缩一个叫做 ‘file1′ 的文件

gunzip file1.gz 解压一个叫做 ‘file1.gz’的文件

gzip file1 压缩一个叫做 ‘file1′的文件

gzip -9 file1 最大程度压缩

rar a file1.rar test_file 创建一个叫做 ‘file1.rar’ 的包

rar a file1.rar file1 file2 dir1 同时压缩 ‘file1′, ‘file2′ 以及目录 ‘dir1′

rar x file1.rar 解压rar包

unrar x file1.rar 解压rar包

tar -cvf archive.tar file1 创建一个非压缩的 tarball

tar -cvf archive.tar file1 file2 dir1 创建一个包含了 ‘file1′, ‘file2′ 以及 ‘dir1′的档案文件

tar -tf archive.tar 显示一个包中的内容

tar -xvf archive.tar 释放一个包

tar -xvf archive.tar -C /tmp 将压缩包释放到 /tmp目录下

tar -cvfj archive.tar.bz2 dir1 创建一个bzip2格式的压缩包

tar -xvfj archive.tar.bz2 解压一个bzip2格式的压缩包

tar -cvfz archive.tar.gz dir1 创建一个gzip格式的压缩包

tar -xvfz archive.tar.gz 解压一个gzip格式的压缩包

zip file1.zip file1 创建一个zip格式的压缩包

zip -r file1.zip file1 file2 dir1 将几个文件和目录同时压缩成一个zip格式的压缩包

unzip file1.zip 解压一个zip格式压缩包

RPM 包 – (Fedora, Redhat及类似系统)

rpm -ivh package.rpm 安装一个rpm包

rpm -ivh –nodeeps package.rpm 安装一个rpm包而忽略依赖关系警告

rpm -U package.rpm 更新一个rpm包但不改变其配置文件

rpm -F package.rpm 更新一个确定已经安装的rpm包

rpm -e package_name.rpm 删除一个rpm包

rpm -qa 显示系统中所有已经安装的rpm包

rpm -qa | grep httpd 显示所有名称中包含 “httpd” 字样的rpm包

rpm -qi package_name 获取一个已安装包的特殊信息

rpm -qg “System Environment/Daemons” 显示一个组件的rpm包

rpm -ql package_name 显示一个已经安装的rpm包提供的文件列表

rpm -qc package_name 显示一个已经安装的rpm包提供的配置文件列表

rpm -q package_name –whatrequires 显示与一个rpm包存在依赖关系的列表

rpm -q package_name –whatprovides 显示一个rpm包所占的体积

rpm -q package_name –scripts 显示在安装/删除期间所执行的脚本l

rpm -q package_name –changelog 显示一个rpm包的修改历史

rpm -qf /etc/httpd/conf/httpd.conf 确认所给的文件由哪个rpm包所提供

rpm -qp package.rpm -l 显示由一个尚未安装的rpm包提供的文件列表

rpm –import /media/cdrom/RPM-GPG-KEY 导入公钥数字证书

rpm –checksig package.rpm 确认一个rpm包的完整性

rpm -qa gpg-pubkey 确认已安装的所有rpm包的完整性

rpm -V package_name 检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间

rpm -Va 检查系统中所有已安装的rpm包- 小心使用

rpm -Vp package.rpm 确认一个rpm包还未安装

rpm2cpio package.rpm | cpio –extract –make-directories *bin* 从一个rpm包运行可执行文件

rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm 从一个rpm源码安装一个构建好的包

rpmbuild –rebuild package_name.src.rpm 从一个rpm源码构建一个 rpm 包

YUM 软件包升级器 – (Fedora, RedHat及类似系统)

yum install package_name 下载并安装一个rpm包

yum localinstall package_name.rpm 将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系

yum update package_name.rpm 更新当前系统中所有安装的rpm包

yum update package_name 更新一个rpm包

yum remove package_name 删除一个rpm包

yum list 列出当前系统中安装的所有包

yum search package_name 在rpm仓库中搜寻软件包

yum clean packages 清理rpm缓存删除下载的包

yum clean headers 删除所有头文件

yum clean all 删除所有缓存的包和头文件

DEB 包 (Debian, Ubuntu 以及类似系统)

dpkg -i package.deb 安装/更新一个 deb 包

dpkg -r package_name 从系统删除一个 deb 包

dpkg -l 显示系统中所有已经安装的 deb 包

dpkg -l | grep httpd 显示所有名称中包含 “httpd” 字样的deb包

dpkg -s package_name 获得已经安装在系统中一个特殊包的信息

dpkg -L package_name 显示系统中已经安装的一个deb包所提供的文件列表

dpkg –contents package.deb 显示尚未安装的一个包所提供的文件列表

dpkg -S /bin/ping 确认所给的文件由哪个deb包提供

APT 软件工具 (Debian, Ubuntu 以及类似系统)

apt-get install package_name 安装/更新一个 deb 包

apt-cdrom install package_name 从光盘安装/更新一个 deb 包

apt-get update 升级列表中的软件包

apt-get upgrade 升级所有已安装的软件

apt-get remove package_name 从系统删除一个deb包

apt-get check 确认依赖的软件仓库正确

apt-get clean 从下载的软件包中清理缓存

apt-cache search searched-package 返回包含所要搜索字符串的软件包名称

Linux查看文件内容

cat file1 从第一个字节开始正向查看文件的内容

tac file1 从最后一行开始反向查看一个文件的内容

more file1 查看一个长文件的内容

less file1 类似于 ‘more’ 命令,但是它允许在文件中和正向操作一样的反向操作

head -2 file1 查看一个文件的前两行

tail -2 file1 查看一个文件的最后两行

tail -f /var/log/messages 实时查看被添加到一个文件中的内容

Linux文本处理

cat file1 file2 … | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT

cat file1 | command( sed, grep, awk, grep, etc…) > result.txt 合并一个文件的详细说明文本,并将简介写入一个新文件中

cat file1 | command( sed, grep, awk, grep, etc…) >> result.txt 合并一个文件的详细说明文本,并将简介写入一个已有的文件中

grep Aug /var/log/messages 在文件 ‘/var/log/messages’中查找关键词”Aug”

grep ^Aug /var/log/messages 在文件 ‘/var/log/messages’中查找以”Aug”开始的词汇

grep [0-9] /var/log/messages 选择 ‘/var/log/messages’ 文件中所有包含数字的行

grep Aug -R /var/log/* 在目录 ‘/var/log’ 及随后的目录中搜索字符串”Aug”

sed ‘s/stringa1/stringa2/g’ example.txt 将example.txt文件中的 “string1″ 替换成 “string2″

sed ‘/^$/d’ example.txt 从example.txt文件中删除所有空白行

sed ‘/ *#/d; /^$/d’ example.txt 从example.txt文件中删除所有注释和空白行

echo ‘esempio’ | tr ‘[:lower:]‘ ‘[:upper:]‘ 合并上下单元格内容

sed -e ’1d’ result.txt 从文件example.txt 中排除第一行

sed -n ‘/stringa1/p’ 查看只包含词汇 “string1″的行

sed -e ‘s/ *$//’ example.txt 删除每一行最后的空白字符

sed -e ‘s/stringa1//g’ example.txt 从文档中只删除词汇 “string1″ 并保留剩余全部

sed -n ’1,5p;5q’ example.txt 查看从第一行到第5行内容

sed -n ’5p;5q’ example.txt 查看第5行

sed -e ‘s/00*/0/g’ example.txt 用单个零替换多个零

cat -n file1 标示文件的行数

cat example.txt | awk ‘NR%2==1′ 删除example.txt文件中的所有偶数行

echo a b c | awk ‘{print $1}’ 查看一行第一栏

echo a b c | awk ‘{print $1,$3}’ 查看一行的第一和第三栏

paste file1 file2 合并两个文件或两栏的内容

paste -d ‘+’ file1 file2 合并两个文件或两栏的内容,中间用”+”区分

sort file1 file2 排序两个文件的内容

sort file1 file2 | uniq 取出两个文件的并集(重复的行只保留一份)

sort file1 file2 | uniq -u 删除交集,留下其他的行

sort file1 file2 | uniq -d 取出两个文件的交集(只留下同时存在于两个文件中的文件)

comm -1 file1 file2 比较两个文件的内容只删除 ‘file1′ 所包含的内容

comm -2 file1 file2 比较两个文件的内容只删除 ‘file2′ 所包含的内容

comm -3 file1 file2 比较两个文件的内容只删除两个文件共有的部分

Linux字符设置和文件格式转换

dos2unix filedos.txt fileunix.txt 将一个文本文件的格式从MSDOS转换成UNIX

unix2dos fileunix.txt filedos.txt 将一个文本文件的格式从UNIX转换成MSDOS

recode ..HTML < page.txt > page.html 将一个文本文件转换成html

recode -l | more 显示所有允许的转换格式

Linux文件系统分析

badblocks -v /dev/hda1 检查磁盘hda1上的坏磁块

fsck /dev/hda1 修复/检查hda1磁盘上linux文件系统的完整性

fsck.ext2 /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性

e2fsck /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性

e2fsck -j /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性

fsck.ext3 /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性

fsck.vfat /dev/hda1 修复/检查hda1磁盘上fat文件系统的完整性

fsck.msdos /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性

dosfsck /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性

Linux初始化文件系统

mkfs /dev/hda1 在hda1分区创建一个文件系统

mke2fs /dev/hda1 在hda1分区创建一个linux ext2的文件系统

mke2fs -j /dev/hda1 在hda1分区创建一个linux ext3(日志型)的文件系统

mkfs -t vfat 32 -F /dev/hda1 创建一个 FAT32 文件系统

fdformat -n /dev/fd0 格式化一个软盘

mkswap /dev/hda3 创建一个swap文件系统

SWAP文件系统

mkswap /dev/hda3 创建一个swap文件系统

swapon /dev/hda3 启用一个新的swap文件系统

swapon /dev/hda2 /dev/hdb3 启用两个swap分区

Linux备份

dump -0aj -f /tmp/home0.bak /home 制作一个 ‘/home’ 目录的完整备份

dump -1aj -f /tmp/home0.bak /home 制作一个 ‘/home’ 目录的交互式备份

restore -if /tmp/home0.bak 还原一个交互式备份

rsync -rogpav –delete /home /tmp 同步两边的目录

rsync -rogpav -e ssh –delete /home ip_address:/tmp 通过SSH通道rsync

rsync -az -e ssh –delete ip_addr:/home/public /home/local 通过ssh和压缩将一个远程目录同步到本地目录

rsync -az -e ssh –delete /home/local ip_addr:/home/public 通过ssh和压缩将本地目录同步到远程目录

dd bs=1M if=/dev/hda | gzip | ssh user@ip_addr ‘dd of=hda.gz’ 通过ssh在远程主机上执行一次备份本地磁盘的操作

dd if=/dev/sda of=/tmp/file1 备份磁盘内容到一个文件

tar -Puf backup.tar /home/user 执行一次对 ‘/home/user’ 目录的交互式备份操作

( cd /tmp/local/ && tar c . ) | ssh -C user@ip_addr ‘cd /home/share/ && tar x -p’ 通过ssh在远程目录中复制一个目录内容

( tar c /home ) | ssh -C user@ip_addr ‘cd /home/backup-home && tar x -p’ 通过ssh在远程目录中复制一个本地目录

tar cf – . | (cd /tmp/backup ; tar xf – ) 本地将一个目录复制到另一个地方,保留原有权限及链接

find /home/user1 -name ‘*.txt’ | xargs cp -av –target-directory=/home/backup/ –parents 从一个目录查找并复制所有以 ‘.txt’ 结尾的文件到另一个目录

find /var/log -name ‘*.log’ | tar cv –files-from=- | bzip2 > log.tar.bz2 查找所有以 ‘.log’ 结尾的文件并做成一个bzip包

dd if=/dev/hda of=/dev/fd0 bs=512 count=1 做一个将 MBR (Master Boot Record)内容复制到软盘的动作

dd if=/dev/fd0 of=/dev/hda bs=512 count=1 从已经保存到软盘的备份中恢复MBR内容

Linux光盘操作

cdrecord -v gracetime=2 dev=/dev/cdrom -eject blank=fast -force 清空一个可复写的光盘内容

mkisofs /dev/cdrom > cd.iso 在磁盘上创建一个光盘的iso镜像文件

mkisofs /dev/cdrom | gzip > cd_iso.gz 在磁盘上创建一个压缩了的光盘iso镜像文件

mkisofs -J -allow-leading-dots -R -V “Label CD” -iso-level 4 -o ./cd.iso data_cd 创建一个目录的iso镜像文件

cdrecord -v dev=/dev/cdrom cd.iso 刻录一个ISO镜像文件

gzip -dc cd_iso.gz | cdrecord dev=/dev/cdrom – 刻录一个压缩了的ISO镜像文件

mount -o loop cd.iso /mnt/iso 挂载一个ISO镜像文件

cd-paranoia -B 从一个CD光盘转录音轨到 wav 文件中

cd-paranoia — “-3″ 从一个CD光盘转录音轨到 wav 文件中(参数-3)

cdrecord –scanbus 扫描总线以识别scsi通道

dd if=/dev/hdc | md5sum 校验一个设备的md5sum编码,例如一张 CD

Linux网络设置 – (以太网和WIFI无线)

ifconfig eth0 显示一个以太网卡的配置

ifup eth0 启用一个 ‘eth0′ 网络设备

ifdown eth0 禁用一个 ‘eth0′ 网络设备

ifconfig eth0 192.168.1.1 netmask 255.255.255.0 控制IP地址

ifconfig eth0 promisc 设置 ‘eth0′ 成混杂模式以嗅探数据包 (sniffing)

dhclient eth0 以dhcp模式启用 ‘eth0′

route -n show routing table

route add -net 0/0 gw IP_Gateway configura default gateway

route add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.1.1 configure static route to reach network ’192.168.0.0/16′

route del 0/0 gw IP_gateway remove static route

echo “1″ > /proc/sys/net/ipv4/ip_forward activate ip routing

hostname show hostname of system

host www.example.com lookup hostname to resolve name to ip address and viceversa(1)

nslookup www.example.com lookup hostname to resolve name to ip address and viceversa(2)

ip link show show link status of all interfaces

mii-tool eth0 show link status of ‘eth0′

ethtool eth0 show statistics of network card ‘eth0′

netstat -tup show all active network connections and their PID

netstat -tupl show all network services listening on the system and their PID

tcpdump tcp port 80 show all HTTP traffic

iwlist scan show wireless networks

iwconfig eth1 show configuration of a wireless network card

hostname show hostname

host www.example.com lookup hostname to resolve name to ip address and viceversa

nslookup www.example.com lookup hostname to resolve name to ip address and viceversa

whois www.example.com lookup on Whois database

Microsoft Windows networks (SAMBA)

nbtscan ip_addr netbios name resolution

nmblookup -A ip_addr netbios name resolution

smbclient -L ip_addr/hostname show remote shares of a windows host

smbget -Rr smb://ip_addr/share like wget can download files from a host windows via smb

mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share mount a windows network share

zz from: http://www.magentonotes.com/linux-ssh-commands.html

使用php发送邮件很简单,实际利用的是linux自带的smtp服务。这里不加赘述。

邮件服务,我的理解是数据包与包的交互。发送邮件时,smtp服务接收client程序的邮件标题、正文、from、to、优先级等信息,拼装为smtp数据包,网络发送给to地址所在的邮件服务器。接收邮件时,smtp服务从网络上的邮件服务器接收数据包,解析出to的email地址,利用推或拉的方式传递给client。

php中的mail函数,作为一种client形式,在其help里写的很清楚:

reject note 返回值

Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise.

It is important to note that just because the mail was accepted for delivery, it does NOT mean the mail will actually reach the intended destination.

即mail的返回值仅代表php.ini里配置的smtp server是否接收发送请求成功,而并不代表最终的to email接收成功。

进而推测,smtp对mail请求应当是异步的,那么也许smtp的log中会有邮件接收的真正状态。进入centos系统的/var/log,果然有maillog!

Feb  7 09:21:45 v080106 sendmail[32612]: q171LiwL032612: to=abc@sohu.com, ctladdr=admin (500/500), delay=00:00:01, xdelay=00:00:01, mailer=relay, pri=32760, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (Ok: queued as AC58F1060001)

这是一条发送成功的邮件记录。各字段意义为:

Feb  7 09:21:45 发送时间
v080106 发送者机器名称
sendmail[32612]: 进程号
q171LiwL032612: 唯一Message-ID,可以根据该字段,找到log里与本次发送相关的所有记录
to=abc@sohu.com, 接收者邮箱
ctladdr=admin (500/500)
delay=00:00:01, xdelay=00:00:01, 延时
mailer=relay, 邮件服务器,是relay,则参考下面的relay字段可知具体信息
pri=32760, 优先级
relay=[127.0.0.1] [127.0.0.1], 中继
dsn=2.0.0, smtp code (200表示成功)
stat=Sent (Ok: queued as AC58F1060001) 状态说明,Sent代表发送成功

Feb  8 01:38:48 v080106 postfix/smtpd[11264]: F1E521060007: client=localhost.localdomain[127.0.0.1]

Feb  8 01:38:49 v080106 postfix/cleanup[11267]: F1E521060007: message-id=<201202071738.q17HcmEB011273@v080106.isv>

Feb  8 01:38:49 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 01:38:49 v080106 sendmail[11273]: q17HcmEB011273: to=abc@vip.sohu.com, ctladdr=admin (500/500), delay=00:00:01, xdelay=00:00:01, mailer=relay, pri=32807, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (Ok: queued as F1E521060007)

Feb  8 01:38:49 v080106 postfix/smtp[11270]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=0.25, delays=0.05/0/0.15/0.05, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 02:04:59 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 02:05:00 v080106 postfix/smtp[22089]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=1572, delays=1571/0.85/0.13/0.04, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 02:38:26 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 02:38:26 v080106 postfix/smtp[28707]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=3577, delays=3577/0.01/0.14/0.05, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 03:45:54 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 03:45:54 v080106 postfix/smtp[10772]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=7625, delays=7625/0.03/0.08/0.05, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 05:08:20 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 05:08:30 v080106 postfix/smtp[19312]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=12581, delays=12572/9.5/0.11/0.04, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 06:31:47 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 06:31:47 v080106 postfix/smtp[21697]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=17578, delays=17578/0/0.08/0.05, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 07:55:00 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 07:55:00 v080106 postfix/smtp[22783]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=22572, delays=22571/0.02/0.11/0.37, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 09:01:41 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 09:01:41 v080106 postfix/smtp[23869]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=26572, delays=26572/0/0/0, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

Feb  8 10:08:21 v080106 postfix/qmgr[18249]: F1E521060007: from=<admin@v080106.isv>, size=3258, nrcpt=1 (queue active)

Feb  8 10:08:21 v080106 postfix/smtp[24922]: F1E521060007: to=<abc@vip.sohu.com>, relay=mx.vip.sohu.com[61.135.132.86]:25, delay=30572, delays=30572/0/0/0, dsn=4.1.8, status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))

以上是一组失败的记录,唯一号是F1E521060007。可以看到,当接收到失败之后,sendmail进行了多次重试。里面还有一些疑问,之后再解决,现在主要关心错误信息:

relay=mx.vip.sohu.com[61.135.132.86]:25, 中继
dsn=4.1.8, # 错误码
status=deferred (host mx.vip.sohu.com[61.135.132.86] said: 450 4.1.8 <admin@v080106.isv>: Sender address rejected: Domain not found (in reply to RCPT TO command))  # 具体描述,延迟发送,mx.vip.sohu.com认为无法找到发送者的domain

还有一类统计数据:

Feb  8 10:50:21 v080106 postfix/scache[25440]: statistics: start interval Feb  8 10:41:42

Feb  8 10:50:21 v080106 postfix/scache[25440]: statistics: domain lookup hits=1692 miss=209 success=89%

Feb  8 10:50:21 v080106 postfix/scache[25440]: statistics: address lookup hits=947 miss=9428 success=9%

Feb  8 10:50:21 v080106 postfix/scache[25440]: statistics: max simultaneous domains=4 addresses=9 connection=30

有了以上这些信息,就可以准备的跟踪真实的邮件到达率了。当然,是否被认为是垃圾邮件之类,是无法从这里看出来的。

———————————————————

以gmail为例,可以点击邮件右上方的more按钮->show original查看到邮件头信息:

Delivered-To: abc@gmail.com
Received: by 10.182.176.71 with SMTP id cg7cs142014obc;
        Tue, 7 Feb 2012 15:44:47 -0800 (PST)
Received: by 10.68.218.167 with SMTP id ph7mr39734334pbc.110.1328658286305;
        Tue, 07 Feb 2012 15:44:46 -0800 (PST)
Return-Path: <201202072344452bac1460e73a42f2b86762ab94c6272d-C29QW58DB99VUH@bounces.amazon.com>
Received: from smtp-out-184-237.amazon.com (smtp-out-184-237.amazon.com. [207.171.184.237])
        by mx.google.com with ESMTP id e6si262857pbj.138.2012.02.07.15.44.45;
        Tue, 07 Feb 2012 15:44:46 -0800 (PST)
Received-SPF: pass (google.com: domain of 201202072344452bac1460e73a42f2b86762ab94c6272d-C29QW58DB99VUH@bounces.amazon.com designates 207.171.184.237 as permitted sender) client-ip=207.171.184.237;
Authentication-Results: mx.google.com; spf=pass (google.com: domain of 201202072344452bac1460e73a42f2b86762ab94c6272d-C29QW58DB99VUH@bounces.amazon.com designates 207.171.184.237 as permitted sender) smtp.mail=201202072344452bac1460e73a42f2b86762ab94c6272d-C29QW58DB99VUH@bounces.amazon.com
Date: Tue, 7 Feb 2012 23:44:45 +0000 (UTC)
From: "Amazon.cn" <store-news@amazon.cn>
To: "abc@gmail.com" <abc@gmail.com>
Message-ID: <677952103.17204211328658285803.JavaMail.em-build@massmail-sender-fe-9004.sea19.amazon.com>

SPF的状态我看到的有pass(可信)、neutral(中性),有些垃圾邮件的状态也是pass的。
大批量发送广告邮件时,目前收集到的需要注意:

  1. 控制发送频率,10个以上ip并行发送,一天控制在几十万的数量
  2. 更真实的header信息,通过配置发件域名等信息
  3. 如果可能,同邮件服务商沟通,争取进入白名单

邮件域名配置:

  1. 主机A记录abc.com
  2. 主机A记录mail.abc.com
  3. 主机A记录www.abc.com
  4. 主机A记录ftp.abc.com
  5. abc.com 到 mail.abc.com的MX记录

另外还有反向解析相关的配置。比如我们的发件地址是news@mail.flykobe.com,则需要在邮件服务器里将HELO地址配成mail.flykobe.com,并且按照上面的方法配置好各种相关域名到固定ip。同时,还需要将ip到mail.flykobe.com做一个映射(这个需要联系DNS提供商)。我们既无固定ip,就无法实现这个了!可以参考:http://hi.baidu.com/yangming/blog/item/323d034ff87a103fafc3ab8a.html

————————————————————-

记录一下利用postfix,即开源的邮件传输代理,搭建邮件服务器的过程。

网上资料可见,需要以下几个套件:

  • SMTP 認證套件: cyrus-sasl ( cyrus-sasl-1.5.27-5mdk 以及其他認證機制函式庫 )
  • Postfix 郵件伺服器: postfix ( postfix-1.1.11-4mdk )
  • POP3 伺服器: imap ( imap-2001a-9mdk, imap-devel-2001a-9mdk 兩個 ) # 最后没有用这个
  • 郵件分析軟體:procmail ( procmail-3.22-3mdk )

提要

身為一個系統管理者,了解所管理的機器發生了什麼事情是非常重要的。而分析記錄檔是最基本且必要的技能,從中我們可以得到許多有用的資訊,例如:今天接收了多少封信件?多少人嘗試登入卻失敗?(也許是個攻擊伺服器的徵兆)諸如此類的資訊。所以我們必須了解記錄檔能告訴我們什麼,並且嘗試去分析記錄檔,進而協助垃圾郵件 (Spam) 的阻擋與防治。這份文件主旨在於協助一個 Sendmail 管理者如何去了解並分析 Sendmail 的記錄檔。

系統環境

平台:Solaris 9
Sendmail 版本:Sendmail 8.12.10

介紹

記錄檔格式

Sendmail 的記錄檔放置的位置是端看其編譯時期參數或是 sendmail.cf 的設定值,一般而言,也會依據所在平台不同而有所差異,通常可以在下面的位置找到它們:
Solaris : /var/adm/log/mail
Linux: /var/log/mail or /var/log/mail/mail
FreeBSD:/var/log/maillog

讓我們看個例子。我們可以從這樣的記錄中獲得什麼資訊呢?

Oct 11 00:08:30 shona sendmail[28560]: [ID 801593 mail.info] j2VG8UoI028560: from=, size=1310,, nrcpts=1, msgid=<20051011160826.3451.qmail@mail.fakeurl.net>, proto=SMTP, daemon=MTA, relay=mail.fakeurl.net [192.168.20.15]

Oct 11 00:08:31 shona sendmail[28521]: [ID 801593 mail.info] j2VG8Gv2028521: from=, size=7591,, nrcpts=3, msgid=<200510111608.j2VG8Gv2028521@wgf.com.tw>, proto=SMTP, daemon=MTA, relay=[172.16.4.41]

Oct 11 00:08:31 shona sendmail[28590]: [ID 801593 mail.info] j2VG8UoI028560: to=, delay=00:00:01, xdelay=00:00:00, mailer=relay, pri=121310, relay=[10.115.1.15] [10.115.1.15], dsn=2.0.0, stat=Sent (j2VG8RjQ013936 Message accepted for delivery)

Oct 11 00:08:31 shona sendmail[28592]: [ID 801593 mail.info] j2VG8Gv2028521: to=,, delay=00:00:12, xdelay=00:00:00, mailer=relay, pri=187591, relay=[10.115.1.15] [10.115.1.15], dsn=2.0.0, stat=Sent (j2VG8RL7013937 Message accepted for delivery)

一行標準的記錄檔需要包含:

1.日期 (Date)
以 “月 日” 為其格式,例如 “Oct 11″

2.時間 (Time)
以 “時:分:秒” 為其格式,例如 “00:08:30″

3.主機名稱 (Host Name)
以此處為例,主機名稱為 shona

4.Sendmail 執行時期的 Process ID
例如 28560, 28512 等等

5.記錄檔層級 (Log Level)
前面曾經說過,Sendmail 記錄檔的位置是依據設定所決定,同樣的我們也可以透過設定決定所需記錄的訊息詳細程度,在 Sendmail 中定義了幾種層級,分別如下

1 Minimal logging.
2 Serious system failures and potential security problems.
3 Other serious failures, malformed addresses, transient forward/include errors, connection timeouts.
4 Minor failures, out of date alias databases, connection rejections via check_rulesets.
5 Message collection statistics.
6 Creation of error messages VRFY and EXPN commands.
7 Delivery failures (host or user unknown, etc).
8 Successful deliveries and alias database rebuilds.
9 Message being deferred (due to a host being down, etc).
10 Database expansion (alias, forward, and userdb lookups).
11 NIS errors and end of job processing.
12 Logs all SMTP connections.
13 Log bad user shells, files with improper permissions, and other questionable situations.
14 Logs refused connections.
15 Log all incoming and outgoing SMTP commands.
20 Logs attempts to run locked queue files. These are not errors, but can be useful to note if your queue appears to be clogged.
30 Lost locks (only if using lockf instead of flock)

其餘還有 64 以上的值是保留給除錯所使用,一般而言是不會使用到他們。

而 Sendmail 的記錄訊息是透過 syslog 來決定要記錄哪些訊息,syslog 中定義了七個層級

0 Emergency
1 Alert
2 Critical
3 Error
4 Warning
5 Notice
6 Info
7 Debug

在 Sendmail 中預設的 Log Level 為 9 ,相當於 syslog 的 Info。

例如上面的記錄檔所屬層級都是 info,通常這樣的記錄都是正常且較為不重要的訊息。

6.訊息辨識碼 (Message-ID)
這是記錄檔中相當重要的一項。由於 mail log 是乏態 (Stateless) 的記錄檔,這意思是說,幾行連續的記錄中也許包含了好幾封信的訊息,而 Message-ID 就是用來分辨該筆記錄檔所記錄的是哪一封郵件,因而他也是唯一的標記,每封不同的郵件就會有不同的 Message-ID。
例如上面第一筆和第三筆訊息的 Message-ID 是 “j2VG8UoI028560″,我們可以由此得知他是同一封郵件的記錄。

基本上每行記錄檔都有上面六項必要的訊息,可以作為分析的基準條件

基本資訊
Oct 11 00:08:30 shona sendmail[28560]: [ID 801593 mail.info] j2VG8UoI028560
日期
時間
主機名稱
Sendmail PID
紀錄層級
訊息識別碼

7.其他欄位
而信件由誰所發送?收件者是誰?傳送成功與否?須分析其他欄位才可得知。以上面第一行紀錄檔為例:

那要怎麼知道這封信是寄給誰呢?由於每封郵件都有他獨特的 Message-ID,在這個例子是 “j2VG8UoI028560″ ,透過 Message-ID 我們便可找到下一筆記錄

基本資訊
Oct 11 00:08:31 shona sendmail[28560]: [ID 801593 mail.info] j2VG8UoI028560
日期
時間
主機名稱
Sendmail PID
紀錄層級
訊息識別碼
其他資訊
to= delay=00:00:01 xdelay=00:00:00 mailer=relay
收件者 email
從接收郵件到嘗試傳送出去所花的時間
嘗試傳送的總時間,通常代表了連線的速度
將傳送給收件者所透過的 mailer
pri=121310 relay=[10.115.1.15] [10.115.1.15] dsn=2.0.0 stat=Sent (j2VG8RjQ013936 Message accepted for delivery)
郵件優先性,進到 queue 排序用
郵件所送到的伺服器位址
Enhanced Error Code,可參考 RFC 2034
傳送狀態

從 Stat 欄位得知這封信傳送成功了!

上面兩種訊息分別是 from (寄件者)和 to (收件者)的紀錄,結果是正常的送出,那麼郵件異常或者錯誤的訊息會怎麼樣呢?這部份也是我們須去特別注意地方,去探討為什麼會發生這樣的錯誤?這樣的錯誤訊息是否仍是屬於可接受程度的錯誤呢?底下是具有異常訊息的記錄:

Oct 11 00:08:23 shona sendmail[28528]: [ID 801593 mail.noticej2VG8NKb028528:ruleset=CheckFrom, arg1=plato@fakeurl.net,relay=mail.fakeurl.net [192.168.20.15], reject=550 5.7.1 We don”t accept junk mail

Oct 11 00:08:25 shona sendmail[28528]: [ID 801593 mail.info] j2VG8NKb028528: from=, size=41096,, nrcpts=1, msgid=<200510111608.j2VG8NKb028528@realurl.net>, proto=ESMTP, daemon=MTA, relay=mail.fakeurl.net, [192.168.20.15]

Oct 11 00:08:25 shona sendmail[28528]: [ID 801593 mail.info] j2VG8NKb028528: to=, delay=00:00:02, pri=71096, stat=We don”t accept junk mail

Oct 11 00:08:31 shona sendmail[28524]: [ID 801593 mail.noticej2VG8QDv028524:ruleset=check_mail, arg1=, relay=fakeurl.net [192.168.20.15] (may be forged), reject=451 4.5.1 Domain must resolve

Oct 11 00:08:31 shona sendmail[28524]: [ID 801593 mail.info] j2VG8QDv028524: from=, size=1665,, nrcpts=0, proto=ESMTP, daemon=MTA, relay=fakeurl.net [192.168.20.15] (may be forged)

除了前六項基本資訊一樣以外,異常的訊息跟正常的訊息有什麼差異呢?前面曾經提過記錄檔的訊息有分層級,在這裡可以看到 Notice 層級的訊息出現,而且正常訊息的 Message-ID 之後只有 from 和 to 兩種標籤,異常訊息則多出現了 “ruleset” 訊息行。這代表了什麼意思呢?是否該特別留意呢?

從 Sendmail 8.8 開始支援 check_* 的 ruleset,透過簡單的設置可以阻擋一些垃圾郵件,上面的訊息便是該封信件的寄件者被我們列入黑名單,所以會產生 ruleset=CheckFrom 的記錄,所以這樣的記錄我們可以將它視為正常訊息。
ruleset 的記錄可分為下列幾種欄位

其他資訊
ruleset=CheckFrom, arg1=plato@fakeurl.net relay=mail.fakeurl.net [192.168.20.15] reject=550 5.7.1 We don”t accept junk mail
ruleset 規則集 收件者 寄件者主機 拒收理由

ruleset 規則集,Sendmail 預設支援下列四種規則,也可自訂規則集,如 CheckFrom 規則

Check_mail 檢驗寄件者 email address
Check_rcpt 檢驗收件者 email address
Check_relay 檢驗連線主機
Check_compat 檢驗寄件者和收件者 email address

check_* 詳細的設定可以參考 Sendmail 官方說明或是我們的範例

錯誤訊息會因 Sendmail compile 進去的功能而多出不同的錯誤訊息,我們無法列出所有的錯誤訊息,不過在分析的時候我們可以大致將訊息分成三個部份:

1.正常訊息:一般而言層級都是 info ,僅需要將其列入統計資料做數量的分析,避免阻斷式攻擊 (DOS)。

2.已知錯誤訊息:向上面的例子屬於 notice 層級的訊息,但是我們已知產生原因,也可將此類訊息當作正常訊息看待。

3.未知錯誤訊息:這類的訊息是我們較想了解的部份,通常層級高於 notice ,可能是 warning 或 critical,須將此類訊息特別另外記錄,觀察是否僅為單一事件,或為常發性的嚴重錯誤訊息,若是可接受範圍的錯誤訊息(例如某些郵件伺服器因連線速度過慢導致 timeout),我們可以將他視為已知錯誤訊息。下面是個嚴重錯誤訊息的例子:

Oct 11 00:08:23 shona sendmail[26212]: [ID 801593 mail.warning] j2VFvlmV026212: collect: premature EOM: Connection reset by [10.10.1.15]

Oct 11 00:08:23 shona sendmail[26212]: [ID 801593 mail.crit] j2VFvlmV026212: SYSERR(root): collect: I/O error on connection from [10.10.1.15], from=

Oct 11 00:08:23 shona sendmail[26212]: [ID 801593 mail.info] j2VFvlmV026212: from=, size=2850,, nrcpts=1, proto=ESMTP, daemon=MTA, relay=[10.10.1.15]

分析

綜合以上資訊,便可透過 Unix-like 常見的指令或是強大的 perl 來作進行 log 檔的分析。底下有幾個簡單的例子。

查詢伺服器收了幾封信件?
$ grep “from=” /var/log/mail | wc -l

查詢記錄檔中的某些日期的郵件數量,例如 Oct 11
$ grep “Oct 11″ /var/adm/mail | grep “from=”| wc -l

查詢某使用者的某封信件狀況
$ grep “dog@realurl.net” /var/log/mail
Oct 11 00:08:31 shona sendmail[28590]: [ID 801593 mail.info] j2VG8UoI028560: to=, delay=00:00:01, xdelay=00:00:00, mailer=relay, pri=121310, relay=[10.115.1.15] [10.115.1.15], dsn=2.0.0, stat=Sent (j2VG8RjQ013936 Message accepted for delivery
接著利用 Message-ID 做搜尋
$ grep “j2VG8UoI028560″ /var/log/mail
Oct 11 00:08:30 shona sendmail[28560]: [ID 801593 mail.info] j2VG8UoI028560: from=, size=1310,, nrcpts=1, msgid=<20051011160826.3451.qmail@mail.fakeurl.net>, proto=SMTP, daemon=MTA, relay=mail.fakeurl.net [192.168.20.15]
Oct 11 00:08:31 shona sendmail[28590]: [ID 801593 mail.info] j2VG8UoI028560: to=, delay=00:00:01, xdelay=00:00:00, mailer=relay, pri=121310, relay=[10.115.1.15] [10.115.1.15], dsn=2.0.0, stat=Sent (j2VG8RjQ013936 Message accepted for delivery)
可得知該封信件寄出成功r

如果想要得到較完整豐富的分析,可以寫個 perl 程式來作處理,網路上也許多免費軟體或收費商業軟體可使用。

免費軟體

SMA – Sendmail log analyzer (written in C, for Sendmail)

sendmail_stat (written in C, for Sendmail)

pflogsumm (written in perl, for Postfix)

eximstats (for exim)

商業軟體

Sawmill ( supports 600 different log formats)

參考資料

Sendmail

zz from: http://enews.cc.ncu.edu.tw/enews/post_view2.php?unit=1&sn=155

CocoaChina社区版主lvyile 分享了多年来与苹果的沟通过程中得到了邮箱联系地址。这些地址包括应用审核、iTC支付、程序开发、iTunes连接、开发者账户、报税和收入报告等。

以下是帖子全文。论坛地址是http://www.cocoachina.com/bbs/read.php?tid=92213

以下是我08年从事iOS开发以来,和苹果打交道过程中,
收集整理下来的邮箱列表,
附上简单说明,希望对广大开发者有帮助:
——————————————————————————————————-
AppReview@apple.com
-应用在提交后(处于“审核中”),应用和应用内购的状态
-状态更新通知——与开发者遭拒和影响审核时间相关的信息
-应用遭拒通知咨询-快速审核请求
——————————————————————————————————-
iTSPayments@apple.com
– 支付状态查询
– 与苹果向开发者支付费用相关的问题
– 咨询财务报表
——————————————————————————————————-
AppStoreNotices@apple.com
-App Store内应用侵权问题,比如我们可以投诉“摩根书院”的关键字侵权
——————————————————————————————————-
DevPrograms@apple.com
-iDP或ADC查询;
-程序信息、收益、账户信息;
-修改邮箱地址、公司联系地址、团队代理人(代理人才有权生成发布证书)
-ADC产品、硬件等退费
-ADC网站查询:合作伙请求
——————————————————————————————————-
iDP-DTS@apple.com
-代码级别的提问
-API使用-代码崩溃/如何使用和查看Crash logs
-X-code使用问题, 证书问题
-修改代码可能会引发iTC上传错误或应用遭拒的情况
注意,
区别于上边这个地址,
99$的iDP每年有2次技术支持的机会,申请地址如下:
https://developer.apple.com/membercenter/index.action#techSupport
——————————————————————————————————-
iTunesConnect@apple.com
-iTC遇到的任何错误
-应用/应用内购买设置和管理
-应用在商店里/用户评论投诉等相关的事宜
-推广码查询
-编辑应用信息(名称、评分、关键词、定价、本地化等)
-iTC 用户以及应用内购买测试用户设置
-关键词/商店搜索查询
-iTC登陆事宜
-崩溃日志
-对Contact Us的疑问等
-iAD激活和获取iAd模板
——————————————————————————————————-
iTSBanking@apple.com
-更新银行账户信息
-与银行账户信息相关的事宜
-协助填写银行信息表格
-所有的开发者可通过iTC Contact Us 模块来修改银行账户信息,将表格发至这个邮箱
——————————————————————————————————-
iTSTax@apple.com
– 与收入和销售税有关的问题-协助填写报税表格
-处理报税表格
——————————————————————————————————-
iTunesAppReporting@apple.com
-销售/销售趋势报告理解的问题
-报告丢失问题
–销售/销售趋势报告与财务报告之差异
——————————————-

zz from:http://www.cocoachina.com/bbs/read.php?tid=92213