我的收藏

CentOS 6.0 关闭IPV6

新增文件 /etc/modprobe.d/ipv6-off.conf 内容:

alias net-pf-10 off alias ipv6 off

编辑 /etc/sysconfig/network 增加内容:

NETWORKING_IPV6=no

编辑 /etc/sysctl.conf 增加内容:

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1

关闭ip6tables

service ip6tables stop
chkconfig ip6tables off
reboot

Linux屏蔽封IP 防御DDOS

互联网如同现实社会一样充满钩心斗角,网站被DDOS也成为站长最头疼的事。在没有硬防的情况下,寻找软件代替是最直接的方法,比如用iptables,但是iptables不能在自动屏蔽,只能手动屏蔽。今天要说的就是一款能够自动屏蔽DDOS攻击者IP的软件:DDoS deflate。

DDoS deflate介绍

DDoS deflate是一款免费的用来防御和减轻DDoS攻击的脚本。它通过netstat监测跟踪创建大量网络连接的IP地址,在检测到某个结点超过预设的限 制时,该程序会通过APF或IPTABLES禁止或阻挡这些IP.

DDoS deflate官方网站:http://deflate.medialayer.com/

如何确认是否受到DDOS攻击?

执行:

netstat -ntu | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -n执行后,将会显示服务器上所有的每个IP多少个连接数。

以下是我自己用VPS测试的结果:

li88-99:~# netstat -ntu | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -n
1 114.226.9.132
1 174.129.237.157
1 58.60.118.142
1 Address
1 servers)
2 118.26.131.78
3 123.125.1.202
3 220.248.43.119
4 117.36.231.253
4 119.162.46.124
6 219.140.232.128
8 220.181.61.31   
2311 67.215.242.196每个IP几个、十几个或几十个连接数都还算比较正常,如果像上面成百上千肯定就不正常了。

1、安装DDoS deflate

wget http://www.inetbase.com/scripts/ddos/install.sh   //下载DDoS  deflate
chmod 0700 install.sh    //添加权限
./install.sh             //执行2、配置DDoS deflate

下面是DDoS deflate的默认配置位于/usr/local/ddos/ddos.conf ,内容如下:

##### Paths of the script and other files
PROGDIR=”/usr/local/ddos”
PROG=”/usr/local/ddos/ddos.sh”
IGNORE_IP_LIST=”/usr/local/ddos/ignore.ip.list”  //IP地址白名单
CRON=”/etc/cron.d/ddos.cron”    //定时执行程序
APF=”/etc/apf/apf”
IPT=”/sbin/iptables”

##### frequency in minutes for running the script
##### Caution: Every time this setting is changed, run the script with –cron
#####          option so that the new frequency takes effect
FREQ=1   //检查时间间隔,默认1分钟

##### How many connections define a bad IP? Indicate that below.
NO_OF_CONNECTIONS=150     //最大连接数,超过这个数IP就会被屏蔽,一般默认即可

##### APF_BAN=1 (Make sure your APF version is atleast 0.96)
##### APF_BAN=0 (Uses iptables for banning ips instead of APF)
APF_BAN=1        //使用APF还是iptables。推荐使用iptables,将APF_BAN的值改为0即可。

##### KILL=0 (Bad IPs are’nt banned, good for interactive execution of script)
##### KILL=1 (Recommended setting)
KILL=1   //是否屏蔽IP,默认即可

##### An email is sent to the following address when an IP is banned.
##### Blank would suppress sending of mails
EMAIL_TO=”root”   //当IP被屏蔽时给指定邮箱发送邮件,推荐使用,换成自己的邮箱即可

##### Number of seconds the banned ip should remain in blacklist.
BAN_PERIOD=600    //禁用IP时间,默认600秒,可根据情况调整用户可根据给默认配置文件加上的注释提示内容,修改配置文件。

查看/usr/local/ddos/ddos.sh文件的第117行

netstat -ntu | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST

修改为以下代码即可!

