作者kbslave (ITer)
看板LinuxDev
标题Re: [问题] 在 Linux 上用写类似 kernel NAT 的 mo …
时间Tue Sep 23 21:11:53 2008
※ 引述《nfsnfs (相片..)》之铭言:
: 大家好,
: 我现在尝试在 Linux kernel 2.6.22 上写一个类似 NAT 的东西,
: hook 的点是利用 NF_IP_PRE_ROUTING,
: 可是我现在遇到一个问题,
: 当我转传 TCP 封包的时候 TCP Checksum 会有问题因而被 DROP,
: 所以可以请问一下有人试过在 kernel 内重新算 TCP Checksum 的吗?
: 请问一下应该要怎麽做才对,感谢!
: <(____ ____)>
刚推文说错,应该是先算TCP chksum再算IP chksum~
Retrieve TCP chksum: get_transport_checksum(packet, protocol)
(in)packet: TCP封包
(in)protocol: 为第四层之协定
Retrieve IP chksum: get_ip_checksum(buf, nwords);
(in)buf: 为ip packet之完整内容
(in)nwords: 为此packet共有几word (16-bit <-- I guess)..
src code如下,请享用~
==================================
unsigned short int calculate_sum( unsigned int* check_buffer, unsigned char*
packet, int protocol, int tcp_len, int iphdr_len )
{
int i;
if ( protocol != IPPROTO_ICMP )
{
for ( i = 0;i < 8;i++ )
check_buffer[ i ] = packet[ 12 + i ];
check_buffer[ 8 ] = 0;
check_buffer[ 9 ] = protocol;
if ( tcp_len > 255 )
{
check_buffer[ 11 ] = tcp_len & 0x00FF;
check_buffer[ 10 ] = tcp_len >> 8;
}
else
{
check_buffer[ 11 ] = tcp_len;
check_buffer[ 10 ] = 0;
}
}
else
{
for ( i = 0;i < 12;i++ )
check_buffer[ i ] = 0;
}
for ( i = 0;i < tcp_len;i++ )
{
check_buffer[ 12 + i ] = packet[ iphdr_len + i ];
}
if ( tcp_len % 2 != 0 )
tcp_len = tcp_len + 1;
unsigned int losum = 0;
for ( i = 0;i < tcp_len / 2 + 6;i++ )
{
losum += check_buffer[ i * 2 + 1 ];
}
unsigned int hisum = 0;
for ( i = 0;i < tcp_len / 2 + 6;i++ )
{
hisum += check_buffer[ i * 2 ];
}
unsigned int sum = ( hisum << 8 ) + losum;
sum = sum + ( sum >> 16 );
sum = sum & 0x0000FFFF;
unsigned short int result = ( unsigned short int ) sum;
return htons( ~result );
}
unsigned short int get_transport_checksum( unsigned char* packet, int
protocol )
{
struct iphdr * iph = ( struct iphdr * ) packet;
struct tcphdr *tcph;
struct icmphdr *icmph;
struct udphdr *udph;
switch ( protocol )
{
case IPPROTO_TCP:
tcph = ( struct tcphdr* ) ( packet + ( iph->ihl << 2 ) );
tcph->check = 0;
break;
case IPPROTO_ICMP:
icmph = ( struct icmphdr* ) ( packet + ( iph->ihl << 2 ) );
icmph->checksum = 0;
break;
case IPPROTO_UDP:
udph = ( struct udphdr* ) ( packet + ( iph->ihl << 2 ) );
udph->check = 0;
break;
}
int data_wordlength = 12 + ntohs( iph->tot_len ) - iph->ihl * 4;
if ( data_wordlength % 2 != 0 )
{
unsigned int chk_buf[ data_wordlength + 1 ];
chk_buf[ data_wordlength ] = 0;
return calculate_sum( chk_buf, packet, protocol, data_wordlength -
12, iph->ihl * 4 );
}
else
{
unsigned int chk_buf[ data_wordlength ];
return calculate_sum( chk_buf, packet, protocol, data_wordlength -
12, iph->ihl * 4 );
}
}
unsigned short get_ip_checksum ( unsigned short *buf, int nwords )
{
unsigned long sum;
for ( sum = 0; nwords > 0; nwords-- )
sum += *buf++;
sum = ( sum >> 16 ) + ( sum & 0xffff );
sum += ( sum >> 16 );
return ~sum;
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 124.8.26.207
1F:推 mecs:IP "header" chksum ... 只计算 header 部份 09/23 23:56
2F:→ mecs:包含 IP options, if any 09/23 23:57
3F:推 nfsnfs:感谢 我再来试试看 ~~ 09/24 09:39