Use C++ socket to validate ethernet interface configuration in QNX - c++

I have a program that configures the ethernet interface on a remote machine running a QNX Environment, which uses ifconfig to assign an IP Address, netmask and default gateway. I now need a way to determine whether the ethernet interface has a valid configuration, that I would be able to connect to remotely.
For example, giving "127.0.0.1", "255.255.255.255", or "0.0.0.0" as IP Addresses should be invalidated, because even though they are valid IP Addresses, I would not be able to establish a remote connection with these.
I need a way for a C++ application to verify that the configuration is valid and can be connected to.
I have heard that one way to do this is to try and create a socket, but I haven't had any luck so far. I was able to create a socket with "0.0.0.0" as the IP Address just as easily as a valid one.
Maybe I'm just not doing it right.
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in ipaddr;
ipaddr.sin_family = AF_INET;
inet_pton(AF_INET, "0.0.0.0", &ipaddr2.sin_addr);
bind(sock2, (struct sockaddr *) &ipaddr2, sizeof(ipaddr2));
Is there anything else I could do with this socket to verify connectivity?
Any help would be greatly appreciated!

Related

How to connect/communicate TCP client with server on another network

I am attempting to create a TCP client/server chat. My goal currently is to switch my client connection from using the local ip address "127.0.0.1" to being able to connect to the server that could possibly be in another computer not in the local network. Essentially if I the client was in Los Angeles, I would like to be able to communicate with the server in San Diego.
I am aware of "port forwarding" and have gone ahead and tried to configure my router. The port that the server is listening to is 8000. The IP address I use in "LAN IP ADDRESS" is the address I obtained from going (on ubuntu) settings->network->IPV4 address: 10.0.2.15.
router settings
Here is the code used in my server.cpp and client.cpp:
// server.cpp
// Attach socket to port:
int option{1};
if(setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &option, sizeof(option)))
{
logE("error in setting socket options");
return EXIT_FAILURE;
}
// INADDR_ANY: bind socket to all local interfaces, using IPV4 family:
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if(bind(server_fd, (struct sockaddr*)&address, sizeof(address)))
{
logE("binding socket failed");
return EXIT_FAILURE;
}
//client.cpp
// setup sockets method of connection:
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
/* serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
/* serverAddr.sin_addr.s_addr = inet_addr("IP 1"); */
serverAddr.sin_addr.s_addr = inet_addr("IP 2");
// Connect to server:
if(connect(server_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)))
{
logE("connection to server failed");
return EXIT_FAILURE;
}
In client.cpp "IP 1" is the IP I get when going on https://whatismyipaddress.com/, "IP 2" is the address I use that logs me into my router.
I have not been able to connect to my server using either of the two IP's, furthermore I have attempted to use different IP's in my router settings as well. Also I am aware of "static ip address" which would help the server maintain one constant IP, but I would first like to try using whatever IP address the servers machine is currently using.
Furthermore, My server.cpp is running within my Ubuntu Virtual Machine, which is hosted on Windows. Since I don't have another machine at my disposal I am testing / running this on the same VM currently for testing purposes, but once everything works I will go ahead and as a friend to test different machines.

How can I set the source IP address to 0.0.0.0?

I want to write simple DHCP client (which will be working over WLAN) and I have a problem with correctly sending the initial message DHCP DISCOVER - it is sent (I see it in Wireshark when capturing the WLAN interface), but source address is address of my adapter. How can I set the IP to '0.0.0.0'?
Here is a part of my code:
sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
src_addr.sin_port = htons(m_sport);
src_addr.sin_addr.s_addr = htonl(INADDR_ANY);
status = bind(m_sockfd, reinterpret_cast<sockaddr *>(&src_addr), sizeof(sockaddr_in));
When I try src_addr.sin_addr.s_addr = inet_addr("0.0.0.0");, source address is still set from eth0 (10.132...).
The kernel is doing you a service by populating "for free" the source address with the IP on the exit interface.
If you don't want that you'll probably have to use raw sockets and provide your own IP header with IP_HDRINCL. Look for SOCK_RAW.
A simple way to cheat through this is to strace or truss your DHCP client and see what it does.

Mix mode communication between IPv4 and IPv6

