Solved

Getting segmentation fault while trying to insert two iptables rules using the same handle

Posted on 2008-06-14
20
506 Views
Last Modified: 2013-11-16
By using the following code i'm getting a segmentation fault:
IPfilter filterobject;
b=0;
while(b<10)
{
filterobject.insert_rule((char *)"23.3.223.1");
b++;
}

If i rerun the constructor every loop by recreating a new object on every loop it works fine.
But the creation of a new handle takes a long time if the iptables table contains about 20000 entries.

By runing ddd it displays that the segmentation fault occours in the iptcc_find_label() method wich is in included in any linked library. I inserted some debug output on several positions into my code and found out that my handle become NULL after calling the "iptc_insert_entry" function.

Do i need to recreate a new handle on every modification?
Is there any error on my code?

Thanks.
class IPfilter{

private:

  iptc_handle_t h;

  char *tablename;

  const struct ipt_entry *e;

  struct ipt_entry_target * append_target(struct ipt_entry *entry, const char *name, size_t target_data_size);

public:

  IPfilter();

  bool insert_rule(char *dstip);

};
 

IPfilter::IPfilter()

{

h=NULL;

e=NULL;

tablename=(char *)malloc(7);

sprintf(tablename,"mangle");

this->h=iptc_init(tablename);

if (!(this->h))

printf("Error createing Iptables Structure!");

};
 

bool IPfilter::insert_rule(char *dstip)

{

       int result;

       int unused = 0;

       struct ipt_entry *new_entry;

       struct ipt_entry_target *target;
 

       if (!(new_entry =(ipt_entry*) calloc(1, sizeof(struct ipt_entry))))

       {

         perror("calloc");

         return false;

       }

       inet_aton(dstip, &new_entry->ip.dst);

       inet_aton("255.255.255.255", &new_entry->ip.dmsk);

       sprintf(new_entry->ip.outiface, "eth0");

       new_entry->ip.proto = IPPROTO_TCP;
 

       // initialize entry parameters

       new_entry->target_offset = sizeof(struct ipt_entry);

       new_entry->next_offset = sizeof(struct ipt_entry);

       target = this->append_target(new_entry, "DROP", sizeof(int));

       memcpy(&target->data[0], &unused, sizeof(int));

       result =  iptc_insert_entry("PREROUTING", new_entry,0, &(this->h));

       if (!result)

         printf("%s\n", iptc_strerror(errno));

       result = iptc_commit( &(this->h));

       if (!result)

       printf("%s\n", iptc_strerror(errno));

       free (new_entry);

       return true;

};
 

struct ipt_entry_target * IPfilter::append_target(struct ipt_entry *entry, const char *name, size_t target_data_size)

{

        struct ipt_entry_target *target;

        size_t target_size = 0;
 

        target_size += IPT_ALIGN(sizeof(struct ipt_entry_target));

        target_size += IPT_ALIGN(target_data_size);

        if (!(entry =(ipt_entry*) realloc(entry, entry->next_offset + target_size)))

        {

                perror("realloc");

                return NULL;

        }

        target = (struct ipt_entry_target *)((int)entry + entry->next_offset);

        entry->next_offset += target_size;

        memset(target, 0, target_size);

        strncpy(target->u.user.name, name, IPT_FUNCTION_MAXNAMELEN);

        target->u.target_size = target_size;

        return target;

};

Open in new window

0
Comment
Question by:ktd85
  • 10
  • 10
20 Comments
 
LVL 53

Expert Comment

by:Infinity08
ID: 21785773
There's a small problem with this line :

>>         if (!(entry =(ipt_entry*) realloc(entry, entry->next_offset + target_size)))

It works on a local copy of the struct ipt_entry*, so after calling append_target, the insert_rule method will still be using its own copy of the struct ipt_entry*, which might or might not be the same as what realloc returned.


So, you'll have to make sure that the value returned by realloc makes it back to the insert_rule method.
0
 
LVL 2

Author Comment

by:ktd85
ID: 21785946
Would it be corrected by calling it like this:
target = this->append_target(&new_entry, "DROP", sizeof(int));

Do you think that can cause the segmentation fault´if i call the function more the one time from a freshly created object ?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21785971
>> target = this->append_target(&new_entry, "DROP", sizeof(int));

If you also change the append_target method accordingly :

        struct ipt_entry_target * IPfilter::append_target(struct ipt_entry **pentry, const char *name, size_t target_data_size)
        {
                /* rest of the code as it was, but using *pentry instead of entry */
        }


>> Do you think that can cause the segmentation fault´if i call the function more the one time from a freshly created object ?

It could. If realloc places the memory block elsewhere, then the new_entry pointer in the insert_rule method no longer points to allocated memory, and could have been overwritten by something else.
It's this overwriting that could cause a segmentation fault (because pointers, and offset fields are overwritten too).
0
 
LVL 2

Author Comment

by:ktd85
ID: 21785976
If i call the function only once there is no problem. If i recreate the object and then call the function there will be no problem too.

