return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
}
-/* If we source map this tuple so reply looks like reply_tuple, will
- * that meet the constraints of mr. */
+/* Does tuple + the source manip come within the range mr */
static int
in_range(const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack_manip *manip,
const struct ip_nat_multi_range *mr)
{
struct ip_nat_protocol *proto = ip_nat_find_proto(tuple->dst.protonum);
unsigned int i;
+ struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
for (i = 0; i < mr->rangesize; i++) {
- /* If we are supposed to map IPs, then we must be in the
- range specified. */
+ /* If we are allowed to map IPs, then we must be in the
+ range specified, otherwise we must be unchanged. */
if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
- if (ntohl(tuple->src.ip) < ntohl(mr->range[i].min_ip)
- || (ntohl(tuple->src.ip)
+ if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
+ || (ntohl(newtuple.src.ip)
> ntohl(mr->range[i].max_ip)))
continue;
+ } else {
+ if (newtuple.src.ip != tuple->src.ip)
+ continue;
}
if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
- || proto->in_range(tuple, IP_NAT_MANIP_SRC,
+ || proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
&mr->range[i].min, &mr->range[i].max))
return 1;
}
}
static inline int
-same_src(const struct ip_conntrack *ct,
- const struct ip_conntrack_tuple *tuple)
+src_cmp(const struct ip_conntrack *ct,
+ const struct ip_conntrack_tuple *tuple,
+ const struct ip_nat_multi_range *mr)
{
return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
== tuple->dst.protonum
&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
== tuple->src.ip
&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
- == tuple->src.u.all);
+ == tuple->src.u.all
+ && in_range(tuple,
+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src, mr));
}
/* Only called for SRC manip */
-static int
+static struct ip_conntrack_manip *
find_appropriate_src(const struct ip_conntrack_tuple *tuple,
- struct ip_conntrack_tuple *result,
const struct ip_nat_multi_range *mr)
{
unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
struct ip_conntrack *ct;
MUST_BE_READ_LOCKED(&ip_nat_lock);
-
- list_for_each_entry(ct, &bysource[h], nat.info.bysource) {
- if (same_src(ct, tuple)) {
- /* Copy source part from reply tuple. */
- invert_tuplepr(result,
- &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- result->dst = tuple->dst;
-
- if (in_range(result, mr))
- return 1;
- }
- }
- return 0;
+ list_for_each_entry(ct, &bysource[h], nat.info.bysource)
+ if (src_cmp(ct, tuple, mr))
+ return &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
+ return NULL;
}
#ifdef CONFIG_IP_NF_NAT_LOCAL
So far, we don't do local source mappings, so multiple
manips not an issue. */
if (hooknum == NF_IP_POST_ROUTING) {
- if (find_appropriate_src(orig_tuple, tuple, mr)) {
+ struct ip_conntrack_manip *manip;
+
+ manip = find_appropriate_src(orig_tuple, mr);
+ if (manip) {
+ /* Apply same source manipulation. */
+ *tuple = ((struct ip_conntrack_tuple)
+ { *manip, orig_tuple->dst });
DEBUGP("get_unique_tuple: Found current src map\n");
if (!ip_nat_used_tuple(tuple, conntrack))
return 1;
iph = (void *)(*pskb)->data + iphdroff;
/* Manipulate protcol part. */
- if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff,
+ if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4,
manip, maniptype))
return 0;