One-way SOCK_STREAM - c++

We're creating a socket using SOCK_STREAM over AF_UNIX (a local file). We have many processes on the system which are clients, and we are only interested in broadcasting messages to those clients. OS is Ubuntu 14.04.5 LTS.
This all works if the file permissions are 666, however as a security measure we want to change it to 644. However, this causes a permission exception when clients try to connect using the below code:
int XyzClient::establish_connection() {
int fd;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
throw XyzException(strerror(errno));
}
sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, DEFAULT_SOCKET_PATH, sizeof(addr.sun_path)-1);
if (connect(fd, (sockaddr*)&addr, sizeof(addr)) == -1) {
// connect failed, close fd and throw exception
close(fd);
throw XyzException(strerror(errno));
}
return fd;
}
Presumably the issue is the above code tries to establish read-write access to the file and which is causing the permission error.
Is it possible to do a one-way SOCK_STREAM such that we can lock down the file to be read-only by everyone except the owner/broadcaster?

It is not possible to make a read-only unix domain socket and enforce this with file permissions. From the relevant man page unix(7)
On Linux, connecting to a stream socket object requires write permission on that socket; sending a datagram to a datagram socket likewise requires write permission on that socket. POSIX does not make any statement about the effect of the permissions on a socket file, and on some systems (e.g., older BSDs), the socket permissions are ignored. Portable programs should not rely on this feature for security.

Related

Sniffing raw sockets (SOCK_RAW) without Administrator account in windows

I am creating a simple sniffer using c++ under visual studio , and windows 10 x64 , but when I tried to run it. I got Failed to create raw socket. which is because admin rights , but I was reaching on internet . I could use something like CAP_NET_ADMIN , but it is linux based . is there a way to do under windows such as wireshark non-root users works?
//Initialise Winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("WSAStartup() failed.\n");
return 1;
}
printf("Initialised");
//Create a RAW Socket
printf("\nCreating RAW Socket...");
sniffer = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
if (sniffer == INVALID_SOCKET)
{
printf("Failed to create raw socket.\n");
return 1;
}
printf("Created.");
Creating a Raw Socket:
Raw sockets offer the capability to manipulate the underlying
transport, so they can be used for malicious purposes that pose a
security threat. Therefore, only members of the Administrators group
can create sockets of type SOCK_RAW on Windows 2000 and later.
If anyone is getting this with Wine, you need to allow the wineserver to use Ping.SendPrivileged:
sudo setcap CAP_NET_RAW=ep /usr/bin/wine
sudo setcap CAP_NET_RAW=ep /usr/bin/wineserver
sudo setcap CAP_NET_RAW=ep YOUREXE.exe

client socket is bindable but not connectable, because already in use