I have a application which acts as client and server both. As a server it accepts SOAP requests on port xxxx[Agent URL] and send notifications to the sender on port yyyy [notification URL].
So basically it acts as a server on port xxxx and client on port yyyy. My service has a dedicated IP either IPv6 or IPv4.
We are using GSOAP for communication and overriding GSOAP function tcp_connect() for client side binding.
Currently I am facing issues with transition of service to IPv6. Use case: when I listening on IPv6 address and my notification URL is IPv4...
From the GSOAP implementation a socket is created from the Notification URL.
sk = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Now we try to bind to this socket accordingly(either IPv4 or IPv6):
struct addrinfo hints, *res, *p;
int status;
const char* client_ip = AGENT_CLIENT_IP;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if( (status=getaddrinfo(client_ip, NULL, &hints, &res))!=0 )
{
sprintf(err_msg_buf,"bind failed in tcp_connect()");
soap->fclosesocket(soap, sk);
return error;
}
for( p=res; p!=NULL; p=p->ai_next){
if(p->ai_family == AF_INET)
{
struct sockaddr_in * ipv4 = (struct sockaddr_in *)p->ai_addr;
status = bind(sk, ipv4, (int)sizeof(struct sockaddr_in));
}
else if(p->ai_family == AF_INET6)
{
struct sockaddr_in6 * ipv6 = (struct sockaddr_in6 *)p->ai_addr;
status = bind(sk, ipv6, (int)sizeof(struct sockaddr_in6));
}
else
{
sprintf(err_msg_buf,"tcp_connect() error. IP Address neither IPv6 nor IPv4 ");
soap->fclosesocket(soap, sk);
return error;
}
break;
}
if(-1 == status)
{
sprintf(err_msg_buf," Binding to client host ip failed in tcp_connect()");
return error;
}
Since the socket is already created(according to the type of Notification URL), bind fails if the socket is of type mismatch is there.
How can I make my client side binding work when socket family and agent ip address are of different family ?
Maybe I am not getting what you are trying or you have some misunderstanding of how TCP/IP and RPC normally works.
Let me paraphrase your set up and then show what I think is odd about it.
You have a server and one or multiple clients. The server accepts IPv4 and IPV6 connections on a fixed port, let us say 1337. To answer the request you open a new TCP stream (or maybe SOAP) on a different fixed port, say 1338. You are now wondering why, when a second client connects the bind to 1338 fails?
The short answer is: "The port is in use, duh, us a different port!"
But that misses the point that the setup, to say the least ODD. Although I have never used GSOAP, I have used SOAP and other RPC frameworks and what you outline is weird, unless I am missing something you did not outline.
The first thing that is odd, if you need an answer to a SOAP request, why do you simply formulate one with a return value? Call the SOAP function and the client will block until it gets an answer. If you don't want the call to block for the relatively long duration of the call do the entire thing asynchronously.
So you want to pass data to the client back later? Here you have two solutions, either the client polls the server or you open a new SOAP connection to the client. The first solution is basically desirable, because in most cases the client can connect to the server but not the other way around. For example the client can be behind a NAT, what do you do now? The second solution works well when you know that the client will always be reachable.
It seems to me that you are trying to do the second "return channel" solution. In this case why are you binding to a port? The client side of any IP connection does not need to bound to a port. The OS will automatically assign an available port. What you need to do is then bind the port on the client to a well known IP. You then use this well known client port and use it in connect on the server (or not, since you are using SOAP).
Since this is all confusing let me illustrate this with a small diagram:
Client Server
------ ------
Request Channel <random port> 1337
Back Channel 1338 <random port>
To sum up:
So either you are reimplementing something that works in SOAP and should stop doing that or if you absolutely need a back channel, simply don't call bind on a client socket.

Manage 2 Internet Connections?

