Home | History | Annotate | Download | only in conntrack
      1 /*
      2  * (C) 2005-2011 by Pablo Neira Ayuso <pablo (at) netfilter.org>
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  */
      9 
     10 #include "internal/internal.h"
     11 
     12 static void __autocomplete(struct nf_conntrack *ct, int dir)
     13 {
     14 	struct __nfct_tuple *this = NULL, *other = NULL;
     15 
     16 	switch(dir) {
     17 	case __DIR_ORIG:
     18 		this = &ct->head.orig;
     19 		other = &ct->repl;
     20 		break;
     21 	case __DIR_REPL:
     22 		this = &ct->repl;
     23 		other = &ct->head.orig;
     24 		break;
     25 	}
     26 
     27 	this->l3protonum = other->l3protonum;
     28 	this->protonum = other->protonum;
     29 
     30 	memcpy(&this->src.v6, &other->dst.v6, sizeof(union __nfct_address));
     31 	memcpy(&this->dst.v6, &other->src.v6, sizeof(union __nfct_address));
     32 
     33 	switch(this->protonum) {
     34 	case IPPROTO_UDP:
     35 	case IPPROTO_TCP:
     36 	case IPPROTO_SCTP:
     37 	case IPPROTO_DCCP:
     38 	case IPPROTO_GRE:
     39 	case IPPROTO_UDPLITE:
     40 		this->l4src.all = other->l4dst.all;
     41 		this->l4dst.all = other->l4src.all;
     42 		break;
     43 	case IPPROTO_ICMP:
     44 	case IPPROTO_ICMPV6:
     45 		/* the setter already autocompletes the reply tuple. */
     46 		break;
     47 	}
     48 
     49 	/* XXX: this is safe but better convert bitset to uint64_t */
     50         ct->head.set[0] |= TS_ORIG | TS_REPL;
     51 }
     52 
     53 static void setobjopt_undo_snat(struct nf_conntrack *ct)
     54 {
     55 	switch (ct->head.orig.l3protonum) {
     56 	case AF_INET:
     57 		ct->snat.min_ip.v4 = ct->repl.dst.v4;
     58 		ct->snat.max_ip.v4 = ct->snat.min_ip.v4;
     59 		ct->repl.dst.v4 = ct->head.orig.src.v4;
     60 		set_bit(ATTR_SNAT_IPV4, ct->head.set);
     61 		break;
     62 	case AF_INET6:
     63 		memcpy(&ct->snat.min_ip.v6, &ct->repl.dst.v6,
     64 		       sizeof(struct in6_addr));
     65 		memcpy(&ct->snat.max_ip.v6, &ct->snat.min_ip.v6,
     66 		       sizeof(struct in6_addr));
     67 		memcpy(&ct->repl.dst.v6, &ct->head.orig.src.v6,
     68 		       sizeof(struct in6_addr));
     69 		set_bit(ATTR_SNAT_IPV6, ct->head.set);
     70 		break;
     71 	default:
     72 		break;
     73 	}
     74 }
     75 
     76 static void setobjopt_undo_dnat(struct nf_conntrack *ct)
     77 {
     78 	switch (ct->head.orig.l3protonum) {
     79 	case AF_INET:
     80 		ct->dnat.min_ip.v4 = ct->repl.src.v4;
     81 		ct->dnat.max_ip.v4 = ct->dnat.min_ip.v4;
     82 		ct->repl.src.v4 = ct->head.orig.dst.v4;
     83 		set_bit(ATTR_DNAT_IPV4, ct->head.set);
     84 	case AF_INET6:
     85 		memcpy(&ct->dnat.min_ip.v6, &ct->repl.src.v6,
     86 		       sizeof(struct in6_addr));
     87 		memcpy(&ct->dnat.max_ip.v6, &ct->dnat.min_ip.v6,
     88 		       sizeof(struct in6_addr));
     89 		memcpy(&ct->repl.src.v6, &ct->head.orig.dst.v6,
     90 		       sizeof(struct in6_addr));
     91 		set_bit(ATTR_DNAT_IPV6, ct->head.set);
     92 		break;
     93 	default:
     94 		break;
     95 	}
     96 }
     97 
     98 static void setobjopt_undo_spat(struct nf_conntrack *ct)
     99 {
    100 	ct->snat.l4min.all = ct->repl.l4dst.tcp.port;
    101 	ct->snat.l4max.all = ct->snat.l4min.all;
    102 	ct->repl.l4dst.tcp.port =
    103 			ct->head.orig.l4src.tcp.port;
    104 	set_bit(ATTR_SNAT_PORT, ct->head.set);
    105 }
    106 
    107 static void setobjopt_undo_dpat(struct nf_conntrack *ct)
    108 {
    109 	ct->dnat.l4min.all = ct->repl.l4src.tcp.port;
    110 	ct->dnat.l4max.all = ct->dnat.l4min.all;
    111 	ct->repl.l4src.tcp.port =
    112 			ct->head.orig.l4dst.tcp.port;
    113 	set_bit(ATTR_DNAT_PORT, ct->head.set);
    114 }
    115 
    116 static void setobjopt_setup_orig(struct nf_conntrack *ct)
    117 {
    118 	__autocomplete(ct, __DIR_ORIG);
    119 }
    120 
    121 static void setobjopt_setup_repl(struct nf_conntrack *ct)
    122 {
    123 	__autocomplete(ct, __DIR_REPL);
    124 }
    125 
    126 static const setobjopt setobjopt_array[__NFCT_SOPT_MAX] = {
    127 	[NFCT_SOPT_UNDO_SNAT] 		= setobjopt_undo_snat,
    128 	[NFCT_SOPT_UNDO_DNAT] 		= setobjopt_undo_dnat,
    129 	[NFCT_SOPT_UNDO_SPAT] 		= setobjopt_undo_spat,
    130 	[NFCT_SOPT_UNDO_DPAT] 		= setobjopt_undo_dpat,
    131 	[NFCT_SOPT_SETUP_ORIGINAL] 	= setobjopt_setup_orig,
    132 	[NFCT_SOPT_SETUP_REPLY]		= setobjopt_setup_repl,
    133 };
    134 
    135 int __setobjopt(struct nf_conntrack *ct, unsigned int option)
    136 {
    137 	if (unlikely(option > NFCT_SOPT_MAX))
    138 		return -1;
    139 
    140 	setobjopt_array[option](ct);
    141 	return 0;
    142 }
    143 
    144 static int getobjopt_is_snat(const struct nf_conntrack *ct)
    145 {
    146 	if (!(test_bit(ATTR_STATUS, ct->head.set)))
    147 		return 0;
    148 
    149 	if (!(ct->status & IPS_SRC_NAT_DONE))
    150 		return 0;
    151 
    152 	switch (ct->head.orig.l3protonum) {
    153 	case AF_INET:
    154 		return ct->repl.dst.v4 != ct->head.orig.src.v4;
    155 	case AF_INET6:
    156 		if (memcmp(&ct->repl.dst.v6, &ct->head.orig.src.v6,
    157 			   sizeof(struct in6_addr)) != 0)
    158 			return 1;
    159 		else
    160 			return 0;
    161 	default:
    162 		return 0;
    163 	}
    164 }
    165 
    166 static int getobjopt_is_dnat(const struct nf_conntrack *ct)
    167 {
    168 	if (!(test_bit(ATTR_STATUS, ct->head.set)))
    169 		return 0;
    170 
    171 	if (!(ct->status & IPS_DST_NAT_DONE))
    172 		return 0;
    173 
    174 	switch (ct->head.orig.l3protonum) {
    175 	case AF_INET:
    176 		return ct->repl.src.v4 != ct->head.orig.dst.v4;
    177 	case AF_INET6:
    178 		if (memcmp(&ct->repl.src.v6, &ct->head.orig.dst.v6,
    179 			   sizeof(struct in6_addr)) != 0)
    180 			return 1;
    181 		else
    182 			return 0;
    183 	default:
    184 		return 0;
    185 	}
    186 }
    187 
    188 static int getobjopt_is_spat(const struct nf_conntrack *ct)
    189 {
    190 	return ((test_bit(ATTR_STATUS, ct->head.set) ?
    191 		ct->status & IPS_SRC_NAT_DONE : 1) &&
    192 		ct->repl.l4dst.tcp.port !=
    193 		ct->head.orig.l4src.tcp.port);
    194 }
    195 
    196 static int getobjopt_is_dpat(const struct nf_conntrack *ct)
    197 {
    198 	return ((test_bit(ATTR_STATUS, ct->head.set) ?
    199 		ct->status & IPS_DST_NAT_DONE : 1) &&
    200 		ct->repl.l4src.tcp.port !=
    201 		ct->head.orig.l4dst.tcp.port);
    202 }
    203 
    204 static const getobjopt getobjopt_array[__NFCT_GOPT_MAX] = {
    205 	[NFCT_GOPT_IS_SNAT] = getobjopt_is_snat,
    206 	[NFCT_GOPT_IS_DNAT] = getobjopt_is_dnat,
    207 	[NFCT_GOPT_IS_SPAT] = getobjopt_is_spat,
    208 	[NFCT_GOPT_IS_DPAT] = getobjopt_is_dpat,
    209 };
    210 
    211 int __getobjopt(const struct nf_conntrack *ct, unsigned int option)
    212 {
    213 	if (unlikely(option > NFCT_GOPT_MAX))
    214 		return -1;
    215 
    216 	return getobjopt_array[option](ct);
    217 }
    218