Skip to contentSkip to conversation

Entirely ignoring TCP and UDP checksum in kernel level

DISCUSSION Josan Kadett 4 participants 12 messages Aug 22, 2004 – Aug 23, 2004 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore
#1 lore raw
In reply to a message not in the archive

It is certainly the solution to the issue. Indeed, everything works fine including NAT because the hack is in the kernel level. Your assistance is greatly appreciated. The first issue is complete but for now I think I will get into a lesser one. (I will write about it when I get have all the details)

Best Regards...

-----Original Message-----
From: Brad Campbell [mailto:[email protected]]
Sent: Sunday, August 22, 2004 10:48 AM
To: Josan Kadett
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

No.. this should work for you.. Try it and see anyway.

Regards,
Brad

#3 lore raw
In reply to a message not in the archive

Bad news... NAT does not work, but it should have worked. Where might be the mistake ? I put another machine connected next to the patched linux server, I sniff the traffic and see that:
(I enabled SNAT);

Packet arrives from 192.168.0.30 (new machine to test nat) The packet is correctly translated and sent over the line With the patch, the new packet seems to arrive from correct source 77.1

*But this is where the problem begins, the system does not send the received packet to the address which is SNATted. I thought, the ip_input.c code would work in the lowest level so IPTABLES would naively use the changed source address...

I do not know if ever this problem will end...

-----Original Message-----
From: Brad Campbell [mailto:[email protected]]
Sent: Sunday, August 22, 2004 10:48 AM
To: Josan Kadett
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

Quoted 5 lines · Josan Kadett

This does actually change the source IP address of the machine and allow NAT??

Client A 192.168.0.20 -- connects to patched linux server Linux 192.168.1.1 -- translates the source address 192.168.x.x to

1.1(SNAT)

Quoted 2 lines

And will NAT actually work with this patch, as far as I see, this code

gets

Quoted 1 line

the saddr and puts another one when the condition matches?

No.. this should work for you.. Try it and see anyway.

Regards,
Brad

#4 lore raw
Quoted 14 lines · Josan Kadett

Bad news... NAT does not work, but it should have worked. Where might be the mistake ? I put another machine connected next to the patched linux server, I sniff the traffic and see that:
(I enabled SNAT);

Packet arrives from 192.168.0.30 (new machine to test nat) The packet is correctly translated and sent over the line With the patch, the new packet seems to arrive from correct source 77.1

*But this is where the problem begins, the system does not send the received packet to the address which is SNATted. I thought, the ip_input.c code would work in the lowest level so IPTABLES would naively use the changed source address...

Quoted 8 lines

I do not know if ever this problem will end...

Quoted 3 lines

Client A 192.168.0.20 -- connects to patched linux server Linux 192.168.1.1 -- translates the source address 192.168.x.x to

1.1(SNAT)

You have 192.168.0.x NAT to 192.168.1.1?
I thought you wanted to NAT to 192.168.77.1?

My understanding was you sent a packet to 192.168.77.1 and the device sent it back from 192.168.1.1

Can you send me your iptables configuration?

#5 lore raw

I am still persistent on the fact that NAT should work with this sense.

I just enable NAT with the following command

iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 192.168.1.5

This IP 192.168.1.5 is our patched linux server which is allowed to acccess 192.168.1.77

Now all protocols in the linux system is working fine as ever, and even ping sent to 192.168.77.1 returns from 192.168.77.1 that is visible in the presumably lowest layer of network stack (as tcpdump also sees it that way).

However; the client on the interface eth0 which has the IP address of 192.168.0.30 gets its IP address translated to 192.168.1.5, the ping is sent and a response is received (tcpdump shows it)

But the patched linux system does not translate it back to the client that requested that ping. That means, only our patched linux system can access to the node, but nothing else.

I tested NAT for another interface (not eth1 whose connection is now somehow patched) to send a request to google.com, the NAT ensuredly works for any other IP but 192.168.77.1.

I am suspiciuous about the fact that IPTables might still see the wrong IP address of the device before it is changed by the patch (192.168.1.1), thus it drops the packet there. However; this event is rather odd...