netstat -ntu | awk ‘{print $5}’ | cut -d: -f1 | sed -n ‘/[0-9]/p’ | sort | uniq -c | sort -nr > $BAD_IP_LIST

 

 

wget http://www.inetbase.com/scripts/ddos/uninstall.ddos
  chmod 0700 uninstall.ddos
  ./uninstall.ddos

如何解决CentOS 5 host命令无效(-bash: host: command not found)的问题

当我们检查DNS设置的时候常常会用到host命令,但Centos5默认安装是没有这个命令的。
当显示-bash: host: command not found的时候,我们就需要安装对应的包了

host这个程序是 bind-utils包里面的
所以要先安装 bind-utils
yum install bind-utils 就ok了

学习CDN不得不读之-Squid 高级优化指南

首先要明确一下,squid 能够用来作什么。很多人没有搞明白 squid 的工作原理,只是听说 squid 性能不错可以用来给网站提速,就直接在自己的 website 前面套了一个 squid ,这基本没有任何用处,即使你都是静态页面,后面apache上面没有开 mod_expires,一样缓存不了,squid只能起到一个连接管理的用处。

一般说来,网站用 squid 加速,目的有二种

1: squid 本身具有缓存功能,可以将webserver输出的内容缓存起来,在缓存没有过期之前来的访问,都直接用缓存里面的内容,这样可以有效减少 webserver 机器上面的请求数量。这是 squid 的主要功用。
2: 网络慢的用户会长时间占用 webserver 的 TCP 连接,webserver 对每个连接占用的资源比较大,如果长时间不能释放出来服务其他请求,性能会有比较大的影响。前面放一个 squid, webserver 就可以迅速处理完逻辑以后,把数据快速发送给 squid, 然后去处理别的逻辑,而 squid 每个 TCP 连接占用的资源很少,不用担心占用太多资源。这个用途也叫做连接管理,有一些网络设备也可以做这个事情,价格都很贵。

下面针对 squid 的两种功用,来讲述如何调整业务逻辑和 squid 参数

预操作

在搞 squid 之前,不管你用什么编译配置,需要什么特殊选项,都请 –enable-snmp ,并配置好 mrtg 之类,可以图形化的显示 squid 状态,例如 Request Hit Ratio(RHR), Byte Hit Ratio(BHR), 等等,反馈是做一切事情的基础,优化也不例外。

缓存

A: 使用 Expires header 来控制缓存

squid在缓存webserver内容的时候,需要后端webserver输出一些控制信息告诉他页面是不是可以被缓存,以及可以缓存多久。否则 squid 是不会自作主张给你缓存内容的。一个页面到底能不能缓存,只有开发网站的人才知道,因此开发人员有责任在动态页面里面输出 Expires 和 Cache-Control header。简单举一个 php 的例子以说明这两个 header 的值是什么含义,其中$expiretime 的单位是秒。

header(”Expires: ” . gmt_date_format(time()+$expiretime));
header(”Cache-Control: max-age=” . “$expiretime”);

对于静态文件,有两种方式来让 squid 自动给静态文件缓存,一种是使用 apache 的 mod_expires ,可以针对路径或者针对文件类型/扩展名来自动输出 cache 头。详细的请参考 mod_expires 的说明 。另一种是用 squid 的 refresh_pattern 来指定。详细的还是请参考 squid 的配置文件。一般来说,如果后端不是配置很麻烦,建议还是在后端做,前端的配置修改大多数都是违背http协议的,如果出现问题,也比较难排查。

B 根据 squid 访问的模式,进行业务拆分

进行了 Expires Header 的处理以后,squid 就真正可以起到加速的作用了,你可能也能感觉到,网站的访问速度明显加快。但是不要满足于这点成绩,查看 squid 的 snmp 统计图,通常 hit ratio 并不会太高,有 50% 就了不起了。这就是我们需要进一步优化的,我们的目标是让大部分 squid 都达到 9X% 的命中率。

