13 Replies
      Latest reply on Aug 24, 2017 12:48 AM by eskimo
      giguerea Level 1 Level 1 (10 points)

        I have a Swift dynamic framework that contain objective-c files for networking purpose,

         

        inside my objective-c file I have these lines, they don't compile anymore on iOS 11 / Xcode 9 Beta 5

         

        #if TARGET_IPHONE_SIMULATOR

        #include <net/route.h>

        #endif

         

        Error

        'net/route.h' file not found

         

        If I set the iOS Simulator to Generic iOS Device, it compiles

         

        any idea ?

         

        thanks

         

        Alex

        • Re: Xcode9 beta 5 net/route.h not found
          eskimo Apple Staff Apple Staff (12,425 points)

          <net/route.h> has never been present in the iOS device SDK, so it’s presence in the iOS simulator SDK is a bit of an anomaly, and a very misleading one at that.  It looks that anomaly was resolved in Xcode 9 (yay!).

          What are you using this header for?

          Share and Enjoy

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

            • Re: Xcode9 beta 5 net/route.h not found
              giguerea Level 1 Level 1 (10 points)

              thanks Eskimo, I found this code on GitHub and it works so far for the last 2 years. This is to get the router IP address.

               

              If I comment it out, I got this error now

               

              field has incomplete type 'struct rt_msghdr2

               

              the code is

               

              @interface Route_Info : NSObject
              {
                  struct sockaddr     m_addrs[RTAX_MAX];
                  struct rt_msghdr2   m_rtm;
                  int                 m_len;      / length of the sockaddr array */
              }
              

               

              Alex

                • Re: Xcode9 beta 5 net/route.h not found
                  eskimo Apple Staff Apple Staff (12,425 points)

                  Routing sockets have never been a supported API on iOS, which is why <net/route.h> is not part of the standard iOS SDK.  This stuff is getting increasingly locked down as the system (and the SDK) evolves, so it would be a bad idea to continue down this path.

                  Note You can find more context in this post on the old DevForums.

                  What are you using the router IP address for?

                  Share and Enjoy

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

                    • Re: Xcode9 beta 5 net/route.h not found
                      giguerea Level 1 Level 1 (10 points)

                      ok thanks, but I need to do a reverse DNS lookup on the router IP,

                       

                      I just send you by email my files that I were using

                       

                      what do you suggest ?

                       

                      alex

                        • Re: Xcode9 beta 5 net/route.h not found
                          eskimo Apple Staff Apple Staff (12,425 points)

                          I need to do a reverse DNS lookup on the router IP

                          Is this for an app that distribute to normal users via the App Store?  Or something enterprise specific?

                          Share and Enjoy

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

                            • Re: Xcode9 beta 5 net/route.h not found
                              giguerea Level 1 Level 1 (10 points)

                              no this is for an enterprise app, we do not pass by the app store, we deploy it directly in our stores with AirWatch

                               

                              tahnks

                                • Re: Xcode9 beta 5 net/route.h not found
                                  eskimo Apple Staff Apple Staff (12,425 points)

                                  There’s a bunch of ways you can proceed here:

                                  • If you want to continue down the “IP address of the router” path, you can do a one hop traceroute and grab the router’s IP address from the response.

                                  • If the routers at all of your sites have different IP addresses, does that mean you use different networks at all of the sites?  If so, you could reverse DNS map the device’s IP address, which is trivial to get (via getifaddrs).  Or algorithmically derive the router’s address from the network address (most folks put the router at the x.x.x.1 or x.x.x.254 position on the network).

                                  • Alternatively, and this is much easier from a coding perspective, you could survey the BSSIDs of all the sites and then get the BSSID of the network (using CNCopyCurrentNetworkInfo) and run that through your BSSID-to-site mapping.

                                  • Finally, have you considered using Core Location for this?  That’s what it was designed for (-:

                                  Share and Enjoy

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

                                    • Re: Xcode9 beta 5 net/route.h not found
                                      giguerea Level 1 Level 1 (10 points)

                                      thanks Eskimo, I will check these options one by one, I am not a very experience low level C programmer, for your first 2 solutions, can I use Swift ?

                                       

                                      As for Core Location, this will give me the longitude latitude, that means I would need a table with all my retail stores with their coordinare to compare and determine where I am. Also we are using iPod Touch 6 gen, no GPS. Will it works ?

                                       

                                      thanks

                                        • Re: Xcode9 beta 5 net/route.h not found
                                          eskimo Apple Staff Apple Staff (12,425 points)

                                          I will check these options one by one, I am not a very experience low level C programmer, for your first 2 solutions, can I use Swift ?

                                          Yes, but these are low-level C APIs so you’ll need a good understanding of how Swift interacts with such APIs.

                                          With regards the specific APIs I mentioned:

                                          • Ping and traceroute are both implemented using BSD Sockets.  Calling BSD Sockets from Swift is a challenge.  I typically use the socket helper infrastructure that you’ll find in the Socket API Helper section of the UnsafeRawPointer Migration doc.

                                          • With regards getifaddrs, I’ve written many different wrappers for this in Swift.  Pasted in below in my latest attempt.

                                          • I posted an example of how to call CNCopyCurrentNetworkInfo from Swift on this thread.

                                          Also we are using iPod Touch 6 gen, no GPS. Will it works ?

                                          Probably.  Most day-to-day location tracking doesn’t fire up the GPS hardware — which is both power hungry and slow — but instead relies on Wi-Fi.  Naturally this works fine on Wi-Fi only hardware, like the iPod touch.

                                          Share and Enjoy

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

                                          import Foundation
                                          
                                          struct Interface {
                                              var name: String
                                              var addresses: [Data]
                                              var type: UInt8             // IFT_ETHER and so on
                                          }
                                          
                                          extension ifaddrs : Sequence {
                                              public func makeIterator() -> UnfoldFirstSequence<ifaddrs> {
                                                  return sequence(first: self, next:{ (x) in x.ifa_next?.pointee })
                                              }
                                          }
                                          
                                          extension Interface {
                                          
                                              static func snapshot() -> [Interface] {
                                                  var addrsToFree: UnsafeMutablePointer<ifaddrs>? = nil
                                                  guard getifaddrs(&addrsToFree) == 0, let addrList = addrsToFree?.pointee else {
                                                      return []
                                                  }
                                                  defer {
                                                      freeifaddrs(addrsToFree)
                                                  }
                                                  var interfacesByName: [String:Interface] = [:]
                                                  for addr in addrList {
                                                      // Need the `as Optional` because `ifa_name` is an implicitly unwrapped optional, 
                                                      // and that always gets unwrapped on access so you can't call `flatMap(_:)` on it.
                                                      // 
                                                      // Need the closure (rather than using `String.init(cString:)` because the 
                                                      // compiler finds the latter ambiguous in this context.
                                                      if let name = (addr.ifa_name as Optional).flatMap({String(cString:$0)}), let sa = addr.ifa_addr {
                                                          if interfacesByName[name] == nil {
                                                             interfacesByName[name] = Interface(name: name, addresses: [], type: 0) 
                                                          }
                                                          switch Int32(sa.pointee.sa_family) {
                                                              case AF_INET, AF_INET6:
                                                                  let address = Data(bytes: sa, count: Int(sa.pointee.sa_len))
                                                                  interfacesByName[name]!.addresses.append( address )
                                                              case AF_LINK:
                                                                  if let ifd = addr.ifa_data {
                                                                      let ifd = ifd.assumingMemoryBound(to: if_data.self)
                                                                      interfacesByName[name]!.type = ifd.pointee.ifi_type
                                                                  }
                                                              default:
                                                                  break
                                                          }
                                                      }
                                                  }
                                                  return [Interface](
                                                      interfacesByName.values
                                                      .filter({$0.type != 0 && !$0.addresses.isEmpty})
                                                      .sorted(by: {$0.name < $1.name})
                                                  )
                                              }
                                          }
                                            • Re: Xcode9 beta 5 net/route.h not found
                                              giguerea Level 1 Level 1 (10 points)

                                              this swift code looks pretty good, the only thing missing is the IP address as a String and not an array of Data,

                                               

                                              I will need to figure it out or I could use objective-c code to find it easily

                                               

                                              To get the router IP, I could take the iPod IP address and change the last digit by 1

                                               

                                              Then I could do a reverse DNS lookup to grab the host name

                                               

                                              that part already works, I did it in objective-C, please have a look at my implementation on my GitHub account

                                              https://github.com/agiguere/ReverseDNSLookup

                                               

                                              another good wrapper around getifaddrs that I found on github

                                              https://github.com/svdo/swift-netutils

                                               

                                              Alex

                                                • Re: Xcode9 beta 5 net/route.h not found
                                                  eskimo Apple Staff Apple Staff (12,425 points)

                                                  the only thing missing is the IP address as a String and not an array of Data

                                                  You can use getnameinfo for that.  There’s an example of that pasted in below.

                                                  IMPORTANT Make sure to pass in NI_NUMERICHOST and NI_NUMERICSERV to guarantee that it won’t hit the network.

                                                  To get the router IP, I could take the iPod IP address and change the last digit by 1

                                                  That’s fine as long as you are sure that all your networks use that convention.

                                                  another good wrapper around getifaddrs that I found on github

                                                  Sure.  Although the fact they use inet_ntop in the IPv6 case is a bit weird.  In my experience getnameinfo handles both IPv4 and IPv6 equally well.

                                                  Share and Enjoy

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

                                                  private static func name(for address: Data) -> String {
                                                      return address.withUnsafeBytes { (sa: UnsafePointer<sockaddr>) in
                                                          var nameBytes = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                                                          let err = getnameinfo(
                                                              sa, 
                                                              socklen_t(address.count), 
                                                              &nameBytes, socklen_t(nameBytes.count), 
                                                              nil, 0, 
                                                              NI_NUMERICHOST | NI_NUMERICSERV
                                                          )
                                                          guard err == 0 else {
                                                              return "?"
                                                          }
                                                          return "\(String(cString: nameBytes))"
                                                      }
                                                  }
                                                    • Re: Xcode9 beta 5 net/route.h not found
                                                      giguerea Level 1 Level 1 (10 points)

                                                      thanks Eskimo, last question

                                                       

                                                      did you had a chance to check my implementation of the reverse DNS on github ?

                                                       

                                                      I merge your code to get the device IP

                                                       

                                                        static func getDeviceIP() -> String? {
                                                        var addrsToFree: UnsafeMutablePointer<ifaddrs>? = nil
                                                        
                                                        guard getifaddrs(&addrsToFree) == 0, let addrList = addrsToFree?.pointee else {
                                                        return nil
                                                        }
                                                        
                                                        defer {
                                                        freeifaddrs(addrsToFree)
                                                        }
                                                        
                                                        var ipAddress: String?
                                                        
                                                        for addr in addrList {
                                                        // Need the `as Optional` because `ifa_name` is an implicitly unwrapped optional,
                                                        // and that always gets unwrapped on access so you can't call `flatMap(_:)` on it.
                                                        //
                                                        // Need the closure (rather than using `String.init(cString:)` because the
                                                        // compiler finds the latter ambiguous in this context.
                                                        guard let name = (addr.ifa_name as Optional).flatMap({String(cString:$0)}), name == "en0", let sa = addr.ifa_addr else { continue }
                                                        
                                                      // let flags = Int32(addr.ifa_flags)
                                                      // 
                                                      // guard (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) else { continue }
                                                        
                                                        guard Int32(sa.pointee.sa_family) == AF_INET else { continue }
                                                        
                                                        var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                                                        
                                                        if (getnameinfo(&addr.ifa_addr.pointee, socklen_t(addr.ifa_addr.pointee.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
                                                        ipAddress = String(cString: hostname)
                                                        }
                                                        }
                                                        
                                                        return ipAddress
                                                        }
                                                      
                                                        • Re: Xcode9 beta 5 net/route.h not found
                                                          eskimo Apple Staff Apple Staff (12,425 points)

                                                          It’s hard to review code like this because you’re writing it for a specific context and, in that context, it makes sense to make simplifying assumptions.  For example:

                                                          • Hard-coding en0 is a really bad idea in the general case

                                                          • You’re completely ignoring IPv6 )-:

                                                          • Your getDeviceIP() API is fundamentally unsound because iOS devices can have multiple IP addresses, some IPv4 and some IPv6, spanning across multiple interfaces

                                                          Then again, if these choices make sense for your app that’s cool.

                                                          did you had a chance to check my implementation of the reverse DNS on github ?

                                                          I took a quick look just now.  I have a number of concerns:

                                                          • You’re using a imp_implementationWithBlock is a neat hack but I’m concerned that it’ll leak.  The doc comments for imp_implementationWithBlock state directly that you have to clean up via imp_removeBlock, which you don’t do.

                                                          • Putting self into info is weird because:

                                                            • You don’t retain the value, which leaves you open to dangling pointers

                                                            • You don’t actually use the info parameter passed to the block, so you don’t need to do this anyway

                                                          • I don’t like mixing blocks and run loops like you’re doing.  Someone calling block-based code like this might be very confused to discover that it relies on the current run loop.

                                                          For an example of how I use CFHost for this sort of thing, check out CFHostSample, which I recently updated to include both Swift and Objective-C implementations.

                                                          Share and Enjoy

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