5 Replies
      Latest reply: Dec 28, 2016 2:58 PM by eskimo RSS
      CloudRuan Level 1 Level 1 (0 points)

        I'm implementing a custom VPN by using iOS9 NetworkExtension framework. The vpn connection has established between my iphone and the vpn server. But my iPhone still can't access Internet.

        I did the following steps:

         

        1. Reading IP packets from tun, and sent it to vpn server using udp:


         

        - (void)startReadingTunPackets{
                [self.packetFlow readPacketsWithCompletionHandler:^(NSArray<NSData*> *packets, NSArray<NSNumber*> *protocols) {
                for(NSData *data in packets){
                    [self.UpdSession writeDatagram:data completionHandler:^(NSError * error){
                    }];
                }
                [self startReadingTunPackets];
          }];
        
        
        
        
        
        
        
        
        
        
        

         

        2. The vpn server received the udp data, decoded them to ip packet (eg. a TCP SYN packet) and changed its source address to the vpn server's address. Send the fake SYN packet to remote site.


         

        3. The remote site responded a TCP SYN/ACK packet to the vpn server.

         

        4. The vpn server modified the SYN/ACK packet's destination address to iPhone's tun address(eg. 10.0.1.100), sent it to iPhone.


         

        5. iPhone used the following code to receive udp data that contains SYN/ACK packet and sent them to tun:


        [udpSession setReadHandler:^(NSArray<NSData *> * datagrams, NSError * error) {
              for(NSData *data in datagrams){
                  NSArray *packet = [[NSArray alloc] initWithObjects:data,nil];
                  NSArray *protocols = [[NSArray alloc] initWithObjects:@(AF_INET),nil];
                  //Write to TUN
                  BOOL r = [self.packetFlow writePackets:packet withProtocols:protocols];
                  }} maxDatagrams:4096];

        
        
        
        
        
        
        
        
        
        
        

         

        I thought an ACK packet can be read from tun in order to complete 'three-way handshake'. But this never happened. Instead, a SYN packet was read from tun, like TUN has never received the SYN/ACK packet, which as I described in step 5. Though,  The call to packetFlow.writePackets() succeeded.

         

        I guess something might went wrong with the packet format in step 5. Should it to be a complete ip packet or just payload? Or should I not modify the SYN/ACK's destination address in step 4?

        • Re: NEPacketTunnelFlow failed to write IP packets
          eskimo Apple Staff Apple Staff (5,995 points)

          2. The vpn server received the udp data, decoded them to ip packet (eg. a TCP SYN packet) and changed its source address to the vpn server's address.

          Packet tunnels act at the IP layer, and thus shouldn’t need to modify the packets flowing through the tunnel.  You should arrange for your VPN server to return an appropriate IP address to the VPN client, which then uses that as the source IP address of the tunnel.  That’ll ensure that you’re packets start out with the correct source address, which makes everything easier.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: NEPacketTunnelFlow failed to write IP packets
              CloudRuan Level 1 Level 1 (0 points)

              Thank a lot for your quick reply, eskimo. But I'm still confused.

               

              You should arrange for your VPN server to return an appropriate IP address to the VPN client, which then uses that as the source IP address of the tunnel.
              
              

               

              What does that mean? Which step below is wrong?

               

              1. The VPN client app makes VPN connection, the TUN address is assigned to : "10.0.1.100" , set TUN as default route.

              2. Open Safari to access Internet (e.g. http://123.123.123.123)
              3. The VPN client reads a TCP SYN packet from TUN. The packet's source address is "10.0.1.100", destination address is "123.123.123.123"

              4. Encapsulates above packet into UDP data, send the UDP data to VPN server

              5. VPN server receives the UDP data,  decapsulates it to a TCP SYN packet.
              6. Modify the TCP SYN packet's  source address to VPN server's address "10.0.0.12" from "10.0.1.100"

              7. Send the TCP SYN packet directly

              8. VPN server receives a TCP SYN/ACK packet from remote site. the packet's source address is remote site(123.123.123.123), destination address is VPN server's address(10.0.0.12)

              9. Modify the TCP SYN/ACK packet's destination address to TUN's address(10.0.1.100). Should I do that or not?

              10. Encapsulates above packet into UDP data , send them to the VPN client

              11. The VPN client receives UDP data, decapsulate it to a TCP SYN/ACK packet.

              12. Writes above packet into TUN

               

              I've tried to skip step 9, keep the TCP SYN/ACK packet's destination address as VPN server's address. But stil got same result.