error in ip address received - c

I am implementing raw sockets in C. I have two programs (say server and client). Client is sending info to server and then server is sending ACK. Client has sent info and server has successfully received it. Now server is sending back ACK. Now, Client has parsed ethernet header successfully. I have problem in receiving the IP address.
1. What should be the type of arguments of the function CreateIPHeader()?
2. How to print IP addresses in ParseIPHeader()?
3. What should be the data type of value returned by ParseIPHeader, if I want just the IP addresses?
struct iphdr *CreateIPHeader(char *src_ip,char *dst_ip)
{
struct iphdr *ip_header;
ip_header=malloc(sizeof(struct iphdr));
//OTHER FIELDS OF IP HEADER
ip_header->saddr = inet_ntoa(*((struct in_addr *)(src_ip)));
ip_header->daddr = inet_ntoa(*((struct in_addr *)(dst_ip)));
ip_header->check=ComputeChecksum((unsigned char *)ip_header,ip_header->ihl*4);
printf("\nip to be sent = %s",ip_header->saddr); //printing correct IP
printf("\nip to be rcvd = %s",ip_header->daddr);
return(ip_header);
}
char* ParseIPHeader(unsigned char *packet,int len)
{
struct iphdr *ip_header,*ret_ip;
unsigned char *out;
struct ethhdr *ethernet_header;
out=malloc(2048);
memset(out, 0, 2048);
ethernet_header=(struct ethhdr *) out;
ret_ip=(struct iphdr *) (out + sizeof(struct ethhdr));
if(ntohs(ethernet_header->h_proto)==ETH_P_IP)
{
if(len>=(sizeof(struct ethhdr)+sizeof(struct iphdr)))
{
ip_header=(struct iphdr*)(packet+sizeof(struct ethhdr));
ret_ip->saddr = ip_header->daddr;
ret_ip->daddr = ip_header->saddr;
printf("daddr SENT = %s",ret_ip->daddr); //how to print them?
printf("saddr SENT = %s",ret_ip->saddr);
}
else
printf("IP packet does not have full header\n");
}
else
{
//not an IP packet
}
return out;
}
int main()
{
unsigned char in[2048];
int len;
char *rcv_ip;
Struct iphdr *ip_header;
memset(in,0,2048);
len=recvfrom(raw,in,2048,0,(struct sockaddr *)&packet_info,&packet_info_size);
rcv_ip=ParseIPHeader(in,len); /*I want this function to return me the ip addresses which I would use in the next line.*/
ip_header =CreateIPHeader(rcv_ip+5,rcv_ip);
memset(in,0,2048);
memcpy(in+sizeof(struct ethhdr),ip_header,ip_header->ihl*4);
sendrawpacket(raw,in,pkt_len);
free(ip_header);
return 0;
}
Any help would be appreciated.
Thanks :)

Instead of:
printf("\nDest Addr %s \n",inet_ntoa(*((struct in_addr *)&((ip_header->daddr)))));
printf("\nSource Addr %s \n",inet_ntoa(*((struct in_addr *)&(ip_header->saddr))));
Perhaps:
printf("\nDest Addr %s \n",inet_ntoa(ip_header->daddr));
printf("\nSource Addr %s \n",inet_ntoa(ip_header->saddr));

If indeed the printf is causing you to segfault and not something else, then perhaps:
struct in_addr dest;
dest.s_addr = ip_header->daddr;
printf("\nDest Addr %s \n", inet_ntoa(dest));
This is because (assuming you are using struct iphdr *ip_header) ip_header->daddr has a type of __u32 and inet_ntoa takes a struct in_addr.

