|
Bugzilla – Full Text Bug Listing |
| Summary: | When the Ipv4RawSocket "IpHeaderInclude" Attribute set true:Ip Checksum error and can not use faked IP | ||
|---|---|---|---|
| Product: | ns-3 | Reporter: | lilun <allanlee8> |
| Component: | internet | Assignee: | George Riley <riley> |
| Status: | RESOLVED FIXED | ||
| Severity: | normal | CC: | nikkipui, ns-bugs |
| Priority: | P5 | ||
| Version: | ns-3.12 | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Attachments: |
Patch for Ipv4RawSocket checksum
Patch for Ipv4RawSocket checksum |
||
|
Description
lilun
2012-07-31 04:32:55 UTC
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.
|