I write a client, where i have to bind the client socket. This works fine. After that i try to connect the Socket and i get error 10048. (Address already in use.) I don't understand how this is possible.
I have to implement a client speaking with multiple server. Every server only accepts messages from a specific port. (every Server expects a different port). so i have to bind my client socket. The code above is to create one of these sockets.
My code works some times. But very often the connect gives me the error 10048, while the binding before was fine. I know that bind can give also the error 10048 if the socket is already in use. But it doesn't. It returns 0. So i guess the port is free. Immediate after binding i call connect and get error 10048. I do not understand why? At the moment of the binding the port was obviously free.
bool TEthernetSocket::Open()
{
WSADATA wsaData;
if (WSAStartup((MAKEWORD(2, 0)), &wsaData) == SOCKET_ERROR)
{
return IsConnected();
}
Socket = socket(AF_INET, SOCK_STREAM, 0); // TCP
if (Socket == INVALID_SOCKET)
{
return false;
}
//bind Socket
struct sockaddr_in sa_loc;
memset(&sa_loc, 0, sizeof(struct sockaddr_in));
sa_loc.sin_family = AF_INET;
sa_loc.sin_port = htons(ClientPort);
sa_loc.sin_addr.s_addr = inet_addr(IPClient.substr(0, 15).c_str());
CALL_TRACE_CB("ethernetSocket connected");
if (!(bind(Socket, (struct sockaddr*)&sa_loc, sizeof(struct
sockaddr))))
{
CALL_TRACE_CB("Bind works");
}
else
{
AnsiString msg = AnsiString().sprintf("EN: error socket Bind:
%d", WSAGetLastError());
CALL_ERROR_CB(ERROR_NO_PORT_HANDLE, msg.c_str());
Close();
}
// TCP
SOCKADDR_IN sAdd;
sAdd.sin_family = AF_INET;
sAdd.sin_port = htons(Port);
sAdd.sin_addr.s_addr = inet_addr(IP.substr(0, 15).c_str());
if (connect(Socket, (SOCKADDR*)&sAdd, sizeof(SOCKADDR_IN)) ==
SOCKET_ERROR)
{
AnsiString msg = AnsiString().sprintf("EN: error connect
errorcode: %d", WSAGetLastError());
}
}
I expect that bind() returns 10048 before connect returns this error, but actual only connect() returns this error
I have to implement a client speaking with multiple server. The server only accepts messages from a specific port, so i have to bind my client socket.
This is an unsolvable problem. When you make an outbound TCP connection, the combination of local IP address and port is reserved exclusively for that particular outbound TCP connection. If you need to make multiple outbound TCP connections from the same port, each will have to be bound to its own local IP address. That is going to be extremely inconvenient.
There are other problems too. Say you finish one connection and then try to start a new one. The new one will have the same local IP address, local port (since the server only tolerates one), remote IP address, and remote port. How will packets from the new connection be distinguished from old, stale packets from the old one?
This is why you get the error when you try to connect. It's not until all four parameters of the connection (local and remote address and local and remote port) are known that the collision with the prior connection is detectable. That's not known until you call connect.
You need to fix the server to ignore the source port. If that absolutely cannot be done, you'll have to adopt a wait and retry mechanism to handle collisions with past connections.

socket() and sendto() dont return error codes when theres no internet connection

Why does socket() not return INVALID_SOCKET when I have no internet connection? I thought it would fail and then I could exit my function. My function's error checking continues till recvfrom() and then just hangs when I have no internet connection. I thought that socket() or sendto() would return an error code when I have no internet connection but they are not. I am trying to rely on their failure as a sign the user has no internet connection and exit my function but thats just not working for some weird reason.
void myFunc()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("myipaddress");
server_addr.sin_port = htons(123);
// Doesn't fail when there's no internet connection
protoent *proto = getprotobyname("udp");
int s = socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if (s == INVALID_SOCKET) {
goto Cleanup;
}
// Doesn't fail when there's no internet connection
char msg[48] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0 };
int iResult = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
// Hangs when there's no internet connection
memset(msg, 0, sizeof(msg));
struct sockaddr saddr;
socklen_t saddr_l = sizeof(saddr);
iResult = recvfrom(s, msg, 48, 0, &saddr, &saddr_l);
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
Cleanup:
closesocket(s);
WSACleanup();
}
Because there is no requirement for sockets to be connected to the internet. Many applications use sockets for inter-process communication on a single machine. Such applications can still run fine when there is no internet connection.
sendto() could arguably return an error code; it can (under certain situations, as demonstrated by the desktop notification about network connection status) know that the packet can never be delivered. However, UDP communication and sendto() make no guarantees about delivery whatsoever, and apparently the implementation you are using does not consider the lack of connection worthy of an error code. Arguably this is a quality of implementation issue.
recvfrom() simply waits as long as you have specified (possibly indefinitely) for a message, but never receives one. Again, this is within spec, and again it could be considered a quality of implementation issue whether or not this particular situation is flagged or not.
I looked into the linux man page for sendto (assuming that all relevant the implementations are sufficiently similar to the berkley sockets baseline) here:
http://linux.die.net/man/2/sendto
The documentation does not mention reporting and error if the network stack 'knows' that the message is undeliverable. This is reasonable, since the socket's transport may well not be IP4 or IP6. It could be any transport we chose to write a driver for: packet radio, serial cables or carrier-pigeons (if we could figure out the hardware for loading the printed messages into their satchels).
The only reference to possible errors from the transport is here:
These are some standard errors generated by the socket layer. Additional errors may be generated and returned from the underlying protocol modules; see their respective manual pages.
As mentioned by others, UDP is an unreliable datagram protocol. Unreliability is expected. Non-delivery of a message is expected. Therefore not really an error. There would be little incentive for a protocol-layer author to code for handling transport errors - since they too are expected and not an error in the context of this protocol.
When a socket is opened over TCP, then lack of socket continuity is an error. If the transport reports that packet delivery is not possible (for a sufficiently long time) then this is an error condition in the protocol.

