Determining IP Address from URL in iOS - objective-c

I need to get the IP address of a CDN from it's URL in an iOS app. From a long stack search, i've determined a method for doing this with the following:
struct hostent *host_entry = gethostbyname("stackoverflow.com");
char *buff;
buff = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
// buff is now equal to the IP of the stackoverflow.com server
However, when using this code snippet, my app fails to compile and presents this warning: "dereferencing pointer to incomplete type"
I have no knowledge of structs and I do not know how to fix this. Any suggestions?
I also tried:
#include <ifaddrs.h>
#include <arpa/inet.h>
But the result is the same warning.

Here is a Swift 3.1 version of converting a URL hostname to IP address.
import Foundation
private func urlToIP(_ url:URL) -> String? {
guard let hostname = url.host else {
return nil
}
guard let host = hostname.withCString({gethostbyname($0)}) else {
return nil
}
guard host.pointee.h_length > 0 else {
return nil
}
var addr = in_addr()
memcpy(&addr.s_addr, host.pointee.h_addr_list[0], Int(host.pointee.h_length))
guard let remoteIPAsC = inet_ntoa(addr) else {
return nil
}
return String.init(cString: remoteIPAsC)
}

I had no problems compiling that code with the following includes:
#import <netdb.h>
#include <arpa/inet.h>

Maybe this function will work?
#import <netdb.h>
#include <arpa/inet.h>
- (NSString*)lookupHostIPAddressForURL:(NSURL*)url
{
// Ask the unix subsytem to query the DNS
struct hostent *remoteHostEnt = gethostbyname([[url host] UTF8String]);
// Get address info from host entry
struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];
// Convert numeric addr to ASCII string
char *sRemoteInAddr = inet_ntoa(*remoteInAddr);
// hostIP
NSString* hostIP = [NSString stringWithUTF8String:sRemoteInAddr];
return hostIP;
}

Related

How can I modify my code to read from a file input in client and then communicate it to a server?

Code:
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <WinSock2.h>
#include <Windows.h>
#define SCK_VERSION 0x0202
int main()
{
//declare sockets first
SOCKET ConSock; // used for connection, hence the name
SOCKET ListenSock; // used for listening from the server
SOCKADDR_IN address; //socket address
int addrsize = sizeof(address);
long ok;
char MESSAGE[200];
char reply[200];
WSADATA WSD;
WORD DllVersion;
DllVersion = MAKEWORD(2,1);
ok = WSAStartup(DllVersion, &WSD);
//start creating our sockets
ConSock = socket(AF_INET, SOCK_STREAM, NULL);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_family = AF_INET;
address.sin_port = htons(10103);
ListenSock = socket(AF_INET, SOCK_STREAM, NULL);
bind(ListenSock, (SOCKADDR*)&address, sizeof(address));
listen(ListenSock, SOMAXCONN);
printf("Server waiting for connections\n\n");
for(;;){
if (ConSock = accept(ListenSock, (SOCKADDR*)&address, &addrsize))
{
ok = recv(ConSock, MESSAGE, sizeof(MESSAGE),NULL);
printf("\nClient says:\t %s", MESSAGE);
printf("\nEnter reply:\t");
gets(reply);
ok = send(ConSock,reply,200,NULL);
}
}
}
//client.c
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <WinSock2.h>
#include <Windows.h>
#define SCK_VERSION 0x0202
int main()
{
SOCKET sock;
SOCKADDR_IN address;
long ok;
char MESSAGE[200];
char reply[200];
WSADATA WSD;
WORD DllVersion;
DllVersion = MAKEWORD(2,1);
ok = WSAStartup(DllVersion, &WSD);
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_family = AF_INET;
address.sin_port = htons(10103);
for(;;)
{
sock = socket(AF_INET,SOCK_STREAM,NULL);
connect(sock, (SOCKADDR*)&address, sizeof(address));
printf("\nEnter Message:\t");
gets(MESSAGE);
ok = send(sock,MESSAGE,200,NULL);
ok = recv(sock,reply,sizeof(reply),NULL);
printf("\nServer says:\t %s",reply);
}
}
//makefile
server:
g++ server.c -o server
client:
g++ client.c -o client
clean:
rm server
rm client
all: server client
This runs with -lwsock32 and it does a good job, but I need to adjust it now to comunicate some data from a file, the data is mostly values of voltages, currents, active reactive power, etc.
I have been trying for quite some time and I cannot seem to adjust it.
If you can rewrite it in terms of the client communicating the values(that are stored in a file) to the server, that will be great. Any help is greatly appreciated, as I am not being succesful currently.

