creating ip header using IP_HDRINCL option not doing anything - c

i wanted to send an icmp packet by writing my own IP header so i used the IP_HDRINCL option the code compiled and runs without any errors but there is no packet being sent when i run the program and capture packets using wireshark no error message from the program as well
here is the code:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 2048
char sendbuf[BUFFSIZE];
int seqno=0;
unsigned short chksum(void *data,int bytes){
unsigned int sum=0;
unsigned short *octate=data,result;
while(bytes>1){
sum+=*octate++;
bytes-=2;
}
if(bytes==1){
sum+=*(unsigned char *)octate;
}
while(sum>>16){
sum=(sum>>16)+(sum&0xffff);
}
result=~sum;
return result;
}
struct addrinfo * getaddr(char *name){ //convert user input host to address structure
int e;
struct addrinfo hints,*res;
memset(&hints,0,sizeof(hints));
hints.ai_flags=AI_CANONNAME;
hints.ai_family=AF_INET;
if(e=getaddrinfo(name,0,&hints,&res)!=0){
printf("getaddrinfo error: %s\n",gai_strerror(e));
}
return res;
}
void create_packet(struct sockaddr *d){
/* Creating IP Packet */
struct ip *ip;
ip=(struct ip*)sendbuf;
ip->ip_v=4;
ip->ip_hl=5;
ip->ip_tos=0;
ip->ip_len=20+8;
ip->ip_id=8848;
ip->ip_off=IP_DF;
ip->ip_ttl=7;
ip->ip_p=IPPROTO_ICMP;
char srcip[]="192.168.1.69";
struct addrinfo *source = getaddr(srcip);
struct sockaddr_in *dest=(struct sockaddr_in *)d;
struct sockaddr_in *src=(struct sockaddr_in *)source->ai_addr;
ip->ip_src=src->sin_addr;
ip->ip_dst=dest->sin_addr;
ip->ip_sum=0;
ip->ip_sum=chksum(ip,sizeof(*ip));
/* Creating ICMP Packet */
struct icmp *icmp;
icmp=(struct icmp *)(sendbuf+20);
icmp->icmp_type=ICMP_ECHO;
icmp->icmp_code=0;
icmp->icmp_id=getpid();
icmp->icmp_seq=++seqno;
icmp->icmp_cksum=0;
icmp->icmp_cksum=chksum(icmp,8);
}
void main(int argc,char **argv){
int sock;
int on=1;
struct addrinfo *addr=getaddr(argv[1]);
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))==-1){
perror("socket error: ");
return;
}
if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on))==-1){
perror("setsockopt error");
return;
}
create_packet(addr->ai_addr);
if(sendto(sock,sendbuf,28,0,addr->ai_addr,addr->ai_addrlen)==-1){
perror("sendto error");
return;
}
}

While I can't be certain based on your code alone, I suspect that you're running this program on a little-endian processor (x86-based), and IP expects its numbers in big-endian order. This means that any multi-byte fields (ip_len, ip_off) are written in the wrong order. I suspect that if you change the following 2 lines:
ip->ip_len=20+8;
ip->ip_off=IP_DF;
to this:
ip->ip_len=htons(20+8);
ip->ip_off=htons(IP_DF);
that the packets will be properly sent.
Incidentally the ip->ip_id field is also in big-endian order, but unless you're sending multiple fragments it doesn't much matter.

Related

Sending Struct over Socket

