X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=dummynet%2Fipfw2_mod.c;h=f47d3655927796669a1f0c8ca8e6ac05ba3e6132;hb=5ad9fec40da13c449d50def12f9cea6e24b6a708;hp=3bf836afd80c2c16e6ff3344decbedabde876bf9;hpb=3e6f20122e1a37a4a6c84b0821827a8d98f0f8ec;p=ipfw.git diff --git a/dummynet/ipfw2_mod.c b/dummynet/ipfw2_mod.c index 3bf836a..f47d365 100644 --- a/dummynet/ipfw2_mod.c +++ b/dummynet/ipfw2_mod.c @@ -49,6 +49,8 @@ #include /* sizeof struct mbuf */ #include /* NGROUPS */ +#include "missing.h" + #ifdef __linux__ #include #include @@ -75,10 +77,12 @@ /* * Here we allocate some global variables used in the firewall. */ -ip_dn_ctl_t *ip_dn_ctl_ptr; +//ip_dn_ctl_t *ip_dn_ctl_ptr; +int (*ip_dn_ctl_ptr)(struct sockopt *); + ip_fw_ctl_t *ip_fw_ctl_ptr; -ip_dn_io_t *ip_dn_io_ptr; +int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa); ip_fw_chk_t *ip_fw_chk_ptr; void (*bridge_dn_p)(struct mbuf *, struct ifnet *); @@ -156,7 +160,7 @@ fini_children(void) mods[i].mod->evhand(NULL, MOD_UNLOAD, mods[i].mod->priv); } } -/*--- end of module bindinghelper functions ---*/ +/*--- end of module binding helper functions ---*/ /*--- * Control hooks: @@ -256,18 +260,18 @@ static struct nf_sockopt_ops ipfw_sockopts = { * - the hook names change between macros (NF_IP*) and enum NF_INET_* * * - the second argument to the netfilter hook is - * struct sk_buff ** in kernels <= 2.6.22 - * struct sk_buff * in kernels > 2.6.22 + * struct sk_buff ** in kernels <= 2.6.22 + * struct sk_buff * in kernels > 2.6.22 * * - NF_STOP is not defined before 2.6 so we remap it to NF_ACCEPT * * - the packet descriptor passed to the queue handler is - * struct nf_info in kernels <= 2.6.24 - * struct nf_queue_entry in kernels <= 2.6.24 + * struct nf_info in kernels <= 2.6.24 + * struct nf_queue_entry in kernels <= 2.6.24 * * - the arguments to the queue handler also change; */ - + /* * declare hook to grab packets from the netfilter interface. * The NF_* names change in different versions of linux, in some @@ -282,13 +286,14 @@ static struct nf_sockopt_ops ipfw_sockopts = { #endif /* - * ipfw hooks the POST_ROUTING and the PRE_ROUTING chain. - * PlanetLab tags the xid in the LOCAL_INPUT and in the - * POST_ROUTING chain, so if we want to intercept the - * traffic by using the id we need to hook the LOCAL_INPUT - * chain instead of the PRE_ROUTING. + * 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. */ -#ifdef IPFW_PLANETLAB +#if 0 // defined(IPFW_PLANETLAB) #define IPFW_HOOK_IN NF_IP_LOCAL_IN #else #define IPFW_HOOK_IN NF_IP_PRE_ROUTING @@ -461,8 +466,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; @@ -473,10 +494,9 @@ 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) + if (proto != IPPROTO_TCP) /* XXX extend for UDP */ return -1; if ((dir ? (void *)skb->dst : (void *)skb->dev) == NULL) { @@ -484,41 +504,55 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, return -1; } - /* - * inet_lookup above 2.6.24 has an additional 'net' parameter - * so we use a macro to conditionally supply it. - * Also we need to switch dst and src depending on the direction. - */ + if (skb->sk) { + sk = skb->sk; + } else { + /* + * Try a lookup. On a match, sk has a refcount that we must + * release on exit (we know it because skb->sk = NULL). + * + * inet_lookup above 2.6.24 has an additional 'net' parameter + * so we use a macro to conditionally supply it. + * swap dst and src depending on the direction. + */ #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 - - sk = (dir) ? - inet_lookup(_OPT_NET_ARG &tcp_hashinfo, - daddr, dport, saddr, sport, // matches outgoing for server sockets +#endif + sk = (dir) ? /* dir != 0 on output */ + inet_lookup(_OPT_NET_ARG &tcp_hashinfo, + daddr, dport, saddr, sport, // match outgoing inet_iif(skb)) : - inet_lookup(_OPT_NET_ARG &tcp_hashinfo, - saddr, sport, daddr, dport, // matches incoming for server sockets + inet_lookup(_OPT_NET_ARG &tcp_hashinfo, + saddr, sport, daddr, dport, // match incoming skb->dev->ifindex); - #undef _OPT_NET_ARG - /* no match, nothing to be done */ - if (sk == NULL) - return -1; + if (sk == NULL) /* no match, nothing to be done */ + return -1; + } + ret = 1; /* retrying won't make things better */ + st = sk->sk_state; +#ifdef CONFIG_VSERVER + ugp->fw_groups[1] = sk->sk_xid; + ugp->fw_groups[2] = sk->sk_nid; +#else + ugp->fw_groups[1] = ugp->fw_groups[2] = 0; +#endif /* - * On a match, sk is returned with a refcount. - * 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. + * Exclude tcp states where sk points to a inet_timewait_sock which + * has no sk_socket field (surely TCP_TIME_WAIT, perhaps more). + * To be safe, use a whitelist and not a blacklist. + * Before dereferencing sk_socket grab a lock on sk_callback_lock. * * Once again we need conditional code because the UID and GID - * location changes between the two kernels. + * location changes between kernels. */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) /* use the current's real uid/gid */ @@ -529,18 +563,37 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, #define _CURR_UID f_cred->fsuid #define _CURR_GID f_cred->fsgid #endif - 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; - ret = 1; + +#ifdef CONFIG_VSERVER + ugp->fw_groups[1] = sk->sk_xid; + ugp->fw_groups[2] = sk->sk_nid; +#else + ugp->fw_groups[1] = + ugp->fw_groups[2] = 0; +#endif + ret = 1; + +#define GOOD_STATES ( \ + (1<sk_callback_lock); + if (sk->sk_socket && sk->sk_socket->file) { + ugp->fw_uid = sk->sk_socket->file->_CURR_UID; + ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID; + } + read_unlock_bh(&sk->sk_callback_lock); + } else { + ugp->fw_uid = ugp->fw_groups[0] = 0; } - sock_put(sk); + if (!skb->sk) /* return the reference that came from the lookup */ + sock_put(sk); +#undef GOOD_STATES #undef _CURR_UID #undef _CURR_GID - - //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; }