How to Parse data packets in iOS Network Extension

Viewed 391

I'm trying to parse the data packets in NEPacketTunnelProvider subclass but after trying different ways not able to parse the data.

        private func readPackets() {
        self.packetFlow.readPackets() { datas, protocolNumbers in
            self.sendPackets(datas, withProtocols: protocolNumbers)
            if let dataArray = datas as? [Data] {
                for dataPackets in dataArray {
                   let ipHeader =  self.processPacket(dataPackets, protocolNumber: 0)
                    self.headerData.append(ipHeader)
                }
            }
            self.readPackets()
        }
    }
   
        private func processPacket(_ rawData: Data, protocolNumber: NSNumber)-> IPHeader {
        let  data = BinaryData.init(data: rawData, bigEndian: true)
           
        let header = IPHeader(version: try? data.get(0),
                            headerLength: try? data.get(1),
                            typeOfService: try? data.get(2),
                            length: try? data.get(3),
                            id: try? data.get(5),
                            offset: try? data.get(7),
                            timeToLive: try? data.get(8),
                            proto: try? data.get(9),
                            checksum: try? data.get(10),
                            source: in_addr(s_addr: try! data.get(12)),
                            destination: in_addr(s_addr:try! data.get(16)))
        
      return header
    }

1 Answers

I've had success using the BinarySwift library. You can find a code sample within the repos readme.

https://github.com/Szaq/BinarySwift

You first want to create your models for the headers that you want to extract. For example, if you're trying extract the IP header information from the packet, you need to create the following IP Header model.

   struct IPHeader {
      let version: UInt8
      let headerLength: UInt8
      let typeOfService: UInt8
      let length: UInt16
      let id: UInt16
      let offset: UInt16
      let timeToLive: UInt8
      let proto:UInt8
      let checksum: UInt16
      let source: in_addr
      let destination: in_addr
    }

Afterwards, you can start using BinarySwift to extract the packet data, where each hardcoded number represents the offset in bytes from the start of the data. You can find more information on how IPv4 headers are structured this from the link below.

https://searchnetworking.techtarget.com/tutorial/Routing-First-Step-IP-header-format

let binaryData = BinaryData(data: data, bigEndian: true)

let header = IPHeader(version: try data.get(0),
                headerLength: try data.get(1),
                typeOfService: try data.get(2),
                length: try data.get(3),
                id: try data.get(5),
                offset: try data.get(7),
                timeToLive: try data.get(8),
                proto: try data.get(9),
                checksum: try data.get(10),
                source: in_addr(s_addr: try data.get(12)),
                destination: in_addr(s_addr: try data.get(16)))

Keep in mind that you may need to bit shift some of the IP Header properties to get the correct value since some of the values are represented by less than 8 bits. You can follow this general format and do the same steps to extract the other headers.

Related