[SOLVED] Thread vs process: icmp packet creation fails in thread
Linux - NetworkingThis forum is for any issue related to networks or networking.
Routing, network cards, OSI, etc. Anything is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Thread vs process: icmp packet creation fails in thread
I want to generate an ICMP echo request through C program, in a posix thread in linux.
As a tryout, i wrote a sample code in main(). ICMP echo and its reply worked as expected. The packet length was 28 (20 bytes IP header + 8 bytes ICMP header).
Than i shifted the code to a thread. Now the main() has thread creation and a wait till thread exits.
But, in the thread, sendto() returns 28, while when observed in tcpdump, this packet is shown with length 48, and a line below as IP bad-hlen 0, which signifies that the ECHO request was not proper. The total length field in IP header shows 0x30 (48 bytes) instead of 0x1c (28 bytes). Following are the tcpdump snapshots.
Successful tcpdump, using process code
As part of troubleshooting, dumped the buffer used for sending to a file and verified through hexdump. Both code generates same packet. Verified by printing hex values too. Same result. Tried forking, instead of creating thread. It worked.
The only difference in two codes is thread and process. Running out of probable problems.
The distros tried are CentOS 7.1 (Kernel 3.10) and Fedora 13 (kernel 2.6.39).
unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* * Our algorithm is simple, using a 32 bit accumulator (sum), we add
* * sequential 16 bit words to it, and at the end, fold back all the
* * carry bits from the top 16 bits into the lower 16 bits.
* */
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
//void* HandleFailoverStrategy(void* arg)
//Dumping headers to a file, to be viewed using hexdump
int ip_file = open("working_header",O_CREAT|O_RDWR);
if(ip_file == -1)
{
perror("Error in file opening");
}
ret = write(ip_file, packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
//binding to a specific interface
struct ifreq ifr;
memset(&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "enp1s0");
if (ioctl (sockfd, SIOCGIFINDEX, &ifr) < 0)
{
//Failed to find interface on device
printf("Failed to find interface on device\n");
return -1;
}
if (setsockopt (sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0)
{
//Failed to bind to interface enp2s0
printf("Failed to bind to interface %s\n",ifr.ifr_name);
return -1;
}
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
printf("Unable to set timeout\n");
return -1;
}
/* IP_HDRINCL must be set on the socket so that the kernel does not attempt
* * to automatically add a default ip header to the packet*/
ret = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* * Our algorithm is simple, using a 32 bit accumulator (sum), we add
* * sequential 16 bit words to it, and at the end, fold back all the
* * carry bits from the top 16 bits into the lower 16 bits.
* */
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
//binding to a specific interface
struct ifreq ifr;
memset(&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "enp1s0");
if (ioctl (sockfd, SIOCGIFINDEX, &ifr) < 0)
{
//Failed to find interface on device
printf("Failed to find interface on device\n");
return NULL;
}
if (setsockopt (sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0)
{
//Failed to bind to interface enp2s0
printf("Failed to bind to interface %s\n",ifr.ifr_name);
return NULL;
}
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
printf("Unable to set timeout\n");
return NULL;
}
/* IP_HDRINCL must be set on the socket so that the kernel does not attempt
* * to automatically add a default ip header to the packet*/
ret = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.