why sockaddr_in and sockaddr each is imcompatible? - c

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.

Related

Why address information are not properly stored with gethostbyname and inet_pton functions?

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");

IP as number without usual functions?

Context
I would like to know if we can extract the ip information without having to use gethostinfo or getnameinfo etc...
Part of my code
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
in_len = sizeof in_addr;
infd = accept( fd , &in_addr , &in_len );
Question
I would like to get the client/incoming ip as a number without the usual formatting (eg 3232238637 instead of 192.168.12.45). Is it even possible ?
The source of those functions is obscure as one would wish, so I cannot figure out.
I read that in_addr (sockaddr) could have the information I need. There is no particular reason but discovering the "inners" of those functions and structures.
Thanks !
For IPv4:
struct sockaddr_in in_addr;
socklen_t in_len = sizeof in_addr;
int infd = accept(fd, (struct sockaddr*) &in_addr, &in_len);
// in_addr.sin_addr.s_addr contains the client's IP address
// as a 4-byte integer, in network byte order...
For IPv6:
struct sockaddr_in6 in_addr;
socklen_t in_len = sizeof in_addr;
int infd = accept(fd, (struct sockaddr*) &in_addr, &in_len);
// in_addr.sin6_addr.s6_addr contains the client's IP address
// as a 16-byte array...
If your question is how to "convert" from the binary representation of an IP address to a string "dotted-decimal" representation, rather than use one of the standard functions, then here is an example of how to do it for an IPV4 address ... if not, please clarify your question:
#include <stdio.h>
#include <netdb.h>
int main()
{
struct hostent *he;
long unsigned nbo;
he = gethostbyname("localhost");
nbo = htonl(*((int*)he->h_addr_list[0]));
printf("h_addr: %lx netbyteorder: %lx = %d.%d.%d.%d\n",
*((int*)he->h_addr_list[0]), nbo,
(nbo&0xFF000000)>>24, (nbo&0x00FF0000)>>16, (nbo&0x0000FF00)>>8,
(nbo&0x000000FF) );
}

Extracting IP Address and Port Info from sockaddr_storage

I'm currently working on a UDP server that receives a request from a client. The datagram I receive is a byte (char) array 5 elements long, with the final two elements being a port number.
Eventually this server will have to return both the IP address and the port number in a datagram of its own.
I already know how to use inet_ntop and the sockaddr struct I've connected with and received from to print out the ip, but it returns a string that's not in the format I want. For instance:
string1 = inet_ntop(their_addr.ss_family,get_in_addr(
(struct sockaddr *)&their_addr),s, sizeof s);
returns:
127.0.0.1
or:
[1][2][7][.][0][.][0][.][1]
when I need something like:
[127][0][0][1]
Should I be using some sort of character and array manipulation to make my 4-element byte array? Or does a sockaddr have this information in a way that I can leave it in this hex form and return it?
Assuming for IPv4.
After taking the address of your sockaddr_storage or sockaddr structure and casting it to the IPv4 version sockaddr_in, you can then access the individual bytes of the IPv4 address.
struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
Then you can take address of the s_addr member which is a 32 bit value (in_addr_t) that holds the 4 bytes of the ip address (in network byte order) and cast it to a pointer to an unsigned char which then lets you access the individual bytes of the value.
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
printf("%d %d %d %d\n", ip[0], ip[1], ip[2], ip[3]);
You want to probably use getnameinfo() function:
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
E.g.:
struct sockaddr_storage client_addr;
socklen_t client_len = sizeof(struct sockaddr_storage);
/* Accept client request */
int client_socket = accept(server_socket,
(struct sockaddr *)&client_addr, &client_len);
char hoststr[NI_MAXHOST];
char portstr[NI_MAXSERV];
int rc = getnameinfo((struct sockaddr *)&client_addr,
client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr),
NI_NUMERICHOST | NI_NUMERICSERV);
if (rc == 0)
printf("New connection from %s %s", hoststr, portstr);
Here is a simple immutable class I used for the same purpose you mentioned in your question:
class address_t {
private:
uint16_t m_Port = 0;
std::string m_Ip = "";
public:
address_t(const sockaddr_in & address) {
m_Ip = inet_ntoa(address.sin_addr);
m_Port = ntohs(address.sin_port);
}
uint16_t GetPort() const { return m_Port; }
std::string GetIp() const { return m_Ip; }
std::string ToString() const {
return "IP: " + m_Ip + ", Port: " + std::to_string(m_Port);
}
};

