I'm trying to use raw sockets and ICMPv6 to read router advertisement messages on Windows. Through Wireshark, I can see the router (a Cisco 877) sending these messages about every 200 seconds, but my application never receives them.
My code takes the following steps:
1) Create an IPv6 raw socket using ICMPv6 protocol
2) Bind the socket to the IPv6 unspecified address (::)
3) Join the link-local all nodes multicast group at FF02::1
4) Receive router advertisements (... or not :))
The code works fine if I join FF02::16...
I've tried setting other socket options like hop limits, multicast hops, to no avail. Any ideas would be welcome, as I am out of them.
#include "stdlib.h"
#include "winsock2.h"
#include "Ws2tcpip.h"
#pragma comment(lib, "ws2_32.lib")
void
main (int argc,char **argv)
{
WSADATA wsaData;
SOCKET nSocket;
struct sockaddr_in6 sockinfo;
struct ipv6_mreq mreq;
char strBuffer[1024];
int nBytes;
WSAStartup (MAKEWORD (2,2),&wsaData);
// Create a raw socket talking ICMPv6
if ((nSocket = socket (AF_INET6,SOCK_RAW,IPPROTO_ICMPV6)) == SOCKET_ERROR)
return;
// Bind to ::
::memset (&sockinfo,0,sizeof (sockinfo));
sockinfo.sin6_family = AF_INET6;
inet_pton (AF_INET6,"::",&sockinfo.sin6_addr);
if (bind (nSocket,(struct sockaddr *) &sockinfo,sizeof (sockinfo)) < 0)
return;
// Join the link-local all nodes multicast group
inet_pton (AF_INET6,"FF02::1",&mreq.ipv6mr_multiaddr);
mreq.ipv6mr_interface = 0;
if (setsockopt (nSocket,IPPROTO_IPV6,IPV6_ADD_MEMBERSHIP,(char *) &mreq,sizeof (mreq)) < 0)
return;
// Wait for advertisements
for (;;)
nBytes = ::recvfrom (nSocket,strBuffer,sizeof (strBuffer),0,NULL,0);
closesocket (nSocket);
WSACleanup ();
}
It works on FF02::16 because that is what Cisco uses for its broadcasting. See this discussion on Cisco's forums for more details:
IPv6 address FF02::16 Significance
Related
I have a server and when a client connects to the server, I want to take all the information from the client and make a struct with it.
What information can I get?
I know that I can get the ipv4 and port from the client, there is anything left that I can get?
This is a short way of doing it:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT 32406
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
sockaddr_in hint;
hint.sin_addr.S_un.S_addr = INADDR_ANY;
hint.sin_port = htons(DEFAULT_PORT);
hint.sin_family = AF_INET;
SOCKET listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
bind(listeningSocket, (sockaddr*)&hint, sizeof(sockaddr_in));
listen(listeningSocket, SOMAXCONN);
sockaddr_in socketInfo;
int socketInfoLen = sizeof(socketInfo);
SOCKET clientSocket = accept(listeningSocket, (sockaddr*)&socketInfo, &socketInfoLen);
std::cout << inet_ntoa(socketInfo.sin_addr) << std::endl;
std::cout << socketInfo.sin_port << std::endl;
shutdown(clientSocket, SD_BOTH);
closesocket(clientSocket);
closesocket(listeningSocket);
WSACleanup();
return 0;
}
There is a whole lot of information available from getsockopt. It is a superset of what the other answer claims, for example
SO_BSP_STATE Returns the local address, local port, remote address, remote port, socket type, and protocol used by a socket.
Since you have a TCP socket you will be particularly interested in
IPPROTO_TCP socket options
There is different information available through WSAIoctl, for example
TCP_INFO_v1 structure
Some of these details will be local socket options (such as blocking or non-blocking), others will relate to the connection itself (e.g. negotiated window size). Some information about the remote client will be revealed, although not as much as if you used a bespoke fingerprinting tool.
Here is the implementation of #Ben Voigt's answer, if someone needs it:
#include <WinSock2.h>
#pragma comment (lib, "Ws2_32.lib")
bool GetSocketState(SOCKET sock, CSADDR_INFO& state) {
union CSADDR_INFO_PADDED {
CSADDR_INFO csaddr;
TCHAR padding[128];
} csaddrPadded {};
int infoLen = sizeof(csaddrPadded);
if (getsockopt(sock, SOL_SOCKET, SO_BSP_STATE, (TCHAR*)&csaddrPadded, &infoLen)) {
return false;
}
state = csaddrPadded.csaddr;
return true;
}
The only information you get that the client doesn't explicitly send is the sockaddr_in structure, ie the port and source IP address. Though of course you only get this when the client initiates a transfer (sends a packet with UDP or connects with TCP).
To get anything else, the client needs to send it as part of regular communication.
I'm having issues working with a UDP socket in Windows. I have a separate application I'm trying to communicate with that outputs on port 1625 and receives on port 26027. I tried to make a simple executable that reads one message and sends one message. The read works fine, but the send ends up with a WSAEADDRNOTAVAIL (10049) error.
To troubleshoot I also tried the equivalent code in Linux with (using Windows Subsystem for Linux) on the same machine and it works fine. So I can't figure out what the issue is. I also tried disabling Windows Firewall but that didn't make a difference. Any suggestions would be appreciated.
The Windows Visual C++ code:
#pragma comment(lib, "Ws2_32.lib")
#include <iostream>
#include <WS2tcpip.h>
#define MAXLINE 1024
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// Define local port address.
sockaddr_in local_port;
memset(&local_port, 0, sizeof(local_port));
local_port.sin_family = AF_INET;
local_port.sin_addr.s_addr = INADDR_ANY;
local_port.sin_port = htons(1625);
// Bind local socket.
int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));
// Receive UDP Port message.
char in_buffer[MAXLINE];
int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
in_buffer[num_bytes] = '\0';
printf("Received : %s\n", in_buffer);
// Set up send destination port.
sockaddr_in dest_port;
memset(&dest_port, 0, sizeof(dest_port));
dest_port.sin_family = AF_INET;
dest_port.sin_addr.s_addr = INADDR_ANY;
dest_port.sin_port = htons(26027);
// Send UDP message to specific UDP port.
char out_buffer[] = "Test message";
int result = sendto(
socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *)&dest_port, sizeof(dest_port));
printf("Send result : %d -- WSA Error : %d\n", result, WSAGetLastError());
closesocket(socket_id);
return 0;
}
Terminal output from running this executable is:
Received : 5e4009df*755=-0.0028:761=0.6942
Send result : -1 -- WSA Error : 10049
The WSL linux C++ code (the same source code except for WSA includes and error output):
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAXLINE 1024
int main()
{
// Define local port address.
sockaddr_in local_port;
memset(&local_port, 0, sizeof(local_port));
local_port.sin_family = AF_INET;
local_port.sin_addr.s_addr = INADDR_ANY;
local_port.sin_port = htons(1625);
// Bind local socket.
int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));
// Receive UDP Port message.
char in_buffer[MAXLINE];
int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
in_buffer[num_bytes] = '\0';
printf("Received : %s\n", in_buffer);
// Set up send destination port.
sockaddr_in dest_port;
memset(&dest_port, 0, sizeof(dest_port));
dest_port.sin_family = AF_INET;
dest_port.sin_addr.s_addr = INADDR_ANY;
dest_port.sin_port = htons(26027);
// Send UDP message to specific UDP port.
char out_buffer[] = "Test message";
int result = sendto(
socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *) &dest_port, sizeof(dest_port));
printf("Send result : %d\n", result);
close(socket_id);
return 0;
}
Terminal output from running this executable is:
Received : 5e4009df*755=-0.0028:761=0.6942
Send result : 12
I can also validate that the output to port 26027 via this Linux implementation is received by the other application and can also see it in Wireshark.
EDIT:
After Remy's answer below I was able to get this working as per the comments below. To clarify my network:
My network if I view it with Wireshark now looks like:
127.0.0.1 UDP 50223 → 1625 Len=32
127.0.0.1 UDP 1625 → 26027 Len=12
Where my node binds to 1625 where it can recv() UDP from some unknown port number (50223 in this case), and sendto() port 26027.
You can't use recv() with a UDP socket unless you first call connect() to statically assign the peer's IP/port to the socket, which you are not doing. So recv() will fail, but you are not checking for that. You need to use recvfrom() instead.
Also, no matter what, you can't send packets to INADDR_ANY (0.0.0.0) as you are. That is why you are getting the send error.
sendto Function
WSAEADDRNOTAVAIL
The remote address is not a valid address, for example, ADDR_ANY.
Windows Sockets Error Codes
WSAEADDRNOTAVAIL
10049
Cannot assign requested address. The requested address is not valid in its context. This normally results from an attempt to bind to an address that is not valid for the local computer. This can also result from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the remote address or port is not valid for a remote computer (for example, address or port 0).
You need to send to an actual IP/port, such as to the peer's IP/port that is reported by recvfrom() when it receives a packet.
I'm trying to get a little SSDP client / server up and running. So far the server is working just fine, responding to my M-SEARCH (according to wireshark). The client code is written in Visual Studio using Winsock2 (see code below). The problem is that the response never reaches my recv call when i send the search to the multicast address.
I already tried sending and receiving directly to the server ip address, which will generate a response that reaches my recv call correctly. However, when i change the ip to the multicast addess, it doesn't work (even though i can see the response on Wireshark!). So for some reason the socket (on OS level?) refuses to pass it on to the application.
I should note that the response is always unicast.
Here's my code:
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define SERVERPORT 1900
char buff[] = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: ssdp:discover\r\nST: ssdp:all\r\n\r\n";
int main()
{
char rcvdbuff[1000];
int len, Ret = 2;
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
perror("WSAStartup");
return 1;
}
struct sockaddr_in their_addr;
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
their_addr.sin_family = AF_INET;
////THIS APPROACH DOES NOT WORK
their_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
//THIS APPROACH WORKS - SOMEHOW THE SOCKET IS BOUND TO THIS IP AND CAN THUS RECEIVE
//their_addr.sin_addr.s_addr = inet_addr("192.168.3.90");
their_addr.sin_port = htons(SERVERPORT);
len = sizeof(struct sockaddr_in);
while (1)
{
printf("buff:\n%s\n", buff);
Ret = sendto(sock, buff, strlen(buff), 0, (struct sockaddr*)&their_addr, len);
if (Ret < 0)
{
printf("error in SENDTO() function");
closesocket(sock);
return 0;
}
//Receiving Text from server
printf("\n\nwaiting to recv:\n");
memset(rcvdbuff, 0, sizeof(rcvdbuff));
Ret = recvfrom(sock, rcvdbuff, sizeof(rcvdbuff), 0, (struct sockaddr *)&their_addr, &len);
if (Ret < 0)
{
printf("Error in Receiving");
return 0;
}
rcvdbuff[Ret - 1] = '\0';
printf("RECEIVED MESSAGE FROM SERVER\t: %s\n", rcvdbuff);
//Delay for testing purpose
Sleep(3 * 1000);
}
closesocket(sock);
WSACleanup();
}
I tried one interesting thing (without restarting the application!):
1) First send to the direct ip address (192.168.3.90)
2) Get response
3) Now send to the multicast address
4) Now the response gets back just fine!
It's as if the socket somehow 'knows' the unicast address from the first send/recv call.
Does anyone know what to do or how to debug?
I think I've found the solution to the question: Windows Firewall.
Here's a quote over from Quora:
Only connections that are explicitly allowed, using firewall rules, are permitted. Windows Firewall, by default, allows all outboundconnections, and permits only established inbound connections (that is, an inbound connection that is in direct response to an outbound connection initiated from your computer or network).
This is exactly the situation: We've not established an outbound connection, and thus it's blocked by Windows Firewall!
In the other case, when I first send directly, Windows Firewall opens up for that exact inbound connection and therefore the subsequent multicast send gets a response.
I'm attempting to use a simple HTTP server written in C that makes use of UNIX BSD sockets. I've got it working somewhat but am having the following issues.
The server only prints "hello world!" on Linux browsers and not on windows browsers; i.e., I can make use of Chrome / Firefox on Linux and see the text in the browser, but not on a Windows machine in the same browsers.
Rather then sending "hello world" with all of the response headers and closing the connection like a normal web page, what I'm seeing is that when I test the server page (localhost:xxxx) I am presented with the text and HTTP responses in the code but the page is in a continuous load (tab keeps spinning). Then the moment I turn the server off the page returns "failed to connect to server".
My question is, given the below code, why does this not display out to browsers on Windows and why does it not close the connection whilst leaving the client with the information sent?
This uses simple BSD sockets.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> //definitions for system variables
#include <sys/socket.h> //definitions / structures for sockets
#include <netinet/in.h> //const's and structures used by internet domain
void error(const char *msg) //takes litteral msg passed in and prints, then exits.
{
perror(msg); //man perror
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, // socket file descriptor 1. both return values from system
newsockfd, // socket file descriptor 2
portno; // port number to associate with this socket
socklen_t clilen; //stored address size of each client
char buffer[256]; //stores chars from socket buffer
struct sockaddr_in serv_addr, cli_addr;
/*sockaddr_in, structure containing an internet address. most of the magic DEFINED BELOW
struct sockaddr_in
{
short sin_family; /* must be AF_INET
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8]; /* Not used, must be zero
};
*/
int n; //stores return values of read() / write() system calls)
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
} //self explanitory
/*socket() creates a new socket and takes 3 arguments, the first being the address domain of the socket
* Sockets in this case can use two types of domains which are both system constants
* AF_UNIX - Used for parent child prc's on the same machine
* AF_INET - Used for host to host communication, Ie internet communication
*
* The second option SOCKET_STREAM is the type of stream/communication used in the socket. ie TCP/UDP, Being
* SOCK_STREAM - TCP - A continuous stream/connection during the life span of the sockets communication
* SOCK_DGRAM - UDP - A connectionless strea/connection which uses less resources/is faster but possible byte loss
*
* The third option is the protocol used, due to specifying the type of stream this is almost always left to 0
* Leaving the arg at 0 implies that the operating system will make the best call and due to setting the stream it will
* more then likely choose to use the requested method
*
* This socket() in general returns a value for the subsequent descriptor for reference. If on failure, the socket()
* will return -1 and fail hence if(sockfd<0){}
*
* man socket() for information Andrew,
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/*bzero() sets all values in buffer to 0(00000000)*/
bzero(
(char *) &serv_addr,
sizeof(serv_addr)
); //Deref &serv_addr, and ensures to 0 out all bytes in buffer(entire struct)
portno = atoi(argv[1]);//port number to be used for communication,
serv_addr.sin_family = AF_INET; //set to internet. sin_family is stored in sockadr_in structure
serv_addr.sin_addr.s_addr = INADDR_ANY; //structure in structure. s_addr holds the host address. IN_ADDR is always the systems ip
serv_addr.sin_port = htons(portno); //convert to network byte order. Holds th eport number, places into readable format
/*
* checks and binds to new file descripter, socketaddr(deref) and allocates the size of the address bound to.
* If less then zero. it will fail(-1)
*/
if (bind(sockfd,
(struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5); // listens on bound socket/descriptor and allows up to 5 connections to be waiting in queue(max allowed on system
clilen = sizeof(cli_addr); // assigns value based on size of bytes in clients address
newsockfd = accept(sockfd, // new descripter to use when accepting a client
(struct sockaddr *) &cli_addr, //gathers client connection information for arg(deref)
&clilen); // Passes in clilen, for lenght of client address. not a copy, the real shiz
if (newsockfd < 0)
error("ERROR on accept"); // again, don't be a fucking dick.
bzero(buffer,256); // ensure buffer is not tampered at this point or gross
n = read(newsockfd,buffer,255); // use sys-call read() to store data in buffer from client. use 255bytes or client input
// which ever is less.
if (n < 0) error("ERROR reading from socket"); // if failed as fuck, let's cry
n = write(newsockfd,"HTTP/1.0 200 OK\n",16); // Write back to client. to bound socket from client. they see this shit.
n = write(newsockfd,"Connection: Keep-alive\n",23);
n = write(newsockfd,"Connection: close\n",18);
n = write(newsockfd,"Content-type: text/html; charset=UTF-8\n",39);
n = write(newsockfd,"\n",1);
n = write(newsockfd,"<!DOCTYPE HTML>\n<html><head><title>Hello World!</title></head>\n",62);
n = write(newsockfd,"<body><h1>Hello World!</h1>\n",28);
n = write(newsockfd,"</body></html>\n",15);
if (n < 0) error("ERROR writing to socket"); // duh
// cleaning up...
//close(newsockfd);
// close(sockfd);
getchar();
return 0;
}
There are lots of things wrong with your code. The main problem you probably have is that you are not telling the client when the end of the response body is reached, so that the client does not know that the body is done and thus will try to read more data forever and not display what it already has. The usual ways are specifying a Content-Length, using chunked transfer encoding (HTTP/1.1+ only), or closing the socket after the body is done. See RFC 2616 Section 4.4 "Message Length" for specific details.
Apart from that (some of the things are already pointed out by EJP in the comments):
wrong line endings, e.g. LF instead of CR LF
conflicting information in the Connection header
you don't properly read the request, but just assume it will be in the first packet and no longer than 255 byte
no proper error checking: write() is not guaranteed to write the whole buffer
I obtained the response codes based on website requests through inspect header information
Please don't do an implementation by only looking at a few samples of traffic without even understanding them properly. There are already enough broken HTTP servers out there and enough clients which work around these servers and all this is causing lots of trouble. Usually these servers are also only tested against a few selected clients and then the trouble starts once this kind of servers are rolled out and then surprisingly break with other clients. Please read the actual HTTP specification and write your server to conform to it.
I'm using winsocks and I am coding an IDS/Honeypot, this is just a small section of it, because at the moment I want the server to listen on multiple sockets (7) and accept the connections, but I've tried to dynamically create the sockets with an array (and the listener etc) but I am still having trouble - I've tried it multiple ways but so far, all I've managed to do is get it working successfully on ONE socket, and LISTEN to all sockets, but not accept them.
So, this was my last attempt but not sure, maybe I need to use threads or declare the sockets differently?
So far, in this small test code, I want:
Initialize server
listen on all 7 ports (1111,2222 ...etc)
Accept an incoming connection on ANY of them
display both messages on client/server
drop the connection
and continue
It's a little sloppy I know, but here is the code so far and I think you can see where I am going with it:
#include <iostream>
#include <winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
int main()
{
std::cout<<"Honeypot server [test #1] by Dreamwalker"<<std::endl;
WSADATA wsa;
SOCKET s[7] , new_socket[7];
struct sockaddr_in server , client;
int c, port[7] = {1111,2222,3333,4444,5555,6666,7777};
char *message;
std::cout<<"\nInitialising Winsock and other components...";
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
std::cout<<"Failed. Error Code :"<<WSAGetLastError()<<std::endl;
return 1;
}
//!IMPORTANT: create multiple new sockets on different ports
int i = 0;
for( i = 0; i < 7; i++)
{
//Create socket
if((s[i] = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std::cout<<"Could not create socket : "<< WSAGetLastError()<<std::endl;
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port[i] );
//Bind
if( bind(s[i] ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
std::cout<<"Bind failed with error code : "<< WSAGetLastError()<<std::endl;
}
/*!ALL CREATION CHECKING DONE, now create multiple sockets on the server
and listen for connections*/
c = sizeof(struct sockaddr_in);
listen(s[i] , SOMAXCONN);
}
///ALL INITIALIZED
std::cout<<"DONE!"<<std::endl;
//Listen/accept incoming connections
std::cout<<"Now listening for connections"<<std::endl;
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
if (new_socket[i] == INVALID_SOCKET)
{
std::cout<<"accept failed with error code : "<< WSAGetLastError()<<std::endl;
}
//Accepted connection
else{
std::cout<<"Someone has connected to this machine!"<<std::endl;
message = "Hello Client , I have received your connection.\n";
send(new_socket[i] , message , strlen(message) , 0);
closesocket(s[i]);
}
std::cout<<"FINISHED"<<std::endl;
WSACleanup();
getchar();
return 0;
}
And now it's throwing a runtime error as well:
WSAENOTSOCK
10038
Socket operation on nonsocket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket,
or for select, a member of an fd_set was not valid.
Which (including debugging) indicates that the socket isn't declared properly when creating on an array, advice?
You code to create/bind/listen is all good. Then:
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
Firstly, by the time this runs you're outside the loop, and i is 7 which is past the end of the array of sockets, which is why you get the not-a-socket error.
Secondly, accept() is a blocking call, so you can't just call accept() on all the sockets from the same thread the way you did for listen. You need to either have a separate thread block in accept() for each of the ports, or find out which one has a client connection attempt in progress using e.g. select (or epoll - does Windows have that?), then accept() a client on that specific socket (but then you've still got to either create a thread to handle the client read/recvs and write/sends or use select/epoll to find out when there's input ready to read, or more space in output buffers for transmission). There's also a race condition to be wary of if you use select/epoll - a listening socket might signal readiness for accepting a client connection, but by the time you call accept() that connection attempt's failed and forgotten, then if the listening socket hasn't been set to non-blocking mode it'll hang there waiting for another client to connect to that specific socket. IMHO, this is a case where threading is actually easier.
I think it's more "Windowsy" to use IO Completion Ports (you might want to Google), but AFAIK they're totally unportable. Winsock's not an exact match for BSD sockets, but the porting or dual-support effort's small.