Convert IPv6 to IPv4 format in c++? - c++

I am maintaining an old system which runs fine on IPv4 format and i found out that the listener did not trigger when the requestor is coming from IPv6. I have the following line of code
SOCKADDR_IN SocketAddr;
INT nBufferSize=sizeof(SocketAddr);
hConnectSocket=WSAAccept(m_hListenSocket,(SOCKADDR *)&SocketAddr,&nBufferSize,NULL,NULL);
if (hConnectSocket==INVALID_SOCKET) return false;
I also googled and i know i should be using SOCKADDR_IN6 for IPv6. Is it possible to convert SOCKADDR_IN6 to SOCKADDR_IN format so that the rest of the application will work?
Thanks.

You can't convert all IPv6 addresses to IPv4 - there are more IPv6 addresses than IPv4 addresses. The best way to tackle this issue is to update/upgrade your application so it understand and store IPv6 addresses. This thread might be useful.

I implemented some time ago a solution that can work with IPV4 and IPV6 addresses. I did even encapsulate that property from the outside world.
The rest of the program should only know about sockets. And if your code accepts an address in the IPV6 or IPV4 format does not really matter /after accepting).
The important point is that you need to specify the ai_family with AF_UNSPEC. Then it will handle both address families. And for the accept function, you can handover a parameter big enough to hold both address types.
I am not sure, but maybe that could help you.
Please see the following code snippet that I developed some years ago in C++98.
// The following structures are used in order to be independent from the internet address families
// e.g. IPV4 or IPV6. The basic original functions have been designed for IPV4 only.
// But now we are in the age of IPV6. And we need to have means to deal with both address types
// So we have one Data type, that can hold both IPV4 and IPV6 (because it has the length of the
// larger IPV6 address). The pointer of this structure can be casted to the original data type
// that the functions always expected.
// The first field in the structures denotes the IP Address Family
// This is the big storage that can hold either a IPV4 or a IPV6 address
typedef struct sockaddr_storage SocketAddressStorage;
// This Type can hold the length of the IP Address container
typedef socklen_t SocketAddressStorageLength;
// This type is the Socket Address that OS function expect. We will cast the pointer of the big
// data type to this one
typedef struct sockaddr SocketAddress;
// The next 2 are specific address containers for either IPV4 or IPV6.
// One of them will be a part of the big "struct sockaddr_storage"
typedef struct sockaddr_in SocketAddressInternetIPV4;
typedef struct sockaddr_in6 SocketAddressInternetIPV6;
// We use the big structure that can hold an IPV4 and IPV6 address
// because we do not know, who is contacting this node
SocketAddressStorage addressOfCommunicationPartner;
// Get the length of the above define data structure
SocketAddressStorageLength socketAddressStorageLength = sizeof(addressOfCommunicationPartner);
// Accept the connection request from a client
// handle is the filedescriptor bound to this node and listening for connection requests
// The function will return a new file descriptor for the connected socket. This is a specific socket
// for the just established connection. The handle will continue to listen for more connection requests
// So this is a factory. We are listening for connection requests and if we get one, we create a new
// file descriptor for the specific communication purposes
// The information of the foreign node will be put in the "addressOfCommunicationPartner"
// Accept the connection request from a client
//lint -e{740,929,1924}
const Handle connectionHandle = accept(handle, reinterpret_cast<SocketAddress *>(&addressOfCommunicationPartner), &socketAddressStorageLength);
// Check, if connection could be established and we have a valid file descriptor
if (connectionHandle > null<Handle>())
{
// Now we want to get the IP address of the partner. Can be IPv4 or IPv6
// The following old style C String can hold both IPv4 and IPv6 address strings
mchar ipAddressCString[INET6_ADDRSTRLEN+1];
// This is a pointer into the address structure of the communication partner
// It points either to sin_addr for IPv4 or sin6_addr for IPv6
const void *ipAddressPEitherV4orV6;
// This will contain the IP Version as a string
std::string ipVersion;
// Now check, what family, what type of IP adress we have
//lint -e{911,1960}
if (AF_INET == addressOfCommunicationPartner.ss_family)
{
// So, it is IPv4. Remember that
ipVersion = "IPv4";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV4 *const>(&addressOfCommunicationPartner))->sin_addr) );
}
else
{
// It is IPv6. Remember that
ipVersion = "IPv6";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV6 *const>(&addressOfCommunicationPartner))->sin6_addr) );
}
// Convert native IP address format to readable C-String
//lint -e{917,1960}
if (null<mchar *>() == inet_ntop(addressOfCommunicationPartner.ss_family, ipAddressPEitherV4orV6, ipAddressCString, sizeof(ipAddressCString)))
{
// If this did not work then we will not show any IP Address. We can live with that
ipAddressCString[0] = '\x0';
}
// Debug Output
{
static long i=1;
ui << "Connection accepted " << i << " " << ipVersion << " " << ipAddressCString << " " << machineNetworkAddressInfo.portNumberString << std::endl;
i++;
}
// So. The connection request was established. We gathered all information
// Create a new TCP connection
TcpConnectionBase *tcpConnectionBase =tcpConnectionFactory->createInstance(machineNetworkAddressInfo.portNumberString, connectionHandle);
// And put a pointer to it in our internal list of Tcp Connection
tcpConnection.push_back(tcpConnectionBase);
You may find the rest here