I have a Linux computer with 2 Ethernet adapters. I also have 2 ADSL models and 2 internet connections. I connect modem A to Ethernet port A and modem B to Ethernet port B.
Now, how to do the following (preferably in C++):
a) Get the IP of each adapter
b) Select the connection to use for downloading (I want to say: download this file with connection A and this with B)
The IPs are dynamic. I am doing this, because my IP must be know to a remote server.
The server must:
a) get the IP
b) send files to this IP
The idea is, every time my IP changes, I will send the new IP to the server, so the server will know where to send the files.
I am using 2 internet connections for:
a) redundancy reasons (if one internet connection is down, I got the second)
b) have faster download speed by opening 2 connections with the server.
If your goal is to simply update a server of your IP address, then you just need to make a connection to this server using a typical TCP socket:
int sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addrLocal = {};
result = connect(sock, (sockaddr*)&server_address, sizeof(server_address));
send(sock, "I have a new IP address", ...);
In the above example, you don't even have to call bind on the socket, as the client TCP/IP stack will consult your computer's routing table for the best local IP address to use (and will pick a random local port).
The client need not even know the IP address it is connecting from nor does it need to tell the server via the socket protocol.. The server in turn can automatically detect your IP address when it does the corresponding accept call when it receives the client connection.
sockaddr_in addrRemote = {};
socklen_t addrRemoteSize = sizeof(addrRemote);
int sockclient = accept(listensocket, (sockaddr*)&addrRemote, &addrRemoteSize);
// the IP address of the client making the connection is in addrRemote.
And if your client just keeps the socket to the server open, then the server can transmit a file back to the client without having to establish a new connection or keep track of any IP address.
Now to answer your original questions, in case you do have a legitimate need to do ascertain a local IP address.
Question 1:
To get the local IP address of each adapter, you can call getifaddrs . From the result list returned from this function, filter out any address that isn't IP, is not UP, or is LOOPBACK.
Question 2:
To bind a socket to a specific adapter, bind to the IP address of the local adapter prior to making a connect call. Example below
...
result = bind(sock, (sockaddr*)&addr, sizeof(addr));
if (result != -1)
connect(sock, (sockaddr_in*)&remoteServer, sizeof(remoteServer));
Where "addr" in the code sample above points to one of the ifa_addr values in the ifaddr array returned by getifaddrs.
Now if there is a NAT involved in any of these connections, then your locally enumerated IP address will be different than the public IP address that the server sees you at.
If you are using UDP sockets, then all of the stuff above still applies, with some tweaks. (e.g. don't call connect(), just call sendto() ).

How to make a TCP socket work with SO_BINDTODEVICE (against routing table)

Background of the question:
On our machine we have multiple network interfaces which lead to different networks. There are possible overlapping IP addresses (e.g. two different machines in two different networks with the same IP address). So when we want to connect with specific peer then we need to specify not only it's IP address but also our network interface which lead to the proper network.
We want to write application in C/C++ able to connect with specific peers via TCP.
Question:
I'm trying to make a TCP connection using socket with SO_BINDTODEVICE set. Here is a simplified snippet:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, interface_name,
strlen(interface_name));
connect(sockfd, (sockaddr *) &serv_addr, sizeof(serv_addr));
(I know about struct ifreq, but it seems that only the first field in it (ifr_name field is in use). So I can pass only name of the interface.)
If forced interface is the same as interface according to the routing table, then everything works correctly.
If forced interface is different, then (tested with Wireshark):
SYN is sent from forced interface to desired peer.
SYN,ACK from desired peer is received on forced interface.
ACK is not sent from forced interface and connection is not established. (And goto step 2.)
How to check where SYN,ACK or ACK is rejected by our system? And how correctly force TCP socket to make connection using specific interface (against routing table)?
Maybe there are some other, more convenient ways to create TCP connection on desired interface?
Thanks!
I know it wouldn't be your quite answer, but you could disable other interfaces and just enable the network you want, in your case it seems that you need all the interfaces, but I think this approach could help others. you could enable/disable network interface with something like this :
enable
ifr.ifr_flags = true;
strcpy(ifr.ifr_name, "eth0"); //you could put any interface name beside "eth0"
res = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
and for disable you just need to set flag to false and the rest of the code is the same :
ifr.ifr_flags = true;
Don't use SO_BINDTODEVICE. Its not supported on all platforms and there's an easier way.
Instead bind the socket to the local IP address on the correct network that you want to use to connect to the remote side.
Ie,
sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = 0; //Auto-determine port.
sin.sin_addr.s_addr = inet_addr("192.168.1.123"); //Your IP address on same network as peer you want to connect to
bind(sockfd, (sockaddr*)&sin, sizeof(sin));
Then call connect.
For the server side you'd do the same thing except specify a port instead of 0, then call listen instead of connect.
This is a problem with kernel configuration - on many distributions it is by default configured to reject incoming packets in this specific case.
I found the solution to this problem in this answer to another similar question:
To allow such traffic you have to set some variables on your machine (as root):
sysctl -w net.ipv4.conf.all.accept_local=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.your_nic.rp_filter=0
where your_nic is the network interface receiving the packet. Beware to change both net.ipv4.conf.all.rp_filter and net.ipv4.conf.your_nic.rp_filter, it will not work otherwise (the kernel defaults to the most restrictive setting).