为什么 squid 命中这么低呢,这大概有两种原因。大多数的网站都是有一些页面不能够被缓存的,例如登录页面。这些页面请求也从 squid 走,成为分母的一部分,直接就降低了命中率,我们首先可以做的事情是,把这些不能够缓存的页面请求,拆分到单独一个 squid 上面,或者访问量不大的话,干脆把 apache 暴露出来。这样能够缓存的那个 squid 命中率马上上升一截。

有人可能会说,把不能缓存的页面分拆开去,就光为了让能缓存的那个数字好看,这不是掩耳盗铃么?其实这么做是有意义的,首先就是去掉了不能缓存页面 的干 扰,使得我们进一步优化 squid 的依据更加准确。其次是不可缓存请求和可缓存请求之间的重要性通常是有差距的,分拆了以后,它们之间不容易互相抢占资源,不会因为下载图片的连接太多把 squid 占满,影响更重要的登录请求。第三就是可缓存内容通常是图片等页面元素, 浏览器在 load 它们的时候,对每个站点的并发连接会有控制,如果分开成不同的IP,可以多一些请求同时执行。提高少许显示速度。

其实观察 sohu, sina 之类的页面,你会发现它们的页面也是分拆的,可以看到页面里面的图片都是指向 images.sohu.com 之类的地址,虽然它们可能和其他页面一样后台都指向同一个 apache。

这样做完,缓存命中率大概能上升到 70%-80% 了,运气好的时候完全可以上 90%。

另一种导致 squid 命中低的原因和这个比较类似,同样都是可缓存的内容,有的可能是软件下载站上面的大文件,有的是新闻站点上面的小图片,如果同一个 squid 对这样差别巨大的文件加速的话,会严重干扰 squid 的缓存策略,两者不能兼顾,要不就是大文件占据了 cache ,把小文件都挤出了 cache, 要不就是小文件特别多,大文件无法进入 cache, 导致大文件经常 miss 。这个比不能缓存的页面还要恶心,因此即使在服务器资源有限的情况下,也要优先拆分这两类型访问。一般来说,文件大小分界线定在 1M 左右就可以了,如果是有软件下载这样特别大的文件,可以在 4M – 10M 左右再拆分一次。对于不同访问类型的 squid, 其系统优化参数也会有所不同,这个我们后面还会讲到。

只要悉心按照访问模式来拆分业务,大部分起缓存作用的 squid 都可以达到很高的命中率,至少都可以到达 9X%。

C 根据不同的需求,调整参数优化缓存

完成 A 和 B 两步优化以后, squid 的命中率经常可以达到 9x%, 可以说我们已经给 squid 创造了非常优秀的外部环境,下面我们就要从 squid 本身入手,通过调整它的缓存参数和缓存策略,甚至系统的参数,来让 squid 发挥出更好的性能。

在 B 步骤中,我们把 squid 划分成了三种用途,缓存大文件,缓存小文件,不缓存文件,这其中最后一种用途情况下面 squid 不起到缓存效果,只用来做连接管理,因此我们把它放到后面的连接管理里面叙述,这里只讨论和缓存相关的 squid 参数。
squid 有内存缓存和磁盘缓存两级缓存, 通常来说, 只要是专门给 squid 用的机器, 内存缓存都建议开得比较大, 大内存缓存总是有好处的嘛, 但是注意不要使得系统开始吃 swap ,像Linux这样一开始吃 swap 性能就下降比较严重的系统尤其要注意. 这个程度需要自己试验确定.
通常 1G 内存的Linux机器用来跑 squid ,内存缓存可以开到 512M.

有些libc比较差的平台, 例如比较老的 freebsd 系统, 其 malloc 函数的质量不高,可能会造成比较多的内存碎片,导致 squid 运行一段时间以后分配不出来内存挂掉. 这时候推荐在编译时候使用 dlmalloc package. 即使如此, 仍然要再缩小 squid 的内存缓存,以防不幸发生.

