最近研究了一下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: ,

redis的性能初测

[| 不指定 2012/06/12 12:13]
    最近准备用用redis,于是做了下性能测试,在一台虚拟机上跑了下,发现add命令大概1s可以执行3-5w条,使用redis官方推荐的php客户端:Predis ,使用pipe功能批量插入1w条数据的话大概要0.3-0.5s,感觉速度有些慢,仔细研究了下,发现时php库在生成那个1w条的redis命令是非常慢,一个请求要耗费掉1s的cpu时间,实在是性能杀手,考虑后续使用c实现。







Tags:
    今天有同学希望将webserver与后端fcgi换成长连接以提高性能,于是在lighttpd里直接配置proxy-core.max-keep-alive-requests即可,为了做测试,后端只启动了一个fcgi进程。然后发现了奇怪的问题,每隔几个请求就会有一个非常非常慢的连接,需要等待10s左右。

    后来决定开strace看看,由于lighttpd配了多进程,不好搞,于是改成单worker,结果问题解决了。


    这样问题就豁然开朗了,原来多个请求落到了不同的lighttpd工作进程上,而唯一的一个fcgi进程被处理第一个请求的worker起长连接占用了,结果导致其他lighttpd无法连接到后端。


    这是一个启用长连接后比较隐蔽的坑,可能会导致各个webserver的worker进程间负载不一致。需要小心了。




Tags:
    今天下载一个资料,直接下载下不了,挂ssh代理拖又太慢了,着急睡觉,用vps下载发现这个地址还做了防盗链,要支持js,运行一下才能对ip进行授权,进而下下来,否则直接返回503错误。虽然模拟一下js运行的网络协议可行,但时间代价太大,那个搞出来都早下完了。于是搞了一个最简单方法。

     挂代理下载,这样代理vps的ip得到了授权,然后在vps上直接wget即可。

     但两台vps,一台实验可行,一台无效。纠结,可行的那个空间不足了。不过只要有一个行就ok,在有空间的那台vps上运行ssh -N can@canvps.com -D 127.0.0.1:9001,建立隧道。然后curl --socks5-hostname 127.0.0.1:9001 -o file http://addr/file

      搞定,可以睡觉了。等明天下完了再拖下来。



    在博客迁移前好几天就把a记录的ttl设成了10分钟,目的是为了减少dns记录在spider处的缓存时间,加快迁移速度,即使是这样,在昨天还有一部分Baidu Spider在爬,到今天还有Yahoo! Slurp China的Spider在爬,处于不一致状态,有的爬虫爬新的,有的爬老的,估计建库模块会比较疑惑,导致不更新网站索引,而Google的很快就都更新到新的上面了。

    差距。






Tags:
    现在很多比较大的站点会把访问顶级域的请求都url重定向到www子域上,主要是为了网站权重统一的考虑。google站长工具里面也提供了将搜索结果统一到www子域或顶级域上,但为什么大的站点都是从顶级域统一到www子域而不是相反呢,最近看dns,也写写从域名解析角度看统一到哪个比较好。

  如果请求访问顶级域,则顶级域的a记录是由顶级域dns指定,而顶级域dns由上级域dns的ns记录指定,这个ns记录的缓存时间是不可控的,有可能会比较短,而访问www子域的话,a记录由顶级域ns记录指定的dns解析,这个ns记录是可以自己控制的,可以设置成比较长的值,并且如果用户访问过其他子域,那么会缓存子域dns地址,这样的话访问www子域直接找子域dns服务器解析即可,无需了解顶级域dns服务器,而如果访问顶级域,就需要查顶级域dns地址了,很有可能要去请求上级dns,像com等域名dns很多同时是由根dns解析的,而根dns均在国外(虽然通过anycast技术可能有国内节点,负载也是不小的)。所以总体来说统一到www子域较好


