最近需要做一个基于php的多进程server。为了优雅重启,需要捕获一下kill发出的SIGTERM信号,于是用到了pcntl_signal。

    刚开始发现捕获信号无效,无法进入信号处理函数。研究了一下文档,发现要运行一下declare(ticks = 1);看解释说是为了产生时钟云云,我的理解就类似于晶振一样。添加后父进程可以收到信号了。

    但是子进程还是无法收到信号,排查了很久,没看到什么异常,子进程是平时阻塞噻socket_accept的,怀疑是不是系统调用在这里无法中断,于是改成while 1循环,可以顺利进入中断处理函数。

    然后搜索了一下,原来pcntl默认都是会自动重新启动被中断的系统调用的,对外表现则是无法中断系统调用的阻塞。

    这时回头看手册,原来pcntl_signal还有第三个参数,也是一个可选参数,就是让我们决定是否自动重启系统调用,选择不重启即可。




Tags:
    台湾vps已经不靠谱了。于是开始迁移至香港,台湾vps决定放弃。这时遇到了问题,就是dns又变成了单点。

    所幸服务商提供了slave dns功能,这个还是很少见的,不过这个功能对于我来说实在太有用了。

    估计也是这个服务太过小众,服务商的功能也是bug多多,发了无数ticket才搞定。

    首先是管理页面就有问题,添加slave dns记录后刷新页面,记录就消失了。也不生效。通知他们修正了下,搞定了。

    然后发现添加记录倒是成功了,但没有slave dns来拉取记录。而这时我操作太激进,把ns记录都切换过来了,结果导致落到slave dns上的请求都返回空记录了,发现后急忙切换回来。发ticket通知他们,告诉我要在allow-transfer里把所有的服务器ip都加上,试了下,似乎nslookup - slave dns ip 使用指定dns后还能成功了。很高兴。

     但过了一会发现请求还是落到了主dns上,并且有很大概率的失败,于是再次联系客服。客服说在添加slave dns记录时我的master dns ip没有记录上,重新添加不行,后来客服搞了一下,可能修复了bug,可以了。

     然后发现slave似乎不支持notify请求,我用rndc reload更新记录时没有slave来请求。

     先是添加also-notify,通知所有slave dns,因为默认是通知所有ns记录里的服务器,不过我并没有用到全部slave server,所以要手动添加其他服务器收到通知。

     发现还是无效,猜测可能是出口ip不对,于是添加notify-source指定了notify时的来源ip。

     重启bind9, 成功了。


Tags: ,
    自用开发机的ubuntu还是9.10版本,不在支持队列了,最近要编译一些东西,版本支持不足,于是决定升级到12.04。

    源列表直接更新成12.04的,然后dist-upgrade,结果出了很多奇奇怪怪问题,主要是python的依赖问题,原来的2.6升级2.7,而装2.7又依赖自身,自己编译了一个跑起来了,最后遇到了一个终极错误:Could not perform immediate configuration python2.7-minimal。 搞了半天解决不了,

    后来发现原来在apt-get命令里加上-o APT::Immediate-Configure=0暂时禁止检查即可。

    另外ubuntu升版本确实问题多多,还遇到很多相关检查版本失败的问题。可以通过修改
   /var/lib/dpkg/info/packagename.*相关文件来使其返回0让相关检查强制通过


Tags:
    今天baidu app engine(BAE)上线了应用防火墙功能,可以设置ip黑/白名单,设置单个ip的5分钟/24小时内请求数/请求流量限制。可以有效防御攻击。

    进入应用管理页面后,点击“应用管理”,页面中会看到“防火墙设置”,进入页面后即可进行设置。

    首先可以点击按钮开启和关闭应用防火墙,只有开启后防火墙各项设置才会生效。

    然后可以设置ip的黑白名单,支持以子网掩码的方式设置ip段。可以设置的数量为100.


    对于有攻击发生时,可以设置每个ip在不同时间周期内访问的次数和流量,对于超出的予以封禁,返回403错误。

    页面下方可以查看封禁情况,并可方便的把封禁的ip加入黑名单中。使用十分方便。




