Hi, i'm working with iptables and libipq for a project and I have a "problem" with IP checksum. My scenario ----------- I'm working with the 2.4.18 kernel. I know, it's hold, but i think the problem is not here :-) My host is on a simple home lan. I also have a virtual network with a single "UserModeLinux" host connected with my real host throw tuntap transport. +-------+ +-----+ | | 192.168.1.1 192.168.1.2 | | | my PC |----------------------------| UML | | | tuntap eth0 | | +-------+ +-----+ eth0 | 192.168.0.59 | | my home lan (192.168.0/24) For my questions i will not care about my home lan, but i think it's better more than less. What i'm doing -------------- I have a very simple "echo" server on my UML host. It is listening on (192.168.1.2, 12345). With 'libipq' i'm simply sniffing packets from chains and printing them on output. My sniffer prints to stdout TCP/IP informations from the packet, checksum included. (I have also modified my sniffer that is now able to print mark value of the ipq_packet_msg structure, so i can see when packets change chain.) Inside the sniffer, I set IP checksum to 0 and recalculate it and set the field with the my new value. I do the same thing with TCP checksum. After this is i set NF_ACCEPT verdict for the packet. I have added these rules: iptables -t mangle -A OUTPUT -j MARK --set-mark 1 iptables -t filter -A OUTPUT -j QUEUE iptables -t nat -A OUTPUT -j QUEUE iptables -t mangle -A POSTROUTING -j MARK --set-mark 2 iptables -t mangle -A POSTROUTING -j QUEUE Now i open a new connection and here the sniffer output: +- mark value +- IP checksum from packet | | +-- my calculated checksum | | | | | | +- TCP checksum from packet | | | | +- my checksum | IP SRC IP DST P.SRC P.DST | | | | 1 | 192.168.1.1 192.168.1.2 | 1075 12345 | 0 68F1 | 81F2 81F2 | syn=1 OUTPUT filter 1 | 192.168.1.1 192.168.1.2 | 1075 12345 | 68F1 68F1 | 81F2 81F2 | syn=1 OUTPUT nat 2 | 192.168.1.1 192.168.1.2 | 1075 12345 | 9E6C 9E6C | 81F2 81F2 | syn=1 POSTROUTING mangle 1 | 192.168.1.1 192.168.1.2 | 1075 12345 | 201 C836 | DAE1 DAE1 | syn=0 OUTPUT filter 2 | 192.168.1.1 192.168.1.2 | 1075 12345 | A56C A56C | DAE1 DAE1 | syn=0 POSTROUTING mangle You can see the output for the first and third three-way handshake packets of my connection. (I have not filtered packet on INPUT so the second packet of connection is not printed). (I can't see the third packet and following packets on 'nat' OUTPUT but this is normal). Now: - IP checksum calculated from kernel before 'filter' OUTPUT is different from my calculated checksum. - It doesn't change from 'filter' OUTPUT to 'nat' OUTPUT - It's changed again before 'mangle' POSTROUTING, but it's well calculated (no difference from my checksum), not like before 'filter' OUTPUT. This is true for the first packet, and also all other packets of my connection. 1 | 192.168.1.1 192.168.1.2 | 1075 12345 | 10 6EF7 | E5ED E5ED | syn=0 2 | 192.168.1.1 192.168.1.2 | 1075 12345 | A26C A26C | E5ED E5ED | syn=0 1 | 192.168.1.1 192.168.1.2 | 1075 12345 | 7406 6FF6 | 8C05 8C05 | syn=0 2 | 192.168.1.1 192.168.1.2 | 1075 12345 | A36C A36C | 8C05 8C05 | syn=0 ... ... I have tested this also between two real host. Why this behaviour on IP checksum? It's to reduce the number of time the IP checksum have to be recalculated after any manipulation of IP header? If so, why it's not the same for TCP checksum? It's calculated with IP pseudo header. If we change ip destination or source address in nat chains why have to recalculate it. When IP checksum is calculated? When and where (what chains) i have to calculate IP checksum if i change packets from user-space without add unuseful overhead? I believe i have seen an other message about this subject, but there was not a full description about this "problem". Thanks to everyone, and sorry for the verbosity and for my bad english. Diego Billi