Re: [問題] 在 Linux 上用寫類似 kernel NAT 的 mo …

看板LinuxDev作者 (ITer)時間15年前 (2008/09/23 21:11), 編輯推噓2(201)
留言3則, 2人參與, 最新討論串1/1
※ 引述《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
IP "header" chksum ... 只計算 header 部份
09/23 23:56, 1F

09/23 23:57, , 2F
包含 IP options, if any
09/23 23:57, 2F

09/24 09:39, , 3F
感謝 我再來試試看 ~~
09/24 09:39, 3F
文章代碼(AID): #18sEiTvK (LinuxDev)