Search code examples
objective-cudpip-addressiossender

How to identify sender's ip address of a udp packet received on iOS device?


How to find out the sender's ip address of a udp packet that was received on a device running iOS 3.2 or higher?

For example, if using Python on a computer, I'd use SocketServer.UDPServer which takes a subclass of SocketServer.BaseRequestHandler which defines the handle callback. When a packet arrives, the callback is called and the sender's ip address would be in self.client_address, where self is the SocketServer.BaseRequestHandler instance.

Unfortunately, I don't know how to extract this information or gain access to the associated ip header when programming in Objective C and using the frameworks provided for iOS.

Right now the only solution I have is to explicitly write the sender's ip on the body of the udp packet, but I'd rather not rely on the sender putting that information there if I don't have to.


Solution

  • You didn't mention what API you are using to receive the packet. Don't write the IP address into the packet itself because the packet may go through a number of network address translations before it gets to you.

    You can use regular BSD sockets to acheive this task. There are also a few Foundation classes that wrap around BSD sockets, but I haven't used them personally, so I can't give you a decent example.

    // for IPv4 (IPv6 is a little different)
    
    ssize_t received;
    char buffer[0x10000];
    struct sockaddr_in listenAddr;
    struct sockaddr_in fromAddr;
    socklen_t fromAddrLen = sizeof fromAddr;
    
    listenAddr.sin_family = AF_INET;
    listenAddr.sin_port = htons(12345); // change to whatever port
    listenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    int s = socket(AF_INET, SOCK_DGRAM, 0); // create UDP socket
    if (s == -1)
        exit(1); // failed to create socket
    
    if (bind(s, (struct sockaddr *) &listenAddr, sizeof listenAddr))
        exit(2); // failed to bind to port 12345 for any address
    
    received = recvfrom(s, buffer, sizeof buffer, 0, (struct sockaddr *)&fromAddr, &fromAddrLen);
    if (received == -1)
        exit(3); // some failure trying to receive data
    
    // check the contents of buffer, the address of the source will be in
    // fromAddr.sin_addr.s_addr but only if (fromAddrLen == sizeof fromAddr)
    // after the call to recvfrom.
    
    char display[16] = {0};
    inet_ntop(AF_INET, &fromAddr.sin_addr.s_addr, display, sizeof display);
    
    NSLog (@"The source is %s.", display);
    // could show "The source is 201.19.91.102."