Re: [問題] 在 Linux 上用寫類似 kernel NAT 的 mo …
※ 引述《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
推
09/23 23:56, , 1F
09/23 23:56, 1F
→
09/23 23:57, , 2F
09/23 23:57, 2F
推
09/24 09:39, , 3F
09/24 09:39, 3F
LinuxDev 近期熱門文章
PTT數位生活區 即時熱門文章