If i create a object of the class IPfilter and call the function insert_rule twice I'm getting a segmentation fault.
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786002
Sorry, ignore my poste above.
I corrected the mentioned issues and now get a compiler error:
src/ipfilter.c:82: error: extra qualification IPfilter:: on member append_target
src/ipfilter.c: In member function xt_entry_target* IPfilter::append_target(ipt_entry**, const char*, size_t):
src/ipfilter.c:182: error: request for member next_offset in * pentry, which is of non-class type ipt_entry*
src/ipfilter.c:187: error: request for member next_offset in * pentry, which is of non-class type ipt_entry*
src/ipfilter.c:188: error: request for member next_offset in * pentry, which is of non-class type ipt_entry*
make: *** [src/ipfilter.o] Error 1


Now code of method append_target attached.
  struct ipt_entry_target * IPfilter::append_target(struct ipt_entry **pentry, const char *name, size_t target_data_size)

{

        struct ipt_entry_target *target;

        size_t target_size = 0;
 

        target_size += IPT_ALIGN(sizeof(struct ipt_entry_target));

        target_size += IPT_ALIGN(target_data_size);

        if (!(pentry =(ipt_entry*) realloc(pentry, pentry->next_offset + target_size)))

        {

                perror("realloc");

                return NULL;

        }

        target = (struct ipt_entry_target *)((int)pentry + pentry->next_offset);

        pentry->next_offset += target_size;

        memset(target, 0, target_size);

        strncpy(target->u.user.name, name, IPT_FUNCTION_MAXNAMELEN);

        target->u.target_size = target_size;

        return target;

};

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786045
You should dereference pentry before using it, ie. *pentry instead of just pentry : (I also modified a few other things and commented them)
struct ipt_entry_target * IPfilter::append_target(struct ipt_entry **pentry, const char *name, size_t target_data_size)

{

        struct ipt_entry *tmp_ptr = 0;

        struct ipt_entry_target *target = 0;       // <--- initialize pointer

        size_t target_size = 0;

 

        target_size += IPT_ALIGN(sizeof(struct ipt_entry_target));

        target_size += IPT_ALIGN(target_data_size);

        if (!(tmp_ptr =(ipt_entry*) realloc(*pentry, (*pentry)->next_offset + target_size)))       // <--- two-step realloc to avoid memory leaks in case realloc fails

        {

                perror("realloc");

                return NULL;         // <--- make sure you check for NULL in insert_rule after calling append_target

        }

        *pentry = tmp_ptr;       // <--- two-step realloc to avoid memory leaks in case realloc fails

        target = (struct ipt_entry_target *)((unsigned char*)*pentry + (*pentry)->next_offset);    // <--- casting to a 1 byte pointer type (unsigned char*) instead of int

        (*pentry)->next_offset += target_size;

        memset(target, 0, target_size);

        strncpy(target->u.user.name, name, IPT_FUNCTION_MAXNAMELEN);

        target->u.target_size = target_size;

        return target;

}                           // <--- notice that I removed the ; here - it's not necessary

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786048
You'll of course also have to modify the method prototype with the new struct ipt_entry **pentry.
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786118
I corrected all the items you metioned but I'm still receiving the segmentation fault.
Current code attached.

Do you have any other idea?
class IPfilter{

private:

  iptc_handle_t h;

  char *tablename;

  const struct ipt_entry *e;
 

  void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert);

  void print_rule(const struct ipt_entry *e, iptc_handle_t *h, const char *chain, int counters);

  struct ipt_entry_target * append_target(struct ipt_entry **pentry, const char *name, size_t target_data_size);

public:

  IPfilter();

  bool insert_rule(char *dstip);

};
 

IPfilter::IPfilter()

{

h=NULL;

e=NULL;

tablename=(char *)malloc(7);

sprintf(tablename,"mangle");
 

this->h=iptc_init(tablename);

if (!(this->h))

printf("Error createing Iptables Structure!");

}
 

bool IPfilter::insert_rule(char *dstip)

{

       int result;

       int unused = 0;

       struct ipt_entry *new_entry;

       struct ipt_entry_target *target;
 

       if (!(new_entry =(ipt_entry*) calloc(1, sizeof(struct ipt_entry))))

       {

         perror("calloc");

         return false;

       }

       inet_aton(dstip, &new_entry->ip.dst);

       inet_aton("255.255.255.255", &new_entry->ip.dmsk);

       sprintf(new_entry->ip.outiface, "eth0");

       new_entry->ip.proto = 6;
 

       // initialize entry parameters

       new_entry->target_offset = sizeof(struct ipt_entry);

       new_entry->next_offset = sizeof(struct ipt_entry);

       target = this->append_target(&new_entry, "DROP", sizeof(int));

       if (target==NULL) return false;

       memcpy(&target->data[0], &unused, sizeof(int));

       result =  iptc_append_entry("PREROUTING", new_entry, &(this->h));

       if (!result)

         printf("%s\n", iptc_strerror(errno));

       result = iptc_commit( &(this->h));

       if (!result)

       printf("%s\n", iptc_strerror(errno));

       free (new_entry);

       return true;

}
 

