QHostAddress setAddress not working - c++

I need to change my host IP Address on Linux app using Qt. I have readed documentation about QHostAddress and method setAddress in this class that say the following:
"Sets the IPv4 or IPv6 address specified by the string representation >specified by address (e.g. "127.0.0.1"). Returns true and sets the address >if the address was successfully parsed; otherwise returns false."
I know that it is possible using QProccess but I'm trying to use Qt-way in order to do that. I'm very confused becuase my app is not in running with root privileges so I find very difficult perform this action using Qt class directly. Then I try this:
QHostAddress hostAddress;
bool ipChange = hostAddress.setAddress("192.168.1.143");
if(ipChange) qDebug() << "IP ADDRESS CHANGED";
else qDebug() << "IP ADDRESS NOT CHANGED";
The result of this code is "IP ADDRESS CHANGED" but doing ifconfig in a terminal, my IP address has not been modified. So, my questions are:
How I can do that?
Why I can see IP ADDRESS CHANGED if this method obviously doesn't works?

You are changing the address stored in hostAddress. You can now use hostAddress to (e.g.) open a stream socket to a port on 192.168.1.143. This has no relation to any IP addresses of the host you happen to be running on - QHostAddress is just a representation of any IP address.
To set an address for a network interface on the host machine, you will need to be root, and to use the native facilities (or an external process - /sbin/ifconfig, for example).

Related

What are legal addresses for binding a QUdpSocket?