Tags: ,
    之前经常拿来备份数据的企业邮箱满了,而qq为了赚钱不让企业邮箱扩容了,所以没办法,准备换成可自动扩容的qq邮箱。但发现一些大邮件无法收到,查看mail.log后发现发送超时。错误信息:
dsn=4.4.2, status=deferred (lost connection with mx3.qq.com[119.147.6.81] while sending message body

而用企业邮箱的时候从来没有这个问题,排查了下,把postfix发送超时设长,无效,还是发送一分钟后就超时,看来是qq的mail服务器设置了1分钟超时,如果1分钟内邮件发送不完就断开连接。

    tracert了一下到两个邮件服务器的路由,前若干跳都是一样的,但后续设置了禁ping,无法得知具体路径。

    看来我的机器到qq邮箱mail服务器速度比较慢,而到企业邮箱速度快,有可能是qq邮箱设置了速度限制之类的东东,只能给企业邮箱开自动转发,把邮件中转一下了。



Tags:

博客vps故障及恢复处理

[| 不指定 2012/07/22 23:06]
    周四上午查看博客统计的时候发现居然一个访问量都没有。由于监控没有报警,所以心想统计坏了。

    中午的时候准备看看日志确认下,结果发现真的一个访问都没有。。蛋疼了,发现凌晨5点后一点日志都没了,奇怪,心想网络没有断,为啥呢,访问了下页面,发现数据库挂掉了,无法更新。一查文件系统,原来只读了。发ticket说磁盘坏了,正在更换。等了一个多小时没好,等不及了,开始切换。

    刚准备好切换,机器down掉了,还好博客数据和程序都有备份,从代码仓库里check出来代码。备份里恢复出来数据库,恢复数据库的时候有个插曲,由于是全量备份,所以导入的时候会把目标库里的mysql库等信息都覆盖,会使目标数据库错乱,所幸没有flush,于是把目标库的备份重新覆盖了下。

    然后dns切换,由于主dns挂掉,只有从dns服务器还能工作,手动修改了数据文件指向新机器。修改ttl为300s,以便切回的时候能快速切回。

    周五机器更换磁盘起来了,但是没数据,客服说等磁盘寄回来后才知道数据能不能恢复。虽然自己有备份,但很多软件配置没备份,自己重新配比较麻烦。还是等数据。
   今天告诉我数据取出来了,给了个ftp取数据,搞到数据后恢复了一下环境,dns切换回来了。


    看来冷门数据也要做长周期备份了。
Tags:
    今天需要临时展示一个样例站点,上传程序太麻烦,修改起来也不方便,而电信宽带没有公网ip,只能先在电脑上用ssh连接到服务器,在服务器开个端口映射到电脑上。

    运行了ssh -Ng -R "*:2222:*:3333" server

    发现在服务器端映射端口是成功了,但只是监听在本地。改了半天也不行,百思不得其解。因为之前用过都是成功的。


    后来发现某些版本的sshd因为安全性考虑,默认只允许监听在本地。

    需要在/etc/ssh/sshd_config里面加一句:
    GatewayPorts clientspecified


    即可
Tags: ,

lighttpd中CONST_STR_LEN的用法

[| 不指定 2012/07/05 19:49]
    今天遇到一个问题,在获取http头的时候怎么也获取不到,手动core出来和gdb上去调试发现都是空的,应该是开了O2优化的缘故,于是在程序中打印http头,正常。

    不得已,单步gdb进匹配函数里,发现一个四字符的key值长度被判定为8,很奇怪,查代码原来是用了个CONST_STR_LEN来代替了本来应该填ptr, strlen(ptr)的位置。而CONST_STR_LEN是一个宏,内容为:x, x ? sizeof(x) - 1 : 0。显然,如果传一个指针进去的话,sizeof指针的结果是8(字节,x64),这个宏只能在内容是字符串常量的时候用,不可以用在指针上。当时用的时候看lighttpd代码中一些地方用了这个宏,于是想当然认为到处都可用。。看来还是要注意一些。









Tags:
   最近研究了一下pptp vpn的插件编写。刚开始的时候以为身份认证等信息是pptpd服务进程做的,后来看了代码后发现并非如此,是在pppd那里做的,也就是ppp软件包。

    下载了ppp源码看了下,当前版本是2.4.5,项目居然在samba域名下,不知道这个跟samba有啥联系。

    在代码的pppd/plugins里面有一些插件,比如radius的,看了下源码。大致了解了下思路:

    一个插件即是一个标准的动态链接库。pppd使用dlopen()库调用来加载。pppd使用plugin选项来加载插件,只有一个参数:插件文件名。如果指定的文件名没有斜线,pppd会到/usr/lib/pppd/目前下面查找该文件,这里面version是pppd的版本,比如2.4.5。也可以设置全路径,在使用自己编写的插件时比较方便。

    插件可以做的事:
    使用add_options(),传入option_t 。最后一项是NULL,跟lighttpd配置是一样的。这个作用应该是时ppp支持相应配置。

    指定hook。pppd会在处理过程中调用各个钩子。插件可以任意设置自己的过程到这些hook。
    
    插件可以用add_notifier消息回调。

引用

#include "pppd.h"
#include "chap-new.h"

char pppd_version[] = VERSION;


static int pppd_chap_check(void) {
        return 1;
}
static int pppd_chap_verify(char *user, char *ourname, int id, struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space) {
        if(digest->verify_response(id, user, "a", strlen("a"), challenge, response, message, message_space)) {
                return 1;
        } else {
                return 0;
        }
}

static int check_address_allowed(int addr) {
        return 1;
}
void plugin_init(void) {
        chap_check_hook = pppd_chap_check;
        chap_verify_hook = pppd_chap_verify;
        allowed_address_hook = check_address_allowed;
}


这是一个简单的插件源码,如果用户密码是a就通过。可以进行扩充就可以让pppd支持多种不同的权限认证,并且可以支持各种计数操作。该插件支持chap认证,包括mschap,mschap-v2,chap方式,至于pap,由于安全性不行,不支持也无所谓。

    这里需要注意allowed_address_hook 需要实现,表示同意使用分配的该ip,没有实现时会在注册网络时失败。

    char pppd_version[]                  = VERSION;
    表示支持的ppp版本。

    plugin_init,就是插件被载入时执行的操作,执行hook注册等等操作。

    chap_check_hook 表示该插件是否可以进行chap认证。
    chap_verify_hook 是身份认证的过程,一般使用digest->verify_response来进行校验。

以下是一篇资料里贴出的函数及消息列表:
  
插件钩子函数列表

int (*idle_time_hook)(struct ppp_idle *idlep);

idle_time_hook在这个连接第一次开始的时候被调用(比如,第一个网络协议开始的时候),那之后被定时调用。在第一次调用的时候,idlep参数是NULL,返回值则是pppd检查连接活跃前的秒数,或者0表示没有超时。

在后来的调用中,idlep指令一个指向最包被发送、接收秒数的结构体。如果返回的值大于0,pppd会在再次检查之前等一些的秒数。如果小于等于0,就是说该连接在不活跃的情况下应该被终结。



int (*holdoff_hook)(void);

当尝试拌连接失败或是连接被终结的时候,holdoff_hook被调用,persist或是demand选项被使用。它返回PPTP重新建立连接应该等待的秒数(0表示立即)。



int (*chap_check_hook)(void);

int (*chap_passwd_hook)(char *user, char *passwd);

int (*chap_auth_hook)(char *user, u_char *remmd, int remmd_len, chap_state *cstate);

这些hook被设计用来在插件里面替换常规的CHAP密码处理过程(比如外部服务器的认证)。

chap_check_hook被调用来检查对端是否有必要向我们认证其自身。如果返回1,pppd将询问询问其自身,否则返回0(如果该认证被要求了,在网络协议协商之前pppd会退出或是终结当前连接)。如果返回-1,pppd将查找chap-secrets文件使用常规方式处理。



chap_passwd_hook决定pppd应该使用什么密码来使用CHAP来向对端认证自身。user字符串使用’user’选项或者’name’选项、主机名进行初始化,有必须可以进行修改。这个钩子只有当ppdp是客户客户端而非服务的时候被调用。passwd可以容纳最多MAXSECRETLEN 字节。如果钩子返回0,PPPD使用 *passwd,如果返回 -1,pppd认证失败。



chap_auth_hook 钩子确定由对应提供的CHAP挑战响应是否有效。user指向一个包含对端提供用户名的非NULL结束的字符串。remmd向向对端提供的响应,由remmd_len表示其长度 。cstate是PPTP维护的内部CHAP状态结构体。chap_auth_hook应该返回CHAP_SUCCESS 或者CHAP_FAILURE。



int (*null_auth_hook)(struct wordlist **paddrs, struct wordlist **popts);

这个钩子允许插件确定当请求的认证被对端拒绝的时候应该采取的策略。 如果返回0,连接被终结;1,连接被允许处理,这种情况下 *paddrs和*popts可像pap_auth_hook一样被设置,以指定被允许的IP地址列表和任意扩展属性。如果返回-1,pppd查找pap-secret文件按常规处理。

void (*ip_choose_hook)(u_int32_t *addrp);

该钩子在IPCP协商开始的时候调用。它使得插件有机会设置对端的IP地址。地方应该保存在*addrp。如果*addrp里什么也没有存储的庆,pppd使用常规方式决定对端的地址。

int (*allowed_address_hook)(u_int32_t addr)

这个钩子确认对端是否可以使用指定的IP地址。如果钩子返回1,地址可以接受,返回0为拒绝。如果返回-1,将使用常规方式查找适当的选项和secrets文件来决定。

void (*snoop_recv_hook)(unsigned char *p, int len)

void (*snoop_send_hook)(unsigned char *p, int len)

这些钩子在接受或是发送数据包的时候被调用。数据包在p里同,长度由 len表式。使得插件可以检查pppd的会话。这些钩子在实现L2TP的时候将会起到很大的作用。

可注册的消息列表

插件可以使用notifier注册自身,通过申明一个下面形式的过程:

void my_notify_proc(void *opaque, int arg);

然后使用适当的notifier,以下面形式调用来注册这个过程。

add_notifier(&interesting_notifier, my_notify_proc, opaque);

add_notifier 中的’opaque’参数每次调用notifier的时候传递给my_notify_proc 。传递的’arg’参数决定于notifier一个nofify过程可以使用下面的方式从当前的notifier列表中被移除。

remove_notifier(&interesting_notifier, my_notify_proc, opaque);



下面是目前pppd实现的notifier列表。

pidchange 由其父进程在pppd已经forked并且子进程在继续pppd’s处理时调用,比如pppd从其控制终端中分离出来的时候。参数就是这个子进程的pid。

phasechange 当pppd从一个阶段操作转移到另一个的时候调用。参数是新阶段的编号。

exitnotify 在pppd退出前调用。参数是pppd退出的状态。(比如exit()的参数)。

sigreceived 在收到信号的时候调用,存在于signal handle里面。参数是signal的编号。

ip_up_notifier 在IPCP发生的时候调用。

ip_down_notifier 在IPCP关闭的时候调用。

auth_up_notifier 在对端认证自身成功的时候调用。

link_down_notifier 在连接关闭的时候调用。




参考资料:http://liaoweiqiang.info/?p=411
Tags: ,
    前几天百度开放云支持绑定自有域名了,在应用列表里有很明显的绑定域名链接,点击后会提示将要绑定的域名cname到应用主域名上,一般是*.duapp.com,然后点击确定即可绑定成功。

    需要注意的一点是,一定要在域名设置生效后再点击绑定按钮,否则由于dns缓存问题,可能需要等待最长24小时才能成功。

    修改域名指向的过程也比较简单,进入dns管理页面(一般域名注册商提供),添加cname记录(如该条记录已存在且不是cname记录,则修改为cname记录),目标设为应用主域名,点确认即可。尽量不要在设置成功前访问或nslookup该域名,这样会使域名生效时间延后,无法绑定后立即体验效果。





Tags: ,
分页: 4/31 第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]