getaddrinfo, Segmentation Fault - getaddrinfo

I am getting Segmentation Fault with the codes below.
What I need the program to do is, when an invalid/unknown name or service is entered as an argument, it displays an error only for that particular service and continues to work on the rest of the provided services.
Right now, the program works if I include an invalid service anywhere in a line of services (e.g ./dnslookup www.nhawurha.com www.google.com OR www.google.com www.nhawurha.com)
But it gives me a Segmentation Fault after printing the error if only the invalid service is used as the sole argument (e.g ./dnslookup www.nhawurha.com)
Any form of help would be much appreciated, thanks!
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#define BUFLEN 1500
int main(int argc, char *argv[]) {
struct addrinfo hints, *ai, *result;
char ipaddrv4[BUFLEN];
char ipaddrv6[BUFLEN];
int error;
if (argc < 2) {
fprintf(stderr, "Missing <hostname> after %s \n", argv[0]);
return 0;
}
for (int j = 1; j < argc; j++) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC; /* IPv4, IPv6, or anything */
hints.ai_socktype = SOCK_DGRAM; /* Dummy socket type */
error = getaddrinfo(argv[j], NULL, &hints, &result);
if (error) {
fprintf(stderr, "ERROR (%s: %s)\n", argv[j], gai_strerror(error));
continue;
}
for (ai = result; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *) ai->ai_addr;
void *addr = &(ipv4->sin_addr);
inet_ntop(AF_INET, addr, ipaddrv4, BUFLEN);
printf("%s IPv4 %s\n", argv[j], ipaddrv4);
}
else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) ai->ai_addr;
void *addr = &(ipv6->sin6_addr);
inet_ntop(AF_INET6, addr, ipaddrv6, BUFLEN);
printf("%s IPv6 %s\n", argv[j], ipaddrv6);
}
else {
continue;
}
}
}
freeaddrinfo(result);
return 0;
}

Have a look at the 'result' parameter - if your one and only lookup fails, result will be uninitialised and freeaddrinfo will segfault. Try initialising it to NULL first.
There is a second problem if you have more than one lookup - a memory leak because you don't call freeaddrinfo on each result.
So I think your logic should be more like:
for each command line arg
if lookup succeeds
print result
free result
else
print error
See man page for getaddrinfo

Related

Trying to implement TCP echo server in C

Was trying to implement a TCP echo server with C, and came across this code while searching the web and was trying to compile it. It shows some error related to socket.h
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
int main(int argc, char **argv)
{
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof(struct sockaddr_in);
int data_len;
char data[MAX_DATA];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("server socket: ");
exit(-1);
}
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[1]));
server.sin_addr.s_addr=INADDR_ANY;
bzero(&server.sin_zero, 0);
if((bind(sock, (struct sockaddr *)&server, sockaddr_len)) == ERROR)
{
perror("bind: ");
exit(-1);
}
if((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror("listen");
exit(-1);
}
while(1)
{
if((new = accept(sock, (struct sockaddr *)&client, sockaddr_len)) == ERROR)
{
perror("accept");
exit(-1);
}
printf("New Client connected from port no %d and IP %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while(data_len)
{
data_len = recv(new, data, MAX_DATA, 0);
if(data_len)
{
send(new, data, data_len, 0);
data[data_len] = '\0';
printf("Sent mesg: %s", data);
}
}
printf("Client disconnected\n");
close(new);
}
close(sock);
}
While compiling in Linux using gcc (Debian 8.3.0-6) 8.3.0 following warnings/errors are thrown,
tcp_srv.c: In function ‘main’:
tcp_srv.c:50:54: warning: passing argument 3 of ‘accept’ makes pointer from integer without a cast [-Wint-conversion]
if((new = accept(sock, (struct sockaddr *)&client, sockaddr_len)) == ERROR)
^~~~~~~~~~~~
In file included from tcp_srv.c:4:
/usr/include/x86_64-linux-gnu/sys/socket.h:233:28: note: expected ‘socklen_t * restrict’ {aka ‘unsigned int * restrict’} but argument is of type ‘int’
socklen_t *__restrict __addr_len);
The binary upon execution is giving a Segmentation fault which I assume due to this error. Tried googling this error but couldn't get any solutions as such.
accept prototype is:
int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
and manual says:
The address_len is a value-result parameter; it should initially
contain the
amount of space pointed to by address; on return it will contain the actual length
(in bytes) of the address returned.
Third argument must be pointer to a socklen_t thus:
if((new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)) == ERROR)

Time the connect syscall