There are a couple things wrong.
CreateIPHeader
You are confusing inet_ntoa() with inet_aton(). When creating the IP header, you want to set ip_header->saddr using something like
inet_aton(src_ip, (struct in_addr *) &ip_header->saddr)
Remember, the s_addr and d_addr in struct iphdr are of type __u32, not char arrays. Thus, when you make this change, the printf statements in CreateIPHeader will break.
main
The reason why your printf's are working is due to Problem #1. On receive, you call CreateIPHeader to create an incorrect struct iphdr (see above), which now incorrectly has C-strings assigned to saddr and daddr. Later, abc points to this incorrect header; your printf's magically work because abc->saddr and abc->daddr actually are C strings.
You are only overwriting the iphdr portion of packet_buffer (your memcpy statement). You must also change the h_dest and h_src values in struct ethhdr.
You really don't need to convert the IP addresses into a C string and then convert them back into IP addresses.
Also, you aren't freeing ip_header.
In general, you can do something like this:
int main()
{
unsigned char in[2048];
unsigned char out[2048];
int len;
memset(in, 0, 2048);
memset(out, 0, 2048);
len = recvfrom(raw, in, 2048, 0,
(struct sockaddr *) &packet_info, &packet_info_size);
struct ethhdr *in_eth = (struct ethhdr *) in;
if (ntohs(ethernet_header->h_proto) == ETH_P_IP &&
len >= sizeof(struct ethhdr) + sizeof(struct iphdr) {
struct iphdr *in_ip = (struct iphdr*) (in + sizeof(struct ethhdr));
/* create outbound packet, starting with eth header */
struct ethhdr *out_eth = (struct ethhdr *) out;
/* ... set h_dest and h_src */
struct iphdr *out_ip = (struct iphdr *) (out + sizeof(struct ethhdr));
out_ip->saddr = in_ip->daddr;
out_ip->daddr = in_ip->saddr;
/* calculate the IPv4 checksum, packet len etc */
sendrawpacket(raw, out, pkt_len);
}
return 0;
};
No guarantee that's bug-free. Just wrote it in the browser.

Related

sockets: right way to access IP and UDP headers on raw socket buffer

struct msghdr msg;
struct iovec iov;
unsigned char buf[BUFSIZE] = { '\0', };
ssize n;
int fd;
...
fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
...
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
...
n = recvmsg(sockfd, &msg, 0);
...
parse_pkt(buf, BUFSIZE);
So far so good, the packet is received, and now I need to parse it:
static int parse_packet(unsigned char *pkt, int len)
{
struct iphdr *ip = (struct iphdr *)(pkt + 14);
struct udphdr *udp;
/* ip has valid pointer and we can explore IP header fields, ip pointer is NOT modified. */
...
udp = (struct udphdr *)(ip + (ip->ihl << 2));
/* at this point I'm expecting udp to point past IP header space. */
...
}
The problem I'm seeing is that udp does not point where I'm expecting, I don't get why: pkt contains the whole packet (including Ethernet header, no VLANs), so ip obtains a pointer past ether_header, so udp = (struct udphdr *)(ip + (ip->ihl << 2)) should just skip over IP header size, but it does not!
What does work though is this:
struct iphdr *ip = (struct iphdr *)(pkt + 14);
...
udp = (struct udphdr *)(pkt + 14 + (ip->ihl << 2));
What is it so, what am I doing wrong?
When you do this:
udp = (struct udphdr *)(ip + (ip->ihl << 2));
You're doing pointer arithmetic in units of sizeof(*ip) instead of 1.
Your alternate works:
udp = (struct udphdr *)(pkt + 14 + (ip->ihl << 2));
Because pkt is an unsigned char * so pointer arithmetic is done in single byte units.
This would also work:
udp = (struct udphdr *)((unsigned char *)ip + (ip->ihl << 2));
As it allow you to perform pointer arithmetic in single byte units.

One Question Basic TCP/IP programming use bind() function

int serv_sock;
struct socckaddr_in serv_addr;
char *serv_port = "9190";
/*make server socket*/
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
/*serv_addr struct init*/
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_faimily = AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(serv_port));
**bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));**
i don't understand that why use (struct sockaddr *) ?
why can't wrote bind(serv_sock, &serv_addr, sizeof(serv_addr)); ?
why add (struct sockaddr *) type ? i don't understand
what's mean (struct sockaddr *) ?
So, i did one example
struct a {
int a;
int b;
};
int i = 10;
struct a b;
b.a = 10;
b.b = 20;
printf("%d \n", b.a); // A sentence
printf("%d \n", (struct a*)b.a); // B sentence
it returned 10, 10; i don't understand why use '(struct a*)'..
i don't understand a,b sentence difference
i want I would like to know the difference between the type with and without '*'.
The expression &serv_addr has type struct sockaddr_in *.
However, the function bind expects that the argument has type struct socckaddr *. This is a generic type for many address families.
The * character in this context indicates a pointer.
From the manual:
The actual structure passed for the addr argument will depend on the address family. The sockaddr structure is defined as something like:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
While the manual describes struct sockaddr_in as:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
The reason the the generic type exists is that IPv4 is not the only address family that exists.
The manual describes the IPv6 version:
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
Note that the all start with a sa_family_t member, which describes which family is being represented. The struct sockaddr sa_data member is the "payload" of the struct.
Directly passing a struct sockaddr_in * or struct sockaddr_in6 * when struct sockaddr * is expected would cause a warning/error. The (struct sockaddr *) explicitly converts the pointer to the type struct sockaddr *, which bind expects.
The statement
printf("%d \n", (struct a*)b.a);
is not valid. You take an integer, convert it to a pointer to a struct, then tell printf to interpret that argument as an integer.

