Error when compiling - unknown field specified in initializer

0

I have found an old script written in C and when I try to compile it I get the following message

 # gcc libipt_rope.c -o libipt_rope.so
libipt_rope.c:349: error: variable ‘rope’ has initializer but incomplete type
libipt_rope.c:350: error: unknown field ‘next’ specified in initializer
libipt_rope.c:350: warning: excess elements in struct initializer
libipt_rope.c:350: warning: (near initialization for ‘rope’)
libipt_rope.c:351: error: unknown field ‘name’ specified in initializer
libipt_rope.c:351: warning: excess elements in struct initializer
libipt_rope.c:351: warning: (near initialization for ‘rope’)
libipt_rope.c:352: error: unknown field ‘version’ specified in initializer
libipt_rope.c:352: warning: excess elements in struct initializer
libipt_rope.c:352: warning: (near initialization for ‘rope’)
libipt_rope.c:353: error: unknown field ‘size’ specified in initializer
libipt_rope.c:353: warning: excess elements in struct initializer
libipt_rope.c:353: warning: (near initialization for ‘rope’)
libipt_rope.c:354: error: unknown field ‘userspacesize’ specified in initializer
libipt_rope.c:354: warning: excess elements in struct initializer
libipt_rope.c:354: warning: (near initialization for ‘rope’)
libipt_rope.c:355: error: unknown field ‘help’ specified in initializer
libipt_rope.c:355: warning: excess elements in struct initializer
libipt_rope.c:355: warning: (near initialization for ‘rope’)
libipt_rope.c:356: error: unknown field ‘init’ specified in initializer
libipt_rope.c:356: warning: excess elements in struct initializer
libipt_rope.c:356: warning: (near initialization for ‘rope’)
libipt_rope.c:357: error: unknown field ‘parse’ specified in initializer
libipt_rope.c:357: warning: excess elements in struct initializer
libipt_rope.c:357: warning: (near initialization for ‘rope’)
libipt_rope.c:358: error: unknown field ‘final_check’ specified in initializer
libipt_rope.c:358: warning: excess elements in struct initializer
libipt_rope.c:358: warning: (near initialization for ‘rope’)
libipt_rope.c:359: error: unknown field ‘print’ specified in initializer
libipt_rope.c:359: warning: excess elements in struct initializer
libipt_rope.c:359: warning: (near initialization for ‘rope’)
libipt_rope.c:360: error: unknown field ‘save’ specified in initializer
libipt_rope.c:360: warning: excess elements in struct initializer
libipt_rope.c:360: warning: (near initialization for ‘rope’)
libipt_rope.c:361: error: unknown field ‘extra_opts’ specified in initializer
libipt_rope.c:362: warning: excess elements in struct initializer
libipt_rope.c:362: warning: (near initialization for ‘rope’

I'm asking the C gurus, since i'm quite familiar with C, but not that much.

And here's the code

/

/* For detailed documentation about ROPE, visit http://www.lowth.com/rope */

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>

#include "iptables.h"

#define _USERLAND_ 1
#define _ROPE_IPTABLES_ 1
#include "rope.h"
#include "rope-enum.h"

#define WANT_ROPE_LOAD_SCRIPT
#include "rope-util.h"

#define IPT_ROPE_SCRIPT     0x0001
#define IPT_ROPE_PUSH_INT   0x0002
#define IPT_ROPE_PUSH_STR   0x0004
#define IPT_ROPE_PUSH_IP    0x0008

#define OPT_SCRIPT   "rope-script"
#define OPT_PUSH_INT "rope-push-int"
#define OPT_PUSH_STR "rope-push-str"
#define OPT_PUSH_IP  "rope-push-ip"

/* Function which prints out usage message. */
static void help(void)
{
    printf(
"ROPE (version " ROPE_VERSION ") match v%s options:\n"
"[!] --" OPT_SCRIPT "    scriptfile    Name of packet-matching ROPE script\n"
"    --" OPT_PUSH_INT "  integer       Push integer onto stack\n"
"    --" OPT_PUSH_STR "  string        Push string onto stack\n"
"    --" OPT_PUSH_IP "   ip-address    Push IPv4 address onto stack\n",
IPTABLES_VERSION);

    fputc('\n', stdout);
}

static struct option opts[] = {
    { "script",     1, 0, '1' },    // for backwards compatibility
    { OPT_SCRIPT,   1, 0, '1' },
    { OPT_PUSH_INT, 1, 0, '2' },
    { OPT_PUSH_STR, 1, 0, '3' },
    { OPT_PUSH_IP,  1, 0, '4' },
    {0}
};

/* Initialize the match. */
static void init(struct ipt_entry_match *m, unsigned int *nfcache)
{
    struct ipt_rope_info *ropeinfo = (struct ipt_rope_info *)(m)->data;
    *nfcache |= NFC_UNKNOWN;
    memset(ropeinfo, 0, sizeof(*ropeinfo));
    ropeinfo->version = ROPE_SCRIPT_VERSION;
    ropeinfo->info_size = (u_int16_t)sizeof(struct ipt_rope_info);
}

static void read_scriptfile(struct ipt_rope_info *info, char *filename)
{
    int i;
    int len = strlen(filename);
    char *scriptdir = "/etc/rope.d/scripts";
    char path[ROPE_MAX_FILENAME + strlen(scriptdir)+8];
    struct stat stat_info;
    int ok, script_offset, script_len, ipsets_offset, ipsets_len, used_buff;

    if (len < 1) exit_error(PARAMETER_PROBLEM, "Script file name cannot be empty" );
    if (len >= ROPE_MAX_FILENAME) exit_error(PARAMETER_PROBLEM, "Script file name too long" );
    for (i=0; i<len; i++) {
        char c = filename[i];
        if ( !isalnum(c) && c != '-' && c != '_' )
            exit_error(
                PARAMETER_PROBLEM,
                "Script file name can only contain letters, digits or hyphens"
            );
    }
    strcpy(path, scriptdir);
    strcat(path, "/");
    strcat(path, filename);
    strcat(path, ".rp");

    /* Verify that it is safe to load scripts from the directory */
    if (lstat(scriptdir, &stat_info) != 0)
        exit_error( PARAMETER_PROBLEM, "Cant stat '%s'", scriptdir );
    if (!S_ISDIR(stat_info.st_mode))
        exit_error( PARAMETER_PROBLEM, "'%s' is not a directory (it should be)", scriptdir);
    if (stat_info.st_uid != 0)
        exit_error( PARAMETER_PROBLEM, "Directory '%s' is not owned by 'root' (it should be)", scriptdir);
    if (stat_info.st_mode & (S_IWGRP | S_IWOTH))
        exit_error( PARAMETER_PROBLEM, "Directory '%s' may be writeable by non-root users (it should not be)", scriptdir);

    /* Verify that only root can modify it */
    if (lstat(path, &stat_info) != 0)
        exit_error( PARAMETER_PROBLEM, "Cant stat '%s'", path);
    if (!S_ISREG(stat_info.st_mode))
        exit_error( PARAMETER_PROBLEM, "'%s' is not a regular file (it should be)", path);
    if (stat_info.st_uid != 0)
        exit_error( PARAMETER_PROBLEM, "File '%s' is not owned by 'root' (it should be)", path);
    if (stat_info.st_mode & (S_IWGRP | S_IWOTH))
        exit_error( PARAMETER_PROBLEM, "File '%s' may be writeable by non-root users (it should not be)", path);

    strcpy(info->scriptfile, filename);

    ok = rope_load_script(
        path,
        info->scriptbuff+info->arguments_len, ROPE_MAX_COMPILED_SIZE - info->arguments_len, &used_buff,
        &script_offset, &script_len,
        &ipsets_offset, &ipsets_len
    );

    if ( !ok )
        exit_error( PARAMETER_PROBLEM, "Cant load file '%s'", path );

    info->script_offset = 0;
    info->script_len = info->arguments_len + script_len;
    info->ipsets_offset = ipsets_offset + info->arguments_len;
    info->ipsets_len = ipsets_len;
    info->scriptbuff_len = used_buff;
}

/* Function which parses command options; returns true if it
   ate an option */

static int parse(int c, char **argv, int invert, unsigned int *flags,
      const struct ipt_entry *entry,
      unsigned int *nfcache,
      struct ipt_entry_match **match)
{
    struct ipt_rope_info *ropeinfo = (struct ipt_rope_info *)(*match)->data;
    int n, len, i;
    struct hostent *he;
    char push_buff[ROPE_MAX_COMPILED_SIZE];
    int push_len = 0;

    switch (c)
    {
        case '1':   // --rope-script
            ropeinfo->invert = invert;
            if (*flags & IPT_ROPE_SCRIPT)
                exit_error( PARAMETER_PROBLEM, "--"OPT_SCRIPT": cant specify more than one script");
            read_scriptfile( ropeinfo, optarg );
            *flags |= IPT_ROPE_SCRIPT;
            break;

        case '2':   // --rope-push-int
            if (invert)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_INT": cant specify '!'");
            n = atoi(optarg);
            if (n >= 0 && n <= 127) {
                push_buff[push_len++] = ROPE_ELEMENT_TYPE_INTEGER8;
                push_buff[push_len++] = n;
            } else if (n >= 0 && n <= 32767) {
                push_buff[push_len++] = ROPE_ELEMENT_TYPE_INTEGER16;
                push_buff[push_len++] = ((unsigned int)n & 0xff00) >> 8;
                push_buff[push_len++] = ((unsigned int)n & 0x00ff);
            } else {
                push_buff[push_len++] = ROPE_ELEMENT_TYPE_INTEGER;
                push_buff[push_len++] = ((unsigned int)n & 0xff000000) >> 24;
                push_buff[push_len++] = ((unsigned int)n & 0x00ff0000) >> 16;
                push_buff[push_len++] = ((unsigned int)n & 0x0000ff00) >> 8;
                push_buff[push_len++] = ((unsigned int)n & 0x000000ff);
            }
            *flags |= IPT_ROPE_PUSH_INT;
            break;

        case '3':   // --rope-push-str
            if (invert)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_STR": cant specify '!'");
            len = strlen(optarg);
            if ((len + 3) > sizeof(push_buff))
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_STR": string too long" );
            if (len < 128) {
                push_buff[push_len++] = ROPE_ELEMENT_TYPE_STRING8;
                push_buff[push_len++] = len;
            } else {
                push_buff[push_len++] = ROPE_ELEMENT_TYPE_STRING;
                push_buff[push_len++] = (len & 0xff00) >> 8;
                push_buff[push_len++] = (len & 0x00ff);
            }

            /*
             * We have to check that the string we provide will work with iptables-save and
             * iptables-restore - which are rather crude in their parsing of the config
             * file they use. Non printable characters, control characters and quotes will
             * all cause us problems.
             */

            for (i=0; i<len; i++) {
                if (iscntrl(optarg[i]) || !isprint(optarg[i]))
                    exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_STR": string includes non-printable character(s)");
                if (optarg[i] == '"')
                    exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_STR": string includes double-quote character(s)");
            }

            memcpy(push_buff+push_len, optarg, len);
            push_len += len;
            *flags |= IPT_ROPE_PUSH_STR;
            break;

        case '4':   // --rope-push-ip
            if (invert)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_IP": cant specify '!'");
            he = gethostbyname( optarg );
            if (he == NULL)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_IP": cant resolve host name");
            if (he->h_length != 4)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_IP": IPv4 address expected");
            if ( he->h_addr_list == NULL || he->h_addr_list[0] == NULL || he->h_addr_list[1] != NULL)
                exit_error( PARAMETER_PROBLEM, "--"OPT_PUSH_IP": name resolved to multiple IPv4 addresses");
            push_buff[push_len++] = ROPE_ELEMENT_TYPE_DOTTED_STRING8;
            push_buff[push_len++] = 4;
            memcpy(push_buff + push_len, he->h_addr_list[0], 4);
            push_len += 4;
            *flags |= IPT_ROPE_PUSH_IP;
            break;

        default:
            return 0;
    }

    memmove(
        ropeinfo->scriptbuff + ropeinfo->arguments_len + push_len,
        ropeinfo->scriptbuff + ropeinfo->arguments_len,
        ropeinfo->scriptbuff_len - ropeinfo->arguments_len
    );
    memcpy(ropeinfo->scriptbuff + ropeinfo->arguments_len, push_buff, push_len);
    ropeinfo->script_len += push_len;
    ropeinfo->ipsets_offset += push_len;
    ropeinfo->arguments_len += push_len;
    ropeinfo->scriptbuff_len += push_len;
    return 1;
}