I would like to see how much time it takes for connect syscall. I get the code for a simple TCP client. However, the program will wait for the server to respond after connect. How can I make it return right after syscall or using some other ways to time the syscall time?
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) {
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2) {
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0) {
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\n Error : Connect Failed \n");
return 1;
}
printf("\nhello\n");
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF) {
printf("\n Error : Fputs error\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
return 0;
}
However, the program will wait for the server to respond after connect.
Yes, and it does so here:
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF) {
printf("\n Error : Fputs error\n");
}
}
How can I make it return right after syscall
Err, remove the receive loop above?

Adding an IPv6 address to the interface USING libmnl and rtnetlink

I am trying to add an IPv6 address to an ethernet interface, using libmnl. After constructing a message and sending to the kernel, I saw that it was not added to the interface, even though the return codes for the kernel reply did not contain any error. Kindly can anybody have a look, and help me correct it. Am I supposed to add more attributes to the nlmsghdr or something else?
#include <assert.h>
#include <string.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <libmnl/libmnl.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <time.h>
static struct mnl_socket *nl;
static unsigned int nlportid;
int mnl_init(void);
int mnl_init(){
nl = mnl_socket_open(NETLINK_ROUTE);
if(nl == NULL){
printf("Error: mnl_socket_open\n");
return 0;
}
if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0){
printf("Error: mnl_socket_bind\n");
return 0;
}
nlportid = mnl_socket_get_portid(nl);
return 1;
}
int add_to_interface(const char* eip){
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
struct ifaddrmsg *ifm;
int ret;
uint8_t seq;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_NEWADDR;
nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
nlh->nlmsg_seq = seq = time(NULL);
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
ifm->ifa_family = AF_INET6;
ifm->ifa_prefixlen = 64;
ifm->ifa_flags = IFA_F_PERMANENT;
ifm->ifa_scope = RT_SCOPE_UNIVERSE;
/* TODO get interaface name from user or configuration*/
ifm->ifa_index = if_nametoindex("eth0");
unsigned char eipn[16];
inet_pton(AF_INET6, eip, eipn);
mnl_attr_put(nlh, IFA_ADDRESS, 16,eipn);
mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct ifaddrmsg));
if(mnl_socket_sendto(nl,nlh, nlh->nlmsg_len) < 0){
printf("Error: mnl_socket_sendto");
return 0;
}
ret = mnl_socket_recvfrom(nl,buf, sizeof(buf));
if(ret == -1){
printf("Error: mnl_socket_recvfrom");
return 0;
}
ret = mnl_cb_run(buf, ret, seq, nlportid, NULL, NULL);
return 0;
}
int main(int argc, char *argv[]){
if(mnl_init()){
add_to_interface("2001::20c:29ff:fe5f:13c7/64"); // for testing
}
}
I don't really know anything about libmnl, and the following solution is not perfect. But in case you're still stuck...
Notice that you're dropping several error codes. This one, in particular:
inet_pton(AF_INET6, eip, eipn);
Should be something in the lines of this:
ret = inet_pton(AF_INET6, eip, eipn);
if (ret != 1) {
printf("Bad address.\n");
return -22;
}
And I suppose you can tell where I'm going with this. This:
add_to_interface("2001::20c:29ff:fe5f:13c7/64"); // for testing
Should be this:
add_to_interface("2001::20c:29ff:fe5f:13c7"); // for testing
That fixes it for me. Except it hags at mnl_socket_recvfrom() because the kernel does not answer, apparently.
But do be more careful with those error codes; the ones I mentioned aren't the only ones.
Solution from Pablo Neira,
eipn should be 'struct in6_addr' instead.
mnl_attr_put(nlh, IFA_ADDRESS, 16,eipn);
So this looks like:
mnl_attr_put(nlh, IFA_ADDRESS, sizeof(eipn), &eipn);

Lazarus: How to list all the available network connection on a system?