磁盘缓存的情况比较复杂, squid 有 ufs, aufs, coss, diskd, null 五种存储后端, 其中 ufs, aufs, diskd 都是在文件系统上面保存很多小文件, coss 是 squid 自己实现了一个简单的文件系统,可以使用一个大文件或者一个磁盘设备来存储. null 则是给不想要磁盘缓存的情况准备的. coss 看起来好像比较拽, 但是以前试验并不足够稳定,因此并不推荐使用. 剩下的三种存储方式,具体选择哪种需要根据操作系统的特性来进行.

ufs 是最传统的存储方式, 我们知道, squid 是一个单进程的程序, 它使用 ufs 存储后端时, 直接在进程里面读写文件. 这是一种很简单的方式, 缺点是当读写磁盘被阻塞的时候, squid 不能够处理请求, 会造成服务质量波动比较大. 因此出现了 aufs 和 diskd 两种存储后端, 原理都是 squid 主服务循环不负责读写文件, 而是通过消息队列或者tcp/pipe连接将数据传送给其他的线程(aufs)/进程(diskd), 然后其他线程/进程进行读写. 很显然,这两种存储方式有一定的通信开销, 因此不一定就比 ufs 好, 需要具体问题具体分析

前面说到, ufs/aufs/diskd都是在文件系统上面存储很多小文件,因此文件系统本身的特性严重影响了squid缓存的性能,对于 Linux ,强烈推荐用 reiserfs 等适合处理小文件的文件系统, bsd 则至少要打开 softupdate, 以及 dirhash 等一切对很多小文件有好处的选项. 在比较新的系统上面, reiserfs 等文件系统的性能已经足够优越, 通常 ufs 就已经可以应付需要. 对于一些老系统,使用 aufs 或者 diskd 是比较好的选择,如果系统的线程库比较好(如Linux,Solaris),那么使用 aufs, 否则 diskd.
也有一些例外情况, 比如多 cpu 的 Linux 2.6 系统, 线程库很优秀, 虽然 ufs 本身已经比较快了,但是 squid 单进程无法利用另外的 cpu , 不如使用 aufs , 让另外的 cpu 也可以起到一些作用, aufs 在编译的时候可以选择使用几个读写线程. 这个个人觉得稍微超过 cpu 个数就可以了.但是并没有实际测试过.

磁盘缓存开多大? 这个问题没有固定答案. 需要经过试验来确定, 一般来说开大一些没有太大问题. 只要你的硬盘足够

单点登录(SSO)的实现—通行证的基本原理

问题起源:想做一个面向校园的网站,因为势单力薄。部分模块采用整合其它开源系统的方案,比如BBS系统和BLOG系统。首先面临的就是用户身份认证的方式。由于这些不是自己开发的系统,都分别有自己的用户系统,于是面临统一身份认证的过程。

以前看过企业级的Web service方案,主要是通过XML,SOAP,WSDL和UDDI来实现。将应用服务都注册到UDDI服务器中,通过SOAP协议使用XML传递信息(当然需经过加密)。由于涉及到很多服务部署的问题,用JAVA来做这样的项目肯定是再好不过的了。我的目的只是几个WEB系统的整合,肯定是要排除这么伟大的方案了。关于Web service有兴趣的朋友可以参考机械工业出版社出版的《Web Servides原理与研发实践》,里面有详细的介绍。

那么对于这样的小WEB系统的整合该怎么来实现?我们假设这是个从零开始的项目,除了自己开发的系统外,还要用到一些其它组织开发的开源系统:比如 BLOG,CMS,BBS。这些系统都有各自的用户系统。要把他们整合到一块有个原则,就是尽量不要破坏或者修改这些系统。那么要实现统一身份认证,我们必须要有一个用户信息库,然后吧这个数据库的信息映射到那些子系统的数据库中,在大型项目中,一般都会独立出一台单独的用户信息服务器,大部分高校采用 LDAP来存放用户信息,因为采用的是树状结构,对经常读取但很少修改的数据而言,它的性能是很高的。