How should I print server address

int server_sockfd, client_sockfd; //server and client filedescriptors
socklen_t server_len, client_len;
struct sockaddr_in server_address; //server address
struct sockaddr_in client_address; //client address
int server_port = 10000;
char *def_server_address ="127.0.0.1";
server_len = sizeof(server_address);
memset(&server_address, 0, server_len );
server_address.sin_family = AF_INET;
if (x == 1) {
server_address.sin_addr.s_addr = INADDR_ANY;}
else {
server_address.sin_addr.s_addr = inet_addr(def_server_address);
}
server_address.sin_port = htons(server_port);
How should I print the address of the server from server_address? Using printf.
Use inet_ntop() to convert it to a string
This function converts the network address structure src in the af
address family into a character string. The resulting string is
copied to the buffer pointed to by dst, which must be a non-null
pointer. The caller specifies the number of bytes available in this
buffer in the argument size.
inet_ntop() extends the inet_ntoa(3) function to support multiple
address families, inet_ntoa(3) is now considered to be deprecated in
favor of inet_ntop().
That worked for me:
struct sockaddr_in sa;
char buffer[INET_ADDRSTRLEN];
inet_ntop( AF_INET, &sa.sin_addr, buffer, sizeof( buffer ));
printf( "address:%s\n", buffer );
AF_INET is used to denote that the sin_addr points to an IPv4 network address. The resulting string is copied to the buffer variable. You should specify the number of bytes available in the buffer in the last argument of inet_ntop().
I used an example from Beej's Networking:
https://beej.us/guide/bgnet/html/#ip-addresses-part-deux
This works:
struct sockaddr_in sa;
struct sockaddr_in6 sa6;
int e1 = inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IP4
int e2 = inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IP6
// Example for IPv4 string
char ip4[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
printf("The IPv4 address is %s\n", ip4);
// Example for IPv6 string
char ip6[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);
printf("The Ipv6 address is %s\n", ip6);
Output:
The IPv4 address is 10.12.110.57
The Ipv6 address is 2001:db8:63b3:1::3490
Try this:
printf("%s\n", inet_ntoa(server_address->sin_addr));

Getting the source address of an incoming socket connection

I have a server with a incoming socket from a client.
I need the get the IP address of the remote client.
Tried searching google for in_addr but it's a bit troublesome.
Any suggestions?
You need the getpeername function:
// assume s is a connected socket
socklen_t len;
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
int port;
len = sizeof addr;
getpeername(s, (struct sockaddr*)&addr, &len);
// deal with both IPv4 and IPv6:
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
} else { // AF_INET6
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}
printf("Peer IP address: %s\n", ipstr);
Assuming you're using accept() to accept incoming socket connections, getpeername() isn't needed. The address information is available via the 2nd and 3rd parameters of the accept() call.
Here is Eli's answer modified to do it without getpeername():
int client_socket_fd;
socklen_t len;
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
int port;
len = sizeof addr;
client_socket_fd = accept(server_socket_fd, (struct sockaddr*)&addr, &len);
// deal with both IPv4 and IPv6:
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
} else { // AF_INET6
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}
printf("Peer IP address: %s\n", ipstr);
Since you say it is an incoming connection from a client, as an alternative to getpeername you can just save the address that was returned by the accept() call, in the second and third parameters.

Resources