- 论坛徽章:
- 0
|
大概搞定了,至少能ping通和访问网页了!晕,这两天都在弄这个东东。
在网上找一大圈(pppd,pppoe的maillist都去找了),发觉很有可能是mppe实现的问题。今天就对照mppe的最新补丁和rfc3078去修改。--- ,只是修改了解密那个函数,真的是运气啊!说实话,自己是完全没有信心的,毕竟假如有问题的话,怎么可能就在那一个函数里面!!!当然还有一个理由就是stateless时能正确处理。
其实自己之所以动手,也是误打误撞的结果: 抓包发现windows client发 flushed包时,并没有特别设置ccount,而自己记忆中的mppe_decompress()好像是假设两者都要设置的!这似乎和rfc里的描述好像也有不对应的地方。所以就......
修改处都有注释:@2009.12.01。就改了几处而已!
/*
* Decompress (decrypt) an MPPE packet.
* @2009.12.01 参考mppe最新补丁 和rfc3078 修改
* 主要修改的地方是:
* 1.discard state,它的步进竟然是256,而后面新版是1;它那里的算法好像也有点问题,主要是循环条件那里
* 2.normal state和 flushed那里,将mppe_rekey()的调用提到normal state,flushed处调用的是arcfour_setkey().这里没明白单独调用arcfour_setkey()有什么用,只是按照最新patch的做法而已,嘿
* 当然,state->ccount 的增长那里可以像新patch那样写成一个函数或者宏,嘿,俺是新手,怕出问题,而且也就两个地方而已,所以就...
*/
int
mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
int osize)
{
ppp_mppe_state *state = (ppp_mppe_state *) arg;
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
int sanity = 0;
if (isize <= PPP_HDRLEN + MPPE_OVHD) {
if (state->debug)
printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n",
state->unit, isize);
return DECOMP_ERROR;
}
/* Strange ... our output size is always LESS than the input size. */
/* assert(osize >= isize - MPPE_OVHD - 2); */
osize = isize - MPPE_OVHD - 2;
ccount = MPPE_CCOUNT(ibuf);
/* sanity checks -- terminate with extreme prejudice */
if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
state->unit);
state->sanity_errors += 100;
sanity = 1;
}
if (!state->stateful && !flushed) {
printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
"stateless mode!\n", state->unit);
state->sanity_errors += 100;
sanity = 1;
}
#if 1 //question. when 0xff, must set flushed? I don't know, so I don't deal with it
if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
"flag packet!\n", state->unit);
state->sanity_errors += 100;
sanity = 1;
}
#endif
if (sanity) {
if (state->sanity_errors < SANITY_MAX)
return DECOMP_ERROR;
else
/*
* Take LCP down if the peer is sending too many bogons.
* We don't want to do this for a single or just a few
* instances since it could just be due to packet corruption.
*/
return DECOMP_FATALERROR;
}
/*
* Check the coherency count.
*/
if (!state->stateful) {
/* RFC 3078, sec 8.1. Rekey for every packet. */
while (state->ccount != ccount) {
mppe_rekey(state, 0);
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
}
} else {
/* RFC 3078, sec 8.2. */
if (!state->discard) {
/* normal state */
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
#if 1 //下面(discard state 也有调用)也有调用,可以做成一个宏@2009.12.01
if ((state->ccount & 0xff) == 0xff) {
//mppe_change_key(state, 0);
mppe_rekey(state, 0);
}
#endif
if (ccount != state->ccount) {
/*
* (ccount > state->ccount)
* Packet loss detected, enter the discard state.
* Signal the peer to rekey (by sending a CCP Reset-Request).
*/
state->discard = 1;
return DECOMP_ERROR;
}
} else {
/* discard state */
if (!flushed) {
/* ccp.c will be silent (no additional CCP Reset-Requests). */
return DECOMP_ERROR;
} else {
/* Rekey for every missed "flag" packet. */
#if 0 //@2009.12.01
while ((ccount & ~0xff) != (state->ccount & ~0xff)) {
mppe_rekey(state, 0);
state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE;
}
#else
while( ccount != state->ccount ){
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
if ((state->ccount & 0xff) == 0xff) {
//mppe_change_key(state, 0);
mppe_rekey(state, 0);
}
}
#endif
/* reset */
state->discard = 0;
state->ccount = ccount;
/*
* Another problem with RFC 3078 here. It implies that the
* peer need not send a Reset-Ack packet. But RFC 1962
* requires it. Hopefully, M$ does send a Reset-Ack; even
* though it isn't required for MPPE synchronization, it is
* required to reset CCP state.
*/
}
}
#if 0 //@2009.12.01
if (flushed)
mppe_rekey(state, 0);
#else
if (flushed){
printk(KERN_DEBUG" recv packet have seted flushed(FLUSHED bit) in stateful mode\n" ;
arcfour_setkey(&state->arcfour_context, state->session_key, state->keylen);
}
#endif
}
/*
* Fill in the first part of the PPP header. The protocol field
* comes from the decrypted data.
*/
obuf[0] = PPP_ADDRESS(ibuf); /* +1 */
obuf[1] = PPP_CONTROL(ibuf); /* +2 */
obuf += 2;
ibuf += PPP_HDRLEN + MPPE_OVHD;
isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */
/* net: -4 */
/* And finally, decrypt the packet. */
arcfour_decrypt(&state->arcfour_context, ibuf, isize, obuf);
state->stats.unc_bytes += osize;
state->stats.unc_packets++;
state->stats.comp_bytes += isize;
state->stats.comp_packets++;
/* good packet credit */
state->sanity_errors >>= 1;
return osize;
}
ps:说实话,回头看自己的过程,真的很惊险,完全都是运气使然!!!
而且好像对自己的提高也不大! 并没有理清/理解 整个框架就在动手了!(嘿,对加解密真的完全不明白,比如密码的初始化、如何加解密、密匙的分发、密匙的同步,一大堆...)。到头来 也没有什么收获,哎...... |
|