libiptc:添加带目标IP的DNAT规则

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libiptc:添加带目标IP的DNAT规则相关的知识,希望对你有一定的参考价值。

我正在尝试使用libiptc创建一个c程序来创建端口转发规则。

static int insert_forward_rule(const char *table, const char *chain, unsigned int src, unsigned int dest, const char * ports, const char *target1, char * proto) {
struct xtc_handle *h;
struct ipt_entry *en = NULL;
struct ipt_entry * e;

struct ipt_entry_match * match_proto, * match_limit;
struct ipt_entry_target * target;
unsigned int size_ipt_entry, size_ipt_entry_match, size_ipt_entry_target, total_length;

size_ipt_entry = IPT_ALIGN(sizeof (struct ipt_entry));
size_ipt_entry_match = IPT_ALIGN(sizeof (struct ipt_entry_match)) + sizeof (struct ipt_tcp) + sizeof (int);
size_ipt_entry_target = IPT_ALIGN(sizeof (struct ipt_entry_target) + sizeof (IPTC_LABEL_ACCEPT));
total_length = 216; //size_ipt_entry + size_ipt_entry_match + size_ipt_entry_target + IPT_ALIGN(sizeof (struct ipt_natinfo)); //size_ipt_entry + 48 + 40
//printf("size of ipt ebtry=%u,match=%u,target=%u,total=%u
", size_ipt_entry, size_ipt_entry_match, size_ipt_entry_target, total_length);
//memory allocation for all structs that represent the netfilter rule we want to insert

e = calloc(1, total_length);
if (e == NULL) {
    printf("malloc failure");
    exit(1);
}
int size = 160;
//offsets to the other bits:
//target struct begining
e->target_offset = size; //size_ipt_entry + size_ipt_entry_match; //+ size_ipt_tcp + size_rateinfo + size_physdevinfo;
//next "e" struct, end of the current one
e->next_offset = total_length;
e->nfcache = NFC_IP_DST_PT;

if (dest) {
    e->ip.dst.s_addr = dest;
    e->ip.dmsk.s_addr = 0xFFFFFFFF;

}
match_limit = (struct ipt_entry_match *) (e->elems); //+ match_proto->u.match_size
match_limit->u.user.match_size = size_ipt_entry_match; //size_ipt_entry_match*3; //+ size_rateinfo;
strncpy(match_limit->u.user.name, "tcp", sizeof (match_limit->u.user.name)); //set name of the module, we will use in this match
struct ipt_tcp *info = (struct ipt_tcp *) match_limit->data;
unsigned int i = 0;
if (strchr(ports, ':') != NULL) {
    char aPort[2][10];
    sscanf(ports, "%[^:], %[^:]", aPort[0], aPort[1]);

    info->dpts[0] = atoi(aPort[0]);
    info->dpts[1] = atoi(aPort[1]);
} else {
    info->dpts[0] = info->dpts[1] = atoi(ports);

}
info->spts[0] = 0;
info->spts[1] = 0xFFFF;
e->ip.proto = IPPROTO_TCP;
printf("Target offset=%d,next offset=%d
", e->target_offset, e->next_offset);
target = (struct ipt_entry_target *) ((void*) e + e->target_offset); // + size_ipt_entry_match); //+ size_ipt_tcp + size_rateinfo + size_physdevinfo
size = 56;
target->u.user.target_size = size_ipt_entry_target + IPT_ALIGN(sizeof (struct nf_nat_range)); // size_ipt_entry_target;
target->u.user.revision = 0;
strncpy(target->u.user.name, target1, sizeof (target->u.user.name));
struct ipt_natinfo *inf = (struct ipt_natinfo*) target->data;
struct nf_nat_range range;
memset(&range, 0, sizeof (range));
range.flags |= IP_NAT_RANGE_MAP_IPS;
range.min_ip = range.max_ip = src;
inf->mr.rangesize++;
inf->mr.range[inf->mr.rangesize] = range;
inf->t.u.target_size = XT_ALIGN(sizeof (*inf) + inf->mr.rangesize * sizeof (struct nf_nat_range));


printf("after s_addr

");


//All the functions, mentioned below could be found in "Querying libiptc HOWTO" manual
h = iptc_init(table);
printf("h=%d
", h);
if (!h) {
    printf("Error initializing: %s
", iptc_strerror(errno));
    return 0;
}

printf("target_size=%d,match=%d,chain=%s,table=%s,target=%s
", target->u.user.target_size, match_limit->u.user.match_size, chain, table, target1);

int x = iptc_append_entry(chain, e, h);
if (!x) {
    printf("Error append_entry: %s
", iptc_strerror(errno));
    goto ERROR;
}
printf("%d,chain=%s,target=%s
", target->u.user.target_size, chain, table);
int y = iptc_commit(h);
if (!y) {
    printf("Error no=%d,commit: %s
", errno, iptc_strerror(errno));
    goto ERROR;
}
iptc_free(h);
if (e != NULL) {
    free(e);
    e = NULL;
}
return 1;
ERROR:
iptc_free(h);
if (e != NULL) {
    free(e);
    e = NULL;
}
return 0;
}

要调用此功能

inet_pton(AF_INET, "20.10.10.254", &a);
inet_pton(AF_INET, "20.10.10.100", &b);
insert_forward_rule("nat", "port_forward", b, a, "1111", "DNAT", "tcp");

每次我运行这段代码我都会得到错误作为无效的参数(代码22)。如果我将rangeize的位置更改为低于iptc_init(),那么它给出了错误代码94(非套接字上的套接字操作)我尝试了struct nf_nat_range结构直接然后它没有在规则中保存目标IP而不是它显示随机。我想做的规则是

iptables  -t nat -A port_forward -j DNAT -d 192.168.10.202 -p udp --dport 8080:8084 --to 20.10.10.112

用结构nf_nat_range创建的是

Chain port_forward (0 references)
pkts      bytes target     prot opt in     out     source               destination         
   0        0 DNAT       tcp  --  *      *       0.0.0.0/0            20.10.10.254        tcp dpt:1111 to: random 
   0        0 DNAT       tcp  --  *      *       0.0.0.0/0            20.10.10.254        tcp dpt:1111 to: random 
   0        0 DNAT       tcp  --  *      *       0.0.0.0/0            20.10.10.254        tcp dpt:1111 to: random 
答案

这些功能帮助我使用libiptc添加或删除DNAT和SNAT规则。我将此上传到我的GitHub帐户。

void iptc_add_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append) {
iptc_handle_t handle;
struct ipt_entry *chain_entry;
struct ipt_entry_match *entry_match = NULL;
struct ipt_entry_target *entry_target;
ipt_chainlabel labelit;
long match_size;
int result = 0;

chain_entry = (struct ipt_entry *) calloc(1, sizeof (*chain_entry));

if (src) {
    chain_entry->ip.src.s_addr = inet_addr(src);
    chain_entry->ip.smsk.s_addr = inet_addr("255.255.255.255");
}
if (dest) {
    chain_entry->ip.dst.s_addr = inet_addr(dest);
    chain_entry->ip.dmsk.s_addr = inet_addr("255.255.255.255");
}

if (iniface) strncpy(chain_entry->ip.iniface, iniface, IFNAMSIZ);
if (outiface) strncpy(chain_entry->ip.outiface, outiface, IFNAMSIZ);

if (strcmp(protocol, "TCP") == 0) {
    chain_entry->ip.proto = IPPROTO_TCP;
    entry_match = get_tcp_match(srcports, destports, &chain_entry->nfcache);
} else if (strcmp(protocol, "UDP") == 0) {
    chain_entry->ip.proto = IPPROTO_UDP;
    entry_match = get_udp_match(srcports, destports, &chain_entry->nfcache);
} else {
    printf("Unsupported protocol: %s", protocol);
    return;
}

if (strcmp(target, "") == 0
        || strcmp(target, IPTC_LABEL_ACCEPT) == 0
        || strcmp(target, IPTC_LABEL_DROP) == 0
        || strcmp(target, IPTC_LABEL_QUEUE) == 0
        || strcmp(target, IPTC_LABEL_RETURN) == 0) {
    size_t size;

    size = IPT_ALIGN(sizeof (struct ipt_entry_target)) + IPT_ALIGN(sizeof (int));
    entry_target = (struct ipt_entry_target *) calloc(1, size);
    entry_target->u.user.target_size = size;
    strncpy(entry_target->u.user.name, target, IPT_FUNCTION_MAXNAMELEN);
} else if (strcmp(target, "DNAT") == 0) {
    entry_target = get_dnat_target(dnat_to, &chain_entry->nfcache);
    printf("dnat
");
} else if (strcmp(target, "SNAT") == 0) {
    entry_target = get_snat_target(dnat_to, &chain_entry->nfcache);
    printf("snat
");
}

if (entry_match)
    match_size = entry_match->u.match_size;
else
    match_size = 0;
struct ipt_entry *tmp_ipt = chain_entry;
chain_entry = (struct ipt_entry *) realloc(chain_entry, sizeof (*chain_entry) + match_size + entry_target->u.target_size);
if (chain_entry == NULL) {
    free(tmp_ipt);
}
memcpy(chain_entry->elems + match_size, entry_target, entry_target->u.target_size);
chain_entry->target_offset = sizeof (*chain_entry) + match_size;
chain_entry->next_offset = sizeof (*chain_entry) + match_size + entry_target->u.target_size;
printf("target->offset=%d,next_offset=%d,target_size=%d
", chain_entry->target_offset, chain_entry->next_offset, entry_target->u.user.target_size);
if (entry_match) {
    memcpy(chain_entry->elems, entry_match, match_size);
    printf("%d
", __LINE__);
}
printf("%d
", __LINE__);
handle = iptc_init(table);
if (!handle) {
    printf("libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno));
    free(chain_entry);
    free(entry_target);
    if (entry_match) free(entry_match);
    return;
}

strncpy(labelit, chain, sizeof (ipt_chainlabel));
printf("%d
", __LINE__);
result = iptc_is_chain(chain, handle);
if (!result) {
    printf("libiptc error: Chain %s does not exist!", chain);
    free(chain_entry);
    free(entry_target);
    if (entry_match) free(entry_match);
    return;
}
printf("%d,labeit=%s
", __LINE__, labelit);
if (append)
    result = iptc_append_entry(labelit, chain_entry, handle);
else
    result = iptc_insert_entry(labelit, chain_entry, 0, handle);
printf("%d
", __LINE__);
if (!result) {
    printf("libiptc error: Can't add, %s", iptc_strerror(errno));
    free(chain_entry);
    free(entry_target);
    if (entry_match) free(entry_match);
    return;
}
printf("%d
", __LINE__);
result = iptc_commit(handle);
if (!result) {
    printf("libiptc error: Commit error, %s", iptc_strerror(errno));
    free(chain_entry);
    free(entry_target);
    if (entry_match) free(entry_match);
    return;
} else
    printf("added new rule to block successfully");

if (entry_match) free(entry_match);
free(entry_target);
free(chain_entry);

}

void iptc_delete_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to) {
iptc_handle_t handle;
const struct ipt_entry *e;
ipt_chainlabel labelit;
int i, result;
unsigned long int s_src, s_dest;

if (src) s_src = inet_addr(src);
if (dest) s_dest = inet_addr(dest);

handle = iptc_init(table);
if (!handle) {
    printf("libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno));
    return;
}

strncpy(labelit, chain, sizeof (ipt_chainlabel));
result = iptc_is_chain(chain, handle);
if (!result) {
    printf("libiptc error: Chain %s does not exist!", chain);
    return;
}
for (e = iptc_first_rule(chain, handle), i = 0; e; e = iptc_next_rule(e, handle), i++) {
    if (src && e->ip.src.s_addr != s_src) continue;
    else if (dest && e->ip.dst.s_addr != s_dest) continue;
    else if (iniface && strcmp(e->ip.iniface, iniface) != 0) continue;
    else if (outiface && strcmp(e->ip.outiface, outiface) != 0) continue;
    else if (protocol && strcmp(protocol, "TCP") == 0 && e->ip.proto != IPPROTO_TCP) continue;
    else if (protocol && strcmp(protocol, "UDP") == 0 && e->ip.proto != IPPROTO_UDP) continue;
    else if ((srcports || destports) && IPT_MATCH_ITERATE_MY(e, matchcmp, srcports, destports) == 0) continue;
    else if (target && strcmp(target, iptc_get_target(e, handle)) != 0) continue;
    else if (dnat_to && strcmp(target, "DNAT") == 0) {
        struct ipt_entry_target *t;
        struct ip_nat_multi_range *mr;
        struct ip_nat_range *r, range;

        t = (struct ipt_entry_target *) (e + e->target_offset);
        mr = (struct ip_nat_multi_range *) ((void *) &t->data);

        if (mr->rangesize != 1) continue; // we have only single dnat_to target now
        r = mr->range;
        parse_range(dnat_to, &range);
        if (r->flags == range.flags
                && r->min_ip == range.min_ip
                && r->max_ip == range.max_ip
                && r->min.all == range.min.all
                && r->max.all == range.max.all) {
            break;
        }
    } else break;
}
if (!e) return;
result = iptc_delete_num_entry(chain, i, handle);
if (!result) {
    printf("libiptc error: Delete error, %s", iptc_strerror(errno));
    return;
}
result = iptc_commit(handle);
if (!result) {
    printf("libiptc error: Commit error, %s", iptc_strerror(errno));
    return;
} else
    printf("deleted rule from block successfully");

}

int matchcmp(const struct ipt_entry_match *match, const char *srcports, const char *destports) {
u_int16_t temp[2];

if (strcmp(match->u.user.name, "tcp") == 0) {
    struct ipt_tcp *tcpinfo = (struct ipt_tcp *) match->data;

    if (srcports) {
        parse_ports(srcports, temp);
        if (temp[0] != tcpinfo->spts[0] || temp[1] != tcpinfo->spts[1]) return 0;
    }
    if (destports) {
        parse_ports(destports, temp);
        if (temp[0] != tcpinfo->dpts[0] || temp[1] != tcpinfo->dpts[1]) return 0;
    }
    return 1;
} else if (strcmp(match->u.user.name, "udp") == 0) {
    struct ipt_udp *udpinfo = (struct ipt_udp *) match->data;

    if (srcports) {
        parse_ports(srcports, temp);
        if 

以上是关于libiptc:添加带目标IP的DNAT规则的主要内容,如果未能解决你的问题,请参考以下文章

动态添加带剪切路径的SVG

SNAT与DNAT原理,实现内外网相互访问

Linux的防火墙

iptables中实现内外网相互访问 SNAT与DNAT的原理与应用

UITableViewCell如何添加带圆角的实心边框

在舞台内添加带参数的构建?