I am wondering in which field is the numeric 32 bit representation of the ip address stored in.
you have the following structures from the API:
struct in_addr {
uint32_t s_addr;
}
struct sockaddr_in {
...
...
struct in_addr sin_addr;
...
}
And I have the following code:
struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_INET;
addrCriteria.ai_socktype = SOCK_STREAM;
addrCriteria.ai_protocol = IPPROTO_TCP;
struct addrinfo *addrList;
int rtnVal = getaddrinfo(serverIP, portNumber, &addrCriteria, &addrList);
if (rtnVal != 0) {
printf("getaddrinfo() failed\n");
exit(1);
}
numericAddress = &((struct sockaddr_in *) addrList->ai_addr)->sin_addr;
addrList->sin_port = htons(servPort);
Please look at the line in bold. I would like to save the bit representation of the ip address in the variable named numericAddress.
numericAddress is initialized as void *numericAddress;
My question is, do I need to access the variable s_addr, which is a field in the in_addr struct, or is it sufficient to use sin_addr to access the bit value?
Related
int main (int argc, char **argv){
int sockfd = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
bzero(&addr,sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
struct hostent *server = gethostbyname("192.168.1.139");
printf("%s %d\n",server->h_addr,inet_pton(AF_INET,server->h_addr,&addr.sin_addr.s_addr));
int res = connect(sockfd,(struct sockaddr *)&addr,sizeof addr);
printf("%d\n",res);
while (1){
char buf[100] = "";
fgets(buf,100,stdin);
send(sockfd,buf,sizeof buf,0);
}
}
If I execute this code, I always get:
$ ./client
��� 0
-1
So:
Why I get these random chars? Why I don't see the IP string of h_addr?
Why the return of inet_pton is 0? It should be 1, 0 is for unsuccessfull, so why it fails?
Obviously, the connect fails.
Also, if instead of using inet_pton, I use this line:
bcopy((char *)server->h_addr,(char *)&addr.sin_addr.s_addr,h_length);
it works. BUT WHY it works this way and in the other way it doesn't??
My English is not very good, so please understand.
See gethostbyname() man page.
The gethostbyname() function returns a structure of type hostent for the given host name. Here name is either a hostname or an IPv4 address in standard dot notation (as for inet_addr(3)). If name is an IPv4 address, no lookup is performed and gethostbyname() simply copies name into the h_name field and its struct in_addr equivalent into the h_addr_list[0] field of the returned hostent structure.
h_addr_list[0] is struct in_addr and h_addr_list[0] is h_addr, See below.
struct hostent
struct hostent {
char * h_name;
char ** h_aliases;
int h_addrtype;
int h_length;
char ** h_addr_list;
};
#define h_addr h_addr_list[0]
struct in_addr
struct in_addr {
uint32_t s_addr;
}
So, if you want to see the IP string of h_addr, see the code below.
printf("%s\n", inet_ntoa(*(struct in_addr*)server->h_addr));
And you can use it by assigning the value of s_addr as addr.sin_addr.s_addr = *(unit32_t *)server->haddr;
Or you can make it simpler using addr.sin_addr.s_addr = inet_addr("192.168.1.139");
int serv_sock;
struct socckaddr_in serv_addr;
char *serv_port = "9190";
/*make server socket*/
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
/*serv_addr struct init*/
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_faimily = AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(serv_port));
**bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));**
i don't understand that why use (struct sockaddr *) ?
why can't wrote bind(serv_sock, &serv_addr, sizeof(serv_addr)); ?
why add (struct sockaddr *) type ? i don't understand
what's mean (struct sockaddr *) ?
So, i did one example
struct a {
int a;
int b;
};
int i = 10;
struct a b;
b.a = 10;
b.b = 20;
printf("%d \n", b.a); // A sentence
printf("%d \n", (struct a*)b.a); // B sentence
it returned 10, 10; i don't understand why use '(struct a*)'..
i don't understand a,b sentence difference
i want I would like to know the difference between the type with and without '*'.
The expression &serv_addr has type struct sockaddr_in *.
However, the function bind expects that the argument has type struct socckaddr *. This is a generic type for many address families.
The * character in this context indicates a pointer.
From the manual:
The actual structure passed for the addr argument will depend on the address family. The sockaddr structure is defined as something like:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
While the manual describes struct sockaddr_in as:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
The reason the the generic type exists is that IPv4 is not the only address family that exists.
The manual describes the IPv6 version:
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
Note that the all start with a sa_family_t member, which describes which family is being represented. The struct sockaddr sa_data member is the "payload" of the struct.
Directly passing a struct sockaddr_in * or struct sockaddr_in6 * when struct sockaddr * is expected would cause a warning/error. The (struct sockaddr *) explicitly converts the pointer to the type struct sockaddr *, which bind expects.
The statement
printf("%d \n", (struct a*)b.a);
is not valid. You take an integer, convert it to a pointer to a struct, then tell printf to interpret that argument as an integer.
Below is an extract of example code for IPv6 and IPv4 clinet code:
IPv6
int s;
struct sockaddr_in6 addr;
s = socket(AF_INET6, SOCK_STREAM, 0);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(5000);
inet_pton(AF_INET6, "::1", &addr.sin6_addr);
connect(s, (struct sockaddr *)&addr, sizeof(addr));
IPv4
int s;
struct sockaddr_in addr;
s = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(5000);
servaddr.sin_addr.s_addr = INADDR_ANY;
connect(s, (struct sockaddr *)&addr, sizeof(addr));
My aim is to write a user defined connect API for both IPv6 and IPv4 addresses. Since both of them convert structures to struct sockaddr structure - programtically how can we convert the sockaddr_in and sockaddr_in6 to sockaddr structure (populate its member variables) and then call connect with sockaddr sturcure?
programtically how can we convert the sockaddr_in and sockaddr_in6 to sockaddr structure (populate its member variables) and then call connect with sockaddr structure?
A typecast is not a conversion. You are not converting anything. Just as the examples you provided show, you create a sockaddr_in or sockaddr_in6 instance as needed and then pass it as-is to connect(). You are merely typecasting the pointer that points at the struct instance. Internally, connect() will look at its input addr's sa_family field and typecast the addr back to either sockaddr_in or sockaddr_in6 accordingly to access the data fields as needed.
My aim is to write a user defined connect API for both IPv6 and IPv4 addresses.
If you want to write protocol-agnostic code, you could do something like this:
int doConnect(int family, const char *ip, u_short port)
{
struct sockaddr_storage ss = {};
socklen_t addrlen;
switch (family)
{
case AF_INET:
{
struct sockaddr_in *addr = (struct sockaddr_in *) &ss;
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
inet_pton(AF_INET, ip, &addr->sin_addr);
addrlen = sizeof(struct sockaddr_in);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &ss;
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
inet_pton(AF_INET6, ip, &addr->sin6_addr);
addrlen = sizeof(struct sockaddr_in6);
break;
}
default:
return -1;
}
int s = socket(family, SOCK_STREAM_IPPROTO_TCP);
if (s != -1)
{
if (connect(s, (struct sockaddr *) &ss, addrlen) < 0)
{
close(s);
s = -1;
}
}
return s;
}
int s = doConnect(AF_INET, "127.0.0.1", 5000);
int s = doConnect(AF_INET6, "::1", 5000);
However, a better solution is to use getaddrinfo() instead and let it allocate the correct sockaddr data for you based on the input values it actually parses, eg:
int doConnect(const char *ip, u_short port)
{
struct addrinfo hints = {};
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *addr;
char szPort[6];
sprintf(szPort, "%hu", port);
int s = -1;
int ret = getaddrinfo(ip, szPort, &hints, &addr);
if (ret == 0)
{
s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (s != -1)
{
if (connect(s, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(s);
s = -1;
}
}
freeaddrinfo(addr);
}
return s;
}
int s = doConnect("127.0.0.1", 5000);
int s = doConnect("::1", 5000);
The nice thing about getaddrinfo() is that you can also use it for servers, too. Simply use the AI_PASSIVE flag in the hints.ai_flags field, and then use the resulting addrinfo item(s) to call socket() and bind().
programtically how can we convert the sockaddr_in and sockaddr_in6 to sockaddr
You can't, as neither sockaddr_in nor sockaddr_in6 are guaranteed to fit into a sockaddr structure.
A POSIX-compliant system will provide a sockaddr_storage type that is guaranteed to be large enough to hold any type of sockaddr structure:
The <sys/socket.h> header shall define the sockaddr_storage
structure, which shall be:
Large enough to accommodate all supported protocol-specific address structures
Aligned at an appropriate boundary so that pointers to it can be cast as pointers to protocol-specific address structures and used to
access the fields of those structures without alignment problems
The sockaddr_storage structure shall include at least the following
members:
sa_family_t ss_family
When a pointer to a sockaddr_storage structure is cast as a pointer
to a sockaddr structure, the ss_family field of the
sockaddr_storage structure shall map onto the sa_family field of
the sockaddr structure. When a pointer to a sockaddr_storage
structure is cast as a pointer to a protocol-specific address
structure, the ss_family field shall map onto a field of that
structure that is of type sa_family_t and that identifies the
protocol's address family.
I try to memcpy ipv4 address in *ai(struct addrinfo)
struct addrinfo *ai;
char *p = (char *)(void *)(ai->ai_addr);
memcpy(p + afd->a_off, "d83adcca", (size_t)afd->a_addrlen); // "d83adcca ipv4 address is hex data - not correct.."
So, i need verify that i have been correctly assigned.
I use this code :
struct sockaddr_in ipv4 = (struct sockaddr_in *)ai->ai_addr;
inet_ntop(AF_INET, &(ipv4->sin_addr), ipAddress, INET_ADDRSTRLEN);
BUT, ipAddress and ai->ai_addr is not matched!!
If you know how to assigned these struct, Please help me.
Thanks.
I'm sending a ICMP packet through a socket in iOS:
struct sockaddr hostAddress;
self->hostAddress.sa_family = AF_INET;
inet_pton(AF_INET, "173.194.67.93", &self->hostAddress.sa_data);
Then, I open the socket and I send the packet:
bytesSent = sendto(
CFSocketGetNative(self->_socket),
[packet bytes],
[packet length],
0,
&self->hostAddress,
sizeof(self->hostAddress)
);
When I see the packet in WireShark, it's being sent to "67.93.0.0", instead to "173.194.67.93".
Where could be the problem?
inet_pton(AF_INET, ...);
should take a struct in_addr as the 3rd argument (see docs).
You're giving it sa_data, from
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
which is really treated as:
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
So, the first 16 bits are going in the port, the second 16 bits of the IPV4 address are actually making it into sin_addr, and the rest appears to be zero-initialized.
You should be doing this (I'll put loads of casts in for clarity)
struct sockaddr *addr = &self->hostAddress; // generic address
struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; // downcast to ipv4
inet_pton(AF_INET, "173.194.67.93", &ipv4->sin_addr);