Tags:
    五一节在家看rfc看的比较晕,rfc的英文貌似都比较晦涩,组织不够有条理,表述也比较模糊,很难了解到详细的东西,昨天公司同事推荐了DNS & BIND(DNS and BIND)这本书,大致浏览了一下,豁然开朗,写出一些总结。

    之前有一个二级域是自己解析的,而顶级域是用一些dns商提供的域名解析服务,最近各个dns提供商的服务都不太靠谱了,国外的老是访问不了,国内的dnspod又很不稳定(高峰期动辄就几s的解析时间),于是开始考虑自建dns了。

    自建dns首先要考虑的问题就是稳定性,毕竟vps稳定性比服务器还是要差一点,并且出了故障的恢复可能也没有那么及时,这样就需要研究在在线率只有99.5%这个级别的vps上如何搭建一个稳定性较高的dns服务。

    经过研究dns的实现原理,发现dns从设计上就是一个高可用性的架构。

    首先dns要求域名最少要有两条ns记录(我之前自己的二级域就设了一个貌似也没啥,但顶级域要求最少设置两个),以保证服务的稳定性。如果只有两台dns服务器,则设置成一主一从即可,从dns周期性从主dns获取最新结果,同步参数由SOA记录指定。如果dns比较多,可以设置多主dns,不过需要维护各个zone文件的统一性(可用rdist),每个域名受限于udp包的大小,最多设置10个左右的ns记录(从该书看到的,未详细考证)。

    对于多个ns记录,windows的客户端和ubuntu的客户端会首先查询第一个记录,如果失败或超时,则查询下一个。对于某些客户端则会随机挑选一个。

    这样的话需要把速度比较优秀的dns服务器放在第一个位置上,把备份服务器放在后面,这样即使第一个dns挂掉,后面的服务器一样能提供服务,只是速度会慢一点而已。但对于随机选ns的客户端就比较蛋疼了,会选到比较慢的服务器,不过这个还是待考证的,可以先搭建一下试试,看看比例如何。

    
    另外搞清了上篇文章所说的域名自身ns记录的问题。很多顶级域的dns都会有@域的ns记录指向自己,之前理解有误,其实这些ns记录是对二级域生效的。这样设置是表示二级域和顶级域由相同的ns服务器负责解析。即使不设置这个记录,顶级域dns服务器也是可以解析子域的,但顶级域的ns记录缓存时间是不可控的(设置时没有ttl),有可能很快过期,这样的话解析二级域时就需要多次去com域dns上查询,而有了ns记录,可以自己控制ttl,在ttl没有过期的时间内,查询时可以直接命中ns记录去查询二级域,有效提高速度。

理论上顶级域dns只负责解析顶级域自身的a、mx、cname、ns记录等,其他二级域记录需要顶级域的ns记录指定的dns来解析,而一般大家使用dns托管的话,二级域名和顶级域往往是一起管理的,所以ns是指向自身的。
Tags: ,
    很久之前有过如下疑惑:比如baidu.com的域名dns设置为ns2.baidu.com。也就是说baidu.com这个域名由ns2.baidu.com解析。但问题是,ns2.baidu.com对应的ip又需要找到baidu.com的解析服务器去解析,这样就陷入一个循环。如何解决这个问题呢?周末看了下相关rfc,原来对于ns记录用到的域名,可以设置一下glue record,用来给这些域名提供解析,显然,这个记录需要由一级dns服务器解析。也就是.com dns服务器。显然,这个记录需要去域名注册商那里设置,我用的域名是godaddy注册的,研究了一下,godaddy将这个记录叫做“summary record”,设置的位置也相当偏僻,在域名管理面板的左下角,有个“Host Summary”框,点击add即可添加相关记录,这个从字面意思上并不太能看出来跟dns有关,找了很多资料才找到这里。

    对于很多dns提供商和服务程序,当添加一个域名时,会默认带有这个域名的ns记录,这个会比较令人疑惑,因为这个记录正常情况下是不会生效的,域名的dns服务器是上级域服务器指定的,在本级指定看起来没意义,不知道有何原因,个人猜测是为了在多ns记录情况下,从任意dns server查询的时候都能获取到所有的ns记录





Tags:
    BGP的全称是Border Gateway Protocol, 边界网关协议。最近在很多机房和服务器/VPS介绍时提到了BGP这个词。并且凡是带了BGP的,价格就要高很多。那么到底什么是BGP,BGP又有什么用呢。

    从一些英文资料上来看,bgp主要用于多个不同as用户访问目标时都能有很好的访问速度,参考国内的跨运营商访问。很久之前记得双线主机是给两个ip的,也就是说双线靠同时接入两个运营商的线路实现,这样双ip的站点要想让用户能够访问到和自己同运营商的ip,往往是通过不同的域名,然后让用户手动选择的(之前很多网站都有电信入口或网通入口的链接供选择,现在很多下载站还有这种设置)高级一点就是使用智能dns,自动解析给用户同线路的ip,cdn就是基于这个原理。至于bgp,就更高级了,同一个ip,对于不同的来源会有不同的路由方式。按我的理解就是将同一个ip广播到多个子网络中,这样各个子网络上的访问者都可以从本网络路由访问到指定ip,避免了跨运营商访问。

    还有一个类似的东西叫anycast,看了一会资料没有太看懂跟bgp是什么关系,貌似是说anycast是bgp的一种增强版实现?
    anycast是更进一步的实现,是多server绑定同一个ip,用户在访问时会路由到离自己最近的server上。比如google.com。同一个ip在全球范围内ping的话值都比较低。原因就是每个地区用户访问该ip时,会路由到离自己最近的服务器上。这样有效避免了数据的远程传输。



Tags: ,
分页: 2/2 第一页 上页 1 2 最后页 [ 显示模式: 摘要 | 列表 ]