/* Final check; must have specified --string. */
static void final_check(unsigned int flags)
{
    if (! (flags & IPT_ROPE_SCRIPT) )
        exit_error(
            PARAMETER_PROBLEM,
            "ROPE match: You must specify `--" OPT_SCRIPT "'"
        );
}

static void print_string(int len, unsigned char *str)
{
    putchar( '\"' );
    while (len) {
        putchar(*str);
        /*if (ch == '\n') printf( "\\n" );
        else if (ch == '\r') printf( "\\r" );
        else if (ch == '\t') printf( "\\t" );
        else if (ch == '"') printf( "\\\"" );
        else if (ch == '\\') printf( "\\\\" );
        else if (isprint( ch )) printf( "%c", ch );
        else printf( "\\%03o", ch );*/
        str ++;
        len --;
    }
    putchar( '\"' );
}

static void print_pushes(struct ipt_rope_info *info, char *prefix, char *delim)
{
    int opcode, len;
    unsigned char *buff = info->scriptbuff;
    unsigned char *end = info->scriptbuff + info->arguments_len;

    while (buff < end) {
        opcode = (*buff++);
        if (opcode == ROPE_ELEMENT_TYPE_INTEGER8) {
            printf( "%spush-int%s%d", prefix, delim, (*buff++) );
        } else if (opcode == ROPE_ELEMENT_TYPE_INTEGER16) {
            printf( "%spush-int%s%d", prefix, delim, buff[0] << 8 | buff[1]);
            buff += 2;
        } else if (opcode == ROPE_ELEMENT_TYPE_INTEGER) {
            printf( "%spush-int%s%d", prefix, delim, buff[0] << 24 | buff[1] << 16 | buff[2] << 8 | buff[3]);
            buff += 4;
        } else if (opcode == ROPE_ELEMENT_TYPE_DOTTED_STRING8 && *buff == 4) {
            printf( "%spush-ip%s%d.%d.%d.%d", prefix, delim, buff[1], buff[2], buff[3], buff[4] );
            buff += 5;
        } else if (opcode == ROPE_ELEMENT_TYPE_STRING8) {
            len = buff[0];
            printf( "%spush-str%s", prefix, delim );
            print_string(len, buff+1);
            buff += len + 1;
        } else if (opcode == ROPE_ELEMENT_TYPE_STRING) {
            len = buff[0] << 8 | buff[1];
            printf( "%spush-str%s", prefix, delim );
            print_string(len, buff+2);
            buff += len + 2;
        } else {
            return;
        }
        printf( " " );
    }
}

