inet_ntoa conversion problem - c

In this snippet of code i capture the packet and i am trying to display the source and destination address by using inet_ntoa , even before that i am printing the packet src and dst address in hexa format. The problem here is both do not match, the o/p of inet_ntoa is wrong as shown in o/p
the src ip address should be 172.28.6.87 but inet_ntoa shows 86.212.172.28
the src ip address should be 172.28.6.110 but inet_ntoa shows 6.87.172.28
char *ptr = NULL;
ptr_fltr = (struct packet_filter*)(packet);
memcpy(out_data,packet,50);
printf("\n");
for(i= 28;i<36;i++)
printf("%#x\t",out_data[i]);
printf("*******************************************************************\n");
printf("---------------------Received Packet Info--------------------\n");
ptr = inet_ntoa(ptr_fltr->ip.ip_src);
printf("Source Ip Addr :%s\n",ptr);
here
struct packet_filter
{
struct mac_filter mac;
struct ip_filter ip;
union {
struct udp_filter proto;
}protocol;
}__attribute__((packed));
struct ip_filter
{
u_char ip_vhl;
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src; /* source and dest address */
struct in_addr ip_dst; /* source and dest address */
}__attribute__((packed));
output
0xac 0x1c 0x6 0x57 0xac 0x1c 0x6 0x6e
************************************************************
--------------------Received Packet Info--------------------
Source Ip Addr :86.212.172.28
Destination Ip Addr :6.87.172.28