Get description of network adapter using Swift [duplicate]

I am trying to get a list of active network interfaces with end user understandable names. Like the names listed in System Preferences instead of en0 en5.
I have the raw interfaces using getifaddrs but haven't been able to find how to take those and get the system names of Ethernet or Wifi.
Anyone know how to do this? This would be for macOS.
What I have now:
struct ifaddrs *ifap;
if( getifaddrs(&ifap) == 0 ){
struct ifaddrs *interface;
for (interface = ifap; interface != NULL; interface = interface->ifa_next) {
unsigned int flags = interface->ifa_flags;
struct sockaddr *addr = interface->ifa_addr;
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if ((flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING)) {
if (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) {
// Convert interface address to a human readable string:
char host[NI_MAXHOST];
getnameinfo(addr, addr->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
printf("interface:%s, address:%s\n", interface->ifa_name, host);
// MAGIC HERE TO CONVERT ifa_name to "Ethernet" or something
}
}
}
freeifaddrs(ifap);
This is possible with System Configuration on macOS. In Objective-C like so:
CFArrayRef ref = SCNetworkInterfaceCopyAll();
NSArray* networkInterfaces = (__bridge NSArray *)(ref);
for(int i = 0; i < networkInterfaces.count; i += 1) {
SCNetworkInterfaceRef interface = (__bridge SCNetworkInterfaceRef)(networkInterfaces[i]);
CFStringRef displayName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
CFStringRef bsdName = SCNetworkInterfaceGetBSDName(interface);
NSLog(#"Name:%# \ninterface: %#\nbsd:%#",displayName, SCNetworkInterfaceGetInterfaceType(interface), bsdName);
}
The localized display name will be something like Display Ethernet or WiFi and the BSD name will be something like en5 which will allow matching to the above code.
This approach doesn't work on iOS, but there aren't really any other configurations on iOS anyway.

WinXP: sendto() failed with 10014 (WSAEFAULT) if destination address is const-qualified, IPv4-specific

It seems, I found a bug in Windows...
Ok, let not be such pathetic one. I'm trying to do generic sendto() operation for UDP and occasionaly found that WinXP (32 bit, SP3, checked on real and virtual machines) returns "-1" bytes sent with WSAGetLastError() as error 10014 (aka WSAEFAULT). Occurs only on IPv4 addresses (same code with IPv6 destination works perfectly). Major condition to reproduce is usage of "const struct sockaddr_in" declared at global scope. Here is the plain C code for VS2010 (also I've tried with Eclipse+MinGW, got same results):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <winsock2.h>
#include <stdint.h>
#pragma comment(lib, "Ws2_32.lib")
#define INADDR_UPNP_V4 0xEFFFFFFA
#define htons(x) ((((uint16_t)(x) & 0xFF00) >> 8) | (((uint16_t)(x) & 0x00FF) << 8))
#define htonl(x) ((((uint32_t)(x) & 0xFF000000) >> 24) | (((uint32_t)(x) & 0x00FF0000) >> 8) | (((uint32_t)(x) & 0x0000FF00) << 8) | (((uint32_t)(x) & 0x000000FF) << 24))
// Magic "const" qualifier, causes run-time error
const struct sockaddr_in addr_global = {
AF_INET,
htons(1900),
{
htonl(INADDR_UPNP_V4)
},
{0},
};
int main(int argc, char** argv)
{
#define CR_LF "\r\n"
// these two lines to un-buffer console window output at Win32, see URL below for details
// http://wiki.eclipse.org/CDT/User/FAQ#Eclipse_console_does_not_show_output_on_Windows
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
printf("Started\n");
const struct sockaddr_in addr_local = {
AF_INET,
htons(1900),
{
htonl(INADDR_UPNP_V4)
},
{0},
};
const char *MSEARCH_REQUEST_V4 = "M-SEARCH * HTTP/1.1"CR_LF
"Host:239.255.255.250:1900"CR_LF
"MAN:\"ssdp:discover\""CR_LF
"ST:ssdp:all"CR_LF
"MX:3"CR_LF
CR_LF;
const int MSEARCH_LEN = strlen(MSEARCH_REQUEST_V4);
WSADATA wsaData;
int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
int af = AF_INET;
int sock_id = socket(af, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == sock_id) {
printf("%s: socket() failed with error %i/%i\n", __FUNCTION__,
errno, WSAGetLastError());
return 1;
}
int data_sent = 0;
printf("1st sendto()\n");
data_sent = sendto(sock_id, MSEARCH_REQUEST_V4,
MSEARCH_LEN, 0,
(const struct sockaddr * const)&addr_local,
sizeof(struct sockaddr_in));
if (data_sent < 0) {
printf("%s: sendto(local) failed with error %i/%i\n", __FUNCTION__,
errno, WSAGetLastError());
}
printf("2nd sendto(), will fail on WinXP SP3 (32 bit)\n");
data_sent = sendto(sock_id, MSEARCH_REQUEST_V4,
MSEARCH_LEN, 0,
(const struct sockaddr * const)&addr_global,
sizeof(struct sockaddr_in));
if (data_sent < 0) {
printf("%s: sendto(global) failed with error %i/%i\n", __FUNCTION__,
errno, WSAGetLastError());
}
closesocket(sock_id);
res = WSACleanup();
printf("Finished\n");
return 0;
}
So, if you run this code at Win7, for example, it will be absolutely OK. But WinXP fails on addr_global usage if it equipped with "const" qualifier (see "Magic" comment above). Also, "Output" window says:
First-chance exception at 0x71a912f4 in SendtoBugXP.exe: 0xC0000005:
Access violation writing location 0x00415744.
With help of "Autos" window, it's easy to figure out that 0x00415744 location is address of addr_global.sin_zero field. It seems, WinXP to write zeros there and violates memory access flags. Or this is just silly me, trying to go wrong door?
Appreciate your comments a lot. Thanks in advance.
Yeah you found a bug. sendto() has that argument declared const, but wrote to it anyway. Good luck getting it fixed though. Hint: it might be in your antivirus or firewall.
To summarize results from other forums: yes, this is Windows bug, existing up to WinXP in "desktop" and Win2003 at "server" segments.
WinSock code does attempt to force-fill "sin_zero" field with zeros. And "const" global scope causes memory access violation. Stack trace is about like that:
Thread [1] 0 (Suspended : Signal : SIGSEGV:Segmentation fault)
WSHTCPIP!WSHGetSockaddrType() at 0x71a912f4
0x71a52f9f
WSAConnect() at 0x71ab2fd7
main() at tests_main.c:77 0x401584
The same behavior observed on bind() by other people.

winsock - Sender UDP socket not bound to the desired port

Below you can see my code that implements a pretty basic UDP sender in C++ with Winsock. The thing is that no matter how many times I run the code, the socket (the listenSocket) gets bound to a different UDP port. Is there any specific reason for this? Am I doing some mistake in my code?
thanks
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKADDR_IN myAddress;
SOCKADDR_IN targetAddress;
int myPort = 60888;
const char *myIP = "192.168.0.1";
int remotePort = 2048;
const char *remoteIP = "192.168.0.2";
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET SendSocket = INVALID_SOCKET;
SOCKET acceptSocket;
char cBuffer[1024] = "Test Buffer";
int nBytesSent = 0;
int nBufSize = strlen(cBuffer);
int iResult;
// Initialize Winsock
if( WSAStartup( MAKEWORD(2, 2), &wsaData ) != NO_ERROR )
{
cerr<<"Socket Initialization: Error with WSAStartup\n";
system("pause");
WSACleanup();
exit(10);
}
ListenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ListenSocket == INVALID_SOCKET or SendSocket == INVALID_SOCKET)
{
cerr<<"Socket Initialization: Error creating socket"<<endl;
system("pause");
WSACleanup();
exit(11);
}
//bind
myAddress.sin_family = AF_INET;
myAddress.sin_addr.s_addr = inet_addr(myIP);
myAddress.sin_port = htons(myPort);
targetAddress.sin_family = AF_INET;
targetAddress.sin_addr.s_addr = inet_addr(remoteIP);
targetAddress.sin_port = htons(remotePort);
if(bind(ListenSocket, (SOCKADDR*) &myAddress, sizeof(myAddress)) == SOCKET_ERROR)
{
cerr<<"ServerSocket: Failed to connect\n";
system("pause");
WSACleanup();
exit(14);
}
else
printf("Server: bind() is OK.\n");
nBytesSent = sendto(SendSocket, cBuffer, nBufSize, 0,
(SOCKADDR *) &targetAddress,
sizeof(SOCKADDR_IN));
printf("Everything is ok\n");
system("PAUSE");
closesocket(ListenSocket);
closesocket(SendSocket);
return EXIT_SUCCESS;
}
EDIT: Maybe I was not so clear. What I do with this code is to send some data to a remote PC. But what is required is that the UDP segments should appear to be originated from a specific port. How can this be done? Is it wrong what I'm doing here? Now that I'm thinking of it, I guess it is wrong indeed. The SendSocket and ListenSocket don't have any connection, correct? So, how can I make it that the UDP segments appear to originate from a specific UDP port? Thanks!
You are not calling bind() on SendSocket before sending data with it, so WinSock is free to bind that socket to whatever random local IP/Port it needs to. If you have to send data with a specific source IP/Port every time, you have to bind() to that IP/Port first. If that local IP/Port is the same pair you are binding ListenSocket to, then you don't need to use two separate sockets to begin with. You can send data with the same socket that is listening for incoming data.