/* Prints out the matchinfo. */
static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric)
{
    printf( "ROPE script: %s%s ",
        ((struct ipt_rope_info *)match->data)->invert ? "!" : "",
        ((struct ipt_rope_info *)match->data)->scriptfile
    );
    print_pushes((struct ipt_rope_info *)match->data, "", ":");
}

/* Saves the union ipt_matchinfo in parsable form to stdout. */
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
    printf( "%s--" OPT_SCRIPT " %s ",
        ((struct ipt_rope_info *)match->data)->invert ? "! " : "",
        ((struct ipt_rope_info *)match->data)->scriptfile
    );
    print_pushes((struct ipt_rope_info *)match->data, "--rope-", " ");
}

static struct iptables_match rope = {
        .next           = NULL,
        .name           = "rope",
        .version        = IPTABLES_VERSION,
        .size           = IPT_ALIGN(sizeof(struct ipt_rope_info)),
        .userspacesize  = IPT_ALIGN(sizeof(struct ipt_rope_info)),
        .help           = &help,
        .init           = &init,
        .parse          = &parse,
        .final_check    = &final_check,
        .print          = &print,
        .save           = &save,
        .extra_opts     = opts
};

void _init(void)
{
    register_match(&rope);
}

Thanks for reading :)

c
gcc
compilation

