📄 netfilter.c
字号:
if (ops->cleanup_task) wake_up_process(ops->cleanup_task); up(&nf_sockopt_mutex); return ret;}int nf_setsockopt(struct sock *sk, int pf, int val, char *opt, int len){ return nf_sockopt(sk, pf, val, opt, &len, 0);}int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len){ return nf_sockopt(sk, pf, val, opt, len, 1);}static unsigned int nf_iterate(struct list_head *head, struct sk_buff **skb, int hook, const struct net_device *indev, const struct net_device *outdev, struct list_head **i, int (*okfn)(struct sk_buff *)){ for (*i = (*i)->next; *i != head; *i = (*i)->next) { struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; switch (elem->hook(hook, skb, indev, outdev, okfn)) { case NF_QUEUE: return NF_QUEUE; case NF_STOLEN: return NF_STOLEN; case NF_DROP: return NF_DROP; case NF_REPEAT: *i = (*i)->prev; break;#ifdef CONFIG_NETFILTER_DEBUG case NF_ACCEPT: break; default: NFDEBUG("Evil return from %p(%u).\n", elem->hook, hook);#endif } } return NF_ACCEPT;}int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data){ int ret; br_write_lock_bh(BR_NETPROTO_LOCK); if (queue_handler[pf].outfn) ret = -EBUSY; else { queue_handler[pf].outfn = outfn; queue_handler[pf].data = data; ret = 0; } br_write_unlock_bh(BR_NETPROTO_LOCK); return ret;}/* The caller must flush their queue before this */int nf_unregister_queue_handler(int pf){ br_write_lock_bh(BR_NETPROTO_LOCK); queue_handler[pf].outfn = NULL; queue_handler[pf].data = NULL; br_write_unlock_bh(BR_NETPROTO_LOCK); return 0;}/* * Any packet that leaves via this function must come back * through nf_reinject(). */static void nf_queue(struct sk_buff *skb, struct list_head *elem, int pf, unsigned int hook, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *)){ int status; struct nf_info *info; if (!queue_handler[pf].outfn) { kfree_skb(skb); return; } info = kmalloc(sizeof(*info), GFP_ATOMIC); if (!info) { if (net_ratelimit()) printk(KERN_ERR "OOM queueing packet %p\n", skb); kfree_skb(skb); return; } *info = (struct nf_info) { (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn }; /* Bump dev refs so they don't vanish while packet is out */ if (indev) dev_hold(indev); if (outdev) dev_hold(outdev); status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data); if (status < 0) { /* James M doesn't say fuck enough. */ if (indev) dev_put(indev); if (outdev) dev_put(outdev); kfree(info); kfree_skb(skb); return; }}int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *)){ struct list_head *elem; unsigned int verdict; int ret = 0; /* This stopgap cannot be removed until all the hooks are audited. */ if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { kfree_skb(skb); return -ENOMEM; } if (skb->ip_summed == CHECKSUM_HW) { if (outdev == NULL) { skb->ip_summed = CHECKSUM_NONE; } else { skb_checksum_help(skb); } } /* We may already have this, but read-locks nest anyway */ br_read_lock_bh(BR_NETPROTO_LOCK);#ifdef CONFIG_NETFILTER_DEBUG if (skb->nf_debug & (1 << hook)) { printk("nf_hook: hook %i already set.\n", hook); nf_dump_skb(pf, skb); } skb->nf_debug |= (1 << hook);#endif elem = &nf_hooks[pf][hook]; verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, outdev, &elem, okfn); if (verdict == NF_QUEUE) { NFDEBUG("nf_hook: Verdict = QUEUE.\n"); nf_queue(skb, elem, pf, hook, indev, outdev, okfn); } switch (verdict) { case NF_ACCEPT: ret = okfn(skb); break; case NF_DROP: kfree_skb(skb); ret = -EPERM; break; } br_read_unlock_bh(BR_NETPROTO_LOCK); return ret;}void nf_reinject(struct sk_buff *skb, struct nf_info *info, unsigned int verdict){ struct list_head *elem = &info->elem->list; struct list_head *i; /* We don't have BR_NETPROTO_LOCK here */ br_read_lock_bh(BR_NETPROTO_LOCK); for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) { if (i == &nf_hooks[info->pf][info->hook]) { /* The module which sent it to userspace is gone. */ NFDEBUG("%s: module disappeared, dropping packet.\n", __FUNCTION__); verdict = NF_DROP; break; } } /* Continue traversal iff userspace said ok... */ if (verdict == NF_REPEAT) { elem = elem->prev; verdict = NF_ACCEPT; } if (verdict == NF_ACCEPT) { verdict = nf_iterate(&nf_hooks[info->pf][info->hook], &skb, info->hook, info->indev, info->outdev, &elem, info->okfn); } switch (verdict) { case NF_ACCEPT: info->okfn(skb); break; case NF_QUEUE: nf_queue(skb, elem, info->pf, info->hook, info->indev, info->outdev, info->okfn); break; case NF_DROP: kfree_skb(skb); break; } br_read_unlock_bh(BR_NETPROTO_LOCK); /* Release those devices we held, or Alexey will kill me. */ if (info->indev) dev_put(info->indev); if (info->outdev) dev_put(info->outdev); kfree(info); return;}#ifdef CONFIG_INET/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */int ip_route_me_harder(struct sk_buff **pskb){ struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt; struct rt_key key = { dst:iph->daddr, src:iph->saddr, oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, tos:RT_TOS(iph->tos)|RTO_CONN,#ifdef CONFIG_IP_ROUTE_FWMARK fwmark:(*pskb)->nfmark#endif }; struct net_device *dev_src = NULL; int err; /* accomodate ip_route_output_slow(), which expects the key src to be 0 or a local address; however some non-standard hacks like ipt_REJECT.c:send_reset() can cause packets with foreign saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ if(key.src && !(dev_src = ip_dev_find(key.src))) key.src = 0; if ((err=ip_route_output_key(&rt, &key)) != 0) { printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, RT_TOS(iph->tos)|RTO_CONN,#ifdef CONFIG_IP_ROUTE_FWMARK (*pskb)->nfmark,#else 0UL,#endif err); goto out; } /* Drop old route. */ dst_release((*pskb)->dst); (*pskb)->dst = &rt->u.dst; /* Change in oif may mean change in hh_len. */ if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { struct sk_buff *nskb; nskb = skb_realloc_headroom(*pskb, (*pskb)->dst->dev->hard_header_len); if (!nskb) { err = -ENOMEM; goto out; } if ((*pskb)->sk) skb_set_owner_w(nskb, (*pskb)->sk); kfree_skb(*pskb); *pskb = nskb; }out: if (dev_src) dev_put(dev_src); return err;}#endif /*CONFIG_INET*//* This does not belong here, but ipt_REJECT needs it if connection tracking in use: without this, connection may not be in hash table, and hence manufactured ICMP or RST packets will not be associated with it. */void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);void __init netfilter_init(void){ int i, h; for (i = 0; i < NPROTO; i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -