sockaddr_in causing segfault? - c

Working on creating a server/client system in C right now, and I'm having a little trouble with the client part. From what I've seen, I need to use sockaddr_in so I can connect to the server. However, I've been getting a segfault every time. I believe that sockaddr_in has something to do with it, as commenting it and it's references later in the program fixes the segfault.
code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char** argv)
{
int Csock;
int con;
char *data = 0;
char buf[101] = "";
struct sockaddr_in addr;
Csock = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(3435);
con = connect(Csock, (struct sockaddr*) &addr, sizeof(addr));
write(con, "Text", sizeof("Text"));
*data = read(con, buf, 100);
puts(data);
return 0;
}
sadly, I am rather new to C, so that's as much as I can figure... can anyone tell me a way to go about eliminating the segfault?
Thanks!

Quick comment:
data is a pointer to char which does not point to an allocated memory, so:
*data = read(con, buf, 100);
is invalid! You cannot dereference a NULL pointer.
Also, read returns ssize_t, and not a char, so perhaps:
ssize_t nread = read(con, buf, 100);
and then print out the nread with printf.

One immediately-apparent thing that's wrong is taking sizeof &addr when you mean sizeof addr. Also you never set the address you want to connect to, only the port. On most systems neither of these errors would cause a crash, but they will keep the program from working.
Also it's advisable never to setup sockaddr structures directly, but instead use getaddrinfo.

The problem I think, lies with your connect statement. You need
con = connect(Csock, (struct sockaddr*) &addr, sizeof(addr));
sizeof() returns the size of the object. I don't offhand know what the size of the addr structure is, but the statement sizeof(&addr) will return 4 (assuming 32 bit system) and I'm quite sure that the size of the addr structure is > 4 bytes.
The & is the reference operator (or address of) and gives you the address of a particular structure. Address (in 32 bit systems) are 4 bytes. Usually the types of functions (like the connect function) want the actual size of the structure. This is often done for backwards compatibility purposes so that if the size of the structure changes in some future version of the SDK or library, older code doesn't need to change in order to work with the newer libraries.

Related

Why do we need an unused char array for a successfull bind?

We're currently developing a small tool that reads CAN-messages and evaluates the data contained. The bind() command doesn't return 0 (for a successfull bind) when the char array empty is too short, too long or not present. This bug is present in the shortened program below.
#include <sys/socket.h> // socket, bind, PF_CAN, SOCK_RAW
#include <linux/if.h> // ifreq
#include <linux/can.h> // sockaddr_can, CAN_RAW
#include <stdio.h> // printf
int main()
{
struct sockaddr_can addr;
struct ifreq ifr;
int socketFd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
addr.can_ifindex = ifr.ifr_ifindex;
char empty[5]; // change length or comment out to provoke the error
if(bind(socketFd, (struct sockaddr *) &addr, sizeof(addr)) != 0)
{
printf("Unable to bind the CAN-socket.\n");
}
}
The behaviour changes with the length of our char array empty.
For example [5] works, while [24] doesn't.
We tested this with GCC 5.4.0 and 7.2.0 which both showed this behaviour.
Under GCC 5.3.0 the presence and lentgh of empty do not influence our bind().
For reference we used
gcc main.c
./a.out
Why do we need an unused char array with GCC 5.4.0 and 7.2.0 for a successfull bind?
You're causing all sorts of undefined behavior due to use of uninitialized variables.
You never initialize ifr, then you use ifr.ifr_ifindex.
You never initialize addr.tp, then you pass addr as the sockaddr parameter to bind().
That it ever succeeds at all is more surprising than the fact that the failure depends on the size of the empty array. What address are you expecting the socket to be bound to?
We followed the documentation found at kernel.org.
In "4. How to use SocketCAN" (approx. line 60) this example is given:
int s;
struct sockaddr_can addr;
struct ifreq ifr;
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
(..)
While it states that no error checking has been implemented neither addr nor ifr have been fully initialised (like all of you mentioned here). Therefore the given example encounters the same problem as our program.
Initialising them with memset like #zwol mentioned to ensure all values are set to 0 before working with them fixes this unexpected behaviour completely.
Thanks everyone.

Wrong output inet_ntop

