jma2000
asked on
Segmentation Fault
I am parsing a TCPDUMP file (in HEX) and when I try and print certain fileds like src and dst address get a segmentation fault. Below is from GDB debug and shows value of my struct IP in memory at the time as well the the line of code that is faulting. Why??
Program received signal SIGSEGV, Segmentation fault.
0x00010e4c in main (argc=2, argv=0xffbffa04) at change.c:71
71 printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
(gdb) print *ip
$1 = {ip_v = 4 '\004', ip_hl = 5 '\005', ip_tos = 0 '\0', ip_len = 52,
ip_id = 14200, ip_off = 16384, ip_ttl = 128 '\200', ip_p = 6 '\006',
ip_sum = 24303, ip_src = {S_un = {S_un_b = {s_b1 = 172 '¬',
s_b2 = 31 '\037', s_b3 = 11 '\v', s_b4 = 23 '\027'}, S_un_w = {
s_w1 = 44063, s_w2 = 2839}, S_addr = 2887715607}}, ip_dst = {S_un = {
S_un_b = {s_b1 = 172 '¬', s_b2 = 31 '\037', s_b3 = 1 '\001',
s_b4 = 7 '\a'}, S_un_w = {s_w1 = 44063, s_w2 = 263},
S_addr = 2887713031}}}
Program received signal SIGSEGV, Segmentation fault.
0x00010e4c in main (argc=2, argv=0xffbffa04) at change.c:71
71 printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
(gdb) print *ip
$1 = {ip_v = 4 '\004', ip_hl = 5 '\005', ip_tos = 0 '\0', ip_len = 52,
ip_id = 14200, ip_off = 16384, ip_ttl = 128 '\200', ip_p = 6 '\006',
ip_sum = 24303, ip_src = {S_un = {S_un_b = {s_b1 = 172 '¬',
s_b2 = 31 '\037', s_b3 = 11 '\v', s_b4 = 23 '\027'}, S_un_w = {
s_w1 = 44063, s_w2 = 2839}, S_addr = 2887715607}}, ip_dst = {S_un = {
S_un_b = {s_b1 = 172 '¬', s_b2 = 31 '\037', s_b3 = 1 '\001',
s_b4 = 7 '\a'}, S_un_w = {s_w1 = 44063, s_w2 = 263},
S_addr = 2887713031}}}
Could you post more of your code areound line 71? In particular how you allocate and initialize 'ip'
ASKER
ok here it is: Thx
/* If we have an IP packet... */
if (ntohs(eth_header_ptr->eth er_type) == EtherType_IP)
{
/* Get the IP header */
struct ip *ip; /* The IP header */
printf ("size %d\n",size_ethernet);
ip = (struct ip*)(pktbuf + size_ethernet);
printf(" Length = %u\n", ip->ip_len);
printf(" IP ID = %u\n", ip->ip_id);
printf(" Protocol = %x\n", ip->ip_p);
/* Print some info for testing */
printf("SrcIP : %c\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
}
/* If we have an IP packet... */
if (ntohs(eth_header_ptr->eth
{
/* Get the IP header */
struct ip *ip; /* The IP header */
printf ("size %d\n",size_ethernet);
ip = (struct ip*)(pktbuf + size_ethernet);
printf(" Length = %u\n", ip->ip_len);
printf(" IP ID = %u\n", ip->ip_id);
printf(" Protocol = %x\n", ip->ip_p);
/* Print some info for testing */
printf("SrcIP : %c\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
}
Are you sure that shouldn't be
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src)); // not '%c'
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src)); // not '%c'
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
ASKER
Sorry..I was exprimenting. %c aso caused a fault but so does %s as you can see in the above GDB trace.
What's the declaration of 'IP'?
ASKER
if it helps this is the struct ip from #include <netinet/ip.h>
struct ip {
48 #if BYTE_ORDER == LITTLE_ENDIAN
49 u_int ip_hl:4, /* header length */
50 ip_v:4; /* version */
51 #endif
52 #if BYTE_ORDER == BIG_ENDIAN
53 u_int ip_v:4, /* version */
54 ip_hl:4; /* header length */
55 #endif
56 u_char ip_tos; /* type of service */
57 u_short ip_len; /* total length */
58 u_short ip_id; /* identification */
59 u_short ip_off; /* fragment offset field */
60 #define IP_RF 0x8000 /* reserved fragment flag */
61 #define IP_DF 0x4000 /* dont fragment flag */
62 #define IP_MF 0x2000 /* more fragments flag */
63 #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
64 u_char ip_ttl; /* time to live */
65 u_char ip_p; /* protocol */
66 u_short ip_sum; /* checksum */
67 struct in_addr ip_src,ip_dst; /* source and dest address */
68 } __packed;
69
struct ip {
48 #if BYTE_ORDER == LITTLE_ENDIAN
49 u_int ip_hl:4, /* header length */
50 ip_v:4; /* version */
51 #endif
52 #if BYTE_ORDER == BIG_ENDIAN
53 u_int ip_v:4, /* version */
54 ip_hl:4; /* header length */
55 #endif
56 u_char ip_tos; /* type of service */
57 u_short ip_len; /* total length */
58 u_short ip_id; /* identification */
59 u_short ip_off; /* fragment offset field */
60 #define IP_RF 0x8000 /* reserved fragment flag */
61 #define IP_DF 0x4000 /* dont fragment flag */
62 #define IP_MF 0x2000 /* more fragments flag */
63 #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
64 u_char ip_ttl; /* time to live */
65 u_char ip_p; /* protocol */
66 u_short ip_sum; /* checksum */
67 struct in_addr ip_src,ip_dst; /* source and dest address */
68 } __packed;
69
After looking at that for a while, it seems OK. Are you compiling with any optimizations enabled? (BTW, I assume that 'Length' etc. are outputted correctly)
ASKER
Yes length, ID, Protocol print correctly but none of the other elements do: for example
printf(" IP version = %d\n", ip_buffer->ip_v); also faults.
compile is gcc - o foo foo.c -lsocket -lnsl
I am going nuts over this as it all looks ok
printf(" IP version = %d\n", ip_buffer->ip_v); also faults.
compile is gcc - o foo foo.c -lsocket -lnsl
I am going nuts over this as it all looks ok
What is the value of size_ethernet?
Does the problem happening the first time or after some parsings?
Does the problem happening the first time or after some parsings?
ASKER
size_ethernet = 14,
It processes the ethernet headers fine but as soon it it sees an IP protocol and tries to parse the IP fields it faults on most fields (not on length, protocol)
It processes the ethernet headers fine but as soon it it sees an IP protocol and tries to parse the IP fields it faults on most fields (not on length, protocol)
Is pktbuf unsiged char?
ASKER
Here is how pktbuf is defined:
char *pktbuf
pktbuf = malloc(frame_header.bytes_ caped + 1);
char *pktbuf
pktbuf = malloc(frame_header.bytes_
What is the CPU? Some CPU's can't access words at odd addresses.
Try to define pktbuf as
unsigned char *pktbuf;
unsigned char *pktbuf;
ASKER
It is a Sun solaris box - tried it on oa few of them.
Unsigned char didn't seem to help.
Is it related to the type of format the data is stored in - it is in HEX not ASCII.
Unsigned char didn't seem to help.
Is it related to the type of format the data is stored in - it is in HEX not ASCII.
I was looking at the netinet/ip.h, and the structure is defined inside a
#ifdef __USE_BSD
which is defined on features.h by defining the following line on the code
#define _BSD_SOURCE 1
or compile using -D_BSD_SOURCE
This came from my linux box. I don't know if its the same thing on Solaris. You can try this as well.
#ifdef __USE_BSD
which is defined on features.h by defining the following line on the code
#define _BSD_SOURCE 1
or compile using -D_BSD_SOURCE
This came from my linux box. I don't know if its the same thing on Solaris. You can try this as well.
I wrote this small program to write an ip header to a file in binary format (unsigned char), read it back and print the source and destination ip addresses.
It works fine for me. You can test it in your environment.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
int main()
{
FILE *f;
struct ip *ip;
unsigned char str[]= { 0x45,0x00,0x00,0x3c,0xeb,0 xc0,0x40,0 x00,0x40,0 x06,0xfc,0 x03,
0xac,0x1a,0x1c,0x61, /*Source IP*/
0xac,0x1a,0x1c,0xa2 }; /* Destination IP*/
unsigned char *strl;
strl = (unsigned char*) malloc (50);
/* create the file of binary file with the ip header */
f=fopen("iphead","w");
fwrite(&str,sizeof(struct ip),1,f);
fclose(f);
/* read the ipheader */
f=fopen("iphead","r");
fread(strl,sizeof(struct ip),1,f);
fclose(f);
ip = (struct ip*) strl;
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
free(strl);
}
It works fine for me. You can test it in your environment.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
int main()
{
FILE *f;
struct ip *ip;
unsigned char str[]= { 0x45,0x00,0x00,0x3c,0xeb,0
0xac,0x1a,0x1c,0x61, /*Source IP*/
0xac,0x1a,0x1c,0xa2 }; /* Destination IP*/
unsigned char *strl;
strl = (unsigned char*) malloc (50);
/* create the file of binary file with the ip header */
f=fopen("iphead","w");
fwrite(&str,sizeof(struct ip),1,f);
fclose(f);
/* read the ipheader */
f=fopen("iphead","r");
fread(strl,sizeof(struct ip),1,f);
fclose(f);
ip = (struct ip*) strl;
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
free(strl);
}
ASKER
It compiles but when I run it nothing happens - not sure what that means.
ASKER
sorry..yes it works - now what? :o)
Good question :-)
This means that isn't the format the data is stored.
I think this will restrict your error to the file loading or to the variable where you are loading the file to. I strongly suggest to use unsigned char, since you are dealing with bytes and not chars. Try to allocate pktbuf as
pktbuf = (unsigned char *) malloc(frame_header.bytes_ caped + 256);
This is just to make sure that there isn't a memory invasion. Is the file that you are trying to parse tcpdumped in the same machine you are running this program?
And a last question: is your tcpdump only ip packets? can it be another protocol?
This means that isn't the format the data is stored.
I think this will restrict your error to the file loading or to the variable where you are loading the file to. I strongly suggest to use unsigned char, since you are dealing with bytes and not chars. Try to allocate pktbuf as
pktbuf = (unsigned char *) malloc(frame_header.bytes_
This is just to make sure that there isn't a memory invasion. Is the file that you are trying to parse tcpdumped in the same machine you are running this program?
And a last question: is your tcpdump only ip packets? can it be another protocol?
Hello,
I think we need to check how inet_ntoa() works here. I checked the documentation and saw that inet_ntoa() returns a static string which is overwritten by recursive calls.The length of the returned string is 16 bytes.
It's quite possible that the inet_ntoa() is returning a NON NULL terminated string and printf throws an exception/error dump when it tries to print a NON NULL terminated string.
What you can do is try and copy the contents of innet_ntoa() into a string.
Do this..
initialize a char array of 20 bytes, lets say bye doing..
char op[20];
using.. memset() , set all bytes to NULL.
and then use strcpy(op,inet_ntoa(ip->ip _src));
later put a trace on the character string op[];
and check its contents, you may as well try printing that string.
Regards,
Siddhesh
I think we need to check how inet_ntoa() works here. I checked the documentation and saw that inet_ntoa() returns a static string which is overwritten by recursive calls.The length of the returned string is 16 bytes.
It's quite possible that the inet_ntoa() is returning a NON NULL terminated string and printf throws an exception/error dump when it tries to print a NON NULL terminated string.
What you can do is try and copy the contents of innet_ntoa() into a string.
Do this..
initialize a char array of 20 bytes, lets say bye doing..
char op[20];
using.. memset() , set all bytes to NULL.
and then use strcpy(op,inet_ntoa(ip->ip
later put a trace on the character string op[];
and check its contents, you may as well try printing that string.
Regards,
Siddhesh
ASKER
thanks for all the good suggestions..let me try and get back shortly.
ASKER
ok..so far tried the pktbuf = (unsigned char *) malloc(frame_header.bytes_ caped + 256); but no luck. It is a raw binary tcpdump file captured on another system. I read it in ethereal with no problem and I use the tcpdump -x option to convert to HEX from raw binary.
I will look at the next suggestion now.
Thx
I will look at the next suggestion now.
Thx
Is the another system also a Sun Solaris?
ASKER
I tried the strcopy for strcpy(op,inet_ntoa(ip->ip _src));
and got a fault on that line.
debug is as follows: basically all zeros
Program received signal SIGSEGV, Segmentation fault.
0x000113e4 in parse_ip_packet (buf=0x23440 "", total=14) at detect.c:197
197 strcpy(op,inet_ntoa(ip->ip _src));
(gdb) print op
$1 = '\0' <repeats 19 times>
(gdb)
$2 = '\0' <repeats 19 times>
(gdb)
$3 = '\0' <repeats 19 times>
(gdb)
$4 = '\0' <repeats 19 times>
(gdb)
$5 = '\0' <repeats 19 times>
(gdb)
$6 = '\0' <repeats 19 times>
(gdb)
$7 = '\0' <repeats 19 times>
(gdb)
$8 = '\0' <repeats 19 times>
(gdb)
$9 = '\0' <repeats 19 times>
(gdb)
$10 = '\0' <repeats 19 times>
(gdb)
$11 = '\0' <repeats 19 times>
(gdb)
$12 = '\0' <repeats 19 times>
(gdb)
$13 = '\0' <repeats 19 times>
(gdb)
$14 = '\0' <repeats 19 times>
(gdb)
$15 = '\0' <repeats 19 times>
(gdb)
$16 = '\0' <repeats 19 times>
(gdb)
$17 = '\0' <repeats 19 times>
(gdb)
$18 = '\0' <repeats 19 times>
(gdb)
$19 = '\0' <repeats 19 times>
(gdb)
$20 = '\0' <repeats 19 times>
(gdb)
$21 = '\0' <repeats 19 times>
(gdb)
$22 = '\0' <repeats 19 times>
and got a fault on that line.
debug is as follows: basically all zeros
Program received signal SIGSEGV, Segmentation fault.
0x000113e4 in parse_ip_packet (buf=0x23440 "", total=14) at detect.c:197
197 strcpy(op,inet_ntoa(ip->ip
(gdb) print op
$1 = '\0' <repeats 19 times>
(gdb)
$2 = '\0' <repeats 19 times>
(gdb)
$3 = '\0' <repeats 19 times>
(gdb)
$4 = '\0' <repeats 19 times>
(gdb)
$5 = '\0' <repeats 19 times>
(gdb)
$6 = '\0' <repeats 19 times>
(gdb)
$7 = '\0' <repeats 19 times>
(gdb)
$8 = '\0' <repeats 19 times>
(gdb)
$9 = '\0' <repeats 19 times>
(gdb)
$10 = '\0' <repeats 19 times>
(gdb)
$11 = '\0' <repeats 19 times>
(gdb)
$12 = '\0' <repeats 19 times>
(gdb)
$13 = '\0' <repeats 19 times>
(gdb)
$14 = '\0' <repeats 19 times>
(gdb)
$15 = '\0' <repeats 19 times>
(gdb)
$16 = '\0' <repeats 19 times>
(gdb)
$17 = '\0' <repeats 19 times>
(gdb)
$18 = '\0' <repeats 19 times>
(gdb)
$19 = '\0' <repeats 19 times>
(gdb)
$20 = '\0' <repeats 19 times>
(gdb)
$21 = '\0' <repeats 19 times>
(gdb)
$22 = '\0' <repeats 19 times>
It seams that everything which is not u_char fails. So it might be an alignment problem. You said size_ethernet == 14, so after skipping 14 bytes, the buffer is not dword aligned any more. Can you try the following:
struct ip *ip; /* The IP header */
ip = (struct ip*) malloc(sizeof(struct ip));
memcpy(ip, pktbuf + size_ethernet, sizeof(struct ip));
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
struct ip *ip; /* The IP header */
ip = (struct ip*) malloc(sizeof(struct ip));
memcpy(ip, pktbuf + size_ethernet, sizeof(struct ip));
printf("SrcIP : %s\n", inet_ntoa(ip->ip_src));
printf("DstIP : %s\n", inet_ntoa(ip->ip_dst));
ASKER
YES!!! that did it!! I will have to look at this a little to understand but Thanks!!!!!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Yes cwwkie is correct, that was my initial doubt, when i said that inet_ntoa() returns a 16 byte string.
The C reference manual by Dennis Ritchie Page no 30, point number B.6) Implementation Difference says.
B.6) Structures and strings are aligned on a word boundary in UNIX , not aligned in GCOS
Regards,
Siddhesh
The C reference manual by Dennis Ritchie Page no 30, point number B.6) Implementation Difference says.
B.6) Structures and strings are aligned on a word boundary in UNIX , not aligned in GCOS
Regards,
Siddhesh