X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=dummynet%2Fipfw2_mod.c;h=b072ab507b518fd144956d183c461e1c088adde4;hb=6c2e192c3237bd46db6ad4230fed71d28f362331;hp=26fb5d9a3be25b64427426c72837a424abbd3444;hpb=90a9fdb668d64fd225973ab1e4bdcfd9bb9d97c5;p=ipfw.git diff --git a/dummynet/ipfw2_mod.c b/dummynet/ipfw2_mod.c index 26fb5d9..b072ab5 100644 --- a/dummynet/ipfw2_mod.c +++ b/dummynet/ipfw2_mod.c @@ -180,7 +180,7 @@ ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user) memset(&t, 0, sizeof(t)); s->sopt_td = &t; - printf("%s called with cmd %d len %d\n", __FUNCTION__, cmd, len); + // printf("%s called with cmd %d len %d\n", __FUNCTION__, cmd, len); if (cmd < IP_DUMMYNET_CONFIGURE && ip_fw_ctl_ptr) ret = ip_fw_ctl_ptr(s); @@ -281,6 +281,20 @@ static struct nf_sockopt_ops ipfw_sockopts = { #define NF_IP_POST_ROUTING NF_INET_POST_ROUTING #endif +/* + * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains. + * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and + * POST_ROUTING chains, so if we want to use that information we + * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING. + * However at the moment the skb_tag info is not reliable so + * we stay with the standard hooks. + */ +#if 0 // defined(IPFW_PLANETLAB) +#define IPFW_HOOK_IN NF_IP_LOCAL_IN +#else +#define IPFW_HOOK_IN NF_IP_PRE_ROUTING +#endif + /* * The main netfilter hook. * To make life simple, we queue everything and then do all the @@ -383,7 +397,7 @@ ipfw2_queue_handler(QH_ARGS) #endif /* XXX add the interface */ - if (info->hook == NF_IP_PRE_ROUTING) { + if (info->hook == IPFW_HOOK_IN) { ret = ipfw_check_in(NULL, &m, info->indev, PFIL_IN, NULL); } else { ret = ipfw_check_out(NULL, &m, info->outdev, PFIL_OUT, NULL); @@ -448,8 +462,24 @@ ip_output(struct mbuf *m, struct mbuf __unused *opt, * * We do this only on selected protocols: TCP, ... * - * Note- for locally generated, outgoing packets we don't need to - * do a lookup because the sk_buff already points to the socket where + * The chain is the following + * sk_buff* sock* socket* file* + * skb -> sk ->sk_socket->file ->f_owner ->pid + * skb -> sk ->sk_socket->file ->f_uid (direct) + * skb -> sk ->sk_socket->file ->f_cred->fsuid (2.6.29+) + * + * Related headers: + * linux/skbuff.h struct skbuff + * net/sock.h struct sock + * linux/net.h struct socket + * linux/fs.h struct file + * + * With vserver we may have sk->sk_xid and sk->sk_nid that + * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2] + * (no matches yet) + * + * Note- for locally generated, outgoing packets we should not need + * need a lookup because the sk_buff already points to the socket where * the info is. */ extern struct inet_hashinfo tcp_hashinfo; @@ -460,6 +490,8 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, { struct sock *sk; int ret = -1; /* default return value */ + int uid = -1; /* user id */ + int st = -1; /* state */ if (proto != IPPROTO_TCP) return -1; @@ -476,10 +508,18 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) #define _OPT_NET_ARG -#else /* 2.6.25 and above */ +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +/* there is no dev_net() on 2.6.25 */ +#define _OPT_NET_ARG (skb->dev->nd_net), +#else /* 2.6.26 and above */ #define _OPT_NET_ARG dev_net(skb->dev), +#endif #endif + if (0 && skb->sk) { + sk=skb->sk; + } else { sk = (dir) ? inet_lookup(_OPT_NET_ARG &tcp_hashinfo, daddr, dport, saddr, sport, // matches outgoing for server sockets @@ -487,6 +527,7 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, inet_lookup(_OPT_NET_ARG &tcp_hashinfo, saddr, sport, daddr, dport, // matches incoming for server sockets skb->dev->ifindex); + } #undef _OPT_NET_ARG /* no match, nothing to be done */ @@ -495,10 +536,13 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, /* * On a match, sk is returned with a refcount. - * In tcp states less that TCP_TIME_WAIT sk references a struct sock - * which is what we want, - * otherwise it references a struct inet_timewait_sock which does - * not point to credentials. + * In tcp some states reference a valid struct sock + * which is what we want, otherwise the struct sock + * referenced can be invalid, as in the case of the + * TCP_TIME_WAIT state, when it references a + * struct inet_timewait_sock which does not point to credentials. + * To be safe we exclude TCP_CLOSE and TCP_LAST_ACK states too. + * * Once again we need conditional code because the UID and GID * location changes between the two kernels. */ @@ -511,15 +555,24 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, #define _CURR_UID f_cred->fsuid #define _CURR_GID f_cred->fsgid #endif - if (sk->sk_state < TCP_TIME_WAIT && sk->sk_socket && sk->sk_socket->file) { + st = sk->sk_state; + if (st != TCP_TIME_WAIT && st != TCP_CLOSE && st != TCP_LAST_ACK && + sk->sk_socket && sk->sk_socket->file) { ugp->fw_uid = sk->sk_socket->file->_CURR_UID; + uid = ugp->fw_uid; + ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID; +#ifdef CONFIG_VSERVER + ugp->fw_groups[1] = sk->sk_xid; + ugp->fw_groups[2] = sk->sk_nid; +#endif ret = 1; } - sock_put(sk); + if (1 && !skb->sk) /* the reference came from the lookup */ + sock_put(sk); #undef _CURR_UID #undef _CURR_GID - //printf("%s dir %d skb->dst %p skb->dev %p ret %d\n", __FUNCTION__, dir, skb->dst, skb->dev, ret); + //printf("%s dir %d sb>dst %p sb>dev %p ret %d id %d st%d\n", __FUNCTION__, dir, skb->dst, skb->dev, ret, uid, st); return ret; } @@ -577,7 +630,7 @@ static struct nf_hook_ops ipfw_ops[] __read_mostly = { { .hook = call_ipfw, .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, + .hooknum = IPFW_HOOK_IN, .priority = NF_IP_PRI_FILTER, SET_MOD_OWNER }, @@ -603,7 +656,7 @@ ipfw_module_init(void) { int ret = 0; - printf("%s called\n", __FUNCTION__); + printf("%s in-hook %d svn id %s\n", __FUNCTION__, IPFW_HOOK_IN, "$Id$"); my_mod_register(moddesc_ipfw, "ipfw", 1); my_mod_register(moddesc_dummynet, "dummynet", 2);