Related

LWIP -- using option `SO_BINDTODEVICE` with `lwip_setsockopt()` returns error `ENODEV`

With LWIP, I usually set up my ethernet interface on my embedded device like this (not all argument definitions are specified here):
struct netif gnetif;
// Set up the ethernet interface on embedded device.
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
// Registers the default network interface.
netif_set_default(&gnetif);
// Make ethernet interface work.
if(netif_is_link_up(&gnetif)){
netif_set_up(&gnetif);
}
else{
netif_set_down(&gnetif);
}
When the interface is set up, I want to bind it to the device using this call to setsockopt():
lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
where:
s is my socket descriptor,
level is set to SOL_SOCKET,
optname is set to SO_BINDTODEVICE,
optval is a pointer to ifreq structure,
optlen is size of the ifreq structure (previous bullet).
This call successfully enters this switch statement and successfully interprets the SOL_SOCKET level and SO_BINDTODEVICE option to end up here.
But for some reason this call to netif_find() sets n to 0 and then I get an error ENODEV which means that there is no device. This is weird, because gnetif.name returns st and also optval which is ifreq structure has only one member ifr_name which looks like this in the debugger (just before the call):
So what am I doing wrong that I get the ENDOV error?

can't copy pointer's address to h_addr_list

I'm having some difficulties with coping the dns server's answare to a Host-Address Query, to the h_addr_list field at the struct hostent.
The function I describe, works fine for hosts that has no alias names, I debuged it and it works just fine.
However, for a host name with alias, when I debug the program, I see it won't copy the pointer of the IPv4 address at the answer buffer from the dns-server, to the struct I created, and leave it with a Bad-Pointer field.
the IPv4 printing function goes like this:
const int numOfAns=ntohs(dns->ans_count);
struct hostent remoteHost;
int numOfIP=0;
char **addressList;
addressList = new char*[numOfAns];
remoteHost.h_addr_list = addressList;
for(i=0;i<numOfAns;i++) {
if(ntohs(answers[i].resource->type) == 1) { //IPv4 address
numOfIP++;
remoteHost.h_addr_list[i] = (char*)answers[i].rdata;
}
}
remoteHost.h_addr_list[numOfIP] = NULL;
return &remoteHost;

Why is the addr variable type-converted?

While surfing on the internet I've found a c++ example that sends GET-requests. The part of this code I couldn't grasp is why (see the section that's bold) the variable addr is type converted. I understand that the function only accepts a certain type. But why using a type and then converting it to another one?
#include <iostream>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
int s, error;
struct sockaddr_in addr;
if((s = socket(AF_INET,SOCK_STREAM,0))<0)
{
cout<<"Error 01: creating socket failed!\n";
close(s);
return 1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
inet_aton("204.27.61.92",&addr.sin_addr);
error = connect(s,(sockaddr*)&addr,sizeof(addr));
if(error!=0)
{
cout<<"Error 02: conecting to server failed!\n";
close(s);
return 1;
}
char msg[] = "GET /beej/inet_ntoaman.html http/1.1\nHOST: retran.com\n\n";
char answ[1024];
//cin.getline(&msg[0],256);
send(s,msg,sizeof(msg),0);
while(recv(s,answ,1024,0)!=0)
cout<<answ<<endl;
close(s);
cin.getline(&msg[0],1);
return 0;
}
This is runtime polymorphism, C style.
sockaddr is effectively an abstract base class - it isn't specific to any concrete type of socket. However, each socket type requires type-specific information.
Since C doesn't have language support for polymorphism, the technique is to write a "derived" type which has the "base" type as it's first data member. This way they have the same address, and you can cast between them.
So, (sockaddr*)&addr is an upcast, yielding a pointer to a valid base-class subobject. When you pass this to an AF_INET socket, it will cast the pointer back to (sockaddr_in*) and recover your inet-specific data.
Equivalent C++ for reference, since it's slightly more expressive:
class SockAddr {
public:
virtual ~SockAddr();
enum Family { INET, UNIX, ... };
Family get_family() const { return family; }
protected:
explicit SockAddr(Family f) : family(f) {}
Family family;
};
class SockAddrInet: public SockAddr {
uint16_t port;
uint32_t addr;
public:
SockAddrInet(uint16_t port, uint32_t addr)
: SockAddr(SockAddr::INET), port(htons(port)), addr(addr)
{}
};
class SockAddrUnix: public SockAddr {
std::string path;
public:
explicit SockAddrInet(std::string path)
: SockAddr(SockAddr::UNIX), path(path) {}
};
void connect(Socket &s, SockAddr const &addr) {
switch (addr.get_family()) {
case SockAddr::INET:
connect_inet(s, dynamic_cast<SockAddrInet const&>(addr));
break;
case SockAddr::UNIX:
connect_unix(s, dynamic_cast<SockAddrUnix const&>(addr));
break;
}
}
It's a technique to have "subtypes" in C. There are various other sockaddr types (e.g. sockaddr_in6 for IPv6). The called function inspects the sin_family field to determine which kind of struct was passed in and handle it accordingly.
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
We have to remember that the socket APIs can work with many different network protocols. Each protocol has a completely different format for how addresses work. This sockaddr structure is, therefore, a generic structure. It contains a place to put the identifying address family, along with a generic "data" field that the address can be placed in, regardless of the format of the address.
There is however the sockaddr_in structure:
struct sockaddr_in { /* socket address (internet) */
short sin_family; /* address family (AF_INET) */
u_short sin_port; /* port number */
struct in_addr sin_addr; /* IP address */
char sin_zero[8]; /* reserved - must be 0x00's */
};
which is designed specially for networking, IP address. This type can be safely type casted to sockaddr* because it is aligned to it.
This is what Richard Stevens says about it in his "UNIX Network Programming":
Generic Socket Address Structure
A socket address structures is always passed by reference when passed as an argument to
any socket functions. But any socket function that takes one of these pointers as an
argument must deal with socket address structures from any of the supported protocol
families.
A problem arises in how to declare the type of pointer that is passed. With ANSI C, the
solution is simple: void * is the generic pointer type. But, the socket functions predate ANSI C and the solution chosen in 1982 was to define a generic socket address structure in the <sys/socket.h> header (...)
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
};
The socket functions are then defined as taking a pointer to the generic socket address
structure, as shown here in the ANSI C function prototype for the bind function:
int bind(int, struct sockaddr *, socklen_t);
This requires that any calls to these functions must cast the pointer to the protocol-specific socket address structure to be a pointer to a generic socket address structure. (...)
From the kernel's perspective, another reason for using pointers to generic socket address
structures as arguments is that the kernel must take the caller's pointer, cast it to a struct sockaddr *, and then look at the value of sa_family to determine the type of the structure.
But from an application programmer's perspective, it would be simpler if the pointer type was void *, omitting the need for the explicit cast.
Returning to the windows's connect function ::connect
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx
It requires sockaddr as a parameter type

