2010年12月27日 星期一

xauth client dpd can not work!

在ipsec tunnel建立後,「雙方」都同意DPD,那兩邊都會送R_U_HERE並等待R_U_HERE_ACK來「確認」
對方是否存在,當在XAUTH時,有個bug:(只有xauthserver會送R_U_HERE),這樣的結果會變成:
只有xauthserver會detect xclient是否存在,但xclient不會知道xserver出問題…
openswan-2.6.24:dpd.c,timer.c,state.c,ikev1.c
APIs: 
event_schedule(enum event_type type, time_t tm, struct state *st):註冊事件
dpd_event(struct state *st): 在event_schedule()的EVENT_DPD timer timeout時的callback

有關DPD的event有兩個EVENT_DPD和EVENT_DPD_TIMEOUT

stf_status dpd_init(struct state *st):在ipsec tunnel建立且DPD enabled時會inital DPD
  的計時器:在isakmp的sa建立及quick_mode(quick_inI2(),quick_inR1_outI2_cryptotail())建立時都會call一次。
dpd_outI(): 送出R_U_THERE,然後記錄DPD delay和DPD timeout時間

重要structs:
struct connection:一個tunnel profile object,記錄該參數,eg:name, policy, ike,ipsec life time etc...有關dpd的部分如下
  • time_t          dpd_delay;              /* time between checks */ 
  • time_t          dpd_timeout;            /* time after which we are dead */
  • enum dpd_action dpd_action;             /* what to do when we die */ 
struct state: state object,記錄sa的內容,狀態,及tunnel的一些細節(如雙方cookie: st_icookie,st_rcookie; nonce,,xauth的username,password;雙向spi,enc的list…)每個stat object會有一個connection object,有關dpd的部分如下:
  •     time_t              st_last_dpd;            /* Time of last DPD transmit */
  •     u_int32_t           st_dpd_seqno;           /* Next R_U_THERE to send */
  •     u_int32_t           st_dpd_expectseqno;     /* Next R_U_THERE_ACK to receive */
  •     u_int32_t           st_dpd_peerseqno;       /* global variables */
  •     struct event       *st_dpd_event;          /* backpointer for DPD events */
    所有state objs會放在一個global variables : statetable
    state.c:
    #define STATE_TABLE_SIZE 32

    static struct state *statetable[STATE_TABLE_SIZE];
struct qke_continuation:在quick mode時會由isakmp的st duplicates quick mode用的st
ikev1_continuations.h
struct qke_continuation {
    struct pluto_crypto_req_cont qke_pcrc;
    struct state                *st;            /* need to use abstract # */
    struct state                *isakmp_sa;     /* used in initiator */
    so_serial_t                  replacing;
    struct msg_digest           *md;            /* used in responder */
};



ikev1_quick.c
stf_status
quick_outI1(int whack_sock
            , struct state *isakmp_sa
            , struct connection *c
            , lset_t policy
            , unsigned long try
            , so_serial_t replacing)
{
    struct state *st = duplicate_state(isakmp_sa);
    struct qke_continuation *qke = alloc_thing(struct qke_continuation
                                               , "quick_outI1 KE");
    st->st_connection = c;
....
    qke->st = st;
    qke->isakmp_sa = isakmp_sa;
...



DPD working flow:
dpd_init(struct state *st)
   \===> find_state_ikev1()
   \===>event_schedule(EVENT_DPD, st->st_connection->dpd_delay, st);

dpd_event(struct state *st): 收到EVENT_DPD後開始check:
    如果是phase1,call p1_dpd_outI1() 如果是在phase2 call p2_dpd_outI1(), 但兩者最後都會call dpd_outI()
 
我的bug是在第一次dpd_init() 註冊後dpd_event()被呼叫時l p2_dpd_outI1()find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);找不到…
../../include/pluto_constants.h
#define ISAKMP_SA_ESTABLISHED_STATES  (LELEM(STATE_MAIN_R3) | \
                                       LELEM(STATE_MAIN_I4) | \
                                       LELEM(STATE_AGGR_I2) | \
                                       LELEM(STATE_AGGR_R2))

state.c
struct state *
find_phase1_state(const struct connection *c, lset_t ok_states)
{
    struct state
        *st,
        *best = NULL;
    int i;

    for (i = 0; i < STATE_TABLE_SIZE; i++) {
        for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
            if (LHAS(ok_states, st->st_state)   <<============### 這一段會fail…why!
                && c->host_pair == st->st_connection->host_pair
                && same_peer_ids(c, st->st_connection, NULL)
                && (best == NULL
                    || best->st_serialno < st->st_serialno))
                {
                    best = st;
                }
        }
    }

    return best;
}


include/constants.h:
typedef unsigned long long lset_t;
#define LEMPTY 0ULL
#define LELEM(opt) (1ULL << (opt))
#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb))
#define LRANGES(first, last) (last - first + last)
#define LHAS(set, elem)  ((LELEM(elem) & (set)) != LEMPTY)


#define ISAKMP_SA_ESTABLISHED_STATES  (LELEM(STATE_MAIN_R3) | \
                                       LELEM(STATE_MAIN_I4) | \
                                       LELEM(STATE_AGGR_I2) | \
                                       LELEM(STATE_AGGR_R2))

enum state_kind {
    STATE_UNDEFINED=0,  /* 0 -- most likely accident */

    /*  Opportunism states: see "Opportunistic Encryption" 2.2 */

