编译时出错 - 在初始化程序中指定的未知字段
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 无法解决对 <未知程序单元> 的引用)