xref: /openbmc/linux/net/netfilter/xt_osf.c (revision d623f60d)
1 /*
2  * Copyright (c) 2003+ Evgeniy Polyakov <zbr@ioremap.net>
3  *
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 
22 #include <linux/capability.h>
23 #include <linux/if.h>
24 #include <linux/inetdevice.h>
25 #include <linux/ip.h>
26 #include <linux/list.h>
27 #include <linux/rculist.h>
28 #include <linux/skbuff.h>
29 #include <linux/slab.h>
30 #include <linux/tcp.h>
31 
32 #include <net/ip.h>
33 #include <net/tcp.h>
34 
35 #include <linux/netfilter/nfnetlink.h>
36 #include <linux/netfilter/x_tables.h>
37 #include <net/netfilter/nf_log.h>
38 #include <linux/netfilter/xt_osf.h>
39 
40 /*
41  * Indexed by dont-fragment bit.
42  * It is the only constant value in the fingerprint.
43  */
44 static struct list_head xt_osf_fingers[2];
45 
46 static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
47 	[OSF_ATTR_FINGER]	= { .len = sizeof(struct xt_osf_user_finger) },
48 };
49 
50 static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
51 			       struct sk_buff *skb, const struct nlmsghdr *nlh,
52 			       const struct nlattr * const osf_attrs[],
53 			       struct netlink_ext_ack *extack)
54 {
55 	struct xt_osf_user_finger *f;
56 	struct xt_osf_finger *kf = NULL, *sf;
57 	int err = 0;
58 
59 	if (!capable(CAP_NET_ADMIN))
60 		return -EPERM;
61 
62 	if (!osf_attrs[OSF_ATTR_FINGER])
63 		return -EINVAL;
64 
65 	if (!(nlh->nlmsg_flags & NLM_F_CREATE))
66 		return -EINVAL;
67 
68 	f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
69 
70 	kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
71 	if (!kf)
72 		return -ENOMEM;
73 
74 	memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
75 
76 	list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
77 		if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
78 			continue;
79 
80 		kfree(kf);
81 		kf = NULL;
82 
83 		if (nlh->nlmsg_flags & NLM_F_EXCL)
84 			err = -EEXIST;
85 		break;
86 	}
87 
88 	/*
89 	 * We are protected by nfnl mutex.
90 	 */
91 	if (kf)
92 		list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
93 
94 	return err;
95 }
96 
97 static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
98 				  struct sk_buff *skb,
99 				  const struct nlmsghdr *nlh,
100 				  const struct nlattr * const osf_attrs[],
101 				  struct netlink_ext_ack *extack)
102 {
103 	struct xt_osf_user_finger *f;
104 	struct xt_osf_finger *sf;
105 	int err = -ENOENT;
106 
107 	if (!capable(CAP_NET_ADMIN))
108 		return -EPERM;
109 
110 	if (!osf_attrs[OSF_ATTR_FINGER])
111 		return -EINVAL;
112 
113 	f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
114 
115 	list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
116 		if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
117 			continue;
118 
119 		/*
120 		 * We are protected by nfnl mutex.
121 		 */
122 		list_del_rcu(&sf->finger_entry);
123 		kfree_rcu(sf, rcu_head);
124 
125 		err = 0;
126 		break;
127 	}
128 
129 	return err;
130 }
131 
132 static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
133 	[OSF_MSG_ADD]	= {
134 		.call		= xt_osf_add_callback,
135 		.attr_count	= OSF_ATTR_MAX,
136 		.policy		= xt_osf_policy,
137 	},
138 	[OSF_MSG_REMOVE]	= {
139 		.call		= xt_osf_remove_callback,
140 		.attr_count	= OSF_ATTR_MAX,
141 		.policy		= xt_osf_policy,
142 	},
143 };
144 
145 static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
146 	.name			= "osf",
147 	.subsys_id		= NFNL_SUBSYS_OSF,
148 	.cb_count		= OSF_MSG_MAX,
149 	.cb			= xt_osf_nfnetlink_callbacks,
150 };
151 
152 static bool
153 xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
154 {
155 	const struct xt_osf_info *info = p->matchinfo;
156 	struct net *net = xt_net(p);
157 
158 	if (!info)
159 		return false;
160 
161 	return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p),
162 			    xt_out(p), info, net, xt_osf_fingers);
163 }
164 
165 static struct xt_match xt_osf_match = {
166 	.name 		= "osf",
167 	.revision	= 0,
168 	.family		= NFPROTO_IPV4,
169 	.proto		= IPPROTO_TCP,
170 	.hooks      	= (1 << NF_INET_LOCAL_IN) |
171 				(1 << NF_INET_PRE_ROUTING) |
172 				(1 << NF_INET_FORWARD),
173 	.match 		= xt_osf_match_packet,
174 	.matchsize	= sizeof(struct xt_osf_info),
175 	.me		= THIS_MODULE,
176 };
177 
178 static int __init xt_osf_init(void)
179 {
180 	int err = -EINVAL;
181 	int i;
182 
183 	for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
184 		INIT_LIST_HEAD(&xt_osf_fingers[i]);
185 
186 	err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
187 	if (err < 0) {
188 		pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
189 		goto err_out_exit;
190 	}
191 
192 	err = xt_register_match(&xt_osf_match);
193 	if (err) {
194 		pr_err("Failed to register OS fingerprint "
195 		       "matching module (%d)\n", err);
196 		goto err_out_remove;
197 	}
198 
199 	return 0;
200 
201 err_out_remove:
202 	nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
203 err_out_exit:
204 	return err;
205 }
206 
207 static void __exit xt_osf_fini(void)
208 {
209 	struct xt_osf_finger *f;
210 	int i;
211 
212 	nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
213 	xt_unregister_match(&xt_osf_match);
214 
215 	rcu_read_lock();
216 	for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
217 
218 		list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
219 			list_del_rcu(&f->finger_entry);
220 			kfree_rcu(f, rcu_head);
221 		}
222 	}
223 	rcu_read_unlock();
224 
225 	rcu_barrier();
226 }
227 
228 module_init(xt_osf_init);
229 module_exit(xt_osf_fini);
230 
231 MODULE_LICENSE("GPL");
232 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
233 MODULE_DESCRIPTION("Passive OS fingerprint matching.");
234 MODULE_ALIAS("ipt_osf");
235 MODULE_ALIAS("ip6t_osf");
236 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
237