Bugzilla – Bug 1479
When the Ipv4RawSocket "IpHeaderInclude" Attribute set true:Ip Checksum error and can not use faked IP
Last modified: 2012-10-19 16:22:15 EDT
Could you provide a specific example when the problem arises?
I use raw socket in applications and wanna use fake IP. When I set IpHeaderInclude true,next things happened: 1 The SendTo function(ipv4-raw-socket-impl.cc) do these: Ipv4Header header; if (!m_iphdrincl) { header.SetDestination (dst); 211 header.SetProtocol (m_protocol); 212 } 213 else 214 { 215 p->RemoveHeader (header); 216 dst = header.GetDestination (); 217 src = header.GetSource (); 218 } if (!oif && src != Ipv4Address::GetAny ()) { int32_t index = ipv4->GetInterfaceForAddress (src); NS_ASSERT (index >= 0); oif = ipv4->GetNetDevice (index); NS_LOG_LOGIC ("Set index " << oif << "from source " << src); } that means we get the ifindex from srcIP,but the srcIP is faked,there's not a srcIP correspond the ifindex,so the assert failed. (In reply to comment #1) > Could you provide a specific example when the problem arises?
Sorry,please look this reply: I use raw socket in applications and wanna use fake IP. When I set IpHeaderInclude true,next things happened: 1 The SendTo function(ipv4-raw-socket-impl.cc) do these: Ipv4Header header; if (!m_iphdrincl) { header.SetDestination (dst); header.SetProtocol (m_protocol); } else { p->RemoveHeader (header); dst = header.GetDestination (); src = header.GetSource (); } the m_iphdrincl is true,so the we first remove the IP header from the packet(it includes the fake ip address),and we get the srcIP from the header(remember the ip is faked),and then : if (!oif && src != Ipv4Address::GetAny ()) { int32_t index = ipv4->GetInterfaceForAddress (src); NS_ASSERT (index >= 0); oif = ipv4->GetNetDevice (index); NS_LOG_LOGIC ("Set index " << oif << "from source " << src); } that means we get the ifindex from srcIP,but the srcIP is faked,there's not a srcIP correspond the ifindex,so the assert failed. (In reply to comment #1) > Could you provide a specific example when the problem arises?
I put this assert code comments off,and the packet can send out,but another bug arises, it's about the ipheader checksum I use the packet send to a real pc,so I need the checksum of IP header. When I package my packet,I enable the checksum and the AddHeader function do the checksum calculating work,so the packet checksum segment is right; And then ,the raw socket SendTo funciton do this: 207Ipv4Header header; 208 if (!m_iphdrincl) 209 { 210 header.SetDestination (dst); 211 header.SetProtocol (m_protocol); 212 } 213 else 214 { 215 p->RemoveHeader (header); 216 dst = header.GetDestination (); 217 src = header.GetSource (); 218 } The code above means the header I packed has been removed from the packet but the check sum is still right; And then: 235 if (!m_iphdrincl) 236 { 237 ipv4->Send (p, route->GetSource (), dst, m_protocol, route); 238 } 239 else 240 { 241 ipv4->SendWithHeader (p, header, route); 242 } here the m_iphdrincl is true, so we use the SendWithHeader function(here ,the "p" hasn't ip header,and the information of ip is at the "header") next in the ipv4-l3-protocol.cc,the SendWithHeader is implemented: 710 packet->AddHeader (ipHeader); That means the header we removed before is added to the packet again here!!So the checksum is calculated twice. So I sniff the packet in WireShark ,and find the packet IP checksum segment is "0". So I must off the EnableChecksum when I package my packet,and on the EnableChecksum before send the packet in raw socket SendTo. (In reply to comment #1) > Could you provide a specific example when the problem arises?
I think one workaround is to bind a socket to a device instead of letting the socket decides which socket to pass the packet to. I tried bind the socket to a specific device and it worked with ASSERT there. (I had the same problem with a fake source address that the ASSERT failed.) I will get back to you regarding the IP checksum.
Thank you very much. I'm Chinese so my English...Anyway I'm very happy to receive this reply. I don't know if these are bugs,maybe it's just because the application is different. But I don't think that I modify the src code is a good way for me to solve the specific problem because I'm afraid these modification for my problem will influnce other applications.So I report the bug. (In reply to comment #5) > I think one workaround is to bind a socket to a device instead of letting the > socket decides which socket to pass the packet to. I tried bind the socket to a > specific device and it worked with ASSERT there. (I had the same problem with a > fake source address that the ASSERT failed.) > I will get back to you regarding the IP checksum.
Ok, I think it's not a problem specific to Ipv4RawSocket. The problem is that Ipv4Header has a variable called m_calcChecksum that indicates whether the checksum should be calculated (and serialized to the buffer). So the first time the code add a Ipv4Header to a packet, the checksum is calculated and put into the buffer. The problem arises when you remove the Ipv4Header from the packet. At this point, the check sum _is_ read from the buffer so you'll still see the checksum here. However, m_calcChecksum is not set to true automatically (you can set it manually, though). If you add the Ipv4Header to a packet, this time the checksum will _not_ be put into the buffer since m_calcChecksum is not set. The problem occurred in Ipv4RawSocket since it removes the Ipv4Header and then pass the packet and the header separately to Ipv4L3Protocol. Ipv4L3Protocol then re-adds them together, which causes the problem. A minimum code to illustrate this: (I modified Ipv4Header::Print to print out checksum) Ptr<Packet> packet = Create <Packet> (512); Ipv4Header ipv4Header; ... ipv4Header.EnableChecksum (); // 1 NS_LOG_DEBUG ("Before serialize: " << ipv4Header); packet->AddHeader (ipv4Header); // 2 Ipv4Header peek; packet->PeekHeader (peek); NS_LOG_DEBUG ("Peek after serialized: " << peek); // 3 Ipv4Header remove; packet->RemoveHeader (remove); NS_LOG_DEBUG ("Remove after serialized: " << remove); // 4 NS_LOG_DEBUG ("Re-add the header back to the packet"); packet->AddHeader (remove); // 5 packet->PeekHeader (peek); NS_LOG_DEBUG ("Peek after re-added the header back: " << peek); Result: // 1 ... before AddHeader, checksum is not calculated (haven't Serialized) Before serialize: ... checksum=0 // 2 ... after serialized, checksum is calculated Peek after serialized: ... checksum=54692 // 3 .. remove the header, the checksum is still in the header Remove after serialized: ... checksum=54692 // 4 ... the checksum is in the header, but didn't get written to the buffer Re-add the header back to the packet // 5 ... peek the header shows checksum = 0 Peek after re-added the header back: ... checksum=0
Created attachment 1454 [details] Patch for Ipv4RawSocket checksum This patch should do the trick for using checksum with Ipv4RawSocket. Remember that you need to enable a global variable --ChecksumEnabled=1 to make this work.
Created attachment 1455 [details] Patch for Ipv4RawSocket checksum Moved from Ipv4RawSocketImpl to Ipv4L3Protocol::SendWithHeader. This way, all checksum-related calls are in Ipv4L3Protocol.