kernel module for netfilter

I have started writing a kernel module for netfilter.
I am able to hook the netfilter and able to access the sk_buff.
Now I am trying to modify the packet(sk_buff) and trying to reinject the packet in tcp stack but it is not working.
My requirement is to drop SYN-ACK packet from a server and sending back a cooked up ack packet back to server without sending the SYN-ACK to client.
I have tried dev_queue_xmit after swapping source/dest IP, source/dest port
and source/dest MAC and recalculating the checksum and then send the packet using dev_queue_xmit. though dev_queue_xmit return success, the packet is not injecting to stack. Any help will be appreciated.
My code:
code is part of NF_INET_POST_ROUTING hook.
void do_exp(struct sk_buff *skb)
{
printk(KERN_INFO "Enering do_exp\n");
struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
struct tcphdr *tcp_header = (struct tcphdr *)skb_transport_header(skb);
struct sk_buff *newskb;
struct iphdr *newiph;
struct tcphdr *newtcph;
newskb = skb_copy(skb, GFP_ATOMIC);
//newskb->pkt_type = PACKET_OUTGOING;
// newskb->pkt_type = PACKET_HOST;
/*changing Mac address */
unsigned char srcaddr[6];
struct ethhdr *eth = eth_hdr(skb);
struct ethhdr *neweth = eth_hdr(newskb);
memcpy(srcaddr, eth->h_source, ETH_ALEN);
memcpy(neweth->h_source, eth->h_dest, ETH_ALEN);
memcpy(neweth->h_dest, srcaddr, ETH_ALEN);
newiph = (struct iphdr *) skb_network_header(newskb);
newtcph = (struct tcphdr *) skb_transport_header(newskb);
newiph->saddr = ip_header->daddr;
newiph->daddr = ip_header->saddr;
newtcph->source = tcp_header->dest;
newtcph->dest = tcp_header->source;
newtcph->syn = 0;
newtcph->ack_seq = tcp_header->seq + 1;
newtcph->seq = tcp_header->ack_seq;
newiph->check = ip_fast_csum((unsigned char *)newiph, newiph->ihl);
int ret = dev_queue_xmit(newskb);
}
TCP dump is showing correctly.

IP as number without usual functions?

