فهرست منبع

ipv4_proto: Add function for checking the IP header (moved from FrameDecider), also check the checksum. Add a function for computing the
checksum.

ambrop7 15 سال پیش
والد
کامیت
f48e937420
2فایلهای تغییر یافته به همراه78 افزوده شده و 48 حذف شده
  1. 2 48
      client/FrameDecider.c
  2. 76 0
      misc/ipv4_proto.h

+ 2 - 48
client/FrameDecider.c

@@ -324,52 +324,6 @@ static void group_entry_timer_handler (struct _FrameDecider_group_entry *group_e
     remove_group_entry(group_entry);
 }
 
-static int check_ipv4_packet (uint8_t *data, int data_len, struct ipv4_header **out_header, uint8_t **out_payload, int *out_payload_len)
-{
-    ASSERT(data_len >= 0)
-    
-    // check base header
-    if (data_len < sizeof(struct ipv4_header)) {
-        BLog(BLOG_DEBUG, "check ipv4: packet too short (base header)");
-        return 0;
-    }
-    struct ipv4_header *header = (struct ipv4_header *)data;
-    
-    // check version
-    if (IPV4_GET_VERSION(*header) != 4) {
-        BLog(BLOG_DEBUG, "check ipv4: version not 4");
-        return 0;
-    }
-    
-    // check options
-    int header_len = IPV4_GET_IHL(*header) * 4;
-    if (header_len < sizeof(struct ipv4_header)) {
-        BLog(BLOG_DEBUG, "check ipv4: ihl too small");
-        return 0;
-    }
-    if (header_len > data_len) {
-        BLog(BLOG_DEBUG, "check ipv4: packet too short for ihl");
-        return 0;
-    }
-    
-    // check total length
-    uint16_t total_length = ntoh16(header->total_length);
-    if (total_length < header_len) {
-        BLog(BLOG_DEBUG, "check ipv4: total length too small");
-        return 0;
-    }
-    if (total_length > data_len) {
-        BLog(BLOG_DEBUG, "check ipv4: total length too large");
-        return 0;
-    }
-    
-    *out_header = header;
-    *out_payload = data + header_len;
-    *out_payload_len = total_length - header_len;
-    
-    return 1;
-}
-
 void FrameDecider_Init (FrameDecider *o, int max_peer_macs, int max_peer_groups, btime_t igmp_group_membership_interval, btime_t igmp_last_member_query_time, BReactor *reactor)
 {
     ASSERT(max_peer_macs > 0)
@@ -445,7 +399,7 @@ void FrameDecider_AnalyzeAndDecide (FrameDecider *o, uint8_t *frame, int frame_l
         case ETHERTYPE_IPV4: {
             // check IPv4 header
             struct ipv4_header *ipv4_header;
-            if (!check_ipv4_packet(pos, len, &ipv4_header, &pos, &len)) {
+            if (!ipv4_check(pos, len, &ipv4_header, &pos, &len)) {
                 BLog(BLOG_INFO, "decide: wrong IP packet");
                 goto out;
             }
@@ -730,7 +684,7 @@ void FrameDeciderPeer_Analyze (FrameDeciderPeer *o, uint8_t *frame, int frame_le
         case ETHERTYPE_IPV4: {
             // check IPv4 header
             struct ipv4_header *ipv4_header;
-            if (!check_ipv4_packet(pos, len, &ipv4_header, &pos, &len)) {
+            if (!ipv4_check(pos, len, &ipv4_header, &pos, &len)) {
                 BLog(BLOG_INFO, "analyze: wrong IP packet");
                 goto out;
             }

+ 76 - 0
misc/ipv4_proto.h

@@ -29,7 +29,11 @@
 
 #include <stdint.h>
 
+#include <misc/debug.h>
+#include <misc/byteorder.h>
+
 #define IPV4_PROTOCOL_IGMP 2
+#define IPV4_PROTOCOL_UDP 17
 
 struct ipv4_header {
     uint8_t version4_ihl4;
@@ -51,4 +55,76 @@ struct ipv4_header {
 #define IPV4_GET_VERSION(_header) (((_header).version4_ihl4&0xF0)>>4)
 #define IPV4_GET_IHL(_header) (((_header).version4_ihl4&0x0F)>>0)
 
+#define IPV4_MAKE_VERSION_IHL(size) (((size)/4) + (4 << 4))
+
+struct ipv4_short {
+    uint16_t v;
+} __attribute__((packed));
+
+static uint16_t ipv4_checksum (uint8_t *ip_hdr, uint16_t len)
+{
+    ASSERT(len % 2 == 0)
+    
+    struct ipv4_short *s = (void *)ip_hdr;
+    
+    uint32_t t = 0;
+    
+    for (uint16_t i = 0; i < len / 2; i++) {
+        t += ntoh16(s[i].v);
+    }
+    
+    t = (t&0xFFFF) + (t >> 16);
+    
+    return hton16(~t);
+}
+
+static int ipv4_check (uint8_t *data, int data_len, struct ipv4_header **out_header, uint8_t **out_payload, int *out_payload_len)
+{
+    ASSERT(data_len >= 0)
+    
+    // check base header
+    if (data_len < sizeof(struct ipv4_header)) {
+        return 0;
+    }
+    struct ipv4_header *header = (struct ipv4_header *)data;
+    
+    // check version
+    if (IPV4_GET_VERSION(*header) != 4) {
+        return 0;
+    }
+    
+    // check options
+    uint16_t header_len = IPV4_GET_IHL(*header) * 4;
+    if (header_len < sizeof(struct ipv4_header)) {
+        return 0;
+    }
+    if (header_len > data_len) {
+        return 0;
+    }
+    
+    // check total length
+    uint16_t total_length = ntoh16(header->total_length);
+    if (total_length < header_len) {
+        return 0;
+    }
+    if (total_length > data_len) {
+        return 0;
+    }
+    
+    // check checksum
+    uint16_t checksum_in_packet = header->checksum;
+    header->checksum = hton16(0);
+    uint16_t checksum_computed = ipv4_checksum(data, header_len);
+    header->checksum = checksum_in_packet;
+    if (checksum_in_packet != checksum_computed) {
+        return 0;
+    }
+    
+    *out_header = header;
+    *out_payload = data + header_len;
+    *out_payload_len = total_length - header_len;
+    
+    return 1;
+}
+
 #endif