I'm fairly new to working with sockets, and so far have only been able to send a char [] over a socket.
Now though, I'm trying to send a struct over a socket and am unsure of how to do this. I have the following struct
struct student_rec {
char name[25];
float gpa;
int pid;
};
In which I've initialized with the following
struct student_rec stu
strcpy(stu.name, "Mike McDonald");
stu.gpa = 2.5;
stu.pid = 0x12345678;
I can send stu.name without any issue, but am unsure of what parameters to use for the method sendto() when sending a struct.
Client
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
/* This program sends a message in datagram to the receiver and waits
for reply. */
#define MSG "CIS 454/554 is a great course!!!"
#define BUFMAX 2048
struct student_rec {
char name[25];
float gpa;
int pid;
};
main(argc,argv)
int argc;
char *argv[];
{
int sk;
char buf[BUFMAX];
struct student_rec stu;
struct sockaddr_in remote;
struct hostent *hp;
strcpy(stu.name, "Mike McDonald");
stu.gpa = 2.5;
stu.pid = 0x12345678;
/* Create an Internet domain datagram socket */
sk = socket(AF_INET,SOCK_DGRAM,0);
remote.sin_family = AF_INET;
/* Get the remote machine address from its symbolic name
given in the command line argument */
hp = gethostbyname(argv[1]);
if (hp == NULL) {
printf("Can't find host name. %s\n", argv[1]);
exit (1);
}
bcopy(hp->h_addr,&remote.sin_addr.s_addr,hp->h_length);
/* get the remote port number from the command line */
remote.sin_port = ntohs(atoi(argv[2]));
sendto(sk,stu.name,strlen(stu.name)+1,0,&remote,sizeof(remote));/* Send the message */
read(sk,buf,BUFMAX); /* Get the reply */
printf("%s\n",buf);
close(sk);
}
Server
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* This program creates an Internet domain datagram socket, binds a
name to it, reads from it, and then replies to the sender. */
#define MSG "Are you sure ? I doubt!!!"
#define BUFMAX 2048
struct student_rec {
char name[25];
float gpa;
int pid;
};
main()
{
struct sockaddr_in local, remote;
int sk,rlen=sizeof(remote),len=sizeof(local);
char buf[BUFMAX];
/* Create an Internet domain datagram socket from which to read */
sk = socket(AF_INET,SOCK_DGRAM,0);
struct student_rec stu;
strcpy(stu.name, "Mike McDonald");
stu.gpa = 2.5;
stu.pid = 0x12345678;
local.sin_family = AF_INET; /* Define the socket domain */
local.sin_addr.s_addr = INADDR_ANY; /* Wildcard mach. addr */
local.sin_port = 0; /* Let the system assign a port */
bind(sk,&local,sizeof(local));
getsockname(sk,&local,&len); /* Get the port number assigned */
printf("socket has port %d\n",htons(local.sin_port)); /* Publish the number */
/* Read from the socket */
recvfrom(sk,buf,BUFMAX,0,&remote,&rlen);
printf("%s\n",buf);
sendto(sk,stu.name,strlen(stu.name)+1,0,&remote,sizeof(remote));
close(sk);
}
I think I'm getting confused as to what to replace strlen(stu.name) with as I'm now sending the entire struct.
Could I use a for loop to read each element of my struct, or is there some parameters I can pass to sendto() to do this?
You should serialize struct to xml, json, text or similar format and read it back on the other end as:
/* Tx */
struct student_rec s = {...};
char txt[100];
const int len = sprintf(txt, "%d,%f,%s", s.pid, s.gpa, s.name);
send_txt(txt);
/* Rx */
char txt[100];
recv_txt(txt);
struct student_rec s
sscanf(txt, "%d,%f,%s", &s.pid, &s.gpa, s.name);

Linux networking (gethostbyaddr)

I am trying to get host information about the host with IP address 89.249.207.231. I know that it exists, because when I type the IP address in my browser's url field it finds the page. Here is my code in C.
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
int main()
{
struct in_addr addr;
inet_aton("89.249.207.231", &addr);
struct hostent* esu = gethostbyaddr((const char*)&addr),sizeof(addr), AF_INET);
printf("%s\n", esu->h_name);
return 0;
}
When I compile and run it, it gives "Segmentation fault". I can not understand the problem with my code.
Any hints and suggestions would be appreciated.
Thanks!
Even if the host exists, you may not be able to extract its hostname.
For example, the following code, without the deprecated functions that you use gives the result host=google-public-dns-a.google.com whereas with your host address gives could not resolve hostname.
The reason of your segfault, is that esu is NULL, because the function could not resolve a hostname by the given IP.
Here is the code:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
struct sockaddr_in sa; /* input */
socklen_t len; /* input */
char hbuf[NI_MAXHOST];
memset(&sa, 0, sizeof(struct sockaddr_in));
/* For IPv4*/
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("8.8.8.8");
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr *) &sa, len, hbuf, sizeof(hbuf),
NULL, 0, NI_NAMEREQD)) {
printf("could not resolve hostname\n");
}
else {
printf("host=%s\n", hbuf);
}
return 0;
}

Get list of devices on LAN in C