I am writing a program on a Linux system using Lazarus IDE. The program is supposed to connect to the Internet or Intranet. So, I want to display to the user list of all the available network connections that they can use to connect to the Internet or Intranet like wifi, if there are two active network cards on the system, then this program should display their available connections.
At the moment, I don't know where to start or what tool(s) to use.
Any hints, clues or advice will be greatly appreciated.
You can use ifconfig to list all available network interfaces and their status.
Edit: For doing it programmatically you have to use function ioctl with SIOCGIFCONF.
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd, len, lastlen;
char *ptr, *buf;
struct ifconf ifc;
struct ifreq *ifr;
char ifname[IFNAMSIZ + 1];
char str[INET6_ADDRSTRLEN];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
lastlen = 0;
len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
for ( ; ; )
{
buf = malloc(len);
ifc.ifc_len = len;
ifc.ifc_buf = buf;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
{
if (errno != EINVAL || lastlen != 0)
exit(-1);
}
else
{
if (ifc.ifc_len == lastlen)
break; /* success, len has not changed */
lastlen = ifc.ifc_len;
}
len += 10 * sizeof(struct ifreq); /* increment */
free(buf);
}
printf("LEN: %d\n", ifc.ifc_len);
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
ifr = (struct ifreq *) ptr;
ptr += sizeof(struct ifreq); /* for next one in buffer */
memcpy(ifname, ifr->ifr_name, IFNAMSIZ);
printf("Interface name: %s\n", ifname);
const char *res;
switch (ifr->ifr_addr.sa_family)
{
case AF_INET6:
res = inet_ntop(ifr->ifr_addr.sa_family, &(((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr), str, INET6_ADDRSTRLEN);
break;
case AF_INET:
res = inet_ntop(ifr->ifr_addr.sa_family, &(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr), str, INET_ADDRSTRLEN);
break;
default:
printf("OTHER\n");
str[0] = 0;
res = 0;
}
if (res != 0)
{
printf("IP Address: %s\n", str);
}
else
{
printf("ERROR\n");
}
}
return 0;
}
ioctl SIOCGIFCONF will return, if success, a struct ifconf which has a pointer to an array of struct ifreq.
These structs are defined in net/if.h
Using this code, from ifc.ifc_req you can get all interfaces, please look at the declaration of struct ifreq in order to determine the length and type of each array element. I think from here you can continue alone, if not please let me know.
The following code does work on my Linux system. It outputs all the available connection point through which you can connect to the Internet or intranet. I modified the code to print out its name and ip address.
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
// you may need to include other headers
int main()
{
struct ifaddrs* interfaces = NULL;
struct ifaddrs* temp_addr = NULL;
int success;
char *name;
char *address;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while (temp_addr != NULL)
{
if (temp_addr->ifa_addr->sa_family == AF_INET) // internetwork only
{
name = temp_addr->ifa_name;
address = inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr);
printf("%s %s\n",name,address);
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
}

Net Link Linux User code bind socket call always fail for multicast group Id (non zero value)

Hi am trying to implement net link user code and kernel code every thing works fine for unicast (src_addr.nl_groups = 0;). For mulicast, user code bind call always fails for non zero src_addr.nl_groups value. Really am not sure what value to put for multicast and how to proceed further. I checked the usage of netlink_broadcast in kernel source tree, so I put the same group Id value (RTMGRP_LINK) here. For unicast I found good number of help in internet but for multicast I don't think so . So Please help me to proceed further.
Error am getting is:
bind: No such file or directory
./a.out: can't bind socket (3)and err : -1: No such file or directory
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define NETLINK_TEST 28
#define GROUP_IB 1
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dst_addr;
struct nlmsghdr *nlh = NULL;
struct msghdr msg;
struct iovec iov;
int sock_fd;
int main(int argc, char ** argv)
{
int err;
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (sock_fd<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't assign fd for socket", argv[0] );
perror(s);
return -1;
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = 0; // Unicast
//src_addr.nl_groups = RTMGRP_LINK; /* Multicast, bind call always fails for non zero values */
err = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
perror("bind");
if (err<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't bind socket (%d)and err : %d", argv[0], sock_fd,err );
perror(s);
return -1;
}
memset(&dst_addr, 0, sizeof(dst_addr));
nlh = (struct nlhmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
msg.msg_name = (void *)&dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("pid : %d\n Waiting for messages from kernel...\n",getpid());
recvmsg(sock_fd, &msg, 0);
printf("Message : %s\n", NLMSG_DATA(nlh));
close(sock_fd);
return 0;
}
Netlink socket binds are sensitive to what USER you are- I've seen them reliably fail if you are not running the program in question as 'root', at least on RedHat 6.
Try running as root 1st, before changing your logic. If you get the same failure as you do in normal operation, then you know it isn't (necessarily) a permissions issue.
The issue is
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
Does you kernel module define the NETLINK_TEST family? your own family might must be supported at kernel module and it should post the message in the proper group using nlmsg_multicast()
RTMGRP_LINK is group defined in NETLINK_ROUTE.
This sample code is example for multicast
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#define MYPROTO NETLINK_USERSOCK
#define MYMGRP 21
int open_netlink(void)
{
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;
sock = socket(AF_NETLINK, SOCK_RAW, MYPROTO);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}
memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
/* addr.nl_groups = MYMGRP; */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
return sock;
}
void read_event(int sock)
{
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;
iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Ok, listening.\n");
ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", NLMSG_DATA((struct nlmsghdr *) &buffer));
}
int main(int argc, char *argv[])
{
int nls;
nls = open_netlink();
if (nls < 0)
return nls;
while (1)
read_event(nls);
return 0;
}
kernel module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#define MYPROTO NETLINK_USERSOCK
#define MYGRP 21
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init hello_init(void)
{
pr_info("Inserting hello module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Exiting hello module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

Resources