I'm trying to print an ip address from inet_ntop, but the output seems pretty weird.
The program seems to work well, I succeed to connect the socket but it print this:
H��H9�u�H�[]A\A]A^A_�ff.�
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = 0;
int s = getaddrinfo("irc.root-me.org", "6667", &hints, &result);
if( s != 0){
printf("erreur\n");
exit(EXIT_FAILURE);
}
int f = connect(sock, result->ai_addr, result->ai_addrlen);
if(f != 0){
printf("erreur connect\n");
}
struct sockaddr_in *sockin;
sockin = (struct sockaddr_in *)result->ai_addr;
char *dst;
inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof(char *));
printf("%s\n", dst);
freeaddrinfo(result);
exit(0);
}
Two issues here:
The 3rd parameter to inet_ntop() should be a char-array or a pointer to the 1st element of a char-array.
The 4th parameter to inet_ntop() should be the size of the destination buffer, whose address is passed as 3rd parameter.
What you do is to pass the uninitialised char-pointer dst as destination and tell the function it would point to sizeof(char*) bytes memory.
An AF_INET address (which has the form xxx.xxx.xxx.xxx) uses a maximum of 4x3 characters plus 3 delimiting . chars which sums up to 15 chars plus 1 additional char used as 0-terminator to make it a C-"string", so the corrected code would look like this:
char dst[16] = ""; /* inet_ntop() does not necessarily 0-terminates the result. */
inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof dst);
As pointed out by Filipe Gonçalves in his comment one can use INET_ADDRSTRLEN (if available) instead of the hard coded "magic number" 16 to define the buffer size for the textual representation of a IPv4 address. It's a good thing.
Documentation for inet_ntop() is here:
POSIX in general
Specific to Linux
The Problem
The problem is with the size of the destination char* you're trying to save the result in, and the fact that it is uninitialized, what you want to do is save it in a char[].
sizeof(char*) on x86 is 4B and 8B on x64, IP Addresses are usually larger than that (an IPv4 address is between 7 to 15 bytes) + 1 for null terminator.
Solution
You can fix the code as follows:
char dst[16] = {0};
inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof(dst));
After the fix:
$ ./main
212.83.153.145
Source Code
If you want the full fixed main.c, I've uploaded it to github.

segmentation fault in linux (socket programming (TCP) in C)

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

Invalid argument from sendto in ansi C when trying to implement UDP

I know there are a few similar question on SO, but I feel like everyone has a different issue that is causing this. So I'm posting my particular case.
I'm working on the raspberry pi, using raspbian, a debian derivative. I'm coding in ansi C. This is a server that sends some data to a udp client on another end through port 500.
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int main()
{
int sockfd;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
char buffer[256];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(500);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
sprintf(buffer,"hi this is a test \n");
if(sendto(sockfd,buffer,sizeof(buffer),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr))==-1)
{ error("fail:")
};
return 0;
}
But this just gives me the error "invalid arguments", I can't figure out what could possibly be wrong. If the type of argument I supply to sendto is incorrect, this would fail on compile. But the type is correct and this compiles, only at runtime does it fail.
You have no initialization for the cliaddr structure. Thus, its contents are random. Your code compiles fine because you have a struct sockaddr_in where it should be but the compiler cannot check if you have properly initialized it.
On the other hand, at runtime when sendto is invoked the glibc or the kernel finds out that that random data in the cliaddr structure doesn't look like a valid address and throws up an invalid argument error.
Solution: initialize the cliaddr variable before using it.
Edit: You also need to properly initialize the socket, the third argument there shouldn't be 0.
Second edit, read me: For resources I recommend the extraordinary guide of Beej. For your exact problem this subchapter can help.

Similar to getifaddrs on old glibc version

There is very useful funcion call getifaddrs which retrieves all machin network addresses. The problem is that I'm using old glibc version which doesn't have this function. Is there any replacement for it? I was looking and found getipnodebyname but it is unuseful when address isn't mapped in /etc/hosts file.
To add to the previous answer, here is an example for the SIOCGIFCONF-approach. You have to do something like this:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int fd;
int get_iface_list(struct ifconf *ifconf)
{
int rval;
if((rval = ioctl(fd, SIOCGIFCONF , (char*) ifconf )) < 0 )
perror("ioctl(SIOGIFCONF)");
return rval;
}
int main()
{
static struct ifreq ifreqs[100];
static struct ifconf ifc;
char *ptr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return 1;
ifc.ifc_buf = (char*) (ifreqs);
ifc.ifc_len = sizeof(ifreqs);
if(get_iface_list(&ifc) < 0) return -1;
/* Go through the list of interfaces */
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len;)
{
struct ifreq *ifr = (struct ifreq*)ptr;
int len = (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len) ?
sizeof(struct sockaddr) : ifr->ifr_addr.sa_len;
ptr += sizeof(ifr->ifr_name) + len;
/* Do what you need with the ifr-structure.
* ifr->ifr_addr contains either sockaddr_dl,
* sockaddr_in or sockaddr_in6 depending on
* what addresses and L2 protocols the interface
* has associated in it.
*/
}
close(fd);
return 0;
}
There are some gotchas, of course. According to Unix Network Programming chapter 17.6 ioctl(fd, SIOCGIFCONF, array) may not return an error on some platforms if the array pointed in the argument is too small. The data will then be concatenated. Only way to work around this is to call ioctl() in a loop until you get same result length twice while increasing the size of the array. Of course, since this is 2012, I'm not sure how relevant this is anymore.
Size of ifreqs array is purely a guess in this case. Keep in mind though that the array will contain one struct ifreq for every L2 and L3 address associated with a interface. For example, assuming you have also IPv6 addresses, for lo-interface you'd get three entries: ethernet, IPv4 and IPv6. Therefore reserve enough space or apply the kludge.
To get broadcast addresses and other additional information, you will need to additional ioctl() calls in the loop. All possible options depends on what your OS provides, of course.
For more information I'd recommend reading Unix Network Programming by W. Richard Stevens. It is the most comprehesive book about this subject.
The traditional way to do the equivalent was with the SIOCGIFCONF operation to ioctl. Any socket can be used for the operation. It's not as easy as a single function call though.

Resources