is it possible someone can help me workout why my ICMP sequence number isn't incrementing on every request, when this was used as a ping program it would increment the sequence number on each ping.
Also does anyone have any idea why my Round Trip Times are displaying as negative numbers? This also worked fine when this was a ping program.
Please assume all the code 'works', i have removed some for easier reading.
void
respond (int signum) {
struct sockaddr_storage peer_addr;
socklen_t peer_addrlen;
struct sockaddr_in addr;
struct sockaddr_in dstaddr;
struct iphdr * ip;
struct icmphdr * icmp;
struct timeval * sent;
int skt;
int sequence = 0;
long int length;
fd_set rdfds;
int ready;
int rtt;
char buff [BUF_SIZE];
/* Create and check Socket Number */
skt = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
int ttl = 0;
setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0;
/* Check Socket */
if (skt < 0) {
perror ("socket()");
exit (1);
}
/* Set IP Addresses */
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
/* Check Socket Bind */
if (bind (skt, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
perror ("Can't bind socket");
exit (1);
}
/* START SEND LOOP*/
int i;
for (i = 0; i < 7; i++){
ttl+=1;
setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
/* IP Buffer */
ip = (struct iphdr *)buff;
peer_addrlen = (socklen_t) sizeof (struct sockaddr_storage);
memset (&dstaddr, 0, sizeof(struct sockaddr_in));
dstaddr.sin_addr.s_addr = inet_addr(HOSTADDR);
dstaddr.sin_family = AF_INET;
/* ICMP Buffer */
memset (buff, 0, sizeof(buff));
icmp = (struct icmphdr *) buff;
icmp->type = ECHO_REQ;
icmp->id = htons(getpid( ) & 0xffff);
icmp->seqNum = htons(sequence++);
/* Check Send Time */
if (gettimeofday ((struct timeval *)icmp->data, NULL)) {
perror ("Can't establish send time");
exit (1);
}
/*Calculating packet size*/
length = sizeof(struct icmphdr) + sizeof(struct timeval);
icmp->checksum = ~(sum (0, buff, length));
/* Packet too small, ERROR
SEND Request */
if (sendto (skt, buff, length, 0,
(struct sockaddr *) &dstaddr, sizeof(struct sockaddr_in)) <= 0) {
perror ("sendto()");
exit (1);
}
/* Define File Descriptor */
timeout.tv_sec = 1;
timeout.tv_usec = 1;
FD_ZERO(&rdfds);
FD_SET (skt, &rdfds);
/* Select Data from File Descriptor */
ready = select (skt + 1, &rdfds, NULL, NULL, &timeout);
if (ready < 0) {
perror ("Select()");
exit (1);
}
/* Recieve Reply */
memset (buff, 0, sizeof(buff));
if (recvfrom (skt, buff, sizeof(buff), 0,
(struct sockaddr *) &peer_addr, &peer_addrlen) <= 0) exit (1);
/* Check Time Stamp */
if (gettimeofday (&end, NULL)) { // Timestamp reception
perror ("Can't establish time of receipt");
exit (1);
}
/* Check IP Protocol */
if (ip->version != 4 ||
sum (0, buff, sizeof(struct iphdr)) != 0xffff ||
ip->protocol != ICMP)
exit(1);
/* Get IP Payload legth and ICMP Address*/
length = ntohs(ip->length) - ip->hdrlen * 4; // Length of IP payload
icmp = (struct icmphdr *)((uint32_t *)ip + ip->hdrlen); // Find ICMP hdr
/* Check ICMP response type*/
if (icmp->type == 11){
printf("");
}
/* if (icmp->type != ECHO_REPL || sum (0, icmp, length) != 0xffff) {
fprintf (stderr, "Received %s\n", messages[icmp->type]);
//exit (1);
} */
/* Find the difference between sent and end times in 10s of ms */
sent = (struct timeval *)icmp->data;
if ((rtt = (end.tv_usec - sent->tv_usec) / 10) < 0)
rtt += 10000; // We've cycled to a new second
rtt += (end.tv_sec - sent->tv_sec) * 10000; // Add any seconds
/* PRINT ICMP REPLY*/
printf ("%ld bytes from %s: icmp_req=%d ttl=%d time= %0.1f ms\n",
length,
iptos(ntohl(ip->srcip)),
ntohs(icmp->seqNum),
ip->ttl,
((float)rtt) / 10);
} /*END SEND LOOP
/* 3 Second Probe */
alarm (5);
}
You're never setting sequence to 0 in this code, only declaring that it's an int.
In this piece of code:
/* IP Buffer */
ip = (struct iphdr *)buff;
peer_addrlen = (socklen_t) sizeof (struct sockaddr_storage);
memset (&dstaddr, 0, sizeof(struct sockaddr_in));
dstaddr.sin_addr.s_addr = inet_addr(HOSTADDR);
dstaddr.sin_family = AF_INET;
/* ICMP Buffer */
memset (buff, 0, sizeof(buff));
icmp = (struct icmphdr *) buff;
icmp->type = ECHO_REQ;
icmp->id = htons(getpid( ) & 0xffff);
icmp->seqNum = htons(sequence++);
you are treating the buffer buff as starting with both an IP header and an ICMP header. I believe you need to offset the icmphdr pointer by the size of the IP header, unless your icmphdr structure includes an iphdr at its start (which the Linux version does not):
icmp = (struct icmphdr*)(buff + sizeof(iphdr));
Also, you are overswriting the IP header by doing memset (buff, 0, sizeof(buff)); after writing the IP header to the buffer.
Related
I am trying to create multiple TUN devices to tunnel the multi-device traffic through a common physical interface.
This is the schema I have:
Socket 1 is sending traffic through tun1 with destiny IP 1.1.1.2 and Socket 2 is doing the same on the other interface.
I have a program running between both TUN devices and the physical interface (eth0) that encapsulates IP packets from the TUN devices into UDP packets and then it sends them to the server. The server unpacks the received packets and answers both clients with echo packets (also encapsulated).
When those packets arrive in eth0, another program reads the packets and forwards them to its TUN device. After that, both programs that are running behind the sockets are blocked on recv() function waiting for the server answer on tunX devices. However, it seems like the kernel is discarding those packets on the TUN devices even when they are well-formed.
I tried by change the netmask of both interfaces to 255.255.255.0 and then only one of the sockets receives correctly the answer.
All this software has been written in C.
This is the function to create a new TUN device:
#define MTU_SIZE 1500
#define SUBNET_MASK 0xFFFFFFFF
int open_tun_iface(char * name, uint8_t * ip)
{
int sock;
struct ifreq ifr_tun;
struct sockaddr_in * sa;
int tunfd = tun_init(name, &ifr_tun, IFF_TUN | IFF_NO_PI);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Open socket");
tun_close(tunfd);
return -1;
}
/* Set tun IP */
if (set_ip(&ifr_tun, sock, ip) < 0) {
tun_close(tunfd);
return -1;
}
sa = (struct sockaddr_in *)&ifr_tun.ifr_netmask;
memset(sa,0,sizeof(*sa));
sa->sin_family = AF_INET;
sa->sin_addr.s_addr = htonl(SUBNET_MASK);
/* Set the mask */
if (ioctl(sock, SIOCSIFNETMASK, &ifr_tun) < 0)
{
perror("SIOCSIFNETMASK");
tun_close(tunfd);
close(sock);
return -1;
}
/* Read flags */
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set Iface up and flags */
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set MTU size */
ifr_tun.ifr_mtu = MTU_SIZE;
if (ioctl(sock, SIOCSIFMTU, &ifr_tun) < 0) {
perror("SIOCSIFMTU");
tun_close(tunfd);
close(sock);
return -1;
}
close(sock);
return tunfd;
}
The function that reads packets from eth0 and forward them to the correct TUN interface is the following one:
void * downlink_distributor(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in spgw_addr;
int sockfd;
int sockaddr_len = sizeof(spgw_addr);
int len, packet_len, teid;
eNB * enb = (eNB *) args;
sockfd = get_spgw_socket(enb);
while(1)
{
/* Read packets from the server */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &spgw_addr, (socklen_t *)&sockaddr_len);
if(len < 0)
{
perror("recv downlink_distributor");
return NULL;
}
/* Get the TEID that identifies the TUN device */
teid = analyze_gtp_header(buffer, &packet_len);
if(teid > -1)
{
/* Write the packet in the TUN device associated with the packet TEID */
tun_write(get_tun_device(tun_descriptors[teid % MAX_TUN_DESCRIPTORS]), buffer + 8, packet_len);
}
}
return NULL;
}
Finally, this is the function that is running on both sockets and generate some traffic:
void * _generate_udp_traffic(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in dest_addr, spgw_addr;
fd_set fds;
struct timeval timeout;
int retval;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
int tunfd;
char msg[] = "Uplink traffic";
int sockfd;
int len;
int sockaddr_len = sizeof(dest_addr);
udp_generator gen;
/* Copy args */
memcpy(&gen, args, sizeof(udp_generator));
free(args);
/* Get TUN device */
tunfd = get_tun_device(gen.ue);
/* Get UE data socket (TUN socket) */
sockfd = get_data_plane_socket(gen.ue);
/* Configure destiny address */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(gen.port_dest);
memcpy((void*) &dest_addr.sin_addr.s_addr, gen.dest_ip, sizeof(struct in_addr));
/* Configure SPGW address */
memset(&spgw_addr, 0, sizeof(spgw_addr));
spgw_addr.sin_family = AF_INET;
spgw_addr.sin_port = htons(S1_U_PORT);
memcpy((void*) &spgw_addr.sin_addr.s_addr, get_spgw_ip(gen.ue), sizeof(struct in_addr));
while(1)
{
sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *) &dest_addr, sizeof(dest_addr));
while(1)
{
FD_ZERO(&fds);
FD_SET(tunfd, &fds);
retval = select(tunfd+1, &fds, 0, 0, &timeout);
if (retval == -1){
perror("select()");
}
else if (retval){
/* Reuse of the buffer with enough space for the GTP header */
len = tun_read(tunfd, buffer+8, BUFFER_DATA_LEN); /* We call read to clean the buffer from external traffic */
/* Detect IPv4 packets*/
if((buffer[8] & 0xF0) == 0x40)
{
generate_gtp_header(buffer, gen.ue, len);
break;
}
}
}
/* Protect the access to the eNB socket with a lock*/
pthread_mutex_lock(&lock);
/* Send tho the SPGW */
sendto(get_spgw_socket(gen.enb), buffer, len+8, 0, (const struct sockaddr *) &spgw_addr, sizeof(spgw_addr));
/* Unlock the mutex */
pthread_mutex_unlock(&lock);
/* Receive server answer listening on the TUN device */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &dest_addr, (socklen_t *)&sockaddr_len);
printf("UE %d has received: %s\n", get_ue_id(gen.ue), buffer);
/* Sleep 5 seconds */
sleep(5);
}
return NULL;
}
If the netmask is 32 both programs that are generating client traffic get blocked on recvfrom() inside _generate_udp_traffic function. If I set both netmask to 24 only one of them receive the answer from the server and the other gets stuck at recvfrom.
How can I configure both TUN devices to make both attached sockets work correctly?
UPDATE: I think that my problem is a kernel route table problem. If I use just one socket, I only receive traffic with netmask <= 30. With a netmask of 32, I can see that the server answer is introduced correctly on the TUN interface but somehow, the socket that is blocked in recv() does not receive anything.
I try to make a function that sends a icmp packet to another computer and when the other computer sends something back, the function returns a 1, else a 0. But the recvfrom function returns an error: "errno: Resource temporarily unavailable". I work on an Mac OS X, so I don't include headers from the linux kernel. Can anyone help me, cause I'm stuck.
#include "info.h"
char *getip()
{
char buffer[256];
struct hostent *h;
gethostname(buffer, 256);
h = gethostbyname(buffer);
return inet_ntoa(*(struct in_addr *)h->h_addr);
}
int host_alive(char *dst_addr, char *src_addr)
{
struct ip *ippacket;
struct ip *ip_reply;
struct icmp *icmppacket;
struct sockaddr_in connection;
struct timeval tv;
char *packet;
char *buffer;
int optval;
int addrlen;
int size;
int sock = 0;
packet = malloc(sizeof(struct ip) + sizeof(struct icmp));
buffer = malloc(sizeof(struct ip) + sizeof(struct icmp));
check(getuid() == 0, "Root priviliges are needed. Try: sudo ./bin/main");
ippacket = (struct ip *) packet;
icmppacket = (struct icmp *) (packet + sizeof(struct ip));
ippacket->ip_hl = 5;
ippacket->ip_v = 4;
ippacket->ip_tos = 0;
ippacket->ip_len = sizeof(struct ip) + sizeof(struct icmp);
ippacket->ip_id = htons(random());
ippacket->ip_ttl = 255;
ippacket->ip_p = IPPROTO_ICMP;
inet_aton(src_addr, &ippacket->ip_src);
inet_aton(dst_addr, &ippacket->ip_dst);
tv.tv_sec = 5;
tv.tv_usec = 0;
check((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1,\
"Failed to create socket");
check(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int)) != -1,\
"Failed to set the option to the socket.");
check(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(struct timeval)) != -1,\
"Failed to set the option to the socket.");
icmppacket->icmp_type = ICMP_ECHO;
icmppacket->icmp_code = 0;
icmppacket->icmp_id = 0;
icmppacket->icmp_seq = 0;
icmppacket->icmp_cksum = in_cksum((unsigned short *)icmppacket, sizeof(struct icmp));
ippacket->ip_sum = in_cksum((unsigned short *)ippacket, sizeof(struct ip));
connection.sin_family = AF_INET;
connection.sin_addr.s_addr = inet_addr(dst_addr);
sendto(sock, packet, ippacket->ip_len, 0, (struct sockaddr *)&connection,\
sizeof(struct sockaddr));
addrlen = sizeof(connection);
check((size = recvfrom(sock, buffer, sizeof(struct ip) + sizeof(struct icmp), 0,\
(struct sockaddr *)&connection, (socklen_t *)&addrlen)) != -1,\
"Failed to receive a message.");
printf("Received %d byte reply from %s:\n", size , dst_addr);
ip_reply = (struct ip*) buffer;
printf("ID: %d\n", ntohs(ip_reply->ip_id));
printf("TTL: %d\n", ip_reply->ip_ttl);
close(sock);
free(packet);
free(buffer);
return 1;
error:
if (sock)
close(sock);
free(packet);
free(buffer);
return 0;
}
unsigned short in_cksum(unsigned short *addr, int len)
{
int sum = 0;
u_short answer = 0;
u_short *w = addr;
int nleft = len;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
According to the documentation for recvfrom this is expected if you're using a non-blocking call:
If no messages are available at the socket, the receive call waits for a message to arrive, unless the socket is nonblocking (see fcntl(2)) in which case the value -1 is returned and the external vari-
able errno set to EAGAIN. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested; this behavior is affected by the
socket-level options SO_RCVLOWAT and SO_RCVTIMEO described in getsockopt(2).
You can look up errno values in /usr/include/sys/errno.h if you're curious as to what values map to what errors.
If you want this function to block you may need to set the MSG_WAITALL flag which "requests that the operation block until the full request is satisfied".
Normally in low-level UNIX socket code you'd do a select on that socket to wait for a read signal, then call recvfrom to receive the data if and only if that signal triggered. You can also do a non-blocking receive and on an EAGAIN just wait a short period of time before trying again, though that is less efficient.
I am implementing a trivial ICMP ping where in sending IP packet down the wire is giving me "Invalid argument".
Here's the code:
/* Create IP Packet */
int packet_size = IPv4_HDRLEN + (int)sizeof(ICMPHeader) + (int)[payload length];
char *packet = (char *) malloc (packet_size);
if (!packet)
{
perror("out of memory");
return;
}
//zero out the packet buffer
memset (packet, 0, packet_size);
//ip header
struct ip *iphdr = (struct ip *) packet;
iphdr->ip_v = 4;
iphdr->ip_hl = 5;
iphdr->ip_tos = 0;
iphdr->ip_len = htons(packet_size);
iphdr->ip_id = (ushort) rand();
iphdr->ip_off = 0;
iphdr->ip_ttl = 255;
iphdr->ip_p = IPPROTO_ICMP;
iphdr->ip_sum = in_cksum((uint16_t *)iphdr, IPv4_HDRLEN);
int status = 0;
char *src_ip = (char *) [#"127.0.0.1" UTF8String];
char *dst_ip = (char *) [#"2.3.4.5" UTF8String];
// Source IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, src_ip, &(iphdr->ip_src))) != 1) {
fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}
// Destination IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, dst_ip, &(iphdr->ip_dst))) != 1) {
fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}
icmpPacket = [NSMutableData dataWithLength:sizeof(*icmpPtr) + [payload length]];
assert(icmpPacket != nil);
icmpPtr = [icmpPacket mutableBytes];
icmpPtr->type = kICMPTypeEchoRequest;
icmpPtr->code = 0;
icmpPtr->checksum = 0;
icmpPtr->identifier = OSSwapHostToBigInt16(self.identifier);
icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
memcpy(&icmpPtr[1], [payload bytes], [payload length]);
icmpPtr->checksum = in_cksum([icmpPacket bytes], [icmpPacket length]);
int on = 1;
/* Copy icmp and data into the packet */
memcpy(packet + IPv4_HDRLEN, icmpPtr, [icmpPacket length]);
// Set flag so socket expects us to provide IPv4 header.
if (setsockopt (CFSocketGetNative(self->_socket), IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
perror ("setsockopt() failed to set IP_HDRINCL ");
exit (EXIT_FAILURE);
}
/* Send the packet */
if (self->_socket == NULL) {
bytesSent = -1;
err = EBADF;
} else {
bytesSent = sendto(
CFSocketGetNative(self->_socket),
packet,
packet_size,
0,
(struct sockaddr *) &sin,
sizeof (struct sockaddr)
);
err = 0;
if (bytesSent < 0) {
err = errno;
}
}
This is actually an extension to Apple's simple ping: https://developer.apple.com/library/mac/samplecode/SimplePing/Listings/SimplePing_m.html#//apple_ref/doc/uid/DTS10000716-SimplePing_m-DontLinkElementID_5
IP Packet that's being framed looks straight forward but for some reason, it's always giving errno 22. I am not sure what else is wrong with the code.
Socket is created using:
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
I cannot use raw sockets as i am building this for an iOS app.
Thanks
In case someone encounters the same issue, the problem was exactly as it's mentioned in this post: Raw socket sendto() failure in OS X
i'm trying to implement a Traceroute program but i've ran into two problems, one is that the TTL and RTT print out wrong; though they printed out right when implemented as a ping program. Finally my main issue is that when i'm incrementing the TTL it's going up by 2 instead of 1.
I've only included the code i think is necessary, thanks.
Thanks in advance :)
void
respond (int signum) {
struct sockaddr_storage peer_addr;
socklen_t peer_addrlen;
struct sockaddr_in addr;
struct sockaddr_in dstaddr;
struct iphdr * ip;
struct icmphdr * icmp;
struct timeval * sent;
int skt;
int sequence;
long int length;
fd_set rdfds;
int ready;
int rtt;
char buff [BUF_SIZE];
/* Create and check Socket Number */
skt = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
int ttl = 0;
setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0;
/* START SEND LOOP*/
int i;
for (i = 0; i < 4; i++){
ttl+=1;
setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
/* Check Socket */
if (skt < 0) {
perror ("socket()");
exit (1);
}
/* Set IP Addresses */
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
/* Check Socket Bind */
if (bind (skt, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
perror ("Can't bind socket");
exit (1);
}
/* IP Buffer */
ip = (struct iphdr *)buff;
peer_addrlen = (socklen_t) sizeof (struct sockaddr_storage);
memset (&dstaddr, 0, sizeof(struct sockaddr_in));
dstaddr.sin_addr.s_addr = inet_addr(HOSTADDR);
dstaddr.sin_family = AF_INET;
ip->ttl=(ttl++);
/* ICMP Buffer */
memset (buff, 0, sizeof(buff));
icmp = (struct icmphdr *) buff;
icmp->type = ECHO_REQ;
icmp->id = htons(getpid( ) & 0xffff);
icmp->seqNum = htons(sequence++);
/* Check Send Time */
if (gettimeofday ((struct timeval *)icmp->data, NULL)) {
perror ("Can't establish send time");
exit (1);
}
/*Calculating packet size*/
length = sizeof(struct icmphdr) + sizeof(struct timeval);
icmp->checksum = ~(sum (0, buff, length));
/* Packet too small, ERROR
SEND Request */
if (sendto (skt, buff, length, 0,
(struct sockaddr *) &dstaddr, sizeof(struct sockaddr_in)) <= 0) {
perror ("sendto()");
exit (1);
}
/* Define File Descriptor */
timeout.tv_sec = 2;
timeout.tv_usec = 0;
FD_ZERO(&rdfds);
FD_SET (skt, &rdfds);
/* Select Data from File Descriptor */
ready = select (skt + 1, &rdfds, NULL, NULL, &timeout);
if (ready < 0) {
perror ("Select()");
exit (1);
}
/* Recieve Reply */
memset (buff, 0, sizeof(buff));
if (recvfrom (skt, buff, sizeof(buff), 0,
(struct sockaddr *) &peer_addr, &peer_addrlen) <= 0) exit (1);
/* Check Time Stamp */
if (gettimeofday (&end, NULL)) { // Timestamp reception
perror ("Can't establish time of receipt");
exit (1);
}
/* Check IP Protocol */
if (ip->version != 4 ||
sum (0, buff, sizeof(struct iphdr)) != 0xffff ||
ip->protocol != ICMP)
exit(1);
/* Get IP Payload legth and ICMP Address*/
length = ntohs(ip->length) - ip->hdrlen * 4; // Length of IP payload
icmp = (struct icmphdr *)((uint32_t *)ip + ip->hdrlen); // Find ICMP hdr
/* Check ICMP response type*/
if (icmp->type == 11){
printf("Type 11: ICMP....");
}
/* if (icmp->type != ECHO_REPL || sum (0, icmp, length) != 0xffff) {
fprintf (stderr, "Received %s\n", messages[icmp->type]);
//exit (1);
} */
/* Find the difference between sent and end times in 10s of ms */
sent = (struct timeval *)icmp->data;
if ((rtt = (end.tv_usec - sent->tv_usec) / 100) < 0)
rtt += 10000; // We've cycled to a new second
rtt += (end.tv_sec - sent->tv_sec) * 10000; // Add any seconds
/* PRINT ICMP REPLY*/
printf ("%ld bytes from %s: icmp_req=%d ttl=%d time=%0.1f ms\n",
length,
iptos(ntohl(ip->srcip)),
ntohs(icmp->seqNum),
/*Set initial TTL */
ip->ttl,
((float)rtt) / 10);
} /*END SEND LOOP
/* Invalid Signal returned */
if (signum == SIGINT) {
printf ("\nGoodbye!\n");
exit(0);
}
/* 3 Second Probe */
alarm (3);
}
/* START SEND LOOP*/
int i;
for (i = 0; i < 4; i++){
ttl+=1;
setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
Here you increase ttl by one each time the loop iterates.
ip->ttl=(ttl++);
And here you increase it by one again. So if it was 1, it will be 2 after this line. However, once the loop iterates, you increase it again, so it will now be 3. That's why your ttl goes up by two on each iteration.
The line ip->ttl=(ttl++) means: Take the value of ttl and copy it to ip->ttl, then after doing so, increase ttl by one.
You're incrementing the ttl twice in that loop. Once when the for loop begins:
ttl+=1;
Then again while assigning it to the struct
ip->ttl=(ttl++);
As for the rtt, well that code just looks wrong to me.
#include<stdlib.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#define P 5000 /* lets flood the port */
unsigned short /* this function generates header checksums */
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 (void)
{
char ipp[10] = "1.2.3.4";
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */
char datagram[4096]; /* this buffer will contain ip header, tcp header,
and payload. we'll point an ip header structure
at its beginning, and a tcp header structure after
that to write the header values into it */
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
struct sockaddr_in sin;
/* the sockaddr_in containing the dest. address is used
in sendto() to determine the datagrams path */
sin.sin_family = AF_INET;
sin.sin_port = htons (P);/* you byte-order >1byte header values to network
byte order (not needed on big endian machines) */
sin.sin_addr.s_addr = inet_addr ("192.168.1.12");
memset (datagram, 0, 4096); /* zero out the buffer */
/* we'll now fill in the ip/tcp header values, see above for explanations */
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* no payload */
iph->ip_id = htonl (54321); /* the value doesn't matter here */
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */
iph->ip_src.s_addr = inet_addr (ipp);/* SYN's can be blindly spoofed */
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->source = htons (1234); /* arbitrary port */
tcph->dest = htons (P);
tcph->seq = random ();/* in a SYN packet, the sequence is a random */
tcph->ack_seq = 0;/* number, and the ack sequence is 0 in the 1st packet */
tcph->doff = 0; /* first and only tcp segment */
tcph->syn = 1;
tcph->window = htonl (65535); /* maximum allowed window size */
tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
should fill in the correct checksum during transmission */
tcph->urg_ptr = 0;
iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
/* finally, it is very advisable to do a IP_HDRINCL call, to make sure
that the kernel knows the header is included in the data, and doesn't
insert its own header into the packet before our data */
{ /* lets do it the ugly way.. */
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
}
int i1=49;
char i2 = 49;
int cc = 0;
int r1;
while (cc<99)
{
ipp[6] = i1;
ipp[7] = i2;
if(i1 == 57)
{
break;
}
if(i2 == 57 )
{ i2 = 48;
i1++;
}
i2++;
cc++;
iph->ip_src.s_addr = inet_addr (ipp);
if (sendto (s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->ip_len, /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof (sin)) < 0) /* a normal send() */
printf ("error\n");
else
printf ("sent \n");
}
return 0;
}
the code creates a raw socket with proper ip address and the source addrewss is 192.168.1.12...port 5000 ... the problem is that when i try to capture the packets sent using wireshark, it says something like bogus tcp headee length...should be atleast 20 ... how can i correct this error ...
P.S. you can refer link for the code explanation if you find the code lengthy ...
After further reading: change this line
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
to this
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
In the first case tcph would pointer far beyond iph.
char *datagramshould be unsigned char *too.