编译时出错 - 在初始化程序中指定的未知字段

Posted

技术标签:

【中文标题】编译时出错 - 在初始化程序中指定的未知字段【英文标题】:Error when compiling - unknown field specified in initializer 【发布时间】:2011-07-15 00:46:22 【问题描述】:

我找到了一个用 C 编写的旧脚本,当我尝试编译它时,我收到以下消息

 # 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’

我在问 C 大师,因为我对 C 很熟悉,但不是那么熟悉。

这是代码

/

/* 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);

感谢阅读:)

【问题讨论】:

【参考方案1】:

这听起来像您的 iptables_match 结构没有预期的帮助,打印,保存...字段给我。由于它是一个旧程序(我们不使用 C 的“脚本”),它依赖于可能已经进化的内核头文件(iptables),你检查过 iptables_match 的新结构吗?

【讨论】:

该程序包含一个 iptables 补丁,所以我认为它会支持这些字段。【参考方案2】:

我对 ROPE 不熟悉,但从 the docs 看来,它应该是作为内核模块构建的,因此构建它可能比直接调用 gcc 更多。

要安装它以在用户空间(不是内核的一部分)中使用,请查看文档中的此部分:http://www.lowth.com/rope/UserLand

此外,ROPE 的最后一个可用版本似乎是针对 2.4 内核开发的,因此 @sylvainulg mentioned 可能存在与当前内核头文件不兼容的问题。

更新

看起来 ROPE 在内核 2.6 上运行良好,但在最新的 iptables 上却不行。网站声明:

到目前为止,ROPE 已经开发和 针对 2.4.x 和 2.6.x 进行测试 linux 内核(用于单个 Intel CPU 平台)和从 1.2.x 到 1.3.x 的 IpTables。

针对several version of iptables 进行编译表明,当再次编译最新版本(1.4.10)时,该错误是可重现的,但1.3.0 不会发生该错误。

更新2

这是试图让它发挥作用的最后一次尝试。尝试将以下内容添加到源代码的顶部:

#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

从 iptables 1.4.0 开始,iptables_match 似乎被定义为xtables_match(参见includes/xtables.h)。假设没有其他更改更新破坏 ROPE,则应该编译(不保证它会按所述想法工作。请彻底测试它)。

【讨论】:

是的,我在同一个目录中有所有需要的标题。它确实是内核模块的一部分,但我需要先编译它,这就是我遇到的问题。 :) 只是检查。没有自卑的意思,诚实。 :) 它是为 2.4 和 2.6 内核开发的(至少网站是这么说的 :))。那么,除了使用旧标题之外别无他法? :) 我看起来 ROPE 要求您修补 iptables 标头。请参阅此处的第 5 步:lowth.com/rope/Building#2。出于好奇,我在新的 iptables 源上尝试了 patch 命令,它适用于 iptables 1.3.0,但对于最新的 (1.4.10) 无效。 #define iptables_match xtables_match 添加到文件顶部有帮助吗? (针对 1.4.10 编译)。【参考方案3】:

您使用哪些编译器选项来编译该代码?

您似乎正在尝试使用 std=c99 进行编译,而您的源代码使用了一些匿名结构,这些结构首先在 c11 中引入。所以可能你应该用那个选项编译。

如果是这种情况,您可以在此处阅读有关此主题的更多信息: Anonymous union within struct not in c99?

【讨论】:

以上是关于编译时出错 - 在初始化程序中指定的未知字段的主要内容,如果未能解决你的问题,请参考以下文章

动态导入在运行时从编译输出中指定的模块

编译 Oracle 表单时出错(加载块 P5_27_MAR_201709_43_49 时 PDE-PSD001 无法解决对 <未知程序单元> 的引用)

VS2012编译的MFC程序XP运行出错R6010

MPLAB编译出错

创建在“system.net/defaultProxy”配置节中指定的 Web 代理时出错。

在Ubuntu中编译android代码出错。