Context
I would like to know if we can extract the ip information without having to use gethostinfo or getnameinfo etc...
Part of my code
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
in_len = sizeof in_addr;
infd = accept( fd , &in_addr , &in_len );
Question
I would like to get the client/incoming ip as a number without the usual formatting (eg 3232238637 instead of 192.168.12.45). Is it even possible ?
The source of those functions is obscure as one would wish, so I cannot figure out.
I read that in_addr (sockaddr) could have the information I need. There is no particular reason but discovering the "inners" of those functions and structures.
Thanks !
For IPv4:
struct sockaddr_in in_addr;
socklen_t in_len = sizeof in_addr;
int infd = accept(fd, (struct sockaddr*) &in_addr, &in_len);
// in_addr.sin_addr.s_addr contains the client's IP address
// as a 4-byte integer, in network byte order...
For IPv6:
struct sockaddr_in6 in_addr;
socklen_t in_len = sizeof in_addr;
int infd = accept(fd, (struct sockaddr*) &in_addr, &in_len);
// in_addr.sin6_addr.s6_addr contains the client's IP address
// as a 16-byte array...
If your question is how to "convert" from the binary representation of an IP address to a string "dotted-decimal" representation, rather than use one of the standard functions, then here is an example of how to do it for an IPV4 address ... if not, please clarify your question:
#include <stdio.h>
#include <netdb.h>
int main()
{
struct hostent *he;
long unsigned nbo;
he = gethostbyname("localhost");
nbo = htonl(*((int*)he->h_addr_list[0]));
printf("h_addr: %lx netbyteorder: %lx = %d.%d.%d.%d\n",
*((int*)he->h_addr_list[0]), nbo,
(nbo&0xFF000000)>>24, (nbo&0x00FF0000)>>16, (nbo&0x0000FF00)>>8,
(nbo&0x000000FF) );
}

Extracting IP Address and Port Info from sockaddr_storage

I'm currently working on a UDP server that receives a request from a client. The datagram I receive is a byte (char) array 5 elements long, with the final two elements being a port number.
Eventually this server will have to return both the IP address and the port number in a datagram of its own.
I already know how to use inet_ntop and the sockaddr struct I've connected with and received from to print out the ip, but it returns a string that's not in the format I want. For instance:
string1 = inet_ntop(their_addr.ss_family,get_in_addr(
(struct sockaddr *)&their_addr),s, sizeof s);
returns:
127.0.0.1
or:
[1][2][7][.][0][.][0][.][1]
when I need something like:
[127][0][0][1]
Should I be using some sort of character and array manipulation to make my 4-element byte array? Or does a sockaddr have this information in a way that I can leave it in this hex form and return it?
Assuming for IPv4.
After taking the address of your sockaddr_storage or sockaddr structure and casting it to the IPv4 version sockaddr_in, you can then access the individual bytes of the IPv4 address.
struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
Then you can take address of the s_addr member which is a 32 bit value (in_addr_t) that holds the 4 bytes of the ip address (in network byte order) and cast it to a pointer to an unsigned char which then lets you access the individual bytes of the value.
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
printf("%d %d %d %d\n", ip[0], ip[1], ip[2], ip[3]);
You want to probably use getnameinfo() function:
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
E.g.:
struct sockaddr_storage client_addr;
socklen_t client_len = sizeof(struct sockaddr_storage);
/* Accept client request */
int client_socket = accept(server_socket,
(struct sockaddr *)&client_addr, &client_len);
char hoststr[NI_MAXHOST];
char portstr[NI_MAXSERV];
int rc = getnameinfo((struct sockaddr *)&client_addr,
client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr),
NI_NUMERICHOST | NI_NUMERICSERV);
if (rc == 0)
printf("New connection from %s %s", hoststr, portstr);
Here is a simple immutable class I used for the same purpose you mentioned in your question:
class address_t {
private:
uint16_t m_Port = 0;
std::string m_Ip = "";
public:
address_t(const sockaddr_in & address) {
m_Ip = inet_ntoa(address.sin_addr);
m_Port = ntohs(address.sin_port);
}
uint16_t GetPort() const { return m_Port; }
std::string GetIp() const { return m_Ip; }
std::string ToString() const {
return "IP: " + m_Ip + ", Port: " + std::to_string(m_Port);
}
};

Resources