Пример #1
0
static void
print_state(unsigned int statemask)
{
	const char *sep = "";

	if (statemask & XT_CONNTRACK_STATE_INVALID) {
		printf("%sINVALID", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
		printf("%sNEW", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
		printf("%sRELATED", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
		printf("%sESTABLISHED", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
		printf("%sUNTRACKED", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_SNAT) {
		printf("%sSNAT", sep);
		sep = ",";
	}
	if (statemask & XT_CONNTRACK_STATE_DNAT) {
		printf("%sDNAT", sep);
		sep = ",";
	}
	printf(" ");
}
Пример #2
0
static int
parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo)
{
	if (strncasecmp(state, "INVALID", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
	else if (strncasecmp(state, "NEW", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
	else if (strncasecmp(state, "ESTABLISHED", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
	else if (strncasecmp(state, "RELATED", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
	else if (strncasecmp(state, "UNTRACKED", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
	else if (strncasecmp(state, "SNAT", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
	else if (strncasecmp(state, "DNAT", len) == 0)
		sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
	else
		return 0;
	return 1;
}
Пример #3
0
static bool
conntrack_ps_state(struct xt_conntrack_mtinfo2 *info, const char *state,
                   size_t z)
{
	if (strncasecmp(state, "INVALID", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_INVALID;
	else if (strncasecmp(state, "NEW", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
	else if (strncasecmp(state, "ESTABLISHED", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
	else if (strncasecmp(state, "RELATED", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
	else if (strncasecmp(state, "UNTRACKED", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
	else if (strncasecmp(state, "SNAT", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_SNAT;
	else if (strncasecmp(state, "DNAT", z) == 0)
		info->state_mask |= XT_CONNTRACK_STATE_DNAT;
	else
		return false;
	return true;
}
Пример #4
0
static bool
conntrack_mt_v0(const struct sk_buff *skb, const struct net_device *in,
                const struct net_device *out, const struct xt_match *match,
                const void *matchinfo, int offset, unsigned int protoff,
                bool *hotdrop)
{
    const struct xt_conntrack_info *sinfo = matchinfo;
    const struct nf_conn *ct;
    enum ip_conntrack_info ctinfo;
    unsigned int statebit;

    ct = nf_ct_get(skb, &ctinfo);

#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & (invflg)))

    if (ct == &nf_conntrack_untracked)
        statebit = XT_CONNTRACK_STATE_UNTRACKED;
    else if (ct)
        statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
    else
        statebit = XT_CONNTRACK_STATE_INVALID;

    if (sinfo->flags & XT_CONNTRACK_STATE) {
        if (ct) {
            if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
                statebit |= XT_CONNTRACK_STATE_SNAT;
            if (test_bit(IPS_DST_NAT_BIT, &ct->status))
                statebit |= XT_CONNTRACK_STATE_DNAT;
        }
        if (FWINV((statebit & sinfo->statemask) == 0,
              XT_CONNTRACK_STATE))
            return false;
    }

    if (ct == NULL) {
        if (sinfo->flags & ~XT_CONNTRACK_STATE)
            return false;
        return true;
    }

    if (sinfo->flags & XT_CONNTRACK_PROTO &&
        FWINV(nf_ct_protonum(ct) !=
          sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
          XT_CONNTRACK_PROTO))
        return false;

    if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
        FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
           sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
          sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
          XT_CONNTRACK_ORIGSRC))
        return false;

    if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
        FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
           sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
          sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
          XT_CONNTRACK_ORIGDST))
        return false;

    if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
        FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
           sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
          sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
          XT_CONNTRACK_REPLSRC))
        return false;

    if (sinfo->flags & XT_CONNTRACK_REPLDST &&
        FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
           sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
          sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
          XT_CONNTRACK_REPLDST))
        return false;

    if (sinfo->flags & XT_CONNTRACK_STATUS &&
        FWINV((ct->status & sinfo->statusmask) == 0,
          XT_CONNTRACK_STATUS))
        return false;

    if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
        unsigned long expires = timer_pending(&ct->timeout) ?
                    (ct->timeout.expires - jiffies)/HZ : 0;

        if (FWINV(!(expires >= sinfo->expires_min &&
                expires <= sinfo->expires_max),
              XT_CONNTRACK_EXPIRES))
            return false;
    }
    return true;
#undef FWINV
}
Пример #5
0
static bool
conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
             const struct net_device *out, const struct xt_match *match,
             const void *matchinfo, int offset, unsigned int protoff,
             bool *hotdrop)
{
    const struct xt_conntrack_mtinfo1 *info = matchinfo;
    enum ip_conntrack_info ctinfo;
    const struct nf_conn *ct;
    unsigned int statebit;

    ct = nf_ct_get(skb, &ctinfo);

    if (ct == &nf_conntrack_untracked)
        statebit = XT_CONNTRACK_STATE_UNTRACKED;
    else if (ct != NULL)
        statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
    else
        statebit = XT_CONNTRACK_STATE_INVALID;

    if (info->match_flags & XT_CONNTRACK_STATE) {
        if (ct != NULL) {
            if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
                statebit |= XT_CONNTRACK_STATE_SNAT;
            if (test_bit(IPS_DST_NAT_BIT, &ct->status))
                statebit |= XT_CONNTRACK_STATE_DNAT;
        }
        if (!!(info->state_mask & statebit) ^
            !(info->invert_flags & XT_CONNTRACK_STATE))
            return false;
    }

    if (ct == NULL)
        return info->match_flags & XT_CONNTRACK_STATE;
    if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
        (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
        !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
        return false;

    if (info->match_flags & XT_CONNTRACK_ORIGSRC)
        if (conntrack_mt_origsrc(ct, info, match->family) ^
            !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
            return false;

    if (info->match_flags & XT_CONNTRACK_ORIGDST)
        if (conntrack_mt_origdst(ct, info, match->family) ^
            !(info->invert_flags & XT_CONNTRACK_ORIGDST))
            return false;

    if (info->match_flags & XT_CONNTRACK_REPLSRC)
        if (conntrack_mt_replsrc(ct, info, match->family) ^
            !(info->invert_flags & XT_CONNTRACK_REPLSRC))
            return false;

    if (info->match_flags & XT_CONNTRACK_REPLDST)
        if (conntrack_mt_repldst(ct, info, match->family) ^
            !(info->invert_flags & XT_CONNTRACK_REPLDST))
            return false;

    if (!ct_proto_port_check(info, ct))
        return false;

    if ((info->match_flags & XT_CONNTRACK_STATUS) &&
        (!!(info->status_mask & ct->status) ^
        !(info->invert_flags & XT_CONNTRACK_STATUS)))
        return false;

    if (info->match_flags & XT_CONNTRACK_EXPIRES) {
        unsigned long expires = 0;

        if (timer_pending(&ct->timeout))
            expires = (ct->timeout.expires - jiffies) / HZ;
        if ((expires >= info->expires_min &&
            expires <= info->expires_max) ^
            !(info->invert_flags & XT_CONNTRACK_EXPIRES))
            return false;
    }
    return true;
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	const struct xt_conntrack_info *sinfo = matchinfo;
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int statebit;

	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);

#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))

	if (ct == &ip_conntrack_untracked)
		statebit = XT_CONNTRACK_STATE_UNTRACKED;
	else if (ct)
 		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
 	else
 		statebit = XT_CONNTRACK_STATE_INVALID;
 
	if(sinfo->flags & XT_CONNTRACK_STATE) {
		if (ct) {
			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
				statebit |= XT_CONNTRACK_STATE_SNAT;

			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
				statebit |= XT_CONNTRACK_STATE_DNAT;
		}

		if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_PROTO) {
		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
                	return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_REPLDST) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_STATUS) {
		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
		unsigned long expires;

		if(!ct)
			return 0;

		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;

		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
			return 0;
	}

	return 1;
}
Пример #7
0
/*
 * Get a list of the current firewall entries
 * @param	fw_list	list of firewall entries
 * @return	0 on success and errno on failure
 */
int
netconf_get_fw(netconf_fw_t *fw_list)
{
	const char **table;
	const char *chain;
	const struct ipt_entry *entry;
	struct iptc_handle *handle = NULL;

	/* Initialize list */
	netconf_list_init(fw_list);

	/* Search all default tables */
	for (table = &netconf_table_names[0]; *table; table++) {

		if (strcmp(*table, "filter") && strcmp(*table, "nat"))
			continue;		

		if (!(handle = iptc_init(*table))) {
			fprintf(stderr, "%s\n", iptc_strerror(errno));
			goto err;
		}

		/* Search all default chains */
		for (chain = iptc_first_chain(handle); chain; chain = iptc_next_chain(handle)) {

			if (strcmp(chain, "INPUT") && strcmp(chain, "FORWARD") && strcmp(chain, "OUTPUT") &&
			    strcmp(chain, "PREROUTING") && strcmp(chain, "POSTROUTING") &&
			    strcmp(chain, "VSERVER") && strcmp(chain, "UPNP"))
				continue;

			/* Search all entries */
			for (entry = iptc_first_rule(chain, handle); entry; entry = iptc_next_rule(entry, handle)) {
				int num = target_num(entry, handle);
				netconf_fw_t *fw = NULL;
				netconf_filter_t *filter = NULL;
				netconf_nat_t *nat = NULL;
				netconf_app_t *app = NULL;

				const struct ipt_entry_match *match;
				const struct ipt_entry_target *target;
				struct ipt_mac_info *mac = NULL;
				struct ipt_state_info *state = NULL;
				struct ipt_conntrack_info *conntrack = NULL;
				struct ipt_time_info *time = NULL;

				/* Only know about TCP/UDP */
				if (!netconf_valid_ipproto(entry->ip.proto))
					continue;

				/* Only know about target types in the specified tables */
				if (!netconf_valid_target(num) || (netconf_table_name[num] &&
				    strncmp(netconf_table_name[num], *table, IPT_FUNCTION_MAXNAMELEN) != 0))
					continue;

				/* Only know about specified target types */
				if (netconf_valid_filter(num))
					fw = (netconf_fw_t *) (filter = calloc(1, sizeof(netconf_filter_t)));
				else if (netconf_valid_nat(num))
					fw = (netconf_fw_t *) (nat = calloc(1, sizeof(netconf_nat_t)));
				else if (num == NETCONF_APP)
					fw = (netconf_fw_t *) (app = calloc(1, sizeof(netconf_app_t)));
				else
					continue;

				if (!fw) {
					perror("calloc");
					goto err;
				}
				netconf_list_add(fw, fw_list);

				/* Get IP addresses */
				fw->match.src.ipaddr.s_addr = entry->ip.src.s_addr;
				fw->match.src.netmask.s_addr = entry->ip.smsk.s_addr;
				fw->match.dst.ipaddr.s_addr = entry->ip.dst.s_addr;
				fw->match.dst.netmask.s_addr = entry->ip.dmsk.s_addr;
				fw->match.flags |= (entry->ip.invflags & IPT_INV_SRCIP) ? NETCONF_INV_SRCIP : 0;
				fw->match.flags |= (entry->ip.invflags & IPT_INV_DSTIP) ? NETCONF_INV_DSTIP : 0;

				/* Get interface names */
				strncpy(fw->match.in.name, entry->ip.iniface, IFNAMSIZ);
				strncpy(fw->match.out.name, entry->ip.outiface, IFNAMSIZ);
				fw->match.flags |= (entry->ip.invflags & IPT_INV_VIA_IN) ? NETCONF_INV_IN : 0;
				fw->match.flags |= (entry->ip.invflags & IPT_INV_VIA_OUT) ? NETCONF_INV_OUT : 0;

				fw->match.ipproto = entry->ip.proto;

				/* Get TCP port(s) */
				if (entry->ip.proto == IPPROTO_TCP) {
					struct ipt_tcp *tcp = NULL;

					for_each_ipt_match(match, entry) {
						if (strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN) != 0)
							continue;

						tcp = (struct ipt_tcp *) &match->data[0];
						break;
					}

					if (tcp) {
						/* Match ports stored in host order for some stupid reason */
						fw->match.src.ports[0] = htons(tcp->spts[0]);
						fw->match.src.ports[1] = htons(tcp->spts[1]);
						fw->match.dst.ports[0] = htons(tcp->dpts[0]);
						fw->match.dst.ports[1] = htons(tcp->dpts[1]);
						fw->match.flags |= (tcp->invflags & IPT_TCP_INV_SRCPT) ? NETCONF_INV_SRCPT : 0;
						fw->match.flags |= (tcp->invflags & IPT_TCP_INV_DSTPT) ? NETCONF_INV_DSTPT : 0;
					}
				}

				/* Get UDP port(s) */
				else if (entry->ip.proto == IPPROTO_UDP) {
					struct ipt_udp *udp = NULL;

					for_each_ipt_match(match, entry) {
						if (strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN) != 0)
							continue;

						udp = (struct ipt_udp *) &match->data[0];
						break;
					}

					if (udp) {
						/* Match ports stored in host order for some stupid reason */
						fw->match.src.ports[0] = htons(udp->spts[0]);
						fw->match.src.ports[1] = htons(udp->spts[1]);
						fw->match.dst.ports[0] = htons(udp->dpts[0]);
						fw->match.dst.ports[1] = htons(udp->dpts[1]);
						fw->match.flags |= (udp->invflags & IPT_UDP_INV_SRCPT) ? NETCONF_INV_SRCPT : 0;
						fw->match.flags |= (udp->invflags & IPT_UDP_INV_DSTPT) ? NETCONF_INV_DSTPT : 0;
					}
				}

				/* Get source MAC address */
				for_each_ipt_match(match, entry) {
					if (strncmp(match->u.user.name, "mac", IPT_FUNCTION_MAXNAMELEN) != 0)
						continue;
			
					mac = (struct ipt_mac_info *) &match->data[0];
					break;
				}
				if (mac) {
					memcpy(fw->match.mac.octet, mac->srcaddr, ETHER_ADDR_LEN);
					fw->match.flags |= mac->invert ? NETCONF_INV_MAC : 0;
				}

				/* Get packet state */
				for_each_ipt_match(match, entry) {
					if (strncmp(match->u.user.name, "state", IPT_FUNCTION_MAXNAMELEN) == 0) {
						state = (struct ipt_state_info *) &match->data[0];
						break;
					} else
					if (strncmp(match->u.user.name, "conntrack", IPT_FUNCTION_MAXNAMELEN) == 0) {
						conntrack = (struct ipt_conntrack_info *) &match->data[0];
						break;
					}
				}
				if (conntrack && (conntrack->match_flags & XT_CONNTRACK_STATE)) {
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_INVALID) ? NETCONF_INVALID : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) ? NETCONF_ESTABLISHED : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) ? NETCONF_RELATED : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) ? NETCONF_NEW : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_UNTRACKED) ? NETCONF_UNTRACKED : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_SNAT) ? NETCONF_STATE_SNAT : 0;
					fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_DNAT) ? NETCONF_STATE_DNAT : 0;
				} else
				if (state) {
					fw->match.state |= (state->statemask & IPT_STATE_INVALID) ? NETCONF_INVALID : 0;
					fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) ? NETCONF_ESTABLISHED : 0;
					fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_RELATED)) ? NETCONF_RELATED : 0;
					fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_NEW)) ? NETCONF_NEW : 0;
				}

				/* Get local time */
				for_each_ipt_match(match, entry) {
					if (strncmp(match->u.user.name, "time", IPT_FUNCTION_MAXNAMELEN) != 0)
						continue;

					/* We added 8 bytes of day range at the end */
					if (match->u.match_size < (IPT_ALIGN(sizeof(struct ipt_entry_match)) +
								   IPT_ALIGN(sizeof(struct ipt_time_info) + 8)))
						continue;

					time = (struct ipt_time_info *) &match->data[0];
					break;
				}
				if (time) {
					fw->match.days    = time->weekdays_match;
					fw->match.secs[0] = time->daytime_start;
					fw->match.secs[1] = time->daytime_stop;
				}

				/* Set target type */
				fw->target = num;
				target = (struct ipt_entry_target *) ((int) entry + entry->target_offset);

				/* Get filter target information */
				if (filter) {
					if (!netconf_valid_dir(filter->dir = filter_dir(chain))) {
						fprintf(stderr, "error direction in %s\n", chain);
						goto err;
					}
				}

				/* Get NAT target information */
				else if (nat) {
					struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *) &target->data[0];
					struct ip_nat_range *range = (struct ip_nat_range *) &mr->range[0];
				
					/* Get mapped IP address */
					nat->ipaddr.s_addr = range->min_ip;
				
					/* Get mapped TCP port(s) */
					if (entry->ip.proto == IPPROTO_TCP) {
						nat->ports[0] = range->min.tcp.port;
						nat->ports[1] = range->max.tcp.port;
					}

					/* Get mapped UDP port(s) */
					else if (entry->ip.proto == IPPROTO_UDP) {
						nat->ports[0] = range->min.udp.port;
						nat->ports[1] = range->max.udp.port;
					}
				}

				/* Get application specific port forward information */
				else if (app) {
					struct ip_autofw_info *info = (struct ip_autofw_info *) &target->data[0];

					app->proto = info->proto;
					app->dport[0] = info->dport[0];
					app->dport[1] = info->dport[1];
					app->to[0] = info->to[0];
					app->to[1] = info->to[1];
				}
			}
		}

		if (!iptc_commit(handle)) {
			fprintf(stderr, "%s\n", iptc_strerror(errno));
			goto err;
		}
		iptc_free(handle);
		handle = NULL;
	}