BTW, the problem is at the edge of being resolved, since the hardest part is now gone. But I could not believe all this would be gone by two lines of code... The solution must be there;

*You could test the NAT to see whether it works for your configuration, this time I am totally out of ideas...

-----Original Message-----
From: Brad Campbell [mailto:[email protected]]
Sent: Sunday, August 22, 2004 11:36 AM
To: Josan Kadett
Cc: [email protected]
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

You have 192.168.0.x NAT to 192.168.1.1?
I thought you wanted to NAT to 192.168.77.1?

My understanding was you sent a packet to 192.168.77.1 and the device sent it back from 192.168.1.1

Can you send me your iptables configuration?

#2 lore raw
In reply to Josan Kadett

Josan,

Would you like to tell us the Make and Model of this problem box, so we can all avoid them in future?

James

Quoted 18 lines · Josan Kadett

It is certainly the solution to the issue. Indeed, everything works fine including NAT because the hack is in the kernel level. Your assistance is greatly appreciated. The first issue is complete but for now I think I will get into a lesser one. (I will write about it when I get have all the details)

Best Regards...

-----Original Message-----
From: Brad Campbell [mailto:[email protected]] Sent: Sunday, August 22, 2004 10:48 AM
To: Josan Kadett
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

No.. this should work for you.. Try it and see anyway.

Regards,
Brad

#6 lore raw
In reply to Josan Kadett
Quoted 9 lines · Josan Kadett

I am still persistent on the fact that NAT should work with this sense.

I just enable NAT with the following command

iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 192.168.1.5

This IP 192.168.1.5 is our patched linux server which is allowed to acccess 192.168.1.77

Ok.. Idea time..
Can you add another linux box in there. Something like

Client (192.168.0.30) ---> Box1Eth0(192.168.0.1) SNAT Box1Eth1(192.168.1.99) ---> Box2Eth0(192.168.1.100) () Box2Eth1(192.168.77.99) ---> HorridBuggyBox(192.168.77.1)

With Box 1 doing the NAT and Box 2 having the patch and just doing normal routing.

Have a route in Box 1 set to send 192.168.77.0/24 to the gateway at 192.168.1.100 which will know to send anything destined for 192.168.77.1 out eth1.

If I try it, it's going to work fine as I don't have a box that munges IP's like yours does so I can't provide a full test. (I guess I could butcher another UML to do it if I really had to)

Doing this stuff is so much easier when you have the faulty device in front of you. Your not in the UAE by any chance ;p)

Regards,
Brad

#7 lore raw
In reply to Josan Kadett
Quoted 9 lines · Josan Kadett

I am still persistent on the fact that NAT should work with this sense.

I just enable NAT with the following command

iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 192.168.1.5

This IP 192.168.1.5 is our patched linux server which is allowed to acccess 192.168.1.77

Quoted 8 lines

Now all protocols in the linux system is working fine as ever, and even ping sent to 192.168.77.1 returns from 192.168.77.1 that is visible in the presumably lowest layer of network stack (as tcpdump also sees it that way).

However; the client on the interface eth0 which has the IP address of 192.168.0.30 gets its IP address translated to 192.168.1.5, the ping is sent and a response is received (tcpdump shows it)

Are you trying to ping 192.168.77.1 from 192.168.0.30?

Can you give me an iptables -L -n -t nat, ifconfig and route -n from the patched box and also route -n and ifconfig from the dummy client at 192.168.0.30 so I can try and get a handle on what you are doing and how it all is supposed to work?

#8 lore raw

Very well I am trying to ping this device from a host connected to our linux box whose source IP is translated. I changed the IP numbers a bit so they won't interfere with each ether in any way (absolutely different subnets)

Eth0 is connected the path where the problematic 192.168.77.1 is reached. The IP number of assigned to eth1 interface is 192.168.1.5. Now with the patch applied, any request to 192.167.77.1 seems to return from 192.168.77.1

Eth1 is connected to a private network with the IP address of 1.1.1.1, and the IP address of the host whose connection will be SNATted is 1.1.1.30.

