IP头校验和计算时将校验和字段预留为0,然后每16bit累加一次,直到计算完成。如果最后剩下一个单数字节,前面补0再累加。计算结果在返回前取反。
校验时不处理校验和位,吧所有数据累加一遍,如果结果为0xFFFF或者0x0000(取决于你是不是使用同一个函数计算,也就是最后一步是否取反)表明正确(很神奇?)其实就是一个数加上这个数的反码结果是一串1,这个方法同样适用于TCP,UDP等等其他协议的计算。参考这个:http://blog.chinaunix.net/u/12313/showart_176114.html
下面是Java实现代码:
public int csum(ByteBuffer buff) { int sum = 0; while (buff.remaining() > 1) { sum += buff.getShort() & 0xFFFF; } if (buff.remaining() > 0) { sum += buff.get() & 0xFF; } while (sum >>> 16 != 0) { sum = (sum & 0xFFFF) + (sum >>> 16); } return (~sum) & 0xFFFF; }
测试:
@Test public void testCsum() { System.out.println("csum"); byte[] buf = new byte[]{ (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x88, (byte) 0x00, (byte) 0x23, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0x2f, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0xfd, (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0xfc }; IPHeader instance = new IPHeader(); int expResult = 0x6fd9; int result = instance.csum(ByteBuffer.wrap(buf)); System.out.printf("0x%04x%n",result); System.out.printf("0x%04x%n",result&((~result)&0xFFFF)); assertEquals(expResult, result); }
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.6 (Debian-3.0.6-1)
用libnet就不用计算crc了!不知道py有没有libnet的portage