3 Answers

2

that sounds like your iptables_match structure doesn't have the expected help, print, save ... fields to me. Since it's an old program (we don't use 'script' for C) that relies on a kernel header (iptables) that is likely to have evolved, have you checked the new structure of iptables_match ?

answered on Stack Overflow Mar 14, 2011 by PypeBros
1

I'm not familiar with ROPE, but from the docs it looks like it is meant to be build as a kernel module so there may be more to building it than a straighforward gcc call.

To install it for use in userland (not part of kernel), look at this section in the docs: http://www.lowth.com/rope/UserLand

Also, it looks like the last available version of ROPE was developed against the 2.4 kernel so as the @sylvainulg mentioned there might be some incompatibility issues with current kernels headers.

updates

Looks like ROPE works fine on kernel 2.6 but not with the latest iptables. Website states:

So far, ROPE has been developed and tested against the 2.4.x and 2.6.x linux kernels (for single Intel CPU platforms) and IpTables from 1.2.x to 1.3.x.

Compiling it against several version of iptables shows that the error is reproducable when compiled agains the lates (1.4.10) but does not occur for 1.3.0.

update2

Here's a last ditch attempt at trying to make it work. Try adding the following to the top of your source:

#ifdef _XTABLES_H
    #define iptables_rule_match        xtables_rule_match
    #define iptables_match             xtables_match
    #define iptables_target            xtables_target
    #define ipt_tryload                xt_tryload

    #if (!defined(IPTABLES_VERSION) && defined(XTABLES_VERSION))
        #define IPTABLES_VERSION   XTABLES_VERSION
    #endif

#endif

As of iptables 1.4.0, iptables_match seems to be defined as xtables_match (see includes/xtables.h). Assuming none of the other changes updates break ROPE, that should compile (no guarantees that it will work as stated thought. Do test it out thoroughly).

answered on Stack Overflow Mar 14, 2011 by Shawn Chin • edited May 23, 2017 by Community
0

Which compiler options do you use to compile that code?

It seems that you're trying to compile with std=c99 and your source code uses some anonymous structs, which are first introduced in c11. So probably you should compile with that option.

If that's the case, you can read more about this topic here: Anonymous union within struct not in c99?

answered on Stack Overflow Jun 9, 2020 by harut2005

User contributions licensed under CC BY-SA 3.0