struct ipt_entry_target * IPfilter::append_target(struct ipt_entry **pentry, const char *name, size_t target_data_size)

{

        struct ipt_entry *tmp_ptr = 0;

        struct ipt_entry_target *target = 0;       // <--- initialize pointer

        size_t target_size = 0;

        target_size += IPT_ALIGN(sizeof(struct ipt_entry_target));

        target_size += IPT_ALIGN(target_data_size);

        if (!(tmp_ptr =(ipt_entry*) realloc(*pentry, (*pentry)->next_offset + target_size)))       // <--- two-step realloc to avoid memory leaks in case realloc fails

        {

        perror("realloc");

        return NULL;         // <--- make sure you check for NULL in insert_rule after calling append_target

        }

        *pentry = tmp_ptr;       // <--- two-step realloc to avoid memory leaks in case realloc fails

        target = (struct ipt_entry_target *)((unsigned char*)*pentry + (*pentry)->next_offset);    // <--- casting to a 1 byte pointer type (unsigned char*) instead of int

        (*pentry)->next_offset += target_size;

        memset(target, 0, target_size);

        strncpy(target->u.user.name, name, IPT_FUNCTION_MAXNAMELEN);

        target->u.target_size = target_size;

        return target;

}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786131
>> but I'm still receiving the segmentation fault.

In the same location ?
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786143
Yes.
Calling once in a instance of the Classe no problem. Calling twice in one instance causes segmentation fault. Found out, that the Handle h, which is initialized by the contructor becomes NULL after the first run.
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 53

Expert Comment

by:Infinity08
ID: 21786172
>> Found out, that the Handle h, which is initialized by the contructor becomes NULL after the first run.

That would explain the segmentation fault.

Now, we just have to find out why heh.


I can't find anything in the code you posted that would do that ... What happens to the IPFilter object between the two calls ?
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786198
What do you mean by "between two calls"?
The While-Loop while goe through and repeat from top.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786216
>> The While-Loop while goe through and repeat from top.

So, it's just the while loop you posted in your first post - nothing more ? That's the exact code ?
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786222
Yes, thats the original code i used to test the function's performance.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786228
Can you find out at what point h is set to 0 ? You can use a debugger for that (just set a watch on h).
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786308
My Installation of ddd complains that <director fo my project>\<<c++ namspaces>> ist not found.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 21786551
Can you try adding these lines then and see what output it gives :

       // initialize entry parameters

       new_entry->target_offset = sizeof(struct ipt_entry);

       new_entry->next_offset = sizeof(struct ipt_entry);

       if (!(this->h)) printf(stderr, "this->h == NULL (A)\n");             // <--- add

       else printf(stderr, "this->h != NULL (A)\n");                        // <--- add

       target = this->append_target(&new_entry, "DROP", sizeof(int));

       if (!(this->h)) printf(stderr, "this->h == NULL (B)\n");             // <--- add

       else printf(stderr, "this->h != NULL (B)\n");                        // <--- add

       if (target==NULL) return false;

       memcpy(&target->data[0], &unused, sizeof(int));

       result =  iptc_append_entry("PREROUTING", new_entry, &(this->h));

       if (!(this->h)) printf(stderr, "this->h == NULL (C)\n");             // <--- add

       else printf(stderr, "this->h != NULL (C)\n");                        // <--- add

       if (!result)

         printf("%s\n", iptc_strerror(errno));

       result = iptc_commit( &(this->h));

       if (!(this->h)) printf(stderr, "this->h == NULL (D)\n");             // <--- add

       else printf(stderr, "this->h != NULL (D)\n");                        // <--- add

       if (!result)

       printf("%s\n", iptc_strerror(errno));

Open in new window

0
 
LVL 2

Author Comment

by:ktd85
ID: 21786781
The Output looks like this:
this->h != NULL (A)
this->h != NULL (B)
this->h != NULL (C)
this->h == NULL (D)
this->h == NULL (A)
this->h == NULL (B)
Segmentation fault
0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 500 total points
ID: 21786794
>> this->h == NULL (D)

It seems that the iptc_commit sets it to NULL. Is that normal behavior ?

What if you call it after the while loop (so not in the insert_rule) ?
0
 
LVL 2

Author Comment

by:ktd85
ID: 21786833
Thank You VERY VERY much.  My Problem is solved!!!!

Thanks.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Sed question 2 46
Linux operating system 12 65
Is this bug still active in RHEL 2 29
PC upgrade to Linux Mint 7 31
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Join Greg Farro and Ethan Banks from Packet Pushers (http://packetpushers.net/podcast/podcasts/pq-show-93-smart-network-monitoring-paessler-sponsored/) and Greg Ross from Paessler (https://www.paessler.com/prtg) for a discussion about smart network …
Learn how to get help with Linux/Unix bash shell commands. Use help to read help documents for built in bash shell commands.: Use man to interface with the online reference manuals for shell commands.: Use man to search man pages for unknown command…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now