c++ Injected DLL vars getting corrupted

I'm currently trying to add some functionality to a basic server application by injecting a DLL and detouring several functions and I'm having a problem with a stored IP address getting corrupted in-between 2 calls.
First I detour 'accept' and parse some values then enter them into a connection class and add it to a list.
Accept detour function:
std::list<Connection*> ConnectionsList;
SOCKET WINAPI MyAccept(SOCKET s, sockaddr *addr, int *addrlen)
{
...
ConnectionsList.push_back(new Connection(ClientSocket, ipstr));
...
}
connection class:
SOCKET s;
char * ipAddress;
char * playerName;
Connection::Connection(SOCKET sock, char * address)
{
s = sock;
ipAddress = address;
}
I've also detoured 'closesocket' at which point I'd like to remove the socket from the list of connections. If I breakpoint on this function the IP address appears to be corrupted.
Does anyone know why this is happening?
ipAddress = address; will just copy the pointer. If something else changes what it points to, you will be in trouble.
Since this is C++ it might be safest to use a std::string.
std::string ipAdreess;
...
ipAddress = address;
Otherwise, stdcpy into a buffer big enough.
BTW, what deletes all the Connection* from the list?
try to protect your ConnectionList etc static/global variable with a lock.

How does nfq_get_payload structure its return data?

Primarily, I'm trying to get the source address and dest port from the payload of a Netfilter queue payload (The payload is retrieved using the nfq_get_payload function). The following question asks the same thing and gets a correct answer:
How to extract source and destination port number from packet in queue of iptables
Unfortunately, there's no explanation as to why adding 20 and 22 to the address puts you in the right spot to read the info. I assume this is because of the structure of the data (obviously), but if there's a defined structure, what is it?
The documentation doesn't explicitly explain how the data is formatted, only that 'type of data retrieved by this function will depend on the mode set with the nfq_set_mode() function', but then the docs for set_mode don't mention anything about data type and the source doesn't immediately reveal anything.
I feel like this must be something very central to common network programming structs that I'm missing or not understanding.
Notes: nfq_get_payload function: http://www.netfilter.org/projects/libnetfilter_queue/doxygen/group__Parsing.html#gaf79628558c94630e25dbfcbde09f2933
I managed to figure this out and I'll leave this here for others to find.
The payload starts with an iphdr struct. The iphdr struct has a protocol field, for example tcp, if it is tcp then the data after the iphdr struct is a tcphdr struct, if it is udp, then there's another struct hdr for that, etc for icmp etc.
To access port, assume q_data is a pointer to a nfq_data struct:
unsigned char *data;
nfq_get_payload(q_data, (unsigned char**)&data);
struct iphdr * ip_info = (struct iphdr *)data;
if(ip_info->protocol == IPPROTO_TCP) {
struct tcphdr * tcp_info = (struct tcphdr*)(data + sizeof(*ip_info));
unsigned short dest_port = ntohs(tcp_info->dest);
} else if(ip_info->protocol == IPPROTO_UDP) {
//etc etc
}