Bug 1479 - When the Ipv4RawSocket "IpHeaderInclude" Attribute set true:Ip Checksum error and can not use faked IP
When the Ipv4RawSocket "IpHeaderInclude" Attribute set true:Ip Checksum error...
Status: RESOLVED FIXED
Product: ns-3
Classification: Unclassified
Component: internet
ns-3.12
All Linux
: P5 normal
Assigned To: George Riley
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-07-31 04:32 EDT by lilun
Modified: 2012-10-19 16:22 EDT (History)
2 users (show)

See Also:


Attachments
Patch for Ipv4RawSocket checksum (413 bytes, patch)
2012-10-12 12:48 EDT, Daniel L.
Details | Diff
Patch for Ipv4RawSocket checksum (476 bytes, patch)
2012-10-15 14:26 EDT, Daniel L.
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description lilun 2012-07-31 04:32:55 EDT

    
Comment 1 Daniel L. 2012-10-11 11:50:08 EDT
Could you provide a specific example when the problem arises?
Comment 2 lilun 2012-10-11 21:25:52 EDT
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?
Comment 3 lilun 2012-10-11 21:29:57 EDT
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?
Comment 4 lilun 2012-10-11 21:51:30 EDT
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?
Comment 5 Daniel L. 2012-10-11 22:47:29 EDT
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.
Comment 6 lilun 2012-10-11 23:11:19 EDT
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.
Comment 7 Daniel L. 2012-10-12 10:27:18 EDT
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
Comment 8 Daniel L. 2012-10-12 12:48:35 EDT
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.
Comment 9 Daniel L. 2012-10-15 14:26:52 EDT
Created attachment 1455 [details]
Patch for Ipv4RawSocket checksum

Moved from Ipv4RawSocketImpl to Ipv4L3Protocol::SendWithHeader. This way, all checksum-related calls are in Ipv4L3Protocol.