When I ping 192.168.77.1, everything seems correct now, but when I ping that IP 1.1.1.30, indeed the transaction is made, but the linux box is somehow "reluctant" to send te response back.

Iptables -L -n -t nat:
Chain POSTROUTING (policy ACCEPT)
Target prot opt source destination
SNAT all -- 0.0.0.0/0 0.0.0.0/0
to:192.168.1.2

0.0.0.0 means anywhere I presume...

Ifconfig of the patched box
Eth0: inet address 192.168.1.5, netmask 255.255.0.0 (external if)
Eth1: inet address 1.1.1.1, netmak 255.255.255.0 (internal if)

Routing tables:
Destination Gateway Genmaks Flags Metric Ref Use
Iface
192.168.77.1 192.168.1.2 255.255.255.0 UGH 0 0 0 eth0
1.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0
eth0

NAT client uses IP address 1.1.1.30, with netmask of 255.255.255.0 with the default gateway 1.1.1.1 (linux box).

Tcpdump[ eth0 / the address translation occurs correctly] Ping request - 192.168.1.5 to 192.168.77.1
Ping reply - From 192.168.77.1 to 192.168.1.5 Ping request - 192.168.1.5 to 192.168.77.1
Ping reply - From 192.168.77.1 to 192.168.1.5 Ping request - 192.168.1.5 to 192.168.77.1
Ping reply - From 192.168.77.1 to 192.168.1.5

Tcpdump[ eth1 / no reply is sent by our linux system] Ping request - 1.1.1.30 to 192.168.77.1
Ping request - 1.1.1.30 to 192.168.77.1
Ping request - 1.1.1.30 to 192.168.77.1

Both dumps are taken at the same time, I ensure that the linux box just does not redirect the ping reply to the client 1.1.1.30 that requested it.

What can this be now? NAT still does not work in a way - or is there something missing ?

-----Original Message-----
From: Brad Campbell [mailto:[email protected]]
Sent: Sunday, August 22, 2004 3:14 PM
To: Josan Kadett
Cc: [email protected]
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

Are you trying to ping 192.168.77.1 from 192.168.0.30?

Can you give me an iptables -L -n -t nat, ifconfig and route -n from the patched box and also route
-n and ifconfig from the dummy client at 192.168.0.30 so I can try and get a handle on what you are
doing and how it all is supposed to work?

#9 lore raw
In reply to Brad Campbell

I have found the exact reason why NAT does not work;

- The patched linux box ignores IP checksum errors
- Since now the source address is mofidified without checksumming, NAT also carries that wrong checksum
- Other boxes does not ignore the checksum and drop packets

I think the solution is here, I have done many different modifications to get the system redirect packets with wrong checksum. Now all to be done, is to correct this checksum by changing some code in ip_input.c so that it recalculates the checksum when the packets seem to arrive from 192.168.1.1.

Where in the code then?

-----Original Message-----
From: Brad Campbell [mailto:[email protected]]
Sent: Sunday, August 22, 2004 3:14 PM
To: Josan Kadett
Cc: [email protected]
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

Are you trying to ping 192.168.77.1 from 192.168.0.30?

Can you give me an iptables -L -n -t nat, ifconfig and route -n from the patched box and also route
-n and ifconfig from the dummy client at 192.168.0.30 so I can try and get a handle on what you are
doing and how it all is supposed to work?

#10 lore raw
Quoted 7 lines · Josan Kadett

I have found the exact reason why NAT does not work;

- The patched linux box ignores IP checksum errors
- Since now the source address is mofidified without checksumming, NAT also carries that wrong checksum
- Other boxes does not ignore the checksum and drop packets

Quoted 6 lines

I think the solution is here, I have done many different modifications to get the system redirect packets with wrong checksum. Now all to be done, is to correct this checksum by changing some code in ip_input.c so that it recalculates the checksum when the packets seem to arrive from 192.168.1.1.

Where in the code then?

