upnp discovery of Philips hue from openWRT router - c++

I am getting response from hue when I send the following packet from my PC.
sprintf(wrbuf,"%s","M-SEARCH* HTTP/1.0\r\n HOST: 239.255.255.250:1900\r\n MAN: \"ssdp:discover\"\r\n MX: 4\r\n ST: libhue:idl\r\n\r\n");
sendto(sd,&wrbuf,sizeof(wrbuf),0,(struct sockaddr *)&serv,(socklen_t)len);
the response is as below.
recived: HTTP/1.1 200 OK
CACHE-CONTROL: max-age=100
EXT:
LOCATION: "ipofhue:80/description.xml"
SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1
ST: upnp:rootdevice
USN: uuid:2f402f80-da50-11e1-9b23-0017880a6643::upnp:rootdevice
though if send the same packet from my openWRT router, I am not getting any response from hue.
my PC IP is 10.10.10.130, hue IP is 10.10.10.109 & my router br-lan IP is 10.10.10.254.
I don't think I need to run miniupnpd from my router, because if I run it starts responding from router, I just need reply from upnp server which is running on hue hub which is I am not getting.
openwrt tool chain donot allow the M-SEARCH packet to reach wan port.it just ignore the the packet .kernel log says The IGMP message was from myself. Ignoring. Feb 4 06:18:55 user.info sysinit: The source address 172.22.xx.xx for group 239.255.255.250, is not in any valid net for upstream VIF. –

It sounds like to me that the packet is being over the Internet instead of the local LAN. I think you need to specifically bind to the BR-LAN IP before calling sendto(). For example:
int sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sin = {};
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("10.10.10.254");
sin.sin_port = 0;
bind(sd, (struct sockaddr *)&sin, sizeof(sin));

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.

Can I use the same sockaddr_in in TCP and UDP?

In my serveur, I bind the TCP and UDP on two different ports.
I first connect my Client with TCP (via accept, etc)
Then I want to use UDP to communicate between my server and my client.
So I tried to use the same sockaddr_in like that :
void AUDPMonitor::sendMessage(Message &msg)
{
for (ISocket *socket: *_fdListClients)
{
if (msg.getClientId() == socket->getSock())
{
UDPSocket *UdpSocket = reinterpret_cast<UDPSocket *>(socket);
UdpSocket->send(msg, socket->getUserAddr());
break;
}
}
}
The _fdListClients is a vector of Socket I got from the TCP connexion.
There is no error messages but my client doesn't receive anything.
So I want to know if it's possible to use the same sockaddr_in or if it's impossible.
Edit : When I accept the client socket
socklen_t client_sin_len;
sockaddr_in *client_sin = new sockaddr_in;
client_sin_len = sizeof(sockaddr_in );
std::cout << "New User ! " << std::endl;
if ((cs = accept(fd, reinterpret_cast<struct sockaddr *>(client_sin), &client_sin_len)) == -1)
You can use the same copy of the sockaddr_in for TCP and UDP, but they have to be on different sockets.
A given socket created with AF_INET also specifies either SOCK_STREAM making TCP or SOCK_DGRAM making it UDP.
So if you have this:
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(12345);
You can pass this to bind with a TCP socket to bind to TCP/12345, and you can pass it to bind with a UDP socket to bind to UDP/12345.
you can use the same SOCAKADDR_IN structure for a TCP or UDP server or client but whenever you want to use it for a different one you should change the values of port and address because servers cannot be bound to the same port.
so if we have two remote stations running a TCP server and a UDP Server then the client to connect them:
SOCKET servTcp; // a remote bound and listing tcp socket waiting for remote clients through the blocking function `accept`
SOCKET servUdp; // a remote bound Udp server waiting for clients
// for the client:
SOCKET clientTcp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKET clientUdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKADDR_IN sa_serv;
sa_serv.sin_addr.S_un.S_addr = inet_addr("127.168.0.1");
sa_serv.sin_family = AF_INET;
sa_serv.sin_port = htons(777);
now the socket clientTcp can connect to the remote tcp server using this address structure.
to use the same SOCKADDR_IN structure sa_serv for the the udp server:
as long as the tpc and the udp servers on the same remote machine we only change the port:
sa_serv.sin_port = htons(1000); // the port is unique for servers to bind on.
now we the udp socket clientUdp can use use sa_serv to send and receive data from the remote udp serv.
SOCKADDR_IN is the same for udp and tcp just change the value of port and sometimes address if server.

How to find the ipaddress of a server which is used for accepting a client in c++?

I have to find the ipaddress of a machine in which my server program is running. Server is listening to all addresses(::0 - ipv6). Now I need to find the ip in which is accepting a client connection. I tried with getsockname(), but it is not working. It gives me an ip 0.0.0.0 even if i am using socket descriptor which accept() returns.
Code snippet:
addr_len = sizeof(addr);
addr.sin_family = AF_INET;
res = getsockname (client, (struct sockaddr *)&addr,(socklen_t*) &addr_len);
inet_ntop(AF_INET, &(addr.sin_addr), ip_str, INET_ADDRSTRLEN);
IPaddr = ip_str;
But if i replace ipv6 address(::0) with ipv4 counterpart(0.0.0.0), This code is working. Can anyone guide me to make this generic and work with both versions of ip address?

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.

weird about send udp packet to local lan

I'm using visual studio 2003 to write a simple program of communcation with local LAN via UDP socket. And I'm trying to not use MFC. The following is a small piece of code I used to test UDP socket:
static void sendMsg(char *buf, int len)
{
SOCKET sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
return;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr("192.168.2.108"); // Specify dest IP
sendto(sock, buf, len, 0, (struct sockaddr*)&addr, sizeof(addr));
closesocket(sock);
}
To verify if the packet is send out, I use wireshark to capture packet.
My PC's IP is 192.168.1.107. The strange is that if dest IP is a local IP like 192.168.1.108, I cannot capture the packet in wireshark. But if the dest IP is 192.168.1.1 (gateway) or 192.168.1.255(broadcast) or outside of LAN ip like 192.168.2.108, I can capture the UDP packet.
Who can explain this for me? Is there any wrong with my code?
If you're sending an UDP packet to an IP address that is not known by your machine, it will ask for the machine's MAC address first via the ARP protocol.
If it gets a response, it will send your packet to the MAC address it receives, if it cannot get a response about the MAC address, the UDP packet won't be sent at all.
192.168.1.1 is an existing machine (the default router) and everything outside your LAN will go through that existing default router, so you will see your UDP packets transmitted. If you try to send to a non existing IP on your LAN, you won't see any packet sent since ARP will fail before your packet is even transmitted.