Multiple places in the net stack open-code the same minimal IPv4 header
validation: pull the fixed header, check version 4 and IHL >= 5 (where 5
is the fixed header size in 32-bit units) - and locate the transport
header at IHL * 4 past the network header.

Add a helper for doing that: it returns the validated header and
the transport header offset, or NULL if truncated or malformed.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Assisted-by: LLM
---
 include/linux/ip.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/include/linux/ip.h b/include/linux/ip.h
index d11c25f5030a0..98012f6d0efb5 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -56,4 +56,28 @@ static inline void iph_set_totlen(struct iphdr *iph, 
unsigned int len)
 {
        iph->tot_len = len <= IP_MAX_MTU ? htons(len) : 0;
 }
+
+/*
+ * Pull and minimally validate the IPv4 header at @nhoff.
+ * Returns the header and stores the transport header offset in
+ * @thoff, or NULL if truncated or malformed.  Only the fixed header
+ * is guaranteed linear; callers that need the options or the
+ * transport header must pull further.
+ */
+static inline struct iphdr *ip4_parse(struct sk_buff *skb,
+                                     unsigned int nhoff,
+                                     unsigned int *thoff)
+{
+       struct iphdr *iph;
+
+       if (!pskb_may_pull(skb, nhoff + sizeof(struct iphdr)))
+               return NULL;
+
+       iph = (struct iphdr *)(skb->data + nhoff);
+       if (iph->version != 4 || iph->ihl < sizeof(struct iphdr) / sizeof(u32))
+               return NULL;
+
+       *thoff = nhoff + iph->ihl * sizeof(u32);
+       return iph;
+}
 #endif /* _LINUX_IP_H */
-- 
MST


Reply via email to