ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language 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.
I'm trying to write a raw socket program where client send a raw IP packet to server and then the server reply a raw IP packet to the client.
Below is the source code of my program. Currently, client can send raw IP packets to the server, but when the server send a reply raw packet to the client, the client can never be able to receive it. I can't understand why. Can you please help with this????
Thanks in advance.
Code:
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define PORT 999
#define IP_PROTOCOL 253
#define PACKET_NUM 24
#define DATAGRAM_SIZE 512
unsigned short csum (unsigned short *buf, int nwords) {
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
int main (int argc, char *argv[]) {
int sk = socket(AF_INET, SOCK_RAW, IP_PROTOCOL);
//contains ip header, payload
//do not include Ethernet head and CRC (kernel will deal with Ethernet head and CRC)
char datagram[DATAGRAM_SIZE];
struct ip *iph = (struct ip *) datagram;
char *payload = datagram + sizeof(struct ip);
struct sockaddr_in cli_sin, cli02;
struct sockaddr_in serv_sin, serv02;
if(argc != 2) {
printf("usage: %s -s|-c\n", argv[0]);
exit(1);
}
memset (datagram, 0, sizeof(datagram)); /* zero out the buffer */
cli_sin.sin_family = AF_INET;
cli_sin.sin_port = htons (PORT);
//client has to run on this machine
cli_sin.sin_addr.s_addr = inet_addr("192.168.0.113");//client ip address
//cli_sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
serv_sin.sin_family = AF_INET;
serv_sin.sin_port = htons (PORT);
//server has to run on this machine
serv_sin.sin_addr.s_addr = inet_addr("192.168.0.111");//server ip address
//serv_sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(datagram);
iph->ip_id = 54321;
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IP_PROTOCOL;
iph->ip_sum = 0;
{
int on = 1;
if (setsockopt (sk, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
}
//if this is client
if (strcmp(argv[1], "-c") == 0) {
while (1) {
static int counter = 0;
ssize_t n = 0;
socklen_t len = DATAGRAM_SIZE;
payload[0] = 'A';
iph->ip_src.s_addr = cli_sin.sin_addr.s_addr;
iph->ip_dst.s_addr = serv_sin.sin_addr.s_addr;
//no need to do checksum
//iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
printf("client sending packet number: %d\n", counter);
if (sendto(sk, datagram, iph->ip_len, 0,
(struct sockaddr *) &serv_sin, sizeof (serv_sin)) < 0)
{
printf("client error sendto\n");
}
n = recvfrom(sk, datagram, sizeof(datagram), 0,
(struct sockaddr *)&serv_sin, &len);
if ( n < 0) {
printf("server error recvfrom\n");
}
printf("Client: ip_p: %d, n: %d, datagram: %d\n",
(int)iph->ip_p, n, payload[0]);
counter++;
if (counter >= PACKET_NUM) {
break;
}
}//end of while (1) loop
//end of client
} else { // server
socklen_t len = DATAGRAM_SIZE;
ssize_t n = 0;
//char buf[DATAGRAM_SIZE];
len = sizeof(cli_sin);
//struct ip *serv_iph = (struct ip *)buf;
for (; ;) {
n = recvfrom(sk, datagram, sizeof(datagram), 0,
(struct sockaddr *)&cli_sin, &len);
if ( n < 0) {
printf("server error recvfrom\n");
}
printf("Server: ip_p: %d, n: %d, datagram: %d\n",
(int)iph->ip_p, n, payload[0]);
payload[0] += 1;
iph->ip_id++;
iph->ip_src.s_addr = serv02.sin_addr.s_addr;
iph->ip_dst.s_addr = cli02.sin_addr.s_addr;
if (sendto(sk, datagram, iph->ip_len, 0,
(struct sockaddr *) &cli_sin, sizeof (cli_sin)) < 0)
{
printf("server error sendto\n");
}
printf("server, after sending a reply to client\n");
}
}
return 0;
}
When last time I write raw packet sender program there were problems with check sum. Check packets using ethereal or some other sniffer which can indicate check sum and some other errors.
Here is some code I have once written that sniffs packets on
specified interface.
Perhaps this could help you:
What I want to do is to build a IP packet myself and then send it using raw socket interface between client and server. I have problems when send a IP packet which is build myself. Can you please help me with this?? Thanks!!!
I'm not shure, but when I do similar prog, I was always calculate checksums. I think you should recalculate checksum for your packet when you change IP fields and send back the packet. Yes, kernel deal with some check sums but there are more then one - I do not remember which is not calculated by the kernel - if you left it as zero kernel will fill it, but if you put there something then kernel will leave it untouched, even if it wrong!
Distribution: Debian, Suse, Mandrake (on old computer)
Posts: 9
Rep:
Hi!
I didn't have much time but I managed to change your code so that it works.
Changes are in setting ip addresses into sockaddr_in's and ip header values
inside loops.
You were also using cli02 and serv02 but never setting values to them.
Because I am not network guru I can not tell you why this code works
after placing setting ip header fileds inside loops.
Hope this helps you.
Code:
Code:
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define PORT 999
#define IP_PROTOCOL 253
#define PACKET_NUM 5
#define DATAGRAM_SIZE 512
#define SERVER_IP "192.168.176.128"
#define CLIENT_IP "192.168.176.1"
unsigned short csum (unsigned short *buf, int nwords) {
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
int main (int argc, char *argv[]) {
int sk = socket(AF_INET, SOCK_RAW, IP_PROTOCOL);
//contains ip header, payload
//do not include Ethernet head and CRC (kernel will deal with Ethernet head and CRC)
char datagram[DATAGRAM_SIZE];
struct ip *iph = (struct ip *) datagram;
char *payload = datagram + sizeof(struct ip);
struct sockaddr_in cli_sin;
struct sockaddr_in serv_sin;
if(argc != 2) {
printf("usage: %s -s|-c\n", argv[0]);
exit(1);
}
memset (datagram, 0, sizeof(datagram)); /* zero out the buffer */
cli_sin.sin_family = AF_INET;
cli_sin.sin_port = htons (PORT);
//client has to run on this machine
//cli_sin.sin_addr.s_addr = inet_addr("192.168.0.113");//client ip address
cli_sin.sin_addr.s_addr = inet_addr (CLIENT_IP);
serv_sin.sin_family = AF_INET;
serv_sin.sin_port = htons (PORT);
//server has to run on this machine
//serv_sin.sin_addr.s_addr = inet_addr("192.168.0.111");//server ip address
serv_sin.sin_addr.s_addr = inet_addr (SERVER_IP);
{
int on = 1;
if (setsockopt (sk, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
}
//if this is client
if (strcmp(argv[1], "-c") == 0) {
payload[0] = 'A';
iph->ip_id = 1;
while (1) {
static int counter = 0;
ssize_t n = 0;
socklen_t len = DATAGRAM_SIZE;
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(datagram);
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IP_PROTOCOL;
iph->ip_sum = 0;
iph->ip_src.s_addr = cli_sin.sin_addr.s_addr;
iph->ip_dst.s_addr = serv_sin.sin_addr.s_addr;
serv_sin.sin_family = AF_INET;
serv_sin.sin_port = htons (PORT);
serv_sin.sin_addr.s_addr = inet_addr (SERVER_IP);
//no need to do checksum
//iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
printf("client sending packet number: %d\n", counter);
printf("src: %d.%d.%d.%d, dst: %d.%d.%d.%d\n",
iph->ip_src.s_addr & 0xff,
(iph->ip_src.s_addr >> 8) & 0xff,
(iph->ip_src.s_addr >> 16) & 0xff,
(iph->ip_src.s_addr >> 24) & 0xff,
iph->ip_dst.s_addr & 0xff,
(iph->ip_dst.s_addr >> 8) & 0xff,
(iph->ip_dst.s_addr >> 16) & 0xff,
(iph->ip_dst.s_addr >> 24) & 0xff);
if (sendto(sk, datagram, iph->ip_len, 0,
(struct sockaddr *) &serv_sin, sizeof (serv_sin)) < 0)
{
printf("client error sendto\n");
}
serv_sin.sin_family = AF_INET;
serv_sin.sin_port = htons (PORT);
serv_sin.sin_addr.s_addr = inet_addr (SERVER_IP);
n = recvfrom(sk, datagram, sizeof(datagram), 0,
(struct sockaddr *)&serv_sin, &len);
if ( n < 0) {
printf("client error recvfrom\n");
}
printf("Client: ip_p: %d, n: %d, datagram: %d (%c), id: %d\n",
(int)iph->ip_p, n, payload[0], payload[0], iph->ip_id);
printf("port: %d\n", ntohs(serv_sin.sin_port));
printf("src: %d.%d.%d.%d, dst: %d.%d.%d.%d\n",
iph->ip_src.s_addr & 0xff,
(iph->ip_src.s_addr >> 8) & 0xff,
(iph->ip_src.s_addr >> 16) & 0xff,
(iph->ip_src.s_addr >> 24) & 0xff,
iph->ip_dst.s_addr & 0xff,
(iph->ip_dst.s_addr >> 8) & 0xff,
(iph->ip_dst.s_addr >> 16) & 0xff,
(iph->ip_dst.s_addr >> 24) & 0xff);
counter++;
if (counter >= PACKET_NUM) {
break;
}
}//end of while (1) loop
//end of client
} else { // server
socklen_t len = DATAGRAM_SIZE;
ssize_t n = 0;
//char buf[DATAGRAM_SIZE];
len = sizeof(cli_sin);
//struct ip *serv_iph = (struct ip *)buf;
for (; ;) {
cli_sin.sin_family = AF_INET;
cli_sin.sin_port = htons (PORT);
cli_sin.sin_addr.s_addr = inet_addr (CLIENT_IP);
n = recvfrom(sk, datagram, sizeof(datagram), 0,
(struct sockaddr *)&cli_sin, &len);
if ( n < 0) {
printf("server error recvfrom\n");
}
printf("port: %d\n", ntohs(serv_sin.sin_port));
cli_sin.sin_family = AF_INET;
cli_sin.sin_port = htons (PORT);
cli_sin.sin_addr.s_addr = inet_addr (CLIENT_IP);
printf("Server: ip_p: %d, n: %d, datagram: %d, id: %d\n",
(int)iph->ip_p, n, payload[0], iph->ip_id);
payload[0] += 1;
iph->ip_id++;
iph->ip_src.s_addr = serv_sin.sin_addr.s_addr;
iph->ip_dst.s_addr = cli_sin.sin_addr.s_addr;
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(datagram);
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IP_PROTOCOL;
iph->ip_sum = 0;
printf("Server: ip_p: %d, n: %d, datagram: %d (%c), id: %d\n",
(int)iph->ip_p, n, payload[0], payload[0], iph->ip_id);
printf("src: %d.%d.%d.%d, dst: %d.%d.%d.%d\n",
iph->ip_src.s_addr & 0xff,
(iph->ip_src.s_addr >> 8) & 0xff,
(iph->ip_src.s_addr >> 16) & 0xff,
(iph->ip_src.s_addr >> 24) & 0xff,
iph->ip_dst.s_addr & 0xff,
(iph->ip_dst.s_addr >> 8) & 0xff,
(iph->ip_dst.s_addr >> 16) & 0xff,
(iph->ip_dst.s_addr >> 24) & 0xff);
printf("port: %d\n", ntohs(serv_sin.sin_port));
if (sendto(sk, datagram, iph->ip_len, 0,
(struct sockaddr *) &cli_sin, sizeof (cli_sin)) < 0)
{
printf("server error sendto\n");
}
printf("server, after sending a reply to client\n");
}
}
return 0;
}
Checksums can be added directly by the hardware. Sometimes while looking at outgoing packet with a sniffer, you will realize that these checksum are zero. The hardware (PHY or MAC component) will in fine put it on the wire.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.