Clearly your struct is off by two bytes by the time you get to the IP addresses. I've checked against the IPv4 protocol and that bit looks OK. So I suspect the struct mac is wrong. I presume struct mac is meant to be an ethernet frame. If so, it's already a bit suspicious because an Ethernet frame is not of a fixed length.
Also, (assuming you are getting these from the Berkeley Packet Filter) make sure you calculate the start of the packet correctly from the bpf header (you can't rely on sizeof(struct bpf_header)).

Your IP packet starts at offset 16, and if you have copied struct mac from ethernet header it is 14 bytes long. Looks like there is some unexpected data in packet.

Related

When implementing traceroute in C , I couldn't find the IP address of the router that send back the timeout error message

In order to receive timeout ICMP message, I set the receive socket recvfd with option IP_RECVERR:
int val=1;
setsockopt(recvfd,IPPROTO_IP,IP_RECVERR,&val,sizeof(int));
And I try to receive the timeout ICMP error message with recvmsg(recvfd,msg,MSG_ERRQUEUE);
The error message is stored in msg, which is a pointer to the struct msghdr.
I look up the manual, 7/ip and recvmsg.
The struct msghdr as follows,
struct iovec { /* Scatter/gather array items */
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
struct msghdr {
void *msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
struct iovec *msg_iov; /* scatter/gather array */
size_t msg_iovlen; /* # elements in msg_iov */
void *msg_control; /* ancillary data, see below */
size_t msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
The field msg_control points to struct cmsghdr, as follows,
struct cmsghdr {
socklen_t cmsg_len; /* data byte count, including hdr */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by
unsigned char cmsg_data[]; */
};
and the field cmsg_data points to a struct sock_extended_err, as follows
#define SO_EE_ORIGIN_NONE 0
#define SO_EE_ORIGIN_LOCAL 1
#define SO_EE_ORIGIN_ICMP 2
#define SO_EE_ORIGIN_ICMP6 3
struct sock_extended_err {
uint32_t ee_errno; /* error number */
uint8_t ee_origin; /* where the error originated */
uint8_t ee_type; /* type */
uint8_t ee_code; /* code */
uint8_t ee_pad;
uint32_t ee_info; /* additional information */
uint32_t ee_data; /* other data */
/* More data may follow */
};
struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);
In the manual, it says
the macro SO_EE_OFFENDER returns a pointer to the address of the network object where the error originated from given a pointer to the ancillary message.
I tried to convert the struct sock_extended_err into IP address and print it out, but the result is 2.0.0.0 all the time. But I couldn't find elsewhere that stores the IP address of the router that send back the timeout ICMP error message in the above three structs.
Code that receives the error message as follows,
//construct the msghdr struct
struct msghdr* msg=(struct msghdr*)malloc(sizeof(struct msghdr));
char recvBuffer[CMSG_SPACE(64)];
msg->msg_control=recvBuffer;
msg->msg_controllen=sizeof(recvBuffer);
//receive the message
recvmsg(recvfd,msg,MSG_ERRQUEUE);
//visit all the nodes in msg and get the IP address
struct cmsghdr* cmsg=CMSG_FIRSTHDR(msg);
for(;cmsg!=NULL;cmsg=CMSG_NXTHDR(msg,cmsg)){
struct sock_extended_err* exterr=(struct sock_extended_err*)(CMSG_DATA(cmsg));
struct sockaddr* DestAddr=SO_EE_OFFENDER(exterr);
struct sockaddr_in* ad=(struct sockaddr_in*)DestAddr;
char destination[20];
inet_ntop(AF_INET,ad,destination,sizeof(destination));
printf("IP: %20s\n",destination);
}
Could anyone help me ? Thanks.

Issue sniffing PCAP

I don't understand why my following code doesn't work properly.
When I sniff ethernet the bytes that I receive are shifted by 2 bytes
I send use sudo sendip -p ipv4 -p udp 127.0.0.1 -d r8 to send packet to my computer
With the following code:
#include <pcap/pcap.h>
#define SIZE_ETHERNET 14
#define ETHER_ADDR_LEN 6
struct sniff_ethernet {
u_char ether_dhost[ETHER_ADDR_LEN];
u_char ether_shost[ETHER_ADDR_LEN];
u_short ether_type;
};
void packet_call_back(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
struct sniff_ethernet *ethernet = (struct sniff_ethernet*)(bytes);
printf("test = %#x\n", ethernet->ether_type); // print is 0x0
}
int main(void) {
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle = pcap_create("any", errbuf);
pcap_set_timeout(handle, -1);
pcap_loop(handle, 0, packet_call_back, NULL);
pcap_close(handle);
}
The ether_type that I receive is incorrect here 0x0000 instead of 0x0800
but if instead of: struct sniff_ethernet *ethernet = (struct sniff_ethernet*)(bytes);
I put struct sniff_ethernet *ethernet = (struct sniff_ethernet*)(bytes + 2);
here everything work fine and I can analyse my packet easily.
I compile with gcc test.c -l pcap
And I work on an Ubuntu VM with parallels
Thank's for reading
When I sniff ethernet the bytes that I receive are shifted by 2 bytes
You're not sniffing Ethernet, you're sniffing the "any" device. That will capture on all interfaces, whether they're Ethernet interfaces or not; even if they are all Ethernet interfaces, that doesn't make a difference.
In order to make this work, a link-layer header type other than Ethernet is used on the "any" device. On Linux, that's a special header; here's what that header looks like.
ALL programs that use libpcap to capture network traffic or to read a capture file must, after opening the capture device (pcap_activate(), pcap_open_live(), pcap_open()) or the capture file (pcap_open_offline()), call pcap_datalink() to determine the link-layer header type from the device or the file.
That function returns a value that can be found in the link-layer header types list; it will be one of the values with a name that begins with DLT_. Do not check for the numerical values given there; check for the DLT_ values.

How can I get the address and port of a client in C sockets (sys/socket.h)?

I am currently messing around with sockets (on a UNIX based system) and would like to get the address and port of a client when they connect. How can I do this?
You can extract it from a struct sockaddr_in (or sockaddr_in6).
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 */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
See the man page: http://man7.org/linux/man-pages/man7/ip.7.html
Also, you can see my DNS-server code as a practical example (there is extracted IPV6 address sin6.sin6_addr).

I can't find DSCP field in IP header, only the deprecated TOS field

I will try to garantee some QoS with my access point made with Raspberry Pi.
Before starting, I'm getting my hands dirty: I read about the tcp, udp and ip headers. In the IP header description I saw the DSCP field, originally defined as the Type of Service field.
DSCP field would provide me interesting infos about the Qos, so I looked for it...but I couldn't find it: I still have the deprecated tos field.
From my /usr/include/netinet/ip.h:
struct ip {
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
Infos about my sistem:
uname -r -> 3.13.0-49-generic
lsb_release -a -> Distributor ID: Ubuntu
Description: Ubuntu 14.04.2 LTS
Release: 14.04
Codename: trusty
The DSCP field has taken the place of the ToS field: these are just two names for the very same field in the IP header. If the sender put a DSCP value into the field, then it's just fine to access it using the ToS field.
Note however that whether and how the DSCP/ToS field will be actually parsed by routers is highly implementation dependent. Most carriers (ISPs) will simply clear the field as it enters their network. Most home routers will ignore the field, although OpenWRT will interpret it as a ToS.
In short — using the DSCP/ToS field without a good understanding of your local network environment is just cargo culting.

How to sniff PPP packet with libpcap?

I can capture packets from eth0 interface, and sniff ip packets as follows
/* IP header */
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
So if need to capture packets from PPP interface, how to define the header struct?
I just notice that, the length of header is 32 bytes in this case.
If, when you capture on the PPP device with libpcap, the pcap_datalink() routine returns DLT_PPP, then you define the header in the fashion indicated by the entry for LINKTYPE_PPP/DLT_PPP in the tcpdump.org link-layer header types page:
PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03, it's PPP in HDLC-like framing, with the PPP header following those two bytes, otherwise it's PPP without framing, and the packet begins with the PPP header.

Resources