Link to home
Start Free TrialLog in
Avatar of jma2000
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}}}
 
Avatar of jkr
jkr
Flag of Germany image

Could you post more of your code areound line 71? In particular how you allocate and initialize 'ip'
Avatar of jma2000
jma2000

ASKER

ok here it is:  Thx

/* If we have an IP packet... */
    if (ntohs(eth_header_ptr->ether_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));
      }
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));
Avatar of jma2000

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'?
Avatar of jma2000

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
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)
Avatar of jma2000

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
What is the value of size_ethernet?
Does the problem happening the first time or after some parsings?
Avatar of jma2000

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)
Is pktbuf unsiged char?
Avatar of jma2000

ASKER

Here is how pktbuf is defined:

char *pktbuf


pktbuf = malloc(frame_header.bytes_caped + 1);
What is the CPU?   Some CPU's can't access words at odd addresses.

Try to define pktbuf as
unsigned char *pktbuf;

Avatar of jma2000

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.
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.
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,0xc0,0x40,0x00,0x40,0x06,0xfc,0x03,
          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);
}

Avatar of jma2000

ASKER

It compiles but when I run it nothing happens - not sure what that means.
Avatar of jma2000

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?
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
Avatar of jma2000

ASKER

thanks for all the good suggestions..let me try and get back shortly.
Avatar of jma2000

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
Is the another system also a Sun Solaris?
Avatar of jma2000

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>
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));
Avatar of jma2000

ASKER

YES!!! that did it!! I will have to look at this a little to understand but Thanks!!!!!
ASKER CERTIFIED SOLUTION
Avatar of cwwkie
cwwkie

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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