The attached patch might work. It changes the IP source address from 192.168.1.1 to 192.168.77.1 and then recalculates the IP header checksum. (I haven't tested it, though).

Do I understand you correctly that the IP checksum is calculated correctly, but for the address 192.168.1.1, and the UDP and TCP checksums are computed as if the address was 192.168.77.1? If so, I think this should work...

Now, can you please oblige us with the name of the manufacturers of the broken router (as someone else also previously requested), so they can be properly publicly ridiculed? :-)

Hope it helps,

Dave

---

net/ipv4/ip_input.c renamed from net/ipv4/ip_input.c~ip-ignore-csum +24 -0
diff -puN net/ipv4/ip_input.c~ip-ignore-csum net/ipv4/ip_input.c
@@ -355,6 +355,27 @@ drop:
         return NET_RX_DROP;
 }
 
+static inline void mangle_addr_and_csum(struct iphdr *iph)
+{
+#define MANGLE_SADDR_IN   htonl(0xc0a80101)
+#define MANGLE_SADDR_OUT  htonl(0xc0a84d01)
+
+	if (iph->saddr != MANGLE_SADDR_IN)
+		return;
+
+	/* Change the source address from 192.168.1.1 to 192.168.77.1 and
+	 * correct the checksum. */
+	iph->saddr = MANGLE_SADDR_OUT;
+	iph->check = 0;
+	iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
+
+	/* Make sure the checksum is correct now. */
+	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) {
+		printk(KERN_ERR "checksum %08x -> %08x failed! (%04x)\n",
+		       MANGLE_SADDR_IN, iph->saddr, iph->check);
+	}
+}
+
 /*
  * 	Main IP Receive routine.
  */ 
@@ -399,6 +420,9 @@ int ip_rcv(struct sk_buff *skb, struct n
 
 	iph = skb->nh.iph;
 
+	/* Take care of broken router. */
+	mangle_addr_and_csum(iph);
+
 	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
 		goto inhdr_error; 
 

_

#11 lore raw

The device is a Cisco AS3640-T1 but it is not the fault of the device but our enforcing an unusual configuration in order to connect two networks to each other. This way we thought it would cut some extra work out, I investigated the configuration and I believed in the fact that Linux can handle this anomaly.

Indeed, we do try to connect two networks without the necessary equipment, and it is at edge of a successful completion.

I tried another patch that is so similar to the code you submitted, indeed now the linux machine can communicate with the device without any problem. But there is only one thing left, I'd be extremely glad if you assist in this last issue so that I will have completed what I started;

Now the system receives the packets from the correct source which is 192.168.77.1. But now, I am trying to establish a "destination nat" scheme, which will enable this linux machine to act as a gateway to this device. However; this gateway should have the exact IP number as the device itself so that the link is not broken for hosts whose subnets are not in the subnet to which the AC would respond. If we change these subnets with the correct one, whole IP configuration would be screwed up.

So now the issue would seem simple;

We would just assign the exact IP number (192.168.77.1) to one of the interfaces of the linux machine that has the uplink, and build a NAT table using Iptables so that any request,

To 192.168.77.1 [IF 1] would be redirected to 192.168.77.1 [IF 2]**

Now the problem lies here, I cannot tell the linux machine not to route NAT to its own loopback adapter. The machine is naturally thinking that this IP address is its own and nothing works out this way.

I have come up with a solution that should do exactly what we wish;

Similar to the patch of ip_input.c, we could tell the machine that it should send all IP data to 192.168.1.1 [dumb port of the AC - the source of all problems]. Just before the system sends that packet, now its destination IP address should be mangled with the correct one [192.168.77.1]. This way NAT should work because the system will still think that it is sending a request to 192.168.1.1, but it will be sent to 77.1 and data will be received from 77.1.

So the code I presume should be as follows;

1. Check if the outgoing packet is going to 192.168.1.1
2. If it is going there mangle it with 192.168.77.1 and checksum
3. TCP and UDP layer should also create their psuedo-headers with 192.168.77.1 because otherwise this time AC won't receive it
4. Receive data back from 192.168.77.1 and translate

** But if the NAT still would insist that it should get packets from the address it intended to communicate [Hopefully not]; in that case;

5. The ip_input.c patch this time would not be used anyway
6. But now the TCP and UDP checksums would be voided as usual
7. Correct TCP and UDP checksums of the input packet
8. Put them on the socket

So this means we require a similar patch for ip_output.c. Regardless of those seeminlgy impossible problems, I will persist on the fact that there are always alternative ways to handle an issue...

Best Regards...

-----Original Message-----
From: David Meybohm [mailto:[email protected]]
Sent: Monday, August 23, 2004 5:38 AM
To: Josan Kadett
Cc: 'Brad Campbell'; [email protected]
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

The attached patch might work. It changes the IP source address from 192.168.1.1 to 192.168.77.1 and then recalculates the IP header checksum. (I haven't tested it, though).

Do I understand you correctly that the IP checksum is calculated correctly, but for the address 192.168.1.1, and the UDP and TCP checksums are computed as if the address was 192.168.77.1? If so, I think this should work...

Now, can you please oblige us with the name of the manufacturers of the broken router (as someone else also previously requested), so they can be properly publicly ridiculed? :-)

Hope it helps,

Dave

---

diff -puN net/ipv4/ip_input.c~ip-ignore-csum net/ipv4/ip_input.c
--- v2.6.8/net/ipv4/ip_input.c~ip-ignore-csum 2004-08-22
22:56:34.000000000 -0400
+++ v2.6.8-dym/net/ipv4/ip_input.c 2004-08-22 23:07:26.000000000 -0400
@@ -355,6 +355,27 @@ drop:

         return NET_RX_DROP;

}

