aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2005-08-09 22:50:45 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:38:01 -0400
commit838ab6364956d9bdcefe84712de1621cf20a40b3 (patch)
tree15f07f237723f682969fd63330097cef366e2aeb
parent32519f11d38ea8f4f60896763bacec7db1760f9c (diff)
[NETFILTER]: Add refcounting and /proc/net/netfilter interface to nfnetlink_queue
Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter/nfnetlink_queue.h1
-rw-r--r--net/netfilter/nfnetlink_queue.c248
2 files changed, 221 insertions, 28 deletions
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
index edb463a87eb4..e142b0ff7c08 100644
--- a/include/linux/netfilter/nfnetlink_queue.h
+++ b/include/linux/netfilter/nfnetlink_queue.h
@@ -81,5 +81,6 @@ enum nfqnl_attr_config {
81 NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ 81 NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */
82 __NFQA_CFG_MAX 82 __NFQA_CFG_MAX
83}; 83};
84#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
84 85
85#endif /* _NFNETLINK_QUEUE_H */ 86#endif /* _NFNETLINK_QUEUE_H */
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 24032610c425..eab309e3d42e 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -20,6 +20,7 @@
20#include <linux/notifier.h> 20#include <linux/notifier.h>
21#include <linux/netdevice.h> 21#include <linux/netdevice.h>
22#include <linux/netfilter.h> 22#include <linux/netfilter.h>
23#include <linux/proc_fs.h>
23#include <linux/netfilter_ipv4.h> 24#include <linux/netfilter_ipv4.h>
24#include <linux/netfilter_ipv6.h> 25#include <linux/netfilter_ipv6.h>
25#include <linux/netfilter/nfnetlink.h> 26#include <linux/netfilter/nfnetlink.h>
@@ -48,6 +49,7 @@ struct nfqnl_queue_entry {
48 49
49struct nfqnl_instance { 50struct nfqnl_instance {
50 struct hlist_node hlist; /* global list of queues */ 51 struct hlist_node hlist; /* global list of queues */
52 atomic_t use;
51 53
52 int peer_pid; 54 int peer_pid;
53 unsigned int queue_maxlen; 55 unsigned int queue_maxlen;
@@ -105,17 +107,28 @@ __instance_lookup(u_int16_t queue_num)
105} 107}
106 108
107static struct nfqnl_instance * 109static struct nfqnl_instance *
108instance_lookup(u_int16_t queue_num) 110instance_lookup_get(u_int16_t queue_num)
109{ 111{
110 struct nfqnl_instance *inst; 112 struct nfqnl_instance *inst;
111 113
112 read_lock_bh(&instances_lock); 114 read_lock_bh(&instances_lock);
113 inst = __instance_lookup(queue_num); 115 inst = __instance_lookup(queue_num);
116 if (inst)
117 atomic_inc(&inst->use);
114 read_unlock_bh(&instances_lock); 118 read_unlock_bh(&instances_lock);
115 119
116 return inst; 120 return inst;
117} 121}
118 122
123static void
124instance_put(struct nfqnl_instance *inst)
125{
126 if (inst && atomic_dec_and_test(&inst->use)) {
127 QDEBUG("kfree(inst=%p)\n", inst);
128 kfree(inst);
129 }
130}
131
119static struct nfqnl_instance * 132static struct nfqnl_instance *
120instance_create(u_int16_t queue_num, int pid) 133instance_create(u_int16_t queue_num, int pid)
121{ 134{
@@ -141,6 +154,8 @@ instance_create(u_int16_t queue_num, int pid)
141 inst->copy_range = 0xfffff; 154 inst->copy_range = 0xfffff;
142 inst->copy_mode = NFQNL_COPY_NONE; 155 inst->copy_mode = NFQNL_COPY_NONE;
143 atomic_set(&inst->id_sequence, 0); 156 atomic_set(&inst->id_sequence, 0);
157 /* needs to be two, since we _put() after creation */
158 atomic_set(&inst->use, 2);
144 inst->lock = SPIN_LOCK_UNLOCKED; 159 inst->lock = SPIN_LOCK_UNLOCKED;
145 INIT_LIST_HEAD(&inst->queue_list); 160 INIT_LIST_HEAD(&inst->queue_list);
146 161
@@ -182,8 +197,8 @@ _instance_destroy2(struct nfqnl_instance *inst, int lock)
182 /* then flush all pending skbs from the queue */ 197 /* then flush all pending skbs from the queue */
183 nfqnl_flush(inst, NF_DROP); 198 nfqnl_flush(inst, NF_DROP);
184 199
185 /* and finally free the data structure */ 200 /* and finally put the refcount */
186 kfree(inst); 201 instance_put(inst);
187 202
188 module_put(THIS_MODULE); 203 module_put(THIS_MODULE);
189} 204}
@@ -471,7 +486,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
471 486
472 QDEBUG("entered\n"); 487 QDEBUG("entered\n");
473 488
474 queue = instance_lookup(queuenum); 489 queue = instance_lookup_get(queuenum);
475 if (!queue) { 490 if (!queue) {
476 QDEBUG("no queue instance matching\n"); 491 QDEBUG("no queue instance matching\n");
477 return -EINVAL; 492 return -EINVAL;
@@ -479,7 +494,8 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
479 494
480 if (queue->copy_mode == NFQNL_COPY_NONE) { 495 if (queue->copy_mode == NFQNL_COPY_NONE) {
481 QDEBUG("mode COPY_NONE, aborting\n"); 496 QDEBUG("mode COPY_NONE, aborting\n");
482 return -EAGAIN; 497 status = -EAGAIN;
498 goto err_out_put;
483 } 499 }
484 500
485 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 501 entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
@@ -487,7 +503,8 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
487 if (net_ratelimit()) 503 if (net_ratelimit())
488 printk(KERN_ERR 504 printk(KERN_ERR
489 "nf_queue: OOM in nfqnl_enqueue_packet()\n"); 505 "nf_queue: OOM in nfqnl_enqueue_packet()\n");
490 return -ENOMEM; 506 status = -ENOMEM;
507 goto err_out_put;
491 } 508 }
492 509
493 entry->info = info; 510 entry->info = info;
@@ -523,6 +540,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
523 __enqueue_entry(queue, entry); 540 __enqueue_entry(queue, entry);
524 541
525 spin_unlock_bh(&queue->lock); 542 spin_unlock_bh(&queue->lock);
543 instance_put(queue);
526 return status; 544 return status;
527 545
528err_out_free_nskb: 546err_out_free_nskb:
@@ -533,6 +551,8 @@ err_out_unlock:
533 551
534err_out_free: 552err_out_free:
535 kfree(entry); 553 kfree(entry);
554err_out_put:
555 instance_put(queue);
536 return status; 556 return status;
537} 557}
538 558
@@ -685,6 +705,12 @@ static struct notifier_block nfqnl_rtnl_notifier = {
685 .notifier_call = nfqnl_rcv_nl_event, 705 .notifier_call = nfqnl_rcv_nl_event,
686}; 706};
687 707
708static const int nfqa_verdict_min[NFQA_MAX] = {
709 [NFQA_VERDICT_HDR-1] = sizeof(struct nfqnl_msg_verdict_hdr),
710 [NFQA_MARK-1] = sizeof(u_int32_t),
711 [NFQA_PAYLOAD-1] = 0,
712};
713
688static int 714static int
689nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, 715nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
690 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) 716 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
@@ -696,26 +722,40 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
696 struct nfqnl_instance *queue; 722 struct nfqnl_instance *queue;
697 unsigned int verdict; 723 unsigned int verdict;
698 struct nfqnl_queue_entry *entry; 724 struct nfqnl_queue_entry *entry;
725 int err;
699 726
700 queue = instance_lookup(queue_num); 727 if (nfattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) {
728 QDEBUG("bad attribute size\n");
729 return -EINVAL;
730 }
731
732 queue = instance_lookup_get(queue_num);
701 if (!queue) 733 if (!queue)
702 return -ENODEV; 734 return -ENODEV;
703 735
704 if (queue->peer_pid != NETLINK_CB(skb).pid) 736 if (queue->peer_pid != NETLINK_CB(skb).pid) {
705 return -EPERM; 737 err = -EPERM;
738 goto err_out_put;
739 }
706 740
707 if (!nfqa[NFQA_VERDICT_HDR-1]) 741 if (!nfqa[NFQA_VERDICT_HDR-1]) {
708 return -EINVAL; 742 err = -EINVAL;
743 goto err_out_put;
744 }
709 745
710 vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]); 746 vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]);
711 verdict = ntohl(vhdr->verdict); 747 verdict = ntohl(vhdr->verdict);
712 748
713 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) 749 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) {
714 return -EINVAL; 750 err = -EINVAL;
751 goto err_out_put;
752 }
715 753
716 entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id)); 754 entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id));
717 if (entry == NULL) 755 if (entry == NULL) {
718 return -ENOENT; 756 err = -ENOENT;
757 goto err_out_put;
758 }
719 759
720 if (nfqa[NFQA_PAYLOAD-1]) { 760 if (nfqa[NFQA_PAYLOAD-1]) {
721 if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]), 761 if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]),
@@ -727,7 +767,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
727 skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1])); 767 skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1]));
728 768
729 issue_verdict(entry, verdict); 769 issue_verdict(entry, verdict);
770 instance_put(queue);
730 return 0; 771 return 0;
772
773err_out_put:
774 instance_put(queue);
775 return err;
731} 776}
732 777
733static int 778static int
@@ -737,6 +782,11 @@ nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
737 return -ENOTSUPP; 782 return -ENOTSUPP;
738} 783}
739 784
785static const int nfqa_cfg_min[NFQA_CFG_MAX] = {
786 [NFQA_CFG_CMD-1] = sizeof(struct nfqnl_msg_config_cmd),
787 [NFQA_CFG_PARAMS-1] = sizeof(struct nfqnl_msg_config_params),
788};
789
740static int 790static int
741nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, 791nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
742 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) 792 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
@@ -744,10 +794,16 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
744 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); 794 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
745 u_int16_t queue_num = ntohs(nfmsg->res_id); 795 u_int16_t queue_num = ntohs(nfmsg->res_id);
746 struct nfqnl_instance *queue; 796 struct nfqnl_instance *queue;
797 int ret = 0;
747 798
748 QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); 799 QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type));
749 800
750 queue = instance_lookup(queue_num); 801 if (nfattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) {
802 QDEBUG("bad attribute size\n");
803 return -EINVAL;
804 }
805
806 queue = instance_lookup_get(queue_num);
751 if (nfqa[NFQA_CFG_CMD-1]) { 807 if (nfqa[NFQA_CFG_CMD-1]) {
752 struct nfqnl_msg_config_cmd *cmd; 808 struct nfqnl_msg_config_cmd *cmd;
753 cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]); 809 cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]);
@@ -766,17 +822,19 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
766 if (!queue) 822 if (!queue)
767 return -ENODEV; 823 return -ENODEV;
768 824
769 if (queue->peer_pid != NETLINK_CB(skb).pid) 825 if (queue->peer_pid != NETLINK_CB(skb).pid) {
770 return -EPERM; 826 ret = -EPERM;
827 goto out_put;
828 }
771 829
772 instance_destroy(queue); 830 instance_destroy(queue);
773 break; 831 break;
774 case NFQNL_CFG_CMD_PF_BIND: 832 case NFQNL_CFG_CMD_PF_BIND:
775 QDEBUG("registering queue handler for pf=%u\n", 833 QDEBUG("registering queue handler for pf=%u\n",
776 ntohs(cmd->pf)); 834 ntohs(cmd->pf));
777 return nf_register_queue_handler(ntohs(cmd->pf), 835 ret = nf_register_queue_handler(ntohs(cmd->pf),
778 nfqnl_enqueue_packet, 836 nfqnl_enqueue_packet,
779 NULL); 837 NULL);
780 838
781 break; 839 break;
782 case NFQNL_CFG_CMD_PF_UNBIND: 840 case NFQNL_CFG_CMD_PF_UNBIND:
@@ -784,20 +842,23 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
784 ntohs(cmd->pf)); 842 ntohs(cmd->pf));
785 /* This is a bug and a feature. We can unregister 843 /* This is a bug and a feature. We can unregister
786 * other handlers(!) */ 844 * other handlers(!) */
787 return nf_unregister_queue_handler(ntohs(cmd->pf)); 845 ret = nf_unregister_queue_handler(ntohs(cmd->pf));
788 break; 846 break;
789 default: 847 default:
790 return -EINVAL; 848 ret = -EINVAL;
849 break;
791 } 850 }
792 } else { 851 } else {
793 if (!queue) { 852 if (!queue) {
794 QDEBUG("no config command, and no instance ENOENT\n"); 853 QDEBUG("no config command, and no instance ENOENT\n");
795 return -ENOENT; 854 ret = -ENOENT;
855 goto out_put;
796 } 856 }
797 857
798 if (queue->peer_pid != NETLINK_CB(skb).pid) { 858 if (queue->peer_pid != NETLINK_CB(skb).pid) {
799 QDEBUG("no config command, and wrong pid\n"); 859 QDEBUG("no config command, and wrong pid\n");
800 return -EPERM; 860 ret = -EPERM;
861 goto out_put;
801 } 862 }
802 } 863 }
803 864
@@ -809,7 +870,9 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
809 ntohl(params->copy_range)); 870 ntohl(params->copy_range));
810 } 871 }
811 872
812 return 0; 873out_put:
874 instance_put(queue);
875 return ret;
813} 876}
814 877
815static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { 878static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
@@ -829,14 +892,132 @@ static struct nfnetlink_subsystem nfqnl_subsys = {
829 .cb = nfqnl_cb, 892 .cb = nfqnl_cb,
830}; 893};
831 894
895#ifdef CONFIG_PROC_FS
896struct iter_state {
897 unsigned int bucket;
898};
899
900static struct hlist_node *get_first(struct seq_file *seq)
901{
902 struct iter_state *st = seq->private;
903
904 if (!st)
905 return NULL;
906
907 for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
908 if (!hlist_empty(&instance_table[st->bucket]))
909 return instance_table[st->bucket].first;
910 }
911 return NULL;
912}
913
914static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
915{
916 struct iter_state *st = seq->private;
917
918 h = h->next;
919 while (!h) {
920 if (++st->bucket >= INSTANCE_BUCKETS)
921 return NULL;
922
923 h = instance_table[st->bucket].first;
924 }
925 return h;
926}
927
928static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
929{
930 struct hlist_node *head;
931 head = get_first(seq);
932
933 if (head)
934 while (pos && (head = get_next(seq, head)))
935 pos--;
936 return pos ? NULL : head;
937}
938
939static void *seq_start(struct seq_file *seq, loff_t *pos)
940{
941 read_lock_bh(&instances_lock);
942 return get_idx(seq, *pos);
943}
944
945static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
946{
947 (*pos)++;
948 return get_next(s, v);
949}
950
951static void seq_stop(struct seq_file *s, void *v)
952{
953 read_unlock_bh(&instances_lock);
954}
955
956static int seq_show(struct seq_file *s, void *v)
957{
958 const struct nfqnl_instance *inst = v;
959
960 return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
961 inst->queue_num,
962 inst->peer_pid, inst->queue_total,
963 inst->copy_mode, inst->copy_range,
964 inst->queue_dropped, inst->queue_user_dropped,
965 atomic_read(&inst->id_sequence),
966 atomic_read(&inst->use));
967}
968
969static struct seq_operations nfqnl_seq_ops = {
970 .start = seq_start,
971 .next = seq_next,
972 .stop = seq_stop,
973 .show = seq_show,
974};
975
976static int nfqnl_open(struct inode *inode, struct file *file)
977{
978 struct seq_file *seq;
979 struct iter_state *is;
980 int ret;
981
982 is = kmalloc(sizeof(*is), GFP_KERNEL);
983 if (!is)
984 return -ENOMEM;
985 memset(is, 0, sizeof(*is));
986 ret = seq_open(file, &nfqnl_seq_ops);
987 if (ret < 0)
988 goto out_free;
989 seq = file->private_data;
990 seq->private = is;
991 return ret;
992out_free:
993 kfree(is);
994 return ret;
995}
996
997static struct file_operations nfqnl_file_ops = {
998 .owner = THIS_MODULE,
999 .open = nfqnl_open,
1000 .read = seq_read,
1001 .llseek = seq_lseek,
1002 .release = seq_release_private,
1003};
1004
1005#endif /* PROC_FS */
1006
832static int 1007static int
833init_or_cleanup(int init) 1008init_or_cleanup(int init)
834{ 1009{
835 int status = -ENOMEM; 1010 int i, status = -ENOMEM;
1011#ifdef CONFIG_PROC_FS
1012 struct proc_dir_entry *proc_nfqueue;
1013#endif
836 1014
837 if (!init) 1015 if (!init)
838 goto cleanup; 1016 goto cleanup;
839 1017
1018 for (i = 0; i < INSTANCE_BUCKETS; i++)
1019 INIT_HLIST_HEAD(&instance_table[i]);
1020
840 netlink_register_notifier(&nfqnl_rtnl_notifier); 1021 netlink_register_notifier(&nfqnl_rtnl_notifier);
841 status = nfnetlink_subsys_register(&nfqnl_subsys); 1022 status = nfnetlink_subsys_register(&nfqnl_subsys);
842 if (status < 0) { 1023 if (status < 0) {
@@ -844,14 +1025,25 @@ init_or_cleanup(int init)
844 goto cleanup_netlink_notifier; 1025 goto cleanup_netlink_notifier;
845 } 1026 }
846 1027
1028#ifdef CONFIG_PROC_FS
1029 proc_nfqueue = create_proc_entry("nfnetlink_queue", 0440,
1030 proc_net_netfilter);
1031 if (!proc_nfqueue)
1032 goto cleanup_subsys;
1033 proc_nfqueue->proc_fops = &nfqnl_file_ops;
1034#endif
1035
847 register_netdevice_notifier(&nfqnl_dev_notifier); 1036 register_netdevice_notifier(&nfqnl_dev_notifier);
1037
848 return status; 1038 return status;
849 1039
850cleanup: 1040cleanup:
851 nf_unregister_queue_handlers(nfqnl_enqueue_packet); 1041 nf_unregister_queue_handlers(nfqnl_enqueue_packet);
852 unregister_netdevice_notifier(&nfqnl_dev_notifier); 1042 unregister_netdevice_notifier(&nfqnl_dev_notifier);
1043#ifdef CONFIG_PROC_FS
1044cleanup_subsys:
1045#endif
853 nfnetlink_subsys_unregister(&nfqnl_subsys); 1046 nfnetlink_subsys_unregister(&nfqnl_subsys);
854
855cleanup_netlink_notifier: 1047cleanup_netlink_notifier:
856 netlink_unregister_notifier(&nfqnl_rtnl_notifier); 1048 netlink_unregister_notifier(&nfqnl_rtnl_notifier);
857 return status; 1049 return status;