If a winsock2 socket is non-blocking, would an SSL object associated with it also exhibit non-blocking behavior?

I'm asking this question because I am unsure whether an SSL object treats a socket as a sink/source for messages like it does with a BIO object. My gut is telling me yes, but I'm not certain.
Goal:
I am integrating a SSL authentication into already existing TCP code. Rather than calling the conventional send()/receive(), I would like to direct the messages through OpenSSL's SSL_read()/SSL_write() instead. My other requirement is that communication is non-blocking and data can be partially sent.
Here's how I've associated the SSL object with the socket (Server code).
SSL_Init(std::wstring &peer_hostname, SOCKET sock){
//...
//Initialize SSL structure
ssl = SSL_new(context);
if (ssl == NULL){
mr = APPZRETURN(E_FAIL, L"%ls (%d) : SSL_new failed. Unable to create SSL structure", __FUNCTIONW__, __LINE__);
}
//Agent uses winsock class, but OpenSSL uses unix socket. Surpressed warning added here for 4244. It works
if (SSL_set_fd(ssl, sock) == 0){ //set file descriptor for ssl
//Operation failed
return -1;
}
//...
int status = SSL_accept(ssl);
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
//...
}
According to the documentation for SSL_read() [https://www.openssl.org/docs/ssl/SSL_read.html], the SSL is non-blocking if the underlying BIO is non-blocking. If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Extension of my Question: Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Thank you for taking the time to read this. It's much appreciated.
If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Yes.
Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Unix sockets are by default blocking. Haven't used Winsock. But am sure Winsock should be by default blocking.
try following code:
SSL_set_fd(ss, sock);
retry:
int ret = SSL_accept(ssl);
if (ret != 1) {
int err = SSL_get_error(ssl, ret);
if (err == SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE) {
// maybe need some sleep or select
goto retry;
}
}

Port to Port data transfer with UDP

I'm working on this project where the source and destination ports are specified for sending a message via a UDP socket in C++. I've got the TCP portion of the project working fine, but I don't understand how to specify both the source and destination ports when setting this up.
The way I would know how to do it is the "receiver" sets up a recvfrom() call, with the port that the "sender" will also use in the sendto() command... but it would need to be the same port.
So, given that I need port x on the "receiver" to talk to port y on the "sender", how would I do that?
Thanks
You can define a source port when you call bind on the sender side. For instance:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { /*error*/}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(source_port); // here
int res = bind(sockfd,(struct sockaddr*)&sin, sizeof(sin));
if (res < 0) { /*error*/}
And the destination port goes into the sockaddr parameter passed to sendto.
If this is one-to-one mapping, i.e. one source talks to one destination, then simply bind(2) the local port and connect(2) to the remote IP and port (contrary to common misconception you can connect UDP sockets). Do that on both sides (with appropriate remote and local IPs/ports of course), and now you can just use recv(2) and send(2) without explicit addressing.
If one side needs to wait for the other to send the first packet, then extract source address/port received with recvfrom(2), and then connect(2) to it.
If, on the other hand, one side acts as a multi-client server, then do same bind(2)/connect(2) dance on the client, but only do bind(2) to local port and then use recvfrom(2)/sendto(2) on the server.
If you need simultaneous duplex communication, then you should use sockets in blocking mode -- fcntl(...O_NONBLOCK...), and use select() to determine if your socket is writable or readable or both. Here is a nice example on how this can be done http://www.lowtek.com/sockets/select.html