LDAP用户库和各子系统用户库的映射有很多种方法,我这里只用最简单的直接映射,也就是帐号和密码都是相同的。

假设我的域名部署如下

http://news.domain.com 这是CMS系统的域名

http://bbs.domain.com 这是论坛的域名

http://blog.domain.com 这是博客域名

http://reg.domain.com 这是统一注册和登录页面的域名
首先是注册,我们让所有子系统注册页面都转向到一个注册页面上来(各种脚本语言都有转向函数),比如说当用户希望在http://blog.domain.com/reg.php注册是,reg.php把这个请求转向到http://reg.domain.com/reg.php.

在实现注册时,由于刚开始时候子系统并不多,注册时把用户注册信息写入主用户数据库的同时写入各子系统的用户库。以后若有新的子系统加入进来时可以通过帐号激活的方式来实现新系统的帐号激活。

用户登录的过程,可以参考如下来自IBM的图片


流程描述如下:(仅描述正常流程)

1. 用户使用在统一认证服务注册的用户名和密码(也可能是其他的授权信息,比如数字签名等)登陆统一认证服务;

2. 统一认证服务创建了一个会话,同时将与该会话关联的访问认证令牌返回给用户;

3. 用户使用这个访问认证令牌访问某个支持统一身份认证服务的应用系统;

4. 该应用系统将访问认证令牌传入统一身份认证服务,认证访问认证令牌的有效性;

5. 统一身份认证服务确认认证令牌的有效性;

6. 应用系统接收访问,并返回访问结果,如果需要提高访问效率的话,应用系统可选择返回其自身的认证令牌已使得用户之后可以使用这个私有令牌持续访问。

上面所说的令牌我在WEB引用中可以用COOKIE或者SEESION来实现。

例如通过COOKIE来实现

1.用户在统一登录页登陆,通过查询主用户数据库判断用户是否合法,若是,则注册该用户的唯一COOKIE标识(可以通过加密用户名和密码得到,网上有很多算法)。

2.用户进入某子系统时,先判断COOKIE是否注册,若注册了,则解密该COOKIE得到用户名和帐号,并判断合法性。
3.如果合法,则立刻在该子系统中注册(可在原子系统的登录脚本种抽出登录的部分做成一个函数)

使用COOKIE的优点就是简单,只要设置一下就可以实现COOKIE的跨子域传递

例如

setcookie(NC_USER_COOKIE, 用户名, 失效时间, 作用路径, ‘.domain.com’);

就能实现在所有.domain.com子域下的传递。

但COOKIE也有他的缺点,首先就是安全级别不高,要提防COOKIE劫持的威胁,其次就是它只能跨子域传递,而不能跨完全不同的域。比如说 domain.com和fuck.com之间就不能传递。

然后再说下SESSION的方式,由于SESSION是存储在服务器端的,所以安全级别肯定要比COOKIE的级别高。但是由于SEESION存储的位置不同,造成了无法跨域传递。可以通过把SEESION村入数据库来解决这个问题。

由于PHP的SESSION需要用到标识SESSION的COOKIE,所以需要设置下COOKIE的作用域
ini_set(’session.cookie_domain’, ‘.domian.com’);

然后重写PHP的SESSION操作函数。

PHP 提供了session_set_save_handle() 函数来自定义 SESSION 的处理过程,先将 session.save_handler 改成 user

session_module_name(‘user’);

然后几可以重写SESSION的操作了,下面是PHP牛人NIO写的SESSION操作

