Okay first here is the code:
int recvMast_sock;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len;
if ((recvMast_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
critErr("listen:socket=");
}
fillSockaddrAny(&serv_addr, UDP_NODE_LISTEN_PORT);// fills the sockaddr_in works fine elsewhere
if ((bind(recvMast_sock, (struct sockaddr*) &serv_addr, sizeof serv_addr)) < 0)
{
critErr("listen:bind recv_mast_sock:");
}
recvReturn_i = recvfrom(recvMast_sock, &recvBuff[0], (size_t)1, 0, (struct sockaddr*) &cli_addr, &cli_len);
if(recvReturn_i <0)
printf("recv error%d\n",errno);
critErr is a function to handle errors which also includes a print of the error and an exit.
This runs in a thread, if this is of any relevance. If I compile and run this on a Zedboard (ZYNQ-7000 SoC) which has an ARM Cortex A9 and Linaro Linux (based on precise Ubuntu). It prints error 22 but still has the received value in recvBuff[0].
Running this in my VM with xubuntu it works fine.
Error 22 equals EINVAL which is described as Invalid argument.
In the manpage of recvfrom(2) it states EINVAL means that the MSG_OOB flag is set but I don't use any flags (passing 0).
Before leaving on friday I started an apt-get upgrade because I hope it is a faulty library or something like this. I can check back at monday but maybe someone here has another idea what is wrong.
You need to initialize cli_len before passing it to recvfrom():
cli_len = sizeof(cli_addr);
You are not initializing it, so it has a random value. If that value happens to be < sizeof(cli_addr), recvfrom() can fail with EINVAL, or at least truncate the address, because it thinks cli_addr is not large enough to receive the client address. If the value is vastly larger than sizeof(cli_addr), recvfrom() might consider the buffer to be outside of the valid memory range.
You have to tell recvfrom() how large cli_addr actually is. This is clearly stated in the documentation:
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
So you have to initialize cli_len with the total size of cli_addr before calling recvfrom(), then recvfrom() updates cli_len with the size of the address that was actually written into cli_addr. cli_addr can be larger than the address, for instance when using a sockaddr_storage structure to accept either IPv4 or IPv6 addresses on a dual-stack socket. In the example in the question, an IPv4 socket is being used, so cli_len must be initialized to a value >= sizeof(sockaddr_in).
This was not caused by the OS or the architecture. The function was not called on the x86-system because of a blocked mutex. So I didn't got the error there.
The problem was that I passed the socket to this function from 'main' (which i did not state in the question because I thought it was irrelevant, my bad...)
In 'main' I used it and used it in this function. Even though it was mutually exclusive, there was this error.
Remy's answer was also relevant but not a solution to the problem. Not setting cli_len beforehand just leads to a cut of sockaddr if its too small. No error was generated for that.
Related
I've just encountered a surprising buffer overflow, while trying to use the flag MSG_TRUNC in recv on a TCP socket.
And it seems to only happen with gcc (not clang) and only when compiling with optimization.
According to this link: http://man7.org/linux/man-pages/man7/tcp.7.html
Since version 2.4, Linux supports the use of MSG_TRUNC in the flags argument of recv(2) (and recvmsg(2)). This flag causes the received bytes of data to be discarded, rather than passed back in a caller-supplied buffer. Since Linux 2.4.4, MSG_PEEK also has this effect when used in conjunction with MSG_OOB to receive out-of-band data.
Does this mean that a supplied buffer will not be written to? I expected so, but was surprised.
If you pass a buffer (non-zero pointer) and size bigger than the buffer size, it results in buffer overflow when client sends something bigger than buffer. It doesn't actually seem to write the message to the buffer if the message is small and fits in the buffer (no overflow).
Apparently if you pass a null pointer the problem goes away.
Client is a simple netcat sending a message bigger than 4 characters.
Server code is based on:
http://www.linuxhowtos.org/data/6/server.c
Changed read to recv with MSG_TRUNC, and buffer size to 4 (bzero to 4 as well).
Compiled on Ubuntu 14.04. These compilations work fine (no warnings):
gcc -o server.x server.c
clang -o server.x server.c
clang -O2 server.x server.c
This is the buggy (?) compilation, it also gives a warning hinting about the problem:
gcc -O2 -o server.x server.c
Anyway like I mentioned changing the pointer to null fixes the problem, but is this a known issue? Or did I miss something in the man page?
UPDATE:
The buffer overflow happens also with gcc -O1.
Here is the compilation warning:
In function ‘recv’,
inlined from ‘main’ at server.c:47:14:
/usr/include/x86_64-linux-gnu/bits/socket2.h:42:2: warning: call to ‘__recv_chk_warn’ declared with attribute warning: recv called with bigger length than size of destination buffer [enabled by default]
return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
Here is the buffer overflow:
./server.x 10003
* buffer overflow detected *: ./server.x terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7338f)[0x7fcbdc44b38f]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7fcbdc4e2c9c]
/lib/x86_64-linux-gnu/libc.so.6(+0x109b60)[0x7fcbdc4e1b60]
/lib/x86_64-linux-gnu/libc.so.6(+0x10a023)[0x7fcbdc4e2023]
./server.x[0x400a6c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7fcbdc3f9ec5]
./server.x[0x400879]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 17732 > /tmp/server.x
... more messages here
Aborted (core dumped)
And gcc version:
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
The buffer and recv call:
char buffer[4];
n = recv(newsockfd,buffer,255,MSG_TRUNC);
And this seems to fix it:
n = recv(newsockfd,NULL,255,MSG_TRUNC);
This will not generate any warnings or errors:
gcc -Wall -Wextra -pedantic -o server.x server.c
And here is the complete code:
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[4];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,4);
n = recv(newsockfd,buffer,255,MSG_TRUNC);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
UPDATE:
Happens also on Ubuntu 16.04, with gcc version:
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
I think you have misunderstood.
With datagram sockets, MSG_TRUNC option behaves as described in man 2 recv man page (at Linux man pages online for most accurate and up to date information).
With TCP sockets, the explanation in the man 7 tcp man page is a bit poorly worded. I believed it is not a discard flag, but a truncate (or "throw away the rest") operation. However, the implementation (in particular, net/ipv4/tcp.c:tcp_recvmsg() function in the Linux kernel handles the details for TCP/IPv4 and TCP/IPv6 sockets) indicates otherwise.
There is also a separate MSG_TRUNC socket flag. These are stored in the error queue associated with the socket, and can be read using recvmsg(socketfd, &msg, MSG_ERRQUEUE). It indicates a datagram that was read was longer than the buffer, so some of it was lost (truncated). This is rarely used, because it is really only relevant to datagram sockets, and there are much easier ways to determine overlength datagrams.
Datagram sockets:
With datagram sockets, the messages are separate, and not merged. When read, the unread part of each received datagram is discarded.
If you use
nbytes = recv(socketfd, buffer, buffersize, MSG_TRUNC);
it means that the kernel will copy up to first buffersize bytes of the next datagram, and discard the rest of the datagram if it is longer (as usual), but nbytes will reflect the true length of the datagram.
In other words, with MSG_TRUNC, nbytes may exceed buffersize, even though only up to buffersize bytes are copied to buffer.
TCP sockets in Linux, kernels 2.4 and later, edited:
A TCP connection is stream-like; there are no "messages" or "message boundaries", just a sequence of bytes flowing. (Although, there can be out-of-band data, but that is not pertinent here).
If you use
nbytes = recv(socketfd, buffer, buffersize, MSG_TRUNC);
the kernel will discard up to next buffersize bytes, whatever is already buffered (but will block until at least one byte is buffered, unless the socket is in non-blocking mode or MSG_TRUNC | MSG_DONTWAIT is used instead). The number of bytes discarded is returned in nbytes.
However, both buffer and buffersize should be valid, because a recv() or recvfrom() call goes through the kernel net/socket.c:sys_recvfrom() function, which verifies buffer and buffersize are valid, and if so, populates the internal iterator structure to match, before calling the aforementioned net/ipv4/tcp.c:tcp_recvmsg().
In other words, the recv() with a MSG_TRUNC flag does not actually try to modify buffer. However, the kernel does check if buffer and buffersize are valid, and if not, will cause the recv() syscall to fail with -EFAULT.
When buffer overflow checks are enabled, GCC and glibc recv() does not just return -1 with errno==EFAULT; it instead halts the program, producing the shown backtraces. Some of these checks include mapping the zero page (where the target of a NULL pointer resides in Linux on x86 and x86-64), in which case the access check done by the kernel (before actually trying to read or write to it) succeeds.
To avoid the GCC/glibc wrappers (so that code compiled with e.g. gcc and clang should behave the same), one can use real_recv() instead,
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
ssize_t real_recv(int fd, void *buf, size_t n, int flags)
{
long retval = syscall(SYS_recvfrom, fd, buf, n, flags, NULL, NULL);
if (retval < 0) {
errno = -retval;
return -1;
} else
return (ssize_t)retval;
}
which calls the syscall directly. Note that this does not include the pthreads cancellation logic; use this only in single-threaded test programs.
In summary, with the stated problem regarding MSG_TRUNC flag for recv() when using TCP sockets, there are several factors complicating the full picture:
recv(sockfd, data, size, flags) actually calls the recvfrom(sockfd, data, size, flags, NULL, NULL) syscall (there is no recv syscall in Linux)
With a TCP socket, recv(sockfd, data, size, MSG_TRUNC) acts as if it were to read up to size bytes into data, if (char *)data+0 to (char *)data+size-1 are valid; it just does not copy them into data. The number of bytes thus skipped is returned.
The kernel verifies data (from (char *)data+0 to (char *)data+size-1, inclusive) is readable, first. (I suspect this check is erroneous, and might be turned into a writability check sometime in the future, so do not rely on this being a readability test.)
Buffer overflow checks can detect the -EFAULT result from the kernel, and instead halts the program with some kind of "out of bounds" error message (with a stack trace)
Buffer overflow checks may make NULL pointer seem like valid from the kernel point of view (because the kernel test is for reading, currently), in which case the kernel verification accepts the NULL pointer as valid. (One can verify if this is the case by recompiling without buffer overflow checks, using e.g. the above real_recv(), and seeing if a NULL pointer causes an -EFAULT result then.)
The reason for such a mapping (that, if allowed by hardware and the kernel structures, only exists, and is not readable or writable) is that with such a mapping, any access generates a SIGBUS signal, which a (library or compiler-provided signal handler) can catch, and dump not just a stack trace, but more details about the exact access (address, code that attempted the access, and so on).
I do believe the kernel access check treats such mappings readable and writable, because there needs to be a read or write attempt for the signal to be generated.
Buffer overflow checks are done by both the compiler and the C library, so different compilers may implement the checks, and the NULL pointer case, differently.
Nota bene: I’m adding this answer here after all this time, as this is still one of the first results on google for recv buffer overflow MSG_TRUNC, and if someone else ends up here, they’ll save themselves a lot of grief, searching and trial-and-error.
The original question is answered well enough already, but the subtlety I wanted to highlight, is the difference between stream and datagram sockets.
A common code pattern is to use recv( socket_, NULL, 0, MSG_DONTWAIT | MSG_PEEK | MSG_TRUNC ) to find how much data is queued before a read. This works perfectly for stream sockets (TCP and SCTP) but for datagram sockets (UDP, UDPL and DCCP) it will intermittently buffer overflow, but only if the executable is compiled with gcp and with optimisations enabled. Without optimisations it seems to work perfectly, which means it will sail through development QA, only to fail in staging/live.
Finding this was a total PITA. You’re welcome. ;)
I am writing a client-server program in C. I am getting an error in Bind function says: Address Already in Use. So I tired to use memset() and I got error says: Invalid Argument. Finally, I looked for similar questions on here, and some of them suggesting the use of setsocketopt() function. I used it and I am getting error says:
/tmp/ccBNsJtU.o: In function main:
socket.c:(.text+0xd0): undefined reference to setsocket
collect2: error: ld returned 1 exit status
I looked at almost-if-not all the similar questions even in different programing languages. Now I am stuck. Do I have to use setsocket() and if I do, is it causing a problem in my code? Or I don't have to use it and the problem is somewhere else? Could the problem be in the client or the server functions where I listen and send messages? This is the part of the code where the bind() and setsocket() functions are:
int main (void) {
int sl, sa, bn, erro, lis;
int status;
//server log socket
struct sockaddr_un server = {AF_UNIX, "log_server"};
sl = socket (AF_UNIX, SOCK_STREAM, 0);
if(sl < 0) {
perror("Faild to create socket - in main");
exit(1);
}
//I added this part
if (setsocket(sl, SOL_SOCKET, SO_REUSEADDR, &server, sizeof(server)) == -1) {
perror("setsocket - in main");
exit(1);
}
bn = bind (sl, (struct sockaddr *)&server, sizeof(server));
if(bn < 0){
perror("Faild to bind - in main");
exit(1);
}
lis = listen (sl, 1); //to be changed to 4
if (lis < 0) {
perror("Faild to listen - in main");
}
"Address already in use" typically means that some other socket is already bound to the given port. This could mean that there's a running program actively listening on that port, or it could mean that a prior instance of your program which is no longer running still has some socket resources open in the OS.
In the latter case, a call to setsockopt (not setsocket) with the SO_REUSEADDR parameter will address this. The fourth parameter should be a pointer to a char whose value is 1, while the fifth parameter should be sizeof(char).
For the users who are facing the problem in bind() function that generate error of the type: Address Already in Use. Here is one tip:
My problem was because the program ran and an address being used by the bind() and then the program generated errors and stopped/terminated. So the unlink() function at the end of the code had no chance to do its job and the address kept in use. So simplest way is at the beginning of the function unlink the processes you are going to bind later in the function.
This seems like so simple and I don't know if it is a good practice but it worked for my purpose.
I need to get the local port used by a (client) socket.
It was my understanding that Windows Sockets performs an implicit bind function call, therefore getsockname() after sendto() should provide the assigned port. However, it always sets 0 as the port number. Am I missing something?
ex:
if (sendto(sockfd, ...) != SOCKET_ERROR)
printf("Sent\n");
if (getsockname(sockfd, (struct sockaddr*)&sin, &sinlen) != SOCKET_ERROR)
printf("port = %u\n", ntohs(sin.sin_port);
else
printf("Error");
//result: Sent, port = 0
Problem solved with a restart of the computer. Still unknown as to the actual cause, but at this point I'm just happy it's working.
If anyone has an idea for fixing the issue without a restart (for future readers), feel free to post.
The only ambiguity I can see in your example code is what size you assigned to sinlen before calling. (you do not show it) If you are using winsock, it should be defined, and assigned int sinlen = sizeof(sin);
I used this code on my system, and it returns a non-zero value for the port I am connecting through:
struct sockaddr_in sin;
int len = sizeof(sin);
if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
//handle error
else
printf("port number %d\n", ntohs(sin.sin_port));
By the way, The ntohs function function returns the value in host byte order. If [ sin.sin_port ] is already in host byte order, then this function will reverse it. It is up to [your] application to determine if the byte order must be reversed. [text in brackets are my emphasis]
In answer to comment question ( getsockname() ):
The function prototype for getsockname():
int getsockname(
_In_ SOCKET s,
_Out_ struct sockaddr *name,
_Inout_ int *namelen //int, not socklen_t
);
For more discussion on socklen_t
Edit (address possible approach to re-setting sockets without rebooting PC.)
If winsock API calls cease to work predictably, you can re-start sockets without rebooting the PC by using WSAStartup and WSACleanup (see code example at bottom of link for WSAStartup)
You say you want to know the LOCAL port, but your line
sendto(sockfd, ...)
implies sockfd is the REMOTE descriptor. Your later code may therefore give you info about the REMOTE port, not the LOCAL one. 'sockets' are not both ends, meaning one connection. A socket is one end, meaning the IP and port number of one end of the connection. The first parameter of your getsockname() is not a reference or a pointer, it is therefore not an output from the function, but an input. You're telling the function to use the same socket descriptor that you just sent to, ie. the remote one.
Formatting error. ntohs() returns unsigned short so the format should be %hu, not %u or %d. If you grab too many bytes they are not the port.
Answer. After using sendto() try using gethostname() then getaddrinfo() on the name that comes back. Note: the addrinfo structures you get back will give you struct sockaddr pointers which you will need to re-cast to struct sockaddr_in pointers to access the local port number.
To find the local port number the kernel dreamed up when you issued a sendto() function perhaps you could write a routine to parse the output from the (gnu linux) commands 'ss' or 'netstat'. (Not sure if these are POSIX compatible.) Or maybe you could access /proc/net if you have the privilege.
I am just learning socket programming on Linux by some websites and here are some parts of my code on server side by using TCP:
#define BufferLength 100
#define SERVPORT 3111
int main()
{
/* Variable and structure definitions. */
int sd, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Server-socket() error");
exit (-1);
}
else
printf("Server-socket() is OK\n");
/* Allow socket descriptor to be reusable */
if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0)
{
perror("Server-setsockopt() error");
close(sd);
exit (-1);
}
else
printf("Server-setsockopt() is OK\n");
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
/* continue */
}
When I did the last line (printf("using......")), I got a segmentation fault, why? Thanks.
The code as shown misses to #include any headers, so as it stands won't compile due to some undefined symbols.
It would compile however if you missed to just prototype any library functions referenced by the code, which would lead to any function being assumed to return int.
The latter fact might be fatal or not.
On a 64bit system at least it is fatal in the case of inet_ntoa() used as a parameter to printf(), as on a 64bit system it most likely is expected to return a 64bit (char-pointer) value (but a 32bit int). So (assuming the prototype misses) when generating the code the compilers assumes inet_ntoa() to return a 32bit int which would lead to "chopping-off" the most significant 32bits of the address returned. Trying to printf() from such a "crippled" and therefore (most likely) invalid address provokes undefined behaviour and in your case leads to the segmentation violation observed.
To fix this, add the relevant prototype (for inet_ntoa()) by adding:
#include <arpa/inet.h>
The compiler should have warned you about this. To enable all compiler's warnings for gcc use the options -Wall -Wextra -pedantic. Take such warnings serious.
It seems likely that inet_ntoa() is somehow returning NULL, leading to the segfault when it is dereferenced in the printf(). I can't find a direct reference plainly stating that this is possible with the Linux version of inet_ntoa, but I found several people who made that claim, and it is the only point in that code where a pointer is being dereferenced.
The answer at the bottom of this question: segmentation fault for inet_ntoa makes the claim that inet_ntoa can return NULL. However, following his reference links, I couldn't find an actual statement of that fact.
There is an MSDN article (which is suggestive, but of course doesn't apply directly to Linux code) that does state plainly that inet_ntoa() can return NULL here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738564%28v=vs.85%29.aspx
I'm writing a clone of inetd in which I must run a server that prints the IP and port of the client connecting to it.
As I overwrite STDIN and STDOUT with the socket descriptor, my initial solution to do this was to recover the sockaddr_in structure, which contains the needed information. Doing this with getsockname(), however, is returning an empty structure, with all bits set to 0.
Any idea of what is wrong with my approach? Are there any other approaches I can use to recover the IP/Port?
Thanks
As R.. pointed out, you should use getpeername. Both that function and getsockname take a file descriptor as its first argument, not a stream pointer (FILE *). Use fileno(stdin) to get the file descriptor for standard input (or hard-code it to STDIN_FILENO, as it's constant).
Also, the last argument to getsockname and getpeername should be a pointer to socklen_t, not a constant, and you should use a sockaddr_in for TCP/IP:
struct sockaddr_in peeraddr;
socklen_t peeraddrlen = sizeof(peeraddr);
getpeername(STDIN_FILENO, &peeraddr, &peeraddrlen);
See a complete example here.
Use getpeername. I suspect your problem is that getsockname is returning the information for your own (local) side of the socket, which is probably bound to 0.0.0.0 (meaning it can accept connections from any interface).
Edit: I think I found your actual bug reading the code. This line is wrong:
getsockname(stdin, &addr, sizeof(addr));
The getsockname and getpeername functions take a socklen_t * (a pointer) as their third argument, not a size_t. The compiler should be telling you about this mistake unless you forgot to include a header with the prototype for getsockname. Also, as has already been said, stdin is incorrect. Try:
socklen_t len = sizeof addr;
getpeername(0, &addr, &len);
or (C99 only):
getpeername(0, &addr, (socklen_t[1]){sizeof addr});
You should also be checking the return value; if you did, you'd see that it's returning errors.
If you need those info for the remote client, you have to call getpeername().