weird about send udp packet to local lan - c++

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.

Related

How to configure Socket to be able to send datagrams via LAN and WLAN?

I wrote an C++ Windows application to send datagrams.
Transferring datagrams are via LAN works as it should.
When I switch to WLAN, no datagrams are transferred.
My understanding is, that the Windows is handling the data transmission, dependent on which connection is established. -> WiFi oder Cable.
My socket configuration is:
WSAStartup(MAKEWORD(2, 2), &m_wsaData);
...
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
...
setsockopt(m_SendSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptval, sizeof(iOptval));
...
bind(m_SendSocket, (SOCKADDR*)&RecvAddr, sizeof(RecvAddr));
...
How to configure or use other API to be able to send datagrams via LAN and WLAN?
Thank you

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 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.

upnp discovery of Philips hue from openWRT router

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

How do i check the data sent to the IP Address on particular port?

I am sending data to the IP address 127.0.0.1 on port number 5152. Through socket programming i am sending the data ("Hello world") . I am receiving a acknowledgement as sent 51 Bytes. But how do i know the data received is correct or not in the above IP address.
I have created a server application , and i am using a same IP and port number here.
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
//
if (bInterface)
{
local.sin_addr.s_addr = inet_addr(szAddress);
if (local.sin_addr.s_addr == INADDR_NONE)
usage();
}
else
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);
if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
Bind fails with 10048 error.
Depend on what you're connecting to. If it's your application, the fact that the socket opens proves that you already have a listening socket : just display what it receives (or configure the traces on the server to display it).
Another idea when dealing with network development is to monitor actual network traffic using wireshark.
You sent your data - now you need to receive it !
You'll need to create a server that listens on port 5152 on the same box and have it display what it receives from your client.
Your error is "address already in use". That means some other program has the port open.
You can see a list of programs listening using "netstat" at the command line. Perhaps that
will help you figure it out.
Wireshark is a handy application to see what's being sent via the network. Very handy for debugging these kinds of programs.