I tried to bind my socket to some random address 10.1.1.1:12001, and got QAbstractSocket::SocketAddressNotAvailableError.
Than i wrote a simple code:
for (int i = 0; i < 256; i++) {
QHostAddress address0(QString::number(i) + ".0.0.1");
quint16 port = 12101;
QUdpSocket* m_socket = new QUdpSocket();
if (m_socket->bind(address0, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
qDebug() << i;
}
}
Only to learn that IP must start with 127 or 224-239. So it must be Class D address.. But I just didn't find anything in the qt documentation.
Is it a normal behaviour? Is there a possibility to use a global net IP for binding? Or at least use 192.168.x.x as IP of another computer in LAN?
You are not allowed to bind the socket to an arbitrary network IP address. You can only do it with an IP address of one of your network devices or some special IP addresses like 0.0.0.0. By default you always have the 127.0.0.1 but surely you have another network address in your computer.
By the other way if you want to write/read some data over an UDP Socket It's not necessary to bind it to a network address, you can use writeDatagram() or readDatagram() methods of the QUdpSocket class

How to resolve the real broadcast address for a IPv4 address with Boost.Asio

Is there any possibility to obtain the "real local" broadcast address for a given IPv4 address with Boost.Asio?
ip::address_v4::netmask only returns the netmask based on the IPv4 address class, so it cannot be used reliably with the overload of ip::address_v4::broadcast.
I need to resolve a specific broadcast address for a given (existing) host IPv4 address on the local machine, since I have trouble using an UDP endpoint with a broadcast address of 255.255.255.255.
Edit: For clarification, I do not want to resolve a hostname to an IP address or vice versa.
Edit: Here is an example:
eth0:
host address: 192.168.0.1
net mask...: 255.255.0.0 (**not** class C)
So I want to retrieve the broadcast address 192.168.255.255, but the only input I want to specify is the local net address. Therefore "resolving" or "querying" is the correct term, since I do not want to calculate it.
I have a UDPv4 server, which I bind to a specific local endpoint (by specifying the local IPv4 host address). I want to use this server in both unicast mode and broadcast mode, so I need to specify the remote endpoint as well. I am unable to do this with the "global broadcast" address returned by ip::address_v4::broadcast, because that always returns 255.255.255.255 which leads to undesired behaviour. In addition to the host address I specify a flag to correctly set the socket option to enable broadcasting via basic_datagram_socket::broadcast.
If you have an example how-to achieve this, I would be grateful. Maybe I am thinking too complicated...
I think indeed the boost::asio::ip::address_v4::broadcast overloads are what you are after:
#include <boost/asio.hpp>
#include <iostream>
using boost::asio::ip::tcp;
int main() {
typedef boost::asio::ip::address_v4 A;
A address = A::from_string("192.168.0.1");
std::cout << "Address " << address << " has broadcast address " << A::broadcast(address, A::from_string("255.255.0.0")) << "\n";
}
Prints:
Address 192.168.0.1 has broadcast address 192.168.255.255
See it Live On Coliru
Note Note: if the confusion is from 192.168.0.1 being classified as Class C, this is by design.
IANA defines the 16-bit block 192.168.0.0/16 as "256 contiguous class C networks" (look at the Classful description here The footnote is enlightening, and the Asio implementation matches it).

Qt - Get hostname & MAC address from IP Adreess

In my application I want to get the hostname & MAC address from an IP address (in my LAN).
I used this code to find the hostname, but nothing appeared in lineedit.
QHostInfo HI;
QHostAddress HA("192.168.1.1");
QList<QHostAddress> List;
List.append(HA);
HI.setAddresses(List);
ui->ledHostname->setText(HI.hostName());
To retrieve the Hostname from an IP address you can call lookupHost(), which takes the host name or IP address, a receiver object, and a slot signature as arguments. The slot is invoked when the results are ready. The results are stored in a QHostInfo object. Call addresses() to get the list of IP addresses for the host, and hostName() to get the host name that was looked up.
QHostInfo::lookupHost("92.168.1.1",
this, SLOT(lookedUp(QHostInfo)));
void MyWidget::lookedUp(const QHostInfo &host)
{
if (host.error() != QHostInfo::NoError) {
qDebug() << "Lookup failed:" << host.errorString();
return;
}
foreach (const QHostAddress &address, host.addresses())
qDebug() << "Found address:" << address.toString();
}
For obtaining the MAC address of a remote IP you should use system commands and platform-specific code. There is no way in Qt to do that. For example on Windows it can be done by:
arp -a <IP>
I used this code:
QHostInfo HI = QHostInfo::fromName("192.168.1.50");
ui->ledHostname->setText(HI.hostName());
Worked for some ip addresses & shows the host name! For other ip addresses shows the ip address again.
For my MAC problem, I`m using ARP packet.

How to get local IP address of a computer using QT [duplicate]

This question already has answers here:
Get local IP address in Qt
(6 answers)
Closed 8 years ago.
I am trying to get the local ip address (IPV4) of a computer in QT.
I found the following code:
QNetworkInterface *inter = new QNetworkInterface();
QList<QHostAddress> list;
list=inter->allAddresses();
QString str;
for (int i = 0; i < list.size(); ++i) {
str = list.at(i).toString();
}
Going through for loop I can see there are a number of values (ip's) in the list, one of them is the actual local ip address that I get by typing ipconfig in a command window.
My question is how to distinguish the ip address from all the ip's that are in list?
PCs often have more than one IP address. There's not really such a thing as "the" local IP address; the IP address which would be used when connecting to some remote host depends at least on the local routing table (which may change drastically at any time, e.g. when starting/stopping VPN software).
It seems to me that it makes more sense to think about IPs as valid only in the context of remote networks, e.g. "this is the local IP address I'd use if I were to connect to this host on the Internet; but this is the local IP address I'd use to connect to this host over my company's VPN".
If you want to find out the local IP address which would be used for general-purpose Internet connectivity, the most accurate way I know is simply to do a connection test to a representative host (and a host with high reliability!)
QTcpSocket socket;
socket.connectToHost("8.8.8.8", 53); // google DNS, or something else reliable
if (socket.waitForConnected()) {
qDebug()
<< "local IPv4 address for Internet connectivity is"
<< socket.localAddress();
} else {
qWarning()
<< "could not determine local IPv4 address:"
<< socket.errorString();
}
Note: the above example is blocking, you probably want to rewrite it to use signals and slots if your app has a UI.
I think, several attempts should be tried for increasing the chance of the GUESS (Regardless how clever the software is, it would be still a guess, which won't cover 1% of configurations which will be possibly you case :-)
I've combined and extended both solutions. First I'd check for google DNS, and then for local IPs having a standard gateway. The assumption is: Getaway has the same mask with the addreess ending with ".1". I couldn't find out, how to obtain std. gateway in Qt (which would be more reliable).
Here is the code which works ON MY COMPUTERS:
QTcpSocket dnsTestSocket;
QString localIP="127.0.0.1"; //fall back
QString googleDns = "8.8.8.83"; //try google DNS or sth. else reliable first
dnsTestSocket.connectToHost(googleDns, 53);
if (dnsTestSocket.waitForConnected(3000))
{
localIP = dnsTestSocket.localAddress().toString();
}
else
{
foreach (const QHostAddress &address, QNetworkInterface::allAddresses())
{
QString guessedGatewayAddress = address.toString().section( ".",0,2 ) + ".1";
if (address.protocol() == QAbstractSocket::IPv4Protocol
&& address != QHostAddress(QHostAddress::LocalHost)
)
{
dnsTestSocket.connectToHost(guessedGatewayAddress, 53);
if (dnsTestSocket.waitForConnected(3000))
{
localIP = dnsTestSocket.localAddress().toString();
break;
}
}
}
}

How to get Current System IP in C under Windows XP [duplicate]

For a communication between two hosts, I need to send the IP address of my host to the other site. The problem is that if I request my IP address, it might be that I get back my local loopback IP addres (127.x.x.x) , not the network (ethernet) IP address.
I use the following code:
char myhostname[32];
gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);
if( (my_ip % 256) == 127) {
/* Wrong IP adress as it's 127.x.x.x */
printf("Error, local IP address!");
return;
}
The only way to solve it is to make sure my hostname in /etc/hosts is behind the real network address, not the local loopback (the default for e.g. Ubuntu).
Is there a way to solve this without relying on the content of /etc/hosts?
Edit: I changed the above code so it makes use of getaddrinfo, but I still get back the loopback device's number (127.0,0,1) instead of the real IP address:
struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;
hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;
if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip = *(unsigned *) &sinp->sin_addr;
(I used to get back a list of 3 addrinfo's with the three SOCK_STREAM,SOCK_DGRAM and SOCK_RAW, but the hint prevents that)
So my question still stands...
There is POSIX function getaddrinfo() that returns linked list of addresses for given hostname, so you just need to go through that list and find non-loopback address.
See man getaddrinfo.
Not an answer, but a relevant comment: be aware that as soon as you start sending addressing information in the content of packets, you run the risk of making your application unable to work across NAT:ing routers and/or through firewalls.
These technologies rely on the information in IP packet headers to keep track of the traffic, and if applications exchange addressing information inside packets, where they remain invisible to this inspection, they might break.
Of course, this might be totally irrelevant to your application, but I thought it worth pointing out in this context.
The originating address will be included in the packet sent... there's no need to duplicate this information. It's obtained when accepting the communication from the remote host (see beej's guide to networking, specifically the part on accept())
I just ran into a situation where when only /etc/hosts has information in it and when I used getaddrinfo to get the IP address list, it returned 127.0.0.1 each time. As it turned out, the hostname was aliased to localhost...something often easy to overlook. Here's what happened:
The /etc/hosts file:
127.0.0.1 localhost.localdomain localhost foo
::1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 bie
172.16.1.250 bletch
So, now, when you call getaddrinfo with host="foo", it returns 127.0.0.1 3 times. The error here, is that foo appears both on the line with "127.0.0.1" and "172.16.1.248". Once I removed foo from the line with "127.0.0.1" things worked fine.
Hope this helps someone.
Look at this:
Discovering public IP programmatically
Note that in some cases a computer can have more than one non-loopback IP address, and in that case the answers to that question tell you how to get the one that is exposed to the internet.
Even if the computer has only one physical network interface (an assumption that may or may not hold, even netbooks have two - ethernet and WLAN), VPNs can add even more IP adresses. Anyway, the host on the other side should be able to determine the IP your host used to contact it.
Use getaddrinfo()
You're almost there. I'm not sure how you're getting my_ip from hp.
gethostbyname() returns a pointer to a hostent structure which has an h_addr_list field.
The h_addr_list field is a null-terminated list of all the ip addresses bound to that host.
I think you're getting the loopback address because it's the first entry in h_addr_list.
EDIT: It should work something like this:
gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);
for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
// hp->addr_list[i] is a non-loopback address
}
}
// no address found
If /etc/hosts is still there and still the same, looking for all entries of h_addr_list won't help.
Your new code hardwires the use of IPv4 (in the hint.ai_family field) which is a terrible idea.
Apart from that, you're close, you just should loop through the results of getaddrinfo. Your code just gets the first IP address but there is an aip->ai_next field to follow...
struct addrinfo {
...
struct addrinfo *ai_next; /* next structure in linked list */
};