Getting ARP table on iPhone/iPad

I am trying to get the ARP entries on my iPad like here.
When compiling the code to run on my iPad (so not the simulator) I am getting missing header error messages. You can resolve them by copying the header files into you project locally as mentioned in this post.
The problem lies in the line
sdl = (struct sockaddr_dl *)(sin + 1);
in this piece of code:
-(NSString*) ip2mac: (char*) ip
{
int expire_time, flags, export_only, doing_proxy, found_entry;
NSString *mAddr = nil;
u_long addr = inet_addr(ip);
int mib[6];
size_t needed;
char *host, *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
extern int h_errno;
struct hostent *hp;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if ((buf = malloc(needed)) == NULL)
err(1, "malloc");
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
err(1, "actual retrieval of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
if (addr) {
if (addr != sin->sin_addr.s_addr)
continue;
found_entry = 1;
}
if (nflag == 0)
hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
sizeof sin->sin_addr, AF_INET);
else
hp = 0;
if (hp)
host = hp->h_name;
else {
host = "?";
if (h_errno == TRY_AGAIN)
nflag = 1;
}
if (sdl->sdl_alen) {
u_char *cp = LLADDR(sdl);
mAddr = [NSString stringWithFormat:#"%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];
// ether_print((u_char *)LLADDR(sdl));
}
else
mAddr = nil;
}
if (found_entry == 0) {
return nil;
} else {
return mAddr;
}
}
It gives the following error message:
Arithmetic on pointer to incomplete type 'struct sockaddr_inarp*'
When you compile the code for the iPad simulator everything runs fine.
Does anyone have an idea how to solve this?
A similar question (but not solved) is asked here.
After importing <netinet/if_ether.h>, you should edit it and change the line
#include <net/if_arp.h>
to
#include "if_arp.h"
and then import <net/if_arp.h> in your project as well. This should fix that error.
Anyway the headers you need to import to compile the code you posted are:
#include "if_ether.h"
#include "route.h"
#include "if_arp.h"
#include "if_dl.h"
Hope this helps =)
EDIT:
You need to "Add files to project", not simply importing it with #import or #include.
You can find above files from following links:
Files under "netinet"
Files under "net"
#include <net/ethernet.h>
instead of messing with the original headers. More info here: Implicit declaration of function 'ether_ntoa' is invalid in C99