1 diff --git a/include/linux/netfilter/xt_SETXID.h b/include/linux/netfilter/xt_SETXID.h
5 +++ b/include/linux/netfilter/xt_SETXID.h
7 +#ifndef _XT_SETXID_H_target
8 +#define _XT_SETXID_H_target
14 +struct xt_setxid_target_info_v2 {
19 +#endif /*_XT_SETXID_H_target*/
20 diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
21 index 5cf7270..95a5fde 100644
22 --- a/include/net/netfilter/nf_conntrack.h
23 +++ b/include/net/netfilter/nf_conntrack.h
24 @@ -119,6 +119,9 @@ struct nf_conn {
25 /* Storage reserved for other modules: */
26 union nf_conntrack_proto proto;
28 + /* PLANETLAB. VNET-specific */
29 + int xid[IP_CT_DIR_MAX];
32 struct nf_ct_ext *ext;
34 diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
35 index 634d14a..a2872f5 100644
36 --- a/net/netfilter/Kconfig
37 +++ b/net/netfilter/Kconfig
38 @@ -543,6 +543,13 @@ config NETFILTER_XT_MATCH_CLUSTER
39 If you say Y or M here, try `iptables -m cluster --help` for
42 +config NETFILTER_XT_TARGET_SETXID
43 + tristate '"SETXID" target support'
44 + depends on NETFILTER_XTABLES
46 + This option adds a `SETXID' target, which allows you to alter the
49 config NETFILTER_XT_MATCH_COMMENT
50 tristate '"comment" match support'
51 depends on NETFILTER_ADVANCED
52 diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
53 index 49f62ee..820655e 100644
54 --- a/net/netfilter/Makefile
55 +++ b/net/netfilter/Makefile
56 @@ -41,6 +41,7 @@ obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
57 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
60 +obj-$(CONFIG_NETFILTER_XT_TARGET_SETXID) += xt_SETXID.o
61 obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
62 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
63 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
64 diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
65 index 1e1df20..144e131 100644
66 --- a/net/netfilter/nf_conntrack_core.c
67 +++ b/net/netfilter/nf_conntrack_core.c
68 @@ -673,6 +673,9 @@ init_conntrack(struct net *net,
69 hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
70 &net->ct.unconfirmed);
72 + ct->xid[IP_CT_DIR_ORIGINAL] = -1;
73 + ct->xid[IP_CT_DIR_REPLY] = -1;
75 spin_unlock_bh(&nf_conntrack_lock);
78 diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
79 index 225f8d1..6cb5101 100644
80 --- a/net/netfilter/xt_MARK.c
81 +++ b/net/netfilter/xt_MARK.c
83 #include <linux/module.h>
84 #include <linux/skbuff.h>
87 #include <net/checksum.h>
88 +#include <net/route.h>
89 +#include <net/inet_hashtables.h>
90 +#include <net/net_namespace.h>
92 +#include <net/netfilter/nf_conntrack.h>
94 #include <linux/netfilter/x_tables.h>
95 #include <linux/netfilter/xt_MARK.h>
96 @@ -24,22 +30,269 @@ MODULE_DESCRIPTION("Xtables: packet mark modification");
97 MODULE_ALIAS("ipt_MARK");
98 MODULE_ALIAS("ip6t_MARK");
100 +DECLARE_PER_CPU(int, sknid_elevator);
102 +#define PEERCRED_SET(x) ((x!=0) && (x!=(unsigned int)-1))
104 +static inline u_int16_t get_dst_port(struct nf_conntrack_tuple *tuple)
106 + switch (tuple->dst.protonum) {
108 + /* XXX Truncate 32-bit GRE key to 16 bits */
109 + return tuple->dst.u.gre.key;
111 + /* Bind on ICMP echo ID */
112 + return tuple->src.u.icmp.id;
114 + return tuple->dst.u.tcp.port;
116 + return tuple->dst.u.udp.port;
118 + return tuple->dst.u.all;
122 +static inline u_int16_t get_src_port(struct nf_conntrack_tuple *tuple)
124 + switch (tuple->dst.protonum) {
126 + /* XXX Truncate 32-bit GRE key to 16 bits */
127 + return htons(ntohl(tuple->src.u.gre.key));
129 + /* Bind on ICMP echo ID */
130 + return tuple->src.u.icmp.id;
132 + return tuple->src.u.tcp.port;
134 + return tuple->src.u.udp.port;
136 + return tuple->src.u.all;
140 +static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
141 + __be16 sport, __be32 daddr, __be16 dport,
142 + int dif, struct udp_table *udptable)
144 + struct sock *sk, *result = NULL;
145 + struct hlist_nulls_node *node;
146 + unsigned short hnum = ntohs(dport);
147 + unsigned int hash = udp_hashfn(net, hnum);
148 + struct udp_hslot *hslot = &udptable->hash[hash];
152 + sk_nulls_for_each_rcu(sk, node, &hslot->head) {
153 + struct inet_sock *inet = inet_sk(sk);
155 + if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
156 + !ipv6_only_sock(sk)) {
157 + int score = (sk->sk_family == PF_INET ? 1 : 0);
159 + if (inet->rcv_saddr) {
160 + if (inet->rcv_saddr != daddr)
164 + /* block non nx_info ips */
165 + if (!v4_addr_in_nx_info(sk->sk_nx_info,
166 + daddr, NXA_MASK_BIND))
170 + if (inet->daddr != saddr)
175 + if (inet->dport != sport)
179 + if (sk->sk_bound_dev_if) {
180 + if (sk->sk_bound_dev_if != dif)
187 + } else if (score > badness) {
203 mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
205 const struct xt_mark_tginfo2 *info = par->targinfo;
207 + enum ip_conntrack_info ctinfo;
208 + struct sock *connection_sk;
210 + struct nf_conn *ct;
211 + extern struct inet_hashinfo tcp_hashinfo;
212 + enum ip_conntrack_dir dir;
216 + u_int16_t proto, src_port;
220 + if (info->mark == ~0U) {
221 + // As of 2.6.27.39, Dec 8 2009,
222 + // NetNS + VNET = Trouble
223 + // Let's handle this as a special case
224 + struct net *net = dev_net(skb->dev);
225 + if (!net_eq(net, &init_net)) {
228 + return XT_CONTINUE;
232 + dif = ((struct rtable *)(skb_dst(skb)))->rt_iif;
234 + ct = nf_ct_get(skb, &ctinfo);
236 + goto out_mark_finish;
238 + dir = CTINFO2DIR(ctinfo);
239 + src_ip = ct->tuplehash[dir].tuple.src.u3.ip;
240 + dst_ip = ct->tuplehash[dir].tuple.dst.u3.ip;
241 + src_port = get_src_port(&ct->tuplehash[dir].tuple);
242 + proto = ct->tuplehash[dir].tuple.dst.protonum;
244 + ip = ct->tuplehash[dir].tuple.dst.u3.ip;
245 + port = get_dst_port(&ct->tuplehash[dir].tuple);
249 + /* The packet is marked, it's going out */
250 + ct->xid[0] = skb->mark;
252 + if (ct->xid[0] > 0)
254 + } else if (proto == 17) {
257 + sk = __udp4_lib_lookup(net, src_ip, src_port,
258 + ip, port, dif, &udp_table);
260 + if (sk && par->hooknum == NF_INET_LOCAL_IN)
265 + } else if (skb->mark > 0)
266 + /* The packet is marked, it's going out */
267 + ct->xid[0] = skb->mark;
268 + } else if (proto == 6) { /* TCP */
269 + int sockettype = 0; /* Established socket */
271 + /* Looks for an established socket or a listening
272 + socket corresponding to the 4-tuple, in that order.
273 + The order is important for Codemux connections
274 + to be handled properly */
276 + connection_sk = inet_lookup_established(net,
282 + if (!connection_sk) {
283 + connection_sk = inet_lookup_listener(net,
287 + sockettype = 1; /* Listening socket */
290 + if (connection_sk) {
291 + if (connection_sk->sk_state == TCP_TIME_WAIT) {
292 + inet_twsk_put(inet_twsk(connection_sk));
293 + goto out_mark_finish;
296 + /* The peercred is not set. We set it if the other side has an xid. */
298 + (connection_sk->sk_peercred.uid)
299 + && ct->xid[!dir] > 0 && (sockettype == 0)) {
300 + connection_sk->sk_peercred.gid =
301 + connection_sk->sk_peercred.uid =
305 + /* The peercred is set, and is not equal to the XID of 'the other side' */
306 + else if (PEERCRED_SET
307 + (connection_sk->sk_peercred.uid)
308 + && (connection_sk->sk_peercred.uid !=
310 + && (sockettype == 0)) {
311 + mark = connection_sk->sk_peercred.uid;
314 + /* Has this connection already been tagged? */
315 + if (ct->xid[dir] < 1) {
316 + /* No - let's tag it */
317 + ct->xid[dir] = connection_sk->sk_nid;
320 + if (mark == -1 && (ct->xid[dir] != 0))
321 + mark = ct->xid[dir];
323 + sock_put(connection_sk);
326 + /* All else failed. Is this a connection over raw sockets?
327 + That explains why we couldn't get anything out of skb->sk,
328 + or look up a "real" connection. */
329 + if (ct->xid[dir] < 1) {
331 + ct->xid[dir] = skb->skb_tag;
334 + /* Covers CoDemux case */
335 + if (mark < 1 && (ct->xid[dir] > 0))
336 + mark = ct->xid[dir];
338 + if (mark < 1 && (ct->xid[!dir] > 0))
339 + mark = ct->xid[!dir];
340 + goto out_mark_finish;
343 + mark = (skb->mark & ~info->mask) ^ info->mark;
349 + curtag = &__get_cpu_var(sknid_elevator);
350 + if (mark > 0 && *curtag == -2 && par->hooknum == NF_INET_LOCAL_IN)
353 - skb->mark = (skb->mark & ~info->mask) ^ info->mark;
357 static struct xt_target mark_tg_reg __read_mostly = {
360 - .family = NFPROTO_UNSPEC,
362 - .targetsize = sizeof(struct xt_mark_tginfo2),
366 + .family = NFPROTO_UNSPEC,
368 + .targetsize = sizeof(struct xt_mark_tginfo2),
372 static int __init mark_tg_init(void)
373 diff --git a/net/netfilter/xt_SETXID.c b/net/netfilter/xt_SETXID.c
375 index 0000000..f8553c5
377 +++ b/net/netfilter/xt_SETXID.c
379 +#include <linux/module.h>
380 +#include <linux/skbuff.h>
381 +#include <linux/ip.h>
382 +#include <net/checksum.h>
383 +#include <linux/vs_network.h>
385 +#include <linux/netfilter/x_tables.h>
386 +#include <linux/netfilter/xt_SETXID.h>
388 +MODULE_LICENSE("GPL");
390 +MODULE_DESCRIPTION("");
391 +MODULE_ALIAS("ipt_SETXID");
394 +target_v2(struct sk_buff **pskb,
395 + const struct net_device *in,
396 + const struct net_device *out,
397 + unsigned int hooknum,
398 + const struct xt_target *target, const void *targinfo)
400 + const struct xt_setxid_target_info_v2 *setxidinfo = targinfo;
402 + switch (setxidinfo->mode) {
403 + case XT_SET_PACKET_XID:
404 + (*pskb)->skb_tag = setxidinfo->mark;
407 + return XT_CONTINUE;
411 +checkentry_v2(const char *tablename,
413 + const struct xt_target *target,
414 + void *targinfo, unsigned int hook_mask)
416 + struct xt_setxid_target_info_v2 *setxidinfo = targinfo;
418 + if (setxidinfo->mode != XT_SET_PACKET_XID) {
419 + printk(KERN_WARNING "SETXID: unknown mode %u\n",
427 +static struct xt_target xt_setxid_target[] = {
432 + .checkentry = checkentry_v2,
433 + .target = target_v2,
434 + .targetsize = sizeof(struct xt_setxid_target_info_v2),
440 +static int __init init(void)
445 + xt_register_target(xt_setxid_target);
449 +static void __exit fini(void)
451 + xt_unregister_target(xt_setxid_target);