| 1 | |
| 2 | |
| 3 | * Rusty Russell (C)2000 -- This code is GPL.
|
| 4 | * Patrick McHardy (c) 2006-2012
|
| 5 |
|
| 6 |
|
| 7 | #include <linux/kernel.h>
|
| 8 | #include <linux/slab.h>
|
| 9 | #include <linux/init.h>
|
| 10 | #include <linux/module.h>
|
| 11 | #include <linux/proc_fs.h>
|
| 12 | #include <linux/skbuff.h>
|
| 13 | #include <linux/netfilter.h>
|
| 14 | #include <linux/netfilter_ipv4.h>
|
| 15 | #include <linux/netfilter_ipv6.h>
|
| 16 | #include <linux/netfilter_bridge.h>
|
| 17 | #include <linux/seq_file.h>
|
| 18 | #include <linux/rcupdate.h>
|
| 19 | #include <net/protocol.h>
|
| 20 | #include <net/netfilter/nf_queue.h>
|
| 21 | #include <net/dst.h>
|
| 22 |
|
| 23 | #include "nf_internals.h"
|
| 24 |
|
| 25 | static const struct nf_queue_handler __rcu *nf_queue_handler;
|
| 26 |
|
| 27 | |
| 28 | * Hook for nfnetlink_queue to register its queue handler.
|
| 29 | * We do this so that most of the NFQUEUE code can be modular.
|
| 30 | *
|
| 31 | * Once the queue is registered it must reinject all packets it
|
| 32 | * receives, no matter what.
|
| 33 |
|
| 34 |
|
| 35 | void nf_register_queue_handler(const struct nf_queue_handler *qh)
|
| 36 | {
|
| 37 |
|
| 38 | WARN_ON(rcu_access_pointer(nf_queue_handler));
|
| 39 | rcu_assign_pointer(nf_queue_handler, qh);
|
| 40 | }
|
| 41 | EXPORT_SYMBOL(nf_register_queue_handler);
|
| 42 |
|
| 43 |
|
| 44 | void nf_unregister_queue_handler(void)
|
| 45 | {
|
| 46 | RCU_INIT_POINTER(nf_queue_handler, NULL);
|
| 47 | }
|
| 48 | EXPORT_SYMBOL(nf_unregister_queue_handler);
|
| 49 |
|
| 50 | static void nf_queue_sock_put(struct sock *sk)
|
| 51 | {
|
| 52 | #ifdef CONFIG_INET
|
| 53 | sock_gen_put(sk);
|
| 54 | #else
|
| 55 | sock_put(sk);
|
| 56 | #endif
|
| 57 | }
|
| 58 |
|
| 59 | static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
|
| 60 | {
|
| 61 | struct nf_hook_state *state = &entry->state;
|
| 62 |
|
| 63 |
|
| 64 | dev_put(entry->skb_dev);
|
| 65 | dev_put(state->in);
|
| 66 | dev_put(state->out);
|
| 67 | if (state->sk)
|
| 68 | nf_queue_sock_put(state->sk);
|
| 69 |
|
| 70 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
| 71 | dev_put(entry->bridge_dev);
|
| 72 | dev_put(entry->physin);
|
| 73 | dev_put(entry->physout);
|
| 74 | #endif
|
| 75 | }
|
| 76 |
|
| 77 | void nf_queue_entry_free(struct nf_queue_entry *entry)
|
| 78 | {
|
| 79 | nf_queue_entry_release_refs(entry);
|
| 80 | kfree(entry);
|
| 81 | }
|
| 82 | EXPORT_SYMBOL_GPL(nf_queue_entry_free);
|
| 83 |
|
| 84 | static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
|
| 85 | {
|
| 86 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
| 87 | const struct sk_buff *skb = entry->skb;
|
| 88 | struct dst_entry *dst = skb_dst(skb);
|
| 89 | struct net_device *dev = NULL;
|
| 90 |
|
| 91 | if (nf_bridge_info_exists(skb)) {
|
| 92 | entry->physin = nf_bridge_get_physindev(skb, entry->state.net);
|
| 93 | entry->physout = nf_bridge_get_physoutdev(skb);
|
| 94 | } else {
|
| 95 | entry->physin = NULL;
|
| 96 | entry->physout = NULL;
|
| 97 | }
|
| 98 |
|
| 99 | if (entry->state.pf == NFPROTO_BRIDGE &&
|
| 100 | dst && (dst->flags & DST_FAKE_RTABLE))
|
| 101 | dev = dst_dev_rcu(dst);
|
| 102 |
|
| 103 | |
| 104 | * the dst itself, but the fake rtable is embedded in bridge-private
|
| 105 | * storage that netdevice teardown can free independently.
|
| 106 |
|
| 107 | entry->bridge_dev = dev;
|
| 108 | #endif
|
| 109 | }
|
| 110 |
|
| 111 |
|
| 112 | bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
|
| 113 | {
|
| 114 | struct nf_hook_state *state = &entry->state;
|
| 115 |
|
| 116 | if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
|
| 117 | return false;
|
| 118 |
|
| 119 | dev_hold(entry->skb_dev);
|
| 120 | dev_hold(state->in);
|
| 121 | dev_hold(state->out);
|
| 122 |
|
| 123 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
| 124 | dev_hold(entry->bridge_dev);
|
| 125 | dev_hold(entry->physin);
|
| 126 | dev_hold(entry->physout);
|
| 127 | #endif
|
| 128 | return true;
|
| 129 | }
|
| 130 | EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
|
| 131 |
|
| 132 | void nf_queue_nf_hook_drop(struct net *net)
|
| 133 | {
|
| 134 | const struct nf_queue_handler *qh;
|
| 135 |
|
| 136 | rcu_read_lock();
|
| 137 | qh = rcu_dereference(nf_queue_handler);
|
| 138 | if (qh)
|
| 139 | qh->nf_hook_drop(net);
|
| 140 | rcu_read_unlock();
|
| 141 | }
|
| 142 | EXPORT_SYMBOL_GPL(nf_queue_nf_hook_drop);
|
| 143 |
|
| 144 | static void nf_ip_saveroute(const struct sk_buff *skb,
|
| 145 | struct nf_queue_entry *entry)
|
| 146 | {
|
| 147 | struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
|
| 148 |
|
| 149 | if (entry->state.hook == NF_INET_LOCAL_OUT) {
|
| 150 | const struct iphdr *iph = ip_hdr(skb);
|
| 151 |
|
| 152 | rt_info->tos = iph->tos;
|
| 153 | rt_info->daddr = iph->daddr;
|
| 154 | rt_info->saddr = iph->saddr;
|
| 155 | rt_info->mark = skb->mark;
|
| 156 | }
|
| 157 | }
|
| 158 |
|
| 159 | static void nf_ip6_saveroute(const struct sk_buff *skb,
|
| 160 | struct nf_queue_entry *entry)
|
| 161 | {
|
| 162 | struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
|
| 163 |
|
| 164 | if (entry->state.hook == NF_INET_LOCAL_OUT) {
|
| 165 | const struct ipv6hdr *iph = ipv6_hdr(skb);
|
| 166 |
|
| 167 | rt_info->daddr = iph->daddr;
|
| 168 | rt_info->saddr = iph->saddr;
|
| 169 | rt_info->mark = skb->mark;
|
| 170 | }
|
| 171 | }
|
| 172 |
|
| 173 | static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
|
| 174 | unsigned int index, unsigned int queuenum)
|
| 175 | {
|
| 176 | struct nf_queue_entry *entry = NULL;
|
| 177 | const struct nf_queue_handler *qh;
|
| 178 | unsigned int route_key_size;
|
| 179 | int status;
|
| 180 |
|
| 181 |
|
| 182 | qh = rcu_dereference(nf_queue_handler);
|
| 183 | if (!qh)
|
| 184 | return -ESRCH;
|
| 185 |
|
| 186 | switch (state->pf) {
|
| 187 | case AF_INET:
|
| 188 | route_key_size = sizeof(struct ip_rt_info);
|
| 189 | break;
|
| 190 | case AF_INET6:
|
| 191 | route_key_size = sizeof(struct ip6_rt_info);
|
| 192 | break;
|
| 193 | default:
|
| 194 | route_key_size = 0;
|
| 195 | break;
|
| 196 | }
|
| 197 |
|
| 198 | if (skb_sk_is_prefetched(skb)) {
|
| 199 | struct sock *sk = skb->sk;
|
| 200 |
|
| 201 | if (!sk_is_refcounted(sk)) {
|
| 202 | if (!refcount_inc_not_zero(&sk->sk_refcnt))
|
| 203 | return -ENOTCONN;
|
| 204 |
|
| 205 |
|
| 206 | skb->destructor = sock_edemux;
|
| 207 | }
|
| 208 | }
|
| 209 |
|
| 210 | entry = kmalloc(sizeof(*entry) + route_key_size, GFP_ATOMIC);
|
| 211 | if (!entry)
|
| 212 | return -ENOMEM;
|
| 213 |
|
| 214 | if (skb_dst(skb) && !skb_dst_force(skb)) {
|
| 215 | kfree(entry);
|
| 216 | return -ENETDOWN;
|
| 217 | }
|
| 218 |
|
| 219 | *entry = (struct nf_queue_entry) {
|
| 220 | .skb = skb,
|
| 221 | .skb_dev = skb->dev,
|
| 222 | .state = *state,
|
| 223 | .hook_index = index,
|
| 224 | .size = sizeof(*entry) + route_key_size,
|
| 225 | };
|
| 226 | __nf_queue_entry_init_physdevs(entry);
|
| 227 |
|
| 228 | if (!nf_queue_entry_get_refs(entry)) {
|
| 229 | kfree(entry);
|
| 230 | return -ENOTCONN;
|
| 231 | }
|
| 232 |
|
| 233 | switch (entry->state.pf) {
|
| 234 | case AF_INET:
|
| 235 | nf_ip_saveroute(skb, entry);
|
| 236 | break;
|
| 237 | case AF_INET6:
|
| 238 | nf_ip6_saveroute(skb, entry);
|
| 239 | break;
|
| 240 | }
|
| 241 |
|
| 242 | status = qh->outfn(entry, queuenum);
|
| 243 | if (status < 0) {
|
| 244 | nf_queue_entry_free(entry);
|
| 245 | return status;
|
| 246 | }
|
| 247 |
|
| 248 | return 0;
|
| 249 | }
|
| 250 |
|
| 251 |
|
| 252 | int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
|
| 253 | unsigned int index, unsigned int verdict)
|
| 254 | {
|
| 255 | int ret;
|
| 256 |
|
| 257 | ret = __nf_queue(skb, state, index, verdict >> NF_VERDICT_QBITS);
|
| 258 | if (ret < 0) {
|
| 259 | if (ret == -ESRCH &&
|
| 260 | (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
|
| 261 | return 1;
|
| 262 | kfree_skb(skb);
|
| 263 | }
|
| 264 |
|
| 265 | return 0;
|
| 266 | }
|
| 267 | EXPORT_SYMBOL_GPL(nf_queue);
|