📄 ip_queue.c
字号:
} if (!skb_make_writable(e->skb, v->data_len)) return -ENOMEM; skb_copy_to_linear_data(e->skb, v->payload, v->data_len); e->skb->ip_summed = CHECKSUM_NONE; return 0;}static inline intid_cmp(struct ipq_queue_entry *e, unsigned long id){ return (id == (unsigned long )e);}static intipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len){ struct ipq_queue_entry *entry; if (vmsg->value > NF_MAX_VERDICT) return -EINVAL; entry = ipq_find_dequeue_entry(id_cmp, vmsg->id); if (entry == NULL) return -ENOENT; else { int verdict = vmsg->value; if (vmsg->data_len && vmsg->data_len == len) if (ipq_mangle_ipv4(vmsg, entry) < 0) verdict = NF_DROP; ipq_issue_verdict(entry, verdict); return 0; }}static intipq_set_mode(unsigned char mode, unsigned int range){ int status; write_lock_bh(&queue_lock); status = __ipq_set_mode(mode, range); write_unlock_bh(&queue_lock); return status;}static intipq_receive_peer(struct ipq_peer_msg *pmsg, unsigned char type, unsigned int len){ int status = 0; if (len < sizeof(*pmsg)) return -EINVAL; switch (type) { case IPQM_MODE: status = ipq_set_mode(pmsg->msg.mode.value, pmsg->msg.mode.range); break; case IPQM_VERDICT: if (pmsg->msg.verdict.value > NF_MAX_VERDICT) status = -EINVAL; else status = ipq_set_verdict(&pmsg->msg.verdict, len - sizeof(*pmsg)); break; default: status = -EINVAL; } return status;}static intdev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex){ if (entry->info->indev) if (entry->info->indev->ifindex == ifindex) return 1; if (entry->info->outdev) if (entry->info->outdev->ifindex == ifindex) return 1;#ifdef CONFIG_BRIDGE_NETFILTER if (entry->skb->nf_bridge) { if (entry->skb->nf_bridge->physindev && entry->skb->nf_bridge->physindev->ifindex == ifindex) return 1; if (entry->skb->nf_bridge->physoutdev && entry->skb->nf_bridge->physoutdev->ifindex == ifindex) return 1; }#endif return 0;}static voidipq_dev_drop(int ifindex){ struct ipq_queue_entry *entry; while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL) ipq_issue_verdict(entry, NF_DROP);}#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)static inline void__ipq_rcv_skb(struct sk_buff *skb){ int status, type, pid, flags, nlmsglen, skblen; struct nlmsghdr *nlh; skblen = skb->len; if (skblen < sizeof(*nlh)) return; nlh = nlmsg_hdr(skb); nlmsglen = nlh->nlmsg_len; if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen) return; pid = nlh->nlmsg_pid; flags = nlh->nlmsg_flags; if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI) RCV_SKB_FAIL(-EINVAL); if (flags & MSG_TRUNC) RCV_SKB_FAIL(-ECOMM); type = nlh->nlmsg_type; if (type < NLMSG_NOOP || type >= IPQM_MAX) RCV_SKB_FAIL(-EINVAL); if (type <= IPQM_BASE) return; if (security_netlink_recv(skb, CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); write_lock_bh(&queue_lock); if (peer_pid) { if (peer_pid != pid) { write_unlock_bh(&queue_lock); RCV_SKB_FAIL(-EBUSY); } } else { net_enable_timestamp(); peer_pid = pid; } write_unlock_bh(&queue_lock); status = ipq_receive_peer(NLMSG_DATA(nlh), type, nlmsglen - NLMSG_LENGTH(0)); if (status < 0) RCV_SKB_FAIL(status); if (flags & NLM_F_ACK) netlink_ack(skb, nlh, 0); return;}static voidipq_rcv_skb(struct sk_buff *skb){ mutex_lock(&ipqnl_mutex); __ipq_rcv_skb(skb); mutex_unlock(&ipqnl_mutex);}static intipq_rcv_dev_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; if (dev->nd_net != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) ipq_dev_drop(dev->ifindex); return NOTIFY_DONE;}static struct notifier_block ipq_dev_notifier = { .notifier_call = ipq_rcv_dev_event,};static intipq_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr){ struct netlink_notify *n = ptr; if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL && n->pid) { write_lock_bh(&queue_lock); if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } return NOTIFY_DONE;}static struct notifier_block ipq_nl_notifier = { .notifier_call = ipq_rcv_nl_event,};static struct ctl_table_header *ipq_sysctl_header;static ctl_table ipq_table[] = { { .ctl_name = NET_IPQ_QMAX, .procname = NET_IPQ_QMAX_NAME, .data = &queue_maxlen, .maxlen = sizeof(queue_maxlen), .mode = 0644, .proc_handler = proc_dointvec }, { .ctl_name = 0 }};static ctl_table ipq_dir_table[] = { { .ctl_name = NET_IPV4, .procname = "ipv4", .mode = 0555, .child = ipq_table }, { .ctl_name = 0 }};static ctl_table ipq_root_table[] = { { .ctl_name = CTL_NET, .procname = "net", .mode = 0555, .child = ipq_dir_table }, { .ctl_name = 0 }};static int ip_queue_show(struct seq_file *m, void *v){ read_lock_bh(&queue_lock); seq_printf(m, "Peer PID : %d\n" "Copy mode : %hu\n" "Copy range : %u\n" "Queue length : %u\n" "Queue max. length : %u\n" "Queue dropped : %u\n" "Netlink dropped : %u\n", peer_pid, copy_mode, copy_range, queue_total, queue_maxlen, queue_dropped, queue_user_dropped); read_unlock_bh(&queue_lock); return 0;}static int ip_queue_open(struct inode *inode, struct file *file){ return single_open(file, ip_queue_show, NULL);}static const struct file_operations ip_queue_proc_fops = { .open = ip_queue_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE,};static struct nf_queue_handler nfqh = { .name = "ip_queue", .outfn = &ipq_enqueue_packet,};static int __init ip_queue_init(void){ int status = -ENOMEM; struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, ipq_rcv_skb, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; } proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net); if (proc) { proc->owner = THIS_MODULE; proc->proc_fops = &ip_queue_proc_fops; } else { printk(KERN_ERR "ip_queue: failed to create proc entry\n"); goto cleanup_ipqnl; } register_netdevice_notifier(&ipq_dev_notifier); ipq_sysctl_header = register_sysctl_table(ipq_root_table); status = nf_register_queue_handler(PF_INET, &nfqh); if (status < 0) { printk(KERN_ERR "ip_queue: failed to register queue handler\n"); goto cleanup_sysctl; } return status;cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); proc_net_remove(&init_net, IPQ_PROC_FS_NAME);cleanup_ipqnl: sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); mutex_unlock(&ipqnl_mutex);cleanup_netlink_notifier: netlink_unregister_notifier(&ipq_nl_notifier); return status;}static void __exit ip_queue_fini(void){ nf_unregister_queue_handlers(&nfqh); synchronize_net(); ipq_flush(NF_DROP); unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); proc_net_remove(&init_net, IPQ_PROC_FS_NAME); sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); mutex_unlock(&ipqnl_mutex); netlink_unregister_notifier(&ipq_nl_notifier);}MODULE_DESCRIPTION("IPv4 packet queue handler");MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");MODULE_LICENSE("GPL");module_init(ip_queue_init);module_exit(ip_queue_fini);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -