blob: a527f27d63922cf13457e7a017da83d83cc75b06 [file] [log] [blame]
/*
* (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <iptables.h>
#include <time.h>
#include "xtables-multi.h"
#include "nft.h"
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <iptables.h>
#include <xtables.h>
#include <libiptc/libxtc.h>
#include <fcntl.h>
#include <getopt.h>
#include "xshared.h"
#include "nft-shared.h"
int xlate_action(const struct iptables_command_state *cs, bool goto_set,
struct xt_buf *buf)
{
int ret = 1;
/* If no target at all, add nothing (default to continue) */
if (cs->target != NULL) {
/* Standard target? */
if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
xt_buf_add(buf, "accept");
else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
xt_buf_add(buf, "drop");
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
xt_buf_add(buf, "return");
else if (cs->target->xlate)
ret = cs->target->xlate(cs->target->t, buf);
else
return 0;
} else if (strlen(cs->jumpto) > 0) {
/* Not standard, then it's a go / jump to chain */
if (goto_set)
xt_buf_add(buf, "goto %s", cs->jumpto);
else
xt_buf_add(buf, "jump %s", cs->jumpto);
}
return ret;
}
int xlate_matches(const struct iptables_command_state *cs, struct xt_buf *buf)
{
struct xtables_rule_match *matchp;
int ret = 1;
for (matchp = cs->matches; matchp; matchp = matchp->next) {
if (!matchp->match->xlate)
return 0;
ret = matchp->match->xlate(matchp->match->m, buf);
if (!ret)
break;
}
return ret;
}
bool xlate_find_match(const struct iptables_command_state *cs, const char *p_name)
{
struct xtables_rule_match *matchp;
/* Skip redundant protocol, eg. ip protocol tcp tcp dport */
for (matchp = cs->matches; matchp; matchp = matchp->next) {
if (strcmp(matchp->match->name, p_name) == 0)
return true;
}
return false;
}
const char *family2str[] = {
[NFPROTO_IPV4] = "ip",
[NFPROTO_IPV6] = "ip6",
};
static int nft_rule_xlate_add(struct nft_handle *h,
const struct nft_xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append)
{
struct xt_buf *buf = xt_buf_alloc(10240);
int ret;
if (append) {
xt_buf_add(buf, "add rule %s %s %s ",
family2str[h->family], p->table, p->chain);
} else {
xt_buf_add(buf, "insert rule %s %s %s ",
family2str[h->family], p->table, p->chain);
}
ret = h->ops->xlate(cs, buf);
if (ret)
printf("%s\n", xt_buf_get(buf));
xt_buf_free(buf);
return ret;
}
static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
struct iptables_command_state *cs,
struct xtables_args *args, bool append,
int (*cb)(struct nft_handle *h,
const struct nft_xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append))
{
unsigned int i, j;
int ret = 1;
for (i = 0; i < args->s.naddrs; i++) {
switch (h->family) {
case AF_INET:
cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
for (j = 0; j < args->d.naddrs; j++) {
cs->fw.ip.dst.s_addr =
args->d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr =
args->d.mask.v4[j].s_addr;
ret = cb(h, p, cs, append);
}
break;
case AF_INET6:
memcpy(&cs->fw6.ipv6.src,
&args->s.addr.v6[i], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.smsk,
&args->s.mask.v6[i], sizeof(struct in6_addr));
for (j = 0; j < args->d.naddrs; j++) {
memcpy(&cs->fw6.ipv6.dst,
&args->d.addr.v6[j],
sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&args->d.mask.v6[j],
sizeof(struct in6_addr));
ret = cb(h, p, cs, append);
}
break;
}
}
return ret;
}
static void print_ipt_cmd(int argc, char *argv[])
{
int i;
printf("# ");
for (i = 1; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
}
static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
char **table, bool restore)
{
int ret = 0;
struct nft_xt_cmd_parse p = {
.table = *table,
.restore = restore,
};
struct iptables_command_state cs;
struct xtables_args args = {
.family = h->family,
};
do_parse(h, argc, argv, &p, &cs, &args);
switch (p.command) {
case CMD_APPEND:
ret = 1;
if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add))
print_ipt_cmd(argc, argv);
break;
case CMD_DELETE:
break;
case CMD_DELETE_NUM:
break;
case CMD_CHECK:
break;
case CMD_REPLACE:
break;
case CMD_INSERT:
ret = 1;
if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add))
print_ipt_cmd(argc, argv);
break;
case CMD_FLUSH:
break;
case CMD_ZERO:
break;
case CMD_ZERO_NUM:
break;
case CMD_LIST:
case CMD_LIST|CMD_ZERO:
case CMD_LIST|CMD_ZERO_NUM:
printf("list table %s %s\n",
family2str[h->family], p.table);
ret = 1;
break;
case CMD_LIST_RULES:
case CMD_LIST_RULES|CMD_ZERO:
case CMD_LIST_RULES|CMD_ZERO_NUM:
break;
case CMD_NEW_CHAIN:
printf("add chain %s %s %s\n",
family2str[h->family], p.table, p.chain);
ret = 1;
break;
case CMD_DELETE_CHAIN:
printf("delete chain %s %s %s\n",
family2str[h->family], p.table, p.chain);
ret = 1;
break;
case CMD_RENAME_CHAIN:
break;
case CMD_SET_POLICY:
break;
default:
/* We should never reach this... */
printf("Unsupported command?\n");
exit(1);
}
xtables_rule_matches_free(&cs.matches);
if (h->family == AF_INET) {
free(args.s.addr.v4);
free(args.s.mask.v4);
free(args.d.addr.v4);
free(args.d.mask.v4);
} else if (h->family == AF_INET6) {
free(args.s.addr.v6);
free(args.s.mask.v6);
free(args.d.addr.v6);
free(args.d.mask.v6);
}
xtables_free_opts(1);
return ret;
}
static void print_usage(const char *name, const char *version)
{
fprintf(stderr, "%s %s "
"(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
"Usage: %s [-h] [-f]\n"
" [ --help ]\n"
" [ --file=<FILE> ]\n", name, version, name);
exit(1);
}
static const struct option options[] = {
{ .name = "help", .has_arg = false, .val = 'h' },
{ .name = "file", .has_arg = true, .val = 'f' },
{ NULL },
};
static int xlate_chain_user_add(struct nft_handle *h, const char *chain,
const char *table)
{
printf("add chain %s %s %s\n", family2str[h->family], chain, table);
return 0;
}
static int commit(struct nft_handle *h)
{
return 1;
}
static void xlate_table_new(struct nft_handle *h, const char *table)
{
printf("add table %s %s\n", family2str[h->family], table);
}
static int xlate_chain_set(struct nft_handle *h, const char *table,
const char *chain, const char *policy,
const struct xt_counters *counters)
{
printf("add chain %s %s %s ", family2str[h->family], table, chain);
if (strcmp(chain, "PREROUTING") == 0)
printf("{ type filter hook prerouting priority 0; }\n");
else if (strcmp(chain, "INPUT") == 0)
printf("{ type filter hook input priority 0; }\n");
else if (strcmp(chain, "FORWARD") == 0)
printf("{ type filter hook forward priority 0; }\n");
else if (strcmp(chain, "OUTPUT") == 0)
printf("{ type filter hook output priority 0; }\n");
else if (strcmp(chain, "POSTROUTING") == 0)
printf("{ type filter hook postrouting priority 0; }\n");
return 1;
}
static struct nft_xt_restore_cb cb_xlate = {
.table_new = xlate_table_new,
.chain_set = xlate_chain_set,
.chain_user_add = xlate_chain_user_add,
.do_command = do_command_xlate,
.commit = commit,
.abort = commit,
};
static int xtables_xlate_main(int family, const char *progname, int argc,
char *argv[])
{
int ret;
char *table = "filter";
struct nft_handle h = {
.family = family,
};
xtables_globals.program_name = progname;
ret = xtables_init_all(&xtables_globals, family);
if (ret < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
xtables_globals.program_name,
xtables_globals.program_version);
exit(1);
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
#endif
if (nft_init(&h, xtables_ipv4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
nft_fini(&h);
exit(EXIT_FAILURE);
}
printf("nft ");
ret = do_command_xlate(&h, argc, argv, &table, false);
if (!ret)
fprintf(stderr, "Translation not implemented\n");
nft_fini(&h);
exit(!ret);
}
static int xtables_restore_xlate_main(int family, const char *progname,
int argc, char *argv[])
{
int ret;
struct nft_handle h = {
.family = family,
};
const char *file = NULL;
struct nft_xt_restore_parse p = {};
time_t now = time(NULL);
int c;
xtables_globals.program_name = progname;
ret = xtables_init_all(&xtables_globals, family);
if (ret < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
xtables_globals.program_name,
xtables_globals.program_version);
exit(1);
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
#endif
if (nft_init(&h, xtables_ipv4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
nft_fini(&h);
exit(EXIT_FAILURE);
}
opterr = 0;
while ((c = getopt_long(argc, argv, "hf:", options, NULL)) != -1) {
switch (c) {
case 'h':
print_usage(argv[0], IPTABLES_VERSION);
exit(0);
case 'f':
file = optarg;
break;
}
}
if (file == NULL) {
fprintf(stderr, "ERROR: missing file name\n");
print_usage(argv[0], IPTABLES_VERSION);
exit(0);
}
p.in = fopen(file, "r");
if (p.in == NULL) {
fprintf(stderr, "Cannot open file %s\n", file);
exit(1);
}
printf("# Translated by %s v%s on %s",
argv[0], IPTABLES_VERSION, ctime(&now));
xtables_restore_parse(&h, &p, &cb_xlate, argc, argv);
printf("# Completed on %s", ctime(&now));
nft_fini(&h);
fclose(p.in);
exit(0);
}
int xtables_ip4_xlate_main(int argc, char *argv[])
{
return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
argc, argv);
}
int xtables_ip6_xlate_main(int argc, char *argv[])
{
return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate",
argc, argv);
}
int xtables_ip4_xlate_restore_main(int argc, char *argv[])
{
return xtables_restore_xlate_main(NFPROTO_IPV4,
"iptables-translate-restore",
argc, argv);
}
int xtables_ip6_xlate_restore_main(int argc, char *argv[])
{
return xtables_restore_xlate_main(NFPROTO_IPV6,
"ip6tables-translate-restore",
argc, argv);
}