+static inline void mangle_addr_and_csum(struct iphdr *iph) +{
+#define MANGLE_SADDR_IN htonl(0xc0a80101)
+#define MANGLE_SADDR_OUT htonl(0xc0a84d01)
+
+ if (iph->saddr != MANGLE_SADDR_IN)
+ return;
+
+ /* Change the source address from 192.168.1.1 to 192.168.77.1 and
+ * correct the checksum. */
+ iph->saddr = MANGLE_SADDR_OUT;
+ iph->check = 0;
+ iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
+
+ /* Make sure the checksum is correct now. */
+ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) {
+ printk(KERN_ERR "checksum %08x -> %08x failed! (%04x)\n",
+ MANGLE_SADDR_IN, iph->saddr, iph->check);
+ }
+}
+
/*
* Main IP Receive routine.
*/
@@ -399,6 +420,9 @@ int ip_rcv(struct sk_buff *skb, struct n

iph = skb->nh.iph;

+ /* Take care of broken router. */
+ mangle_addr_and_csum(iph);
+
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto inhdr_error;

_

#12 lore raw
In reply to David Meybohm

So to summarize the AC issue;

There is an AC whose "real" failure is a simple programming error. Normally it had to have two different IP adresses, one for 192.168.77.0 subnet, the other for 192.168.1.0 subnet. Indeed it has two addresses but the address at 192.168.1.1 is wrongly bound to TCP/IP socket.

If everything were correct, when I would ping 192.168.1.1, it would return a ping from 192.168.1.1. But now when I ping 192.168.1.1, it just discards the packet. That lies in the source of this trouble.

I am extremely glad to have got a solution for this issue in less than three days by fanatical assistance from the linux-kernel mailing list. Everything has been put on place and two networks are bound together perfectly. Technically, this event shows what an open-source O/S can do in case of network anomalies.

However; for now I wish to get deeper into the kernel networking code to continue my started work even I resolved this issue. This way, I think I will be able to handle possible future troubles much easier.

Today, I have discovered that NAT does not handle packets correctly if the return address is different from the intended destination. That is, in a complex network network, if a node is sending a packet through another address (even if this packet is fully correct in checksums, unlike this exceptional trouble, which is now a patched issue), NAT will not be able to correctly translate packets. I thought it could have been resolved by disabling rp_filter in /proc/../conf/*, but it was not correct.

So for now, I wish to implement another patch to be able to transparently surpass this exceptional failure in the AC just to learn some more about the kernel and packet mangling.

1. The system must think that it is sending the packet to 192.168.1.1 even if it will be mangled by the kernel to be sent to 192.168.77.1. All three checksums should be correct (IP, TCP and UDP) so that the remote node will receive packets correctly.

2. The system must think that it is receiving packets from 192.168.77.1, indeed before the kernel patch was applied, the packets had a source address of 192.168.1.1, but they had incorrect checksums in the underlying protocols (TCP and UDP) so that our system would drop all that was received. Now I will have to update the CRC's in these corrupted packets with the correct ones.

In order to establish the first;

- Ip_output.c should be patched so that, when the condition matches, the system will mangle the destination address of the outgoing packet and append correct checksums to the IP header.

- After that it should be ensured that the underlying protocols also compute the correct checksum using the mangled destination address in their psuedo-headers. [ Perhaps this is already done automatically by a call to a function ]

In order to establish the second;

- Ip_input.c should be unpatched for now, since our aim is much different. It will receive a packet from the 192.168.1.1, and leave the address and checksum in it, unchanged.

- tcp_input.c and udp.c now would be in action to decode and put the data in the socket buffer. They would naturally construct the psuedo-headers using the destination address of 192.168.1.1, and as in the beginning, the checksums will be voided.

- These two codes should be patched in such a way that they re-compute the checksums whilst they are copying them in to the datagram buffer using the function int skb_copy_and_csum_datagram_iovec(). This is not a normal behaviour of operation, but simply ignoring checksums would cause other clients to fail, even if the linux machine just ignores the wrong CRC's and copies the data to the socket buffer.

This issue is not critical now because the "critical" part is gone, it is just an experimentation with the code, but I would be glad to receive any contribution from the mailing-list.

Best Regards...

-----Original Message-----
From: David Meybohm [mailto:[email protected]]
Sent: Monday, August 23, 2004 5:38 AM
To: Josan Kadett
Cc: 'Brad Campbell'; [email protected]
Subject: Re: Entirely ignoring TCP and UDP checksum in kernel level

The attached patch might work. It changes the IP source address from 192.168.1.1 to 192.168.77.1 and then recalculates the IP header checksum. (I haven't tested it, though).

Do I understand you correctly that the IP checksum is calculated correctly, but for the address 192.168.1.1, and the UDP and TCP checksums are computed as if the address was 192.168.77.1? If so, I think this should work...

Now, can you please oblige us with the name of the manufacturers of the broken router (as someone else also previously requested), so they can be properly publicly ridiculed? :-)

Hope it helps,

Dave

---

diff -puN net/ipv4/ip_input.c~ip-ignore-csum net/ipv4/ip_input.c
--- v2.6.8/net/ipv4/ip_input.c~ip-ignore-csum 2004-08-22
22:56:34.000000000 -0400
+++ v2.6.8-dym/net/ipv4/ip_input.c 2004-08-22 23:07:26.000000000 -0400
@@ -355,6 +355,27 @@ drop:

         return NET_RX_DROP;

}

+static inline void mangle_addr_and_csum(struct iphdr *iph) +{
+#define MANGLE_SADDR_IN htonl(0xc0a80101)
+#define MANGLE_SADDR_OUT htonl(0xc0a84d01)
+
+ if (iph->saddr != MANGLE_SADDR_IN)
+ return;
+
+ /* Change the source address from 192.168.1.1 to 192.168.77.1 and
+ * correct the checksum. */
+ iph->saddr = MANGLE_SADDR_OUT;
+ iph->check = 0;
+ iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
+
+ /* Make sure the checksum is correct now. */
+ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) {
+ printk(KERN_ERR "checksum %08x -> %08x failed! (%04x)\n",
+ MANGLE_SADDR_IN, iph->saddr, iph->check);
+ }
+}
+
/*
* Main IP Receive routine.
*/
@@ -399,6 +420,9 @@ int ip_rcv(struct sk_buff *skb, struct n

iph = skb->nh.iph;

+ /* Take care of broken router. */
+ mangle_addr_and_csum(iph);
+
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto inhdr_error;

_