define(‘MY_SESS_TIME’, 3600);    //SESSION 生存时长
//类定义
class My_Sess
{
     function init()
     {
         $domain = ‘.infor96.com’;
         //不使用 GET/POST 变量方式
         ini_set(’session.use_trans_sid’,     0);
         //设置垃圾回收最大生存时间
         ini_set(’session.gc_maxlifetime’,    MY_SESS_TIME);

         //使用 COOKIE 保存 SESSION ID 的方式
         ini_set(’session.use_cookies’,       1);
         ini_set(’session.cookie_path’,       ‘/’);
         //多主机共享保存 SESSION ID 的 COOKIE
         ini_set(’session.cookie_domain’,     $domain);

         //将 session.save_handler 设置为 user,而不是默认的 files
         session_module_name(‘user’);
         //定义 SESSION 各项操作所对应的方法名:
         session_set_save_handler(
             array(‘My_Sess’, ‘open’),    //对应于静态方法 My_Sess::open(),下同。
             array(‘My_Sess’, ‘close’),
             array(‘My_Sess’, ‘read’),
             array(‘My_Sess’, ‘write’),
             array(‘My_Sess’, ‘destroy’),
             array(‘My_Sess’, ‘gc’)
         );
     }    //end function
     function open($save_path, $session_name) {
         return true;
     }    //end function

     function close() {
         global $MY_SESS_CONN;

         if ($MY_SESS_CONN) {     //关闭数据库连接
             $MY_SESS_CONN->Close();
         }
         return true;
     }    //end function

     function read($sesskey) {
         global $MY_SESS_CONN;

         $sql = ‘SELECT data FROM sess WHERE sesskey=’ . $MY_SESS_CONN->qstr($sesskey) . ‘ AND expiry>=’ . time();
         $rs =& $MY_SESS_CONN->Execute($sql);
         if ($rs) {
             if ($rs->EOF) {
                 return ‘’;
             } else {     //读取到对应于 SESSION ID 的 SESSION 数据
                 $v = $rs->fields[0];
                 $rs->Close();
                 return $v;
             }    //end if
         }    //end if
         return ‘’;
     }    //end function

     function write($sesskey, $data) {
         global $MY_SESS_CONN;
      
         $qkey = $MY_SESS_CONN->qstr($sesskey);
         $expiry = time() + My_SESS_TIME;     //设置过期时间
      
         //写入 SESSION
         $arr = array(
             ’sesskey’ => $qkey,
             ‘expiry’   => $expiry,
             ‘data’     => $data);
         $MY_SESS_CONN->Replace(’sess’, $arr, ’sesskey’, $autoQuote = true);
         return true;
     }    //end function

     function destroy($sesskey) {
         global $MY_SESS_CONN;

         $sql = ‘DELETE FROM sess WHERE sesskey=’ . $MY_SESS_CONN->qstr($sesskey);
         $rs =& $MY_SESS_CONN->Execute($sql);
         return true;
     }    //end function

     function gc($maxlifetime = null) {
         global $MY_SESS_CONN;

         $sql = ‘DELETE FROM sess WHERE expiry. time();
         $MY_SESS_CONN->Execute($sql);
         //由于经常性的对表 sess 做删除操作,容易产生碎片,
         //所以在垃圾回收中对该表进行优化操作。
         $sql = ‘OPTIMIZE TABLE sess’;
         $MY_SESS_CONN->Execute($sql);
         return true;
     }    //end function
}    ///:~

//使用 ADOdb 作为数据库抽象层。
require_once(‘adodb/adodb.inc.php’);
//数据库配置项,可放入配置文件中(如:config.inc.php)。
$db_type = ‘mysql’;
$db_host = ‘192.168.212.1′;
$db_user = ’sess_user’;
$db_pass = ’sess_pass’;
$db_name = ’sess_db’;
//创建数据库连接,这是一个全局变量。
$GLOBALS[‘MY_SESS_CONN’] =& ADONewConnection($db_type);
$GLOBALS[‘MY_SESS_CONN’]->Connect( $db_host, $db_user, $db_pass, $db_name);
//初始化 SESSION 设置,必须在 session_start() 之前运行!!
My_Sess::init();

基本的原理差不多就这样,细节方面就看还有很多需要琢磨的地方..