I'd like to get a list of available devices (their IP address or hostname should be fine) connected to my local network. I've got some examples in C#, but I couldn't find any sample using C/C++. I'm familiar with the BSD socket API, just to clarify.
I have a "stub" kind of idea: maybe I should determine the range of the IP addresses that the devices on my LAN can potentially belong to, and then determine if they e. g. respond to PING, or something like that. How could I achieve these?
I want my application to run on Linux and iOS. That's why I'd prefer BSD sockets, or at a maximum, Foundation/GNUstep (although they are written in Objective-C).
You can also e.g. send an ICMP echo request packet to 224.0.0.1. This is a special all-nodes multicast address every node should respond to (except if a firewall rule or network policy setting prevents it).
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
// Define the Packet Constants
// ping packet size
#define PING_PKT_S 64
// Automatic port number
#define PORT_NO 0
// Automatic port number
#define PING_SLEEP_RATE 1000000
// Gives the timeout delay for receiving packets
// in seconds
#define RECV_TIMEOUT 1
// Performs a DNS lookup
char *dns_lookup(char *addr_host, struct sockaddr_in *addr_con)
{
//printf("\nResolving DNS..\n");
struct hostent *host_entity;
char *ip=(char*)malloc(NI_MAXHOST*sizeof(char));
int i;
if ((host_entity = gethostbyname(addr_host)) == NULL)
{
// No ip found for hostname
return NULL;
}
//filling up address structure
strcpy(ip, inet_ntoa(*(struct in_addr *)
host_entity->h_addr));
(*addr_con).sin_family = host_entity->h_addrtype;
(*addr_con).sin_port = htons (PORT_NO);
(*addr_con).sin_addr.s_addr = *(long*)host_entity->h_addr;
return ip;
}
// Resolves the reverse lookup of the hostname
char* reverse_dns_lookup(char *ip_addr)
{
struct sockaddr_in temp_addr;
socklen_t len;
char buf[NI_MAXHOST], *ret_buf;
temp_addr.sin_family = AF_INET;
temp_addr.sin_addr.s_addr = inet_addr(ip_addr);
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr *) &temp_addr, len, buf,
sizeof(buf), NULL, 0, NI_NAMEREQD))
{
//printf("Could not resolve reverse lookup of hostname\n");
return NULL;
}
ret_buf = (char*)malloc((strlen(buf) +1)*sizeof(char) );
strcpy(ret_buf, buf);
return ret_buf;
}
// Driver Code
int main(int argc, char *argv[])
{
int sockfd;
char *ip_addr, *reverse_hostname;
struct sockaddr_in addr_con;
int addrlen = sizeof(addr_con);
char net_buf[NI_MAXHOST];
int i=0;
for(int i=1;i<255;++i)
{
char ip[80];
sprintf(ip, "192.168.2.%d", i);
ip_addr = dns_lookup(ip, &addr_con);
if(ip_addr==NULL)
{
//printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
reverse_hostname = reverse_dns_lookup(ip_addr);
if(reverse_hostname==NULL)
{
//printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
//printf("\nTrying to connect to '%s' IP: %s\n",ip, ip_addr);
printf("\nReverse Lookup domain: %s",
reverse_hostname);
printf("\n %s \n", ip);
}
return 0;
}

How can retrive all TCP UDP opened ports?

I need to make a custom port scanner that scan only opened TCP and UDP ports. I'm working in standard C with sockets. For the moment i retrieve all ports in a range i set.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
int scanPort(struct hostent *hostaddr,int port){
char responce[1024];
char *message="checking port";
struct sockaddr_in server_address;
int socket_d;
int rval;
socket_d = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(socket_d == -1)
{
perror("Socket()\n");
return errno;
}
memset(&server_address,0,sizeof(server_address));
server_address.sin_family=AF_INET;
server_address.sin_port=htons(port);
memcpy(&server_address.sin_addr,hostaddr->h_addr,hostaddr->h_length);
rval = connect(socket_d,(struct sockaddr *) &server_address, sizeof(server_address));
if(rval == -1)
{
close(socket_d);
return 0;
}else{
close(socket_d);
return 1;
}
}
int main(int argc, char **argv)
{
if(argc < 4){
printf("Exemplu: ./portscanner <adresa_ip> <port_pornire> <port_oprire> \n");
return (EINVAL);
}
int startPort;
int endPort;
int port;
struct hostent *host_address;
host_address = gethostbyname( argv[1] );
startPort = atoi(argv[2]);
endPort = atoi(argv[3]);
for(port = startPort;port<=endPort;port++)
{
if(scanPort(host_address,port)==1){
printf("Port %d is open\n",port);
}
}
}
In the example you can see how i tried to resolve this problem. But i don't see a method to check only the TCP and UDP ports. Please help me with this.
Regards,
Badea Sorin!
There is a plenty ways to do it. I recommend you to install nmap and read the manual.
Many scan methods are implemented there and described in the manual.
You can also refer to the source code if you need more details.
Good luck.

Why is my packet reading program returning incorrect data?

I have written a packet reader that uses libpcap to read a capture file. It reads the capture file and uploads captured data to a MySQL database. Sometimes it seems to work fine and others it returns invalid data (e.g. the source and destination ip will be the same, the tcp ports are all junk). I'm running this under a virtual RHEL 5. Here is my code (sorry if it's rather long or unnecessarily convoluted, this is my first attempt at this).
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include "npc_tcp.h"
#include "npc_udp.h"
#include <ftw.h>
#include <pcap.h>
#include <stdio.h>
#include <sys/stat.h>
#include <regex.h>
#include <string.h>
#include <time.h>
const int IPTYPE_TCP = 6;
const int IPTYPE_UDP = 17;
struct cap_data {
char ts[64];
u_int16_t ether_type;
u_int16_t proto;
char *srcip;
char *dstip;
char *srcmac;
u_int16_t srcport;
u_int16_t dstport;
u_int8_t flags;
u_int capsize;
};
int main(int argc, char **argv) {
//pcap
struct cap_data data;
struct pcap_pkthdr pkthdr;
const u_char *packet;
pcap_t *handle;
char *fname = argv[1];
printf("%s\n", fname);
char errbuf[PCAP_ERRBUF_SIZE];
handle = pcap_open_offline(fname, errbuf);
char buf[1000];
while (packet = pcap_next(handle, &pkthdr)) {
int ether_flag;
struct ether_header *ether;
u_short ether_type;
ether = (struct ether_header *) packet;
data.ether_type = ntohs(ether->ether_type);
ether_flag = 1;
if (ether_flag) {
if (data.ether_type == ETHERTYPE_IP) {
struct ip *ip_hdr;
u_int length = pkthdr.len;
ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
data.proto = ip_hdr->ip_p;
data.dstip = inet_ntoa(ip_hdr->ip_dst);
data.srcip = inet_ntoa(ip_hdr->ip_src);
if (data.proto == IPTYPE_TCP) {
struct tcphdr *tcp;
tcp = (struct tcphdr*)(packet + sizeof(struct ether_header) +
sizeof(struct ip));
data.srcport = tcp->th_sport;
data.dstport = tcp->th_dport;
printf("%s %u %s %u\n\n", inet_ntoa(ip_hdr->ip_src), tcp->th_sport, inet_ntoa(ip_hdr->ip_dst), tcp->th_dport);
} else if (data.proto == IPTYPE_UDP) {
struct udphdr *udp;
udp = (struct udphdr *)(packet + sizeof(struct ether_header) +
sizeof(struct ip));
data.srcport = udp->uh_sport;
data.dstport = udp->uh_dport;
printf("%s %u %s %u\n\n", inet_ntoa(ip_hdr->ip_src), udp->uh_sport, inet_ntoa(ip_hdr->ip_dst), udp->uh_dport);
}
}
}
}//while
pcap_close(handle);
return 0;
}
UPDATE:
This outputs..
source ip port dest ip port
66.68.236.207 30151 66.68.236.207 47873
172.22.162.235 60920 172.22.162.235 36175
67.207.28.150 23007 67.207.28.150 22038
172.22.162.235 60920 172.22.162.235 36175
67.207.28.151 22038 67.207.28.151 23007
65.55.87.43 20480 65.55.87.43 21764
67.207.28.150 23007 67.207.28.150 22038
The addresses should not be the same and the port numbers are wrong as well.
I have no idea where to even start looking for errors as my code (at least to me) looks correct. Any help, tips, or advice would be greatly appreciated. Thanks :)
Two problems:
inet_ntoa returns a pointer to a static buffer.
When calling it twice within the same printf, it overwrites the same buffer. So you end up printing the same data.
Use inet_ntop instead, and give each call a separate buffer.
You should use ntohs() to convert the ports to host-order before printing.
What happens if, right after calling pcap_open_offline(), you do
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "This program handles only Ethernet captures\n");
return 2;
}

Resources