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 :)
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 ?
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.
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
.
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).
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?
User contributions licensed under CC BY-SA 3.0