    OPPO_ACQUIRE,       /* got an ACQUIRE message for this pair */
    OPPO_GW_DISCOVERED, /* got TXT specifying gateway */

    /* IKE states */

    STATE_MAIN_R0,
    STATE_MAIN_I1,
    STATE_MAIN_R1,
    STATE_MAIN_I2,
    STATE_MAIN_R2,
    STATE_MAIN_I3,
    STATE_MAIN_R3,
    STATE_MAIN_I4,

    STATE_AGGR_R0,
    STATE_AGGR_I1,
    STATE_AGGR_R1,
    STATE_AGGR_I2,
    STATE_AGGR_R2,

    STATE_QUICK_R0,
    STATE_QUICK_I1,
    STATE_QUICK_R1,
    STATE_QUICK_I2,
    STATE_QUICK_R2,

    STATE_INFO,
    STATE_INFO_PROTECTED,


    STATE_XAUTH_R0,    /* server state has sent request, awaiting reply */
    STATE_XAUTH_R1,    /* server state has sent success/fail, awaiting reply */
    STATE_MODE_CFG_R0,           /* these states are used on the responder */
    STATE_MODE_CFG_R1,
    STATE_MODE_CFG_R2,

    STATE_MODE_CFG_I1,           /* this is used on the initiator */

    STATE_XAUTH_I0,              /* client state is awaiting request */
    STATE_XAUTH_I1,              /* client state is awaiting result code */

先將find_phase1_state()加上一些messages
    for (i = 0; i < STATE_TABLE_SIZE; i++) {
        loglog(RC_LOG_SERIOUS, "%s:%d,i: %d\n", __FUNCTION__, __LINE__, i);
        for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
            loglog(RC_LOG_SERIOUS, "%s:%d,a [%llX:%llX]LHAS: %s, host_pair: %s, "
                        "same_peer_ids: %s\n",
                        __FUNCTION__, __LINE__,
                        (unsigned long long)ok_states,
                        (unsigned long long)st->st_state,
                    LHAS(ok_states, st->st_state)?"Ture":"Fail",
                    c->host_pair == st->st_connection->host_pair?"Ture":"Fail",
                    same_peer_ids(c, st->st_connection, NULL)?"True":"Fail");
......
在正常沒有XAUTH時
以下 [C600:A」的0xc600就是「 ISAKMP_SA_ESTABLISHED_STATES」而0xA(10)就是C600h的bit 10. 所以為true,也就是state落在STATE_MAIN_I4。

"conn_xauthclient" #4: find_phase1_state:1195,a [C600:13]LHAS: Fail, host_pair: Ture, same_peer_ids: True
"conn_xauthclient" #4: find_phase1_state:1195,a [C600:A]LHAS: Ture, host_pair: Ture, same_peer_ids: True

然而:xauth client會是其它的value:1E.
"conn_xauthclient" #2: find_phase1_state:1195,a [C600:13]LHAS: Fail, host_pair: Ture, same_peer_ids: True
"conn_xauthclient" #2: find_phase1_state:1195,a [C600:1E]LHAS: Fail, host_pair: Ture, same_peer_ids: True


修改此macro後…似乎就可了,testing中…, 另一個小發現是:如果對方在時間內有先送R_U_THERE,該週期就不再送R_U_THERE了
#define ISAKMP_SA_ESTABLISHED_STATES  (LELEM(STATE_MAIN_R3) | \
                                       LELEM(STATE_MAIN_I4) | \
                                       LELEM(STATE_AGGR_I2) | \
                                       LELEM(STATE_AGGR_R2) | \
                                       LELEM(STATE_XAUTH_I1))
===================================================

RFC3706

1. Introduction

These schemes tend to be unidirectional (a HELLO only)
   or bidirectional (a HELLO/ACK pair).  For the purpose of this
   document, the term "heartbeat" will refer to a unidirectional message
   to prove liveliness.  Likewise, the term "keepalive" will refer to a
   bidirectional message.

Keepalives vs. Heartbeats

A send HELLO to B, B send ACK to A.
It is conceivable in such a scheme that peer B would
   never be interested in peer A's liveliness
(A在意B, 但B不care A, also bidirection)

Heartbeats:

只送HELLO來證明自已存在
unidirection
適用在大量的remote users or大量sessions.


set --debug-dpd to pluto for debug
------------------------------------------------

這是用pre_share key client的情況由initiator發R_U_THERE

"conn_conn_ipsec" #1: Main mode peer ID is ID_IPV4_ADDR: '172.21.46.139'
"conn_conn_ipsec" #1: transition from state STATE_MAIN_I3 to state STATE_MAIN_I4
"conn_conn_ipsec" #1: STATE_MAIN_I4: ISAKMP SA established {auth=OAKLEY_PRESHARE                                             D_KEY cipher=oakley_3des_cbc_192 prf=oakley_md5 group=modp1024}
"conn_conn_ipsec" #1: Dead Peer Detection (RFC 3706): enabled
| state: 1 requesting event none to be deleted by /home/samba/ubicom-distro/uCli                                             nux/openswan-2.6.24rc4/programs/pluto/dpd.c:159
| unpending state #1
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #2: initiating Quick Mode PSK+ENCRYPT+TUNNEL+PFS {using isakmp                                             #1 msgid:5e3a8c6c proposal=3DES(3)_192-MD5(1)_128, AES(12)_128-MD5(1)_128, AES(1                                             2)_128-MD5(1)_128, AES(12)_192-MD5(1)_128 pfsgroup=OAKLEY_GROUP_MODP1024}
| processing connection conn_conn_ipsec
| removing pending policy for "none" {0x429728a4}
| processing connection conn_conn_ipsec
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #2: Dead Peer Detection (RFC 3706): enabled
| state: 2 requesting event none to be deleted by /home/samba/ubicom-distro/uCli                                             nux/openswan-2.6.24rc4/programs/pluto/dpd.c:159
| state: 1 requesting event EVENT_DPD to be deleted by /home/samba/ubicom-distro                                             /uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:171
"conn_conn_ipsec" #2: transition from state STATE_QUICK_I1 to state STATE_QUICK_                                             I2
"conn_conn_ipsec" #2: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode                                              {ESP=>0x2df79419 <0x56c3adf7 xfrm=3DES_0-HMAC_MD5 NATOA=none NATD=none DPD=enab                                             led}

     #####事實上,responder和initiator都會送R_U_THERE...#######

/ # | processing connection conn_IPSec
| received R_U_THERE seq:2568 time:1291695452 (state=#1 name="conn_IPSec")
| processing connection conn_IPSec
| processing dpd for state #3 ("conn_IPSec")
| not yet time for dpd event: 1291695452 < 1291695482

/ #
/ # | processing connection conn_IPSec
| processing dpd for state #3 ("conn_IPSec")
| scheduling timeout to 120
| state: 1 requesting event none to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:192
| sending R_U_THERE 29742 to 192.168.3.100:500 (state #1)
| processing connection conn_IPSec
| received R_U_THERE seq:2569 time:1291695482 (state=#1 name="conn_IPSec")
| state: 1 requesting event EVENT_DPD_TIMEOUT to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:437
| processing connection conn_IPSec
| R_U_THERE_ACK, seqno received: 29742 expected: 29742 (state=#1)dpd_inR()


-----------------------------------------------------------------------------------



 # | processing connection conn_IPSec
| received R_U_THERE seq:2589 time:1291696322 (state=#1 name="conn_IPSec")
| processing connection conn_IPSec
| processing dpd for state #3 ("conn_IPSec")
| not yet time for dpd event: 1291696322 < 1291696352


/ # | processing connection conn_IPSec
| processing dpd for state #3 ("conn_IPSec")
| scheduling timeout to 120
| state: 1 requesting event none to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:192
| sending R_U_THERE 29764 to 192.168.3.100:500 (state #1)
| processing connection conn_IPSec
| R_U_THERE_ACK, seqno received: 29764 expected: 29764 (state=#1)
| state: 1 requesting event EVENT_DPD_TIMEOUT to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:514





---------------------------------------------------
---------------------------------------------------
但xauth的方向是相反的,xauthserver送R_U_THERE, xauthclient回R_U_THERE_ACK


"conn_conn_ipsec" #1: Dead Peer Detection (RFC 3706): enabled
| state: 1 requesting event none to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:159
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #1: =========xclient_account(conn_conn_ipsec)
"conn_conn_ipsec" #1: GET DB:[peter,1234 ] FORM [conn_conn_ipsec]
"conn_conn_ipsec" #1: user:peter, pass:1234
"conn_conn_ipsec" #1: XAUTH: Answering XAUTH challenge with user='peter'
"conn_conn_ipsec" #1: transition from state STATE_XAUTH_I0 to state STATE_XAUTH_I1
"conn_conn_ipsec" #1: STATE_XAUTH_I1: XAUTH client - awaiting CFG_set
"conn_conn_ipsec" #1: Dead Peer Detection (RFC 3706): enabled
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #1: XAUTH: Successfully Authenticated
"conn_conn_ipsec" #1: transition from state STATE_XAUTH_I0 to state STATE_XAUTH_I1
"conn_conn_ipsec" #1: STATE_XAUTH_I1: XAUTH client - awaiting CFG_set
"conn_conn_ipsec" #1: Dead Peer Detection (RFC 3706): enabled
| unpending state #1
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #2: initiating Quick Mode PSK+ENCRYPT+TUNNEL+PFS {using isakmp#1 msgid:9227c94a proposal=3DES(3)_192-MD5(1)_128, AES(12)_128-MD5(1)_128, AES(12)_128-MD5(1)_128, AES(12)_192-MD5(1)_128 pfsgroup=OAKLEY_GROUP_MODP1024}
| processing connection conn_conn_ipsec
| removing pending policy for "none" {0x4105d324}
| processing connection conn_conn_ipsec
| processing connection conn_conn_ipsec

/ # "conn_conn_ipsec" #2: Dead Peer Detection (RFC 3706): enabled
| state: 2 requesting event none to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:159
| state: 1 requesting event EVENT_DPD to be deleted by /home/samba/ubicom-distro/uClinux/openswan-2.6.24rc4/programs/pluto/dpd.c:171
"conn_conn_ipsec" #2: transition from state STATE_QUICK_I1 to state STATE_QUICK_I2
"conn_conn_ipsec" #2: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode {ESP=>0xe7bb4694 <0xc780201b xfrm=3DES_0-HMAC_MD5 NATOA=none NATD=none DPD=enabled}

/ #
/ # | processing connection conn_conn_ipsec
| received R_U_THERE seq:16359 time:1292989489 (state=#1 name="conn_conn_ipsec")
| processing connection conn_conn_ipsec
"conn_conn_ipsec" #2: DPD Error: could not find newest phase 1 state

trace一下「find_phase1_state」
struct state *
find_phase1_state(const struct connection *c, lset_t ok_states)

"conn_conn_ipsec" #2: find_phase1_state:1193,i: 13
"conn_conn_ipsec" #2: find_phase1_state:1195, LHAS: Fail, host_pair: Ture, same_peer_ids: True
"conn_conn_ipsec" #2: find_phase1_state:1195, LHAS: Fail, host_pair: Ture, same_peer_ids: True
"conn_conn_ipsec" #2: find_phase1_state:1193,i: 14

struct state *
find_phase1_state(const struct connection *c, lset_t ok_states)
{
    struct state
        *st,
        *best = NULL;
    int i;

    loglog(RC_LOG_SERIOUS, "%s:%d, STATE_TABLE_SIZE=:%d\n",
                 __FUNCTION__, __LINE__, STATE_TABLE_SIZE);

    for (i = 0; i < STATE_TABLE_SIZE; i++) {
        loglog(RC_LOG_SERIOUS, "%s:%d,i: %d\n", __FUNCTION__, __LINE__, i);
        for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
            loglog(RC_LOG_SERIOUS, "%s:%d, [%X:%X]LHAS: %s, host_pair: %s, same_peer_ids: %s\n", __FUNCTION__, __LINE__,
                        ok_states, st->st_state,
                    LHAS(ok_states, st->st_state)?"Ture":"Fail",
                    c->host_pair == st->st_connection->host_pair?"Ture":"Fail",
                    same_peer_ids(c, st->st_connection, NULL)?"True":"Fail");

            if (LHAS(ok_states, st->st_state)
                && c->host_pair == st->st_connection->host_pair
                && same_peer_ids(c, st->st_connection, NULL)
                && (best == NULL
                    || best->st_serialno < st->st_serialno))
                {
                    loglog(RC_LOG_SERIOUS, "%s:%d\n", __FUNCTION__, __LINE__);
                    best = st;
                }
        }
    }

    return best;
}



-------------------------------------
"conn_conn_ipsec" #2: find_phase1_state:1195, [C600:1341485BC0]LHAS: Ture, host_pair: True, same_peer_ids: \001\003d\343\220
"conn_conn_ipsec" #2: find_phase1_state:1195, [C600:1E41485BC0]LHAS: Ture, host_pair: True, same_peer_ids: \001\003d\343\220

2010年11月29日 星期一

我的git使用經驗

我在一個新的sdk中自已用了git來測驗
我發現git-status有時候很慢,查了一下,有人說用git-gc來加快access
於是我下了git-gc,等了幾分鐘後還是沒run完,一看memroy,竟被吃光了:

peter$ git-gc
Counting objects: 88839, done.

Compressing objects:  18% (15328/84733)
後來改用
git-diff --stat就快多了

petert$ git diff --stat drivers/
 .../hal/linux/public/mipsisa32-be-elf.opt_ah.h     |   18 +++---------------
 1 files changed, 3 insertions(+), 15 deletions(-)
git-status用git-commit同樣的options, 主要是用來比較git-commit時會發生那些變動
git-status其實就是git-commit --preview, 見意採用git-diff --stat…
http://stackoverflow.com/questions/715321/git-status-is-there-a-way-to-show-changes-only-in-a-specific-directory

The reason that git status takes the same options as git commit is that the purpose of git status is to show what would happen if you committed with the same options as you passed to git status. In this respect git status is really git commit --preview.
To get what you want, you could do this which shows staged changes:
git diff --stat --cached -- 
and this, which shows unstaged changes:
git diff --stat -- 
or this which shows both:
git diff --stat HEAD -- 

lighttpd porting


CC="mips-linux-gcc -I/tmp/rootfs/lighttpd/include -L/tmp/rootfs/lighttpd/lib" LD="mips-linux-ld -L/tmp/rootfs/lighttpd/lib" ./configure --target=mips-linux --host=mips-linux --without-zlib --prefix=/tmp/rootfs/lighttpd --without-bzip2 --disable-ipv6 --with-pcre=/tmp/rootfs/lighttpd/lib/

-----------------------------------------------------
設定 lighttpd.conf
  1. document root
    修改lighttpd.conf
    var.server_root = "/tmp/rootfs/www"
    server.port = 1234
    var.conf_dir    = "/tmp/rootfs/etc/lighttpd"
  2. cgi module.
    修改modules.conf
    include "conf.d/cgi.conf"
  3. 修改conf.d/cgi.conf
    cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                                 ".cgi" => "/tmp/rootfs/www/cgi/ssi",
                                   ".rb"  => "/usr/bin/ruby",
                                   ".erb" => "/usr/bin/eruby",
                                   ".py"  => "/usr/bin/python" )



 在target board edit 「/tmp/rootfs/www/cgi/ssi」如下,and chmod +x.
#!/bin/sh
echo -ne "Content-Type: text/plain\n\n";
echo -ne "Hi there! This is a sample perl program!!!\n";
set

 測試 url: http://172.21.46.138:1234/index.cgi
CONTENT_LENGTH='0'
DOCUMENT_ROOT='/tmp/rootfs/www'
GATEWAY_INTERFACE='CGI/1.1'
HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
HTTP_ACCEPT_CHARSET='UTF-8,*'
HTTP_ACCEPT_ENCODING='gzip,deflate'
HTTP_ACCEPT_LANGUAGE='zh-tw,en-us;q=0.7,en;q=0.3'
HTTP_CACHE_CONTROL='max-age=0'
HTTP_CONNECTION='keep-alive'
HTTP_HOST='172.21.46.138:1234'
HTTP_KEEP_ALIVE='115'
HTTP_USER_AGENT='Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 GTB7.1 (.NET CLR 3.5.30729)'
IFS='  
'
LD_LIBRARY_PATH='/tmp/rootfs/lighttpd/lib'
PATH='/usr/local/bin:/usr/bin:/sbin:/bin'
PPID='797'
PS1='\w \$ '
PS2='> '
PS4='+ '
PWD='/tmp/rootfs/www'
REDIRECT_STATUS='200'
REMOTE_ADDR='172.21.33.212'
REMOTE_PORT='2161'
REQUEST_METHOD='GET'
REQUEST_URI='/index.cgi'
SCRIPT_FILENAME='/tmp/rootfs/www/index.cgi'
SCRIPT_NAME='/index.cgi'
SERVER_ADDR='0.0.0.0'
SERVER_NAME='172.21.46.138'
SERVER_PORT='1234'
SERVER_PROTOCOL='HTTP/1.1'
SERVER_SOFTWARE='lighttpd/1.4.28'
當IE brower URL:http://172.21.46.138:1234/index.cgi 時,lighttpd會根據cgi.conf所設定的副檔名來執行程式(以此為例,真正的執行檔為「/tmp/rootfs/www/cgi/ssi, 而index.cgi這個file實際上可能不存在

但這不是我想要的結果:
所以我做了點小修改: 
  1. 將www/cgi/ssi link到www
    再將原來的ssi rename為ssi.exe
  2. 小改一下cgi.conf
    cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                                   ".cgi" => "/tmp/rootfs/www/cgi/ssi.exe",
                                   ".asp" => "/tmp/rootfs/www/cgi/ssi.exe",
                                   ".rb"  => "/usr/bin/ruby",
                                   ".erb" => "/usr/bin/eruby",
                                   ".py"  => "/usr/bin/python" )
peter@team-server:www$ tree cgi
cgi
|-- ssi -> ../
`-- ssi.exe


測試一下

http://172.21.46.138:1234/cgi/ssi/index.asp
可以work了!




2010年10月13日 星期三

CVS,GIT,Mercurial和SVN

轉自: http://hi.baidu.com/tigerwooz/blog/item/edbb40c64442ce159c163d74.html


最近关于DVCS讨论的如火如荼,转一篇4个著名VCS的比较
特征CVSGitMercurialSubversion
是否原子提交CVS: 没有. CVS提交不是原子的Git: 是的. 提交都是原子的Mercurial: 是的Subversion: 提交都是原子的
文件和目录是否可以移动或重命名CVS: 不是. 重命名不支持. 如果手动进行, 可能会损坏历史记录Git: 支持重命名, 这是很实用的目的. git甚至能检测到重命名之后文件的改变. 尽管如此, 基于特殊的存储结构, 重命名不会被显示的记录, git能够推导出来(在实际使用中很容易做到)Mercurial: 是的, 重命名是支持的Subversion: 是的. 支持重命名
在移动或重命名之后智能合并CVS: 不能. 重命名都不支持, 就不必说智能了Git: 不支持. 细节在Git FAQ里: “Git有一个重命名的命令git mv, 但是这仅仅是为了便利. 效果和移掉某个文件, 增加另外一个文件没有任何区别”Mercurial: 是的. 重命名之后智能合并是支持的. Mercurtial文档说:“如果我修改一个文件,而你重新命名了这个文件, 然后我们合并我们的变更, 那么我所做的修改就会被更新到根据旧文件名字而产生的新文件里(这可能就是你所期望的‘最简单的动作’, 但是不是所有版本控制系统都支持)Subversion: 不支持. “svn help me“中提到“注意: 这个子命令相当于拷贝和删除.“并且可能有个bug
文件和目录拷贝CVS: 不能. 拷贝不支持Git: 不能. 拷贝不支持Mercurtial: 是的. 支持拷贝Subversion: 是的. 并且拷贝非常容易(O(1)). 包括产生分支
远程存储仓库的备份CVS: 间接的. 可以使用John Polstra写的CVSupGit: 是的. 是git的内部特征Mercurial: 是的Subversion: 间接的. 可以使用Chia-liang Kao的SVN::Mirror插件(好像是台湾人)或Shlomi Fish的SVN-Pusher工具
是否传递变更到父仓库CVS: 不会Git: 是的(Linux内核开发过程经常使用这个特征)Mercurtial: 是的Subversion: 是的, 使用要么是Chia-Ling Kao的SVN::Mirror脚本或者Shlomi Fish的svn-push工具
仓库权限CVS: 很有限. “pre-commit hook scripts“能够被用来实现各种权限控制系统Git: 请看和Git一起附带的contrib/hooks/update-paranoid. 看和svnperms类似的path_rules的代码Mercutial: 是的. 它能够锁住仓库, 子目录或者使用hooks后的文件Subversion: 是的. 基于HTTP权限的WebDAV-based模块能够支持基于目录级的仓库
变更集CVS: 不是. 变更是基于文件的Git: 是的. 是支持的, 创建他们很容易Mercurial: 是的. 变更集是支持的Subversion: 部分支持. 对于一次提交会隐式创建一个变更集
跟踪线性的文件历史CVS: 是的. cvs annotateGit: 是的.(git blame)Mercurial: 是的(hg annotate)Subversion: 是的(svn blame)
能够只在仓库的单目录下作用CVS: 是的Git: 不是. 尽管如此, 提交多少能被限制, 请看“Repository Permissions”Mercurial: 能够基于某树的某个子集进行提交. 也有局部检出的能力Subversion: 是的
跟踪未提交的变化CVS: 是的. 通过cvs diffGit: 是的. 另外, 分支在git里非常智能, 在某些工作流里能够被当成是另外一个未提交代码的存储库. 请看“git stash“命令Mercurial: 是的. 使用hg diffSubversion: 是的. 使用svn diff
基于单个文件的提交信息CVS: 不是. 提交信息是基于单次变化的Git: 是的. 提交信息基于变更集Mercurial: 不是Subversion: 不是. 没有这个特征
文档CVS: 非常棒. 有很多在线的tutorials和资源, 在线的书籍. 命令行客户端也支持一个在线的帮助系统Git: 良好. 短的帮助比较简洁难懂. man页很有分量, 但容易误解. 有很多tutorialMercurial: 很好. 有基于公司的书籍和wiki. 每个命令都集成了帮助Subversion: 很好. 有一些在线的书籍和一些在线的tutorials和资源. 并且书籍是以docbook/xml写的所以很容易变换成其他格式. 命令行同样提供了在线的帮助系统
配置是否轻松CVS: 好. 是个事实上的标准. 基于每个系统都有并且很容易配置Git: 好. 在现有平台上二进制可用. 需要C编译器和Perl. 在windows上需要cygwin. 并有一些Unix特征Mercurial: 非常好. 几乎所有平台都有二进制包. 从源码编译需要python2.3以上, 并且需要C编译器Subversion: Subversion服务器需要安装在apache2模块里(如果有人希望HTTP作为底层协议的话)或使用它自身的服务器. 客户端需要Subversion特征的逻辑还有WebDAV库(针对HTTP). 安装组件很直接, 但是需要一些额外的工作(假定subversion在某些平台没有二进制包可用)
命令集CVS: 包含了3个经常用到的命令的简单的命令集(cvs commit, cvs update和cvs checkout)和其它一些Git: 命令集很丰富, 并且和CVS不兼容Mercurial: 尝试模仿CVS交互方式, 但是偏离了基于不同的设计的意图Subversion: 类CVS的命令集, 能够很容易被CVS用户使用
网络支持CVS: 好. cvs在不同的场合使用不同的协议. 协议能够通过ssh链接的加密隧道进行Git: 非常棒. 能够使用本地的git协议, 但也能在rsync, ssh, HTTP和HTTPS上使用Mercurial: 非常棒. 使用HTTP或ssh. 远程访问会非常安全, 在只读网络里不需要上锁Subversion: 非常好. Subversion服务器支持WebDAV+DeltaV(基于HTTP或HTTPS)作为底层协议, 或者它自身的协议同样能在ssh链接通道里使用.
可移植性CVS: 好. 客户端能在UNIX, Windows和Mac OS上使用. 服务器端能在UNIX, 附有UNIX模拟层的Windows上使用Git: 客户端运行在大多数的UNIX系统上, 但没有MS-Windows本地程序. 基于cygwin的系统看起来也能使用Mercurial: 非常棒. 运行在基于所有能运行python的平台.仓库是兼容性的基于CPU结构和字节序的Subversion: 非常好. 客户端和服务器端都能在UNIX, Windows和Mac OS X上运行
web接口CVS: 是的. CVSweb, ViewVC, Chora和wwCVSGit: 是的. Gitweb包含在发布包中Mercurial: 是的. Web接口是内置组件Subversion: 是的. ViewVC, SVN::Web, WebSVN, ViewSVN, mod_svn_view, Chora, Trac, SVN::RaWeb::Light, SVN Browser, Insurrection和perl_svn.另外, Subversion的apache服务也提供了一个基础的web接口
图形用户界面CVS: 非常好. 有很多图形界面可以用: WinCVS, Cervisia(对于KDE), TortoiseCVS(Windows浏览器插件)Git: Gitk包含在发行版中. Qqit和Git-gui工具也可使用Mercurial: 通过hgit扩展查看历史; 检入扩展(hgct)使得提交很容易. 一些第三方的IDEs和GUI工具(如eric3, meld)有一些集成的Mercurial支持Subversion: 非常好. 有很多GUIs可用: RapidSVN(跨平台), TortoiseSVN(Windows浏览器插件), Jsvn(java), 等. 大多数都还在开发中

2010年9月13日 星期一

iproute2 xfrm state command

這是我用來手動新增(test) ipsec的方法,當然還要配合policy
ip xfrm state add \
   src 172.21.46.133 dst 172.21.33.235 \
   proto esp spi 0xc1764476 mode tunnel \
   auth md5 0xbde367f6722286d104212c864d3041ff \
   enc blowfish \
 0xb860a53627435c27c5862ebf7e2e2de15e2fd2786db612eff0ce4b181a9373c34dd1b6ca17b1ffb2d118a575b9f8a9aa865783500b2cd38a

ip xfrm stat delete src 172.21.46.133 dst 172.21.33.235 proto esp spi 0xc1764476

 也可以用sha1加aes
ip xfrm state add src 172.21.46.131 dst 172.21.33.235  proto esp spi 0x4db377c8 reqid 16385 mode tunnel  auth sha1 0xe0a21cb441a0790188f8d5a7573608ae1e75af07 enc aes 0x86e4685642435deb2b53bee6c23723974d0207a4abed037c5028a310ef355a6e

ip xfrm state delete src 172.21.46.131 dst 172.21.33.235  proto esp spi 0x4db377c8
twofish
ip xfrm state add src 172.21.46.131 dst 172.21.33.235  proto esp spi 0x4db377c8 reqid 16385 mode tunnel  auth sha1 0xe0a21cb441a0790188f8d5a7573608ae1e75af07 enc twofish 0x86e4685642435deb2b53bee6c23723974d0207a4abed037c5028a310ef355a6e

ip xfrm state delete src 172.21.46.131 dst 172.21.33.235  proto esp spi 0x4db377c8
IPSec manual mode by iproute2
ip xfrm st add src 172.21.46.131 dst 172.21.33.235 proto esp spi 0x12345678 mode tunnel auth md5 0xbde367f6722286d104212c864d3041ff  enc aes 0xf82bbcccc0e01308e9a8edba1f2c058be3af44bfde5c26657d4a6609ca488ac2

----------------------------------------------------------------------------------------------

其它可以參考的url
http://lwn.net/Articles/375829/
http://osdir.com/ml/linux.kernel.cryptoapi/2008-04/msg00017.html

[lho@svdclab161 sec]$ cat ip-start-transport-ccm
#!/bin/sh

NODE=$1

echo "Starting IPSec transport mode using CCM..."

./ip xfrm policy flush
./ip xfrm state flush
#
# SA
./ip xfrm state add src 10.66.21.164 dst 10.66.21.166 proto esp spi
0x201 mode transport aead "rfc4309(ccm(aes))"
0x0102037aeaca3f87d060a12f4a4487d5a5c335 96
./ip xfrm state add src 10.66.21.166 dst 10.66.21.164 proto esp spi
0x301 mode transport aead "rfc4309(ccm(aes))"
0x010203f6ddb555acfd9d77b03ea3843f265325 96
#
# Policy
if [ "${NODE}" = "A" ]; then
./ip xfrm policy add dir out src 10.66.21.164 dst 10.66.21.166
tmpl proto esp mode transport
./ip xfrm policy add dir in src 10.66.21.166 dst 10.66.21.164
tmpl proto esp mode transport
fi
if [ "${NODE}" = "B" ]; then
./ip xfrm policy add dir in src 10.66.21.164 dst 10.66.21.166
tmpl proto esp mode transport
./ip xfrm policy add dir out src 10.66.21.166 dst 10.66.21.164
tmpl proto esp mode transport
fi

[lho@svdclab161 sec]$ cat ip-start-transport-gcm
#!/bin/sh

NODE=$1

echo "Starting IPSec transport mode using GCM..."

./ip xfrm policy flush
./ip xfrm state flush
#
# SA
./ip xfrm state add src 10.66.21.164 dst 10.66.21.166 proto esp spi
0x201 mode transport aead "rfc4106(gcm(aes))"
0x010203047aeaca3f87d060a12f4a4487d5a5c335 96
./ip xfrm state add src 10.66.21.166 dst 10.66.21.164 proto esp spi
0x301 mode transport aead "rfc4106(gcm(aes))"
0x01020304f6ddb555acfd9d77b03ea3843f265325 96
#
# Policy
if [ "${NODE}" = "A" ]; then
./ip xfrm policy add dir out src 10.66.21.164 dst 10.66.21.166
tmpl proto esp mode transport
./ip xfrm policy add dir in src 10.66.21.166 dst 10.66.21.164
tmpl proto esp mode transport
fi
if [ "${NODE}" = "B" ]; then
./ip xfrm policy add dir in src 10.66.21.164 dst 10.66.21.166
tmpl proto esp mode transport
./ip xfrm policy add dir out src 10.66.21.166 dst 10.66.21.164
tmpl proto esp mode transport
fi

2010年9月3日 星期五

PF_KEYv2 to cipher support internal(二)

這次,我從一個crypto_null.ko的crypto module開始
如同其名,這是一個不做任何事情的cihper
Kernel version 2.6.10

crypto/crypto_null.c
145 static int __init crypto_null_mod_init(void)
146 {
147         int ret = 0;
148
149         ret = crypto_register_alg(&cipher_null);
150         if (ret < 0)
151                 goto out;
152
153         ret = crypto_register_alg(&skcipher_null);
154         if (ret < 0)
155                 goto out_unregister_cipher;
156
157         ret = crypto_register_alg(&digest_null);
158         if (ret < 0)
159                 goto out_unregister_skcipher;
160
161         ret = crypto_register_alg(&compress_null);
162         if (ret < 0)
163                 goto out_unregister_digest
crypto_register_alg will add struct list_head crypto_register_alg.
107 static struct crypto_alg cipher_null = {
108         .cra_name               =       "cipher_null",
109         .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
110         .cra_blocksize          =       NULL_BLOCK_SIZE,
111         .cra_ctxsize            =       0,
112         .cra_module             =       THIS_MODULE,
113         .cra_list               =       LIST_HEAD_INIT(cipher_null.cra_list),
114         .cra_u                  =       { .cipher = {
115         .cia_min_keysize        =       NULL_KEY_SIZE,
116         .cia_max_keysize        =       NULL_KEY_SIZE,
117         .cia_setkey             =       null_setkey,
118         .cia_encrypt            =       null_crypt,
119         .cia_decrypt            =       null_crypt } }
120 };
Both of cia_encrypt,cia_decrypt do nothing just call null_crypt

55 static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 56 {
 57         memcpy(dst, src, NULL_BLOCK_SIZE);
 58 }
But in blockcipher is different
122 static struct crypto_alg skcipher_null = {
123         .cra_name               =       "ecb(cipher_null)",
124         .cra_driver_name        =       "ecb-cipher_null",
125         .cra_priority           =       100,
126         .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
127         .cra_blocksize          =       NULL_BLOCK_SIZE,
128         .cra_type               =       &crypto_blkcipher_type,
129         .cra_ctxsize            =       0,
130         .cra_module             =       THIS_MODULE,
131         .cra_list               =       LIST_HEAD_INIT(skcipher_null.cra_list),
132         .cra_u                  =       { .blkcipher = {
133         .min_keysize            =       NULL_KEY_SIZE,
134         .max_keysize            =       NULL_KEY_SIZE,
135         .ivsize                 =       NULL_IV_SIZE,
136         .setkey                 =       null_setkey,
137         .encrypt                =       skcipher_null_crypt,
138         .decrypt                =       skcipher_null_crypt } }
139 };

Blockcipher encrypt/decrypt有些不同其中,
(1).  首先inital一個struct blkcipher_walk 
        來記錄src 和dststruct scatterlist (一般這是和platform的dma有關)
            參考: http://lwn.net/Articles/263343/
                      http://lwn.net/Articles/256368/
(2). blkcipher_walk_virt用來

 60 static int skcipher_null_crypt(struct blkcipher_desc *desc,
 61                                struct scatterlist *dst,
 62                                struct scatterlist *src, unsigned int nbytes)
 63 {
 64         struct blkcipher_walk walk;
 65         int err;
 66
 67         blkcipher_walk_init(&walk, dst, src, nbytes);
 68         err = blkcipher_walk_virt(desc, &walk);
 69
 70         while (walk.nbytes) {
 71                 if (walk.src.virt.addr != walk.dst.virt.addr)
 72                         memcpy(walk.dst.virt.addr, walk.src.virt.addr,
 73                                walk.nbytes);
 74                 err = blkcipher_walk_done(desc, &walk, 0);
 75         }
 76
 77         return err;
 78 }
 79


blkcipher_walk describes the relationship of  physical / virtual address whare raw date stored in.
include/crypto/algapi.h
 65 struct scatter_walk {
 66         struct scatterlist *sg;
 67         unsigned int offset;
 68 };
The struct scatterlist is platform depend.
eg: arch/mips/include/asm/scatterlist.h
struct scatterlist {
#ifdef CONFIG_DEBUG_SG
        unsigned long   sg_magic;
#endif
        unsigned long   page_link;
        unsigned int    offset;
        dma_addr_t      dma_address;
        unsigned int    length;
};
 70 struct blkcipher_walk {
 71         union {
 72                 struct {
 73                         struct page *page;
 74                         unsigned long offset;
 75                 } phys;
 76
 77                 struct {
 78                         u8 *page;
 79                         u8 *addr;
 80                 } virt;
 81         } src, dst;
 82
 83         struct scatter_walk in;
 84         unsigned int nbytes;
 85
 86         struct scatter_walk out;
 87         unsigned int total;
 88
 89         void *page;
 90         u8 *buffer;
 91         u8 *iv;
 92
 93         int flags;
 94         unsigned int blocksize;
 95 };

再舉個(VIA PadLock hardware crypto engine)例子
drivers/crypto/padlock-aes.c
255 static int ecb_aes_encrypt(struct blkcipher_desc *desc,
256                            struct scatterlist *dst, struct scatterlist *src,
257                            unsigned int nbytes)
258 {
259         struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
260         struct blkcipher_walk walk;
261         int err;
262         int ts_state;
263
264         padlock_reset_key();
265
266         blkcipher_walk_init(&walk, dst, src, nbytes);
267         err = blkcipher_walk_virt(desc, &walk);
268
269         ts_state = irq_ts_save();
270         while ((nbytes = walk.nbytes)) {
271                 padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
272                                    ctx->E, &ctx->cword.encrypt,
273                                    nbytes / AES_BLOCK_SIZE);
274                 nbytes &= AES_BLOCK_SIZE - 1;
275                 err = blkcipher_walk_done(desc, &walk, nbytes);
276         }
277         irq_ts_restore(ts_state);
278
279         return err;
280 }

再來看一下cipher_alg這個structure, 其中rca_u會根據不同的cipher:(eg: crypto/hash/digest)
在register時inital相對應的methods

linux/crypto.h
 322 struct crypto_alg {
 323         struct list_head cra_list;
 324         struct list_head cra_users;
 325
 326         u32 cra_flags;
 327         unsigned int cra_blocksize;
 328         unsigned int cra_ctxsize;
 329         unsigned int cra_alignmask;
 330
 331         int cra_priority;
 332         atomic_t cra_refcnt;
 333
 334         char cra_name[CRYPTO_MAX_ALG_NAME];
 335         char cra_driver_name[CRYPTO_MAX_ALG_NAME];
 336
 337         const struct crypto_type *cra_type;
 338
 339         union {
 340                 struct ablkcipher_alg ablkcipher;
 341                 struct aead_alg aead;
 342                 struct blkcipher_alg blkcipher;
 343                 struct cipher_alg cipher;
 344                 struct digest_alg digest;
 345                 struct hash_alg hash;
 346                 struct ahash_alg ahash;
 347                 struct compress_alg compress;
 348                 struct rng_alg rng;
 349         } cra_u;
 350
 351         int (*cra_init)(struct crypto_tfm *tfm);
 352         void (*cra_exit)(struct crypto_tfm *tfm);
 353         void (*cra_destroy)(struct crypto_alg *alg);
 354
 355         struct module *cra_module;
 356 };