2 * Copyright (c) 2003+ Evgeniy Polyakov <zbr@ioremap.net>
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.
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.
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/>.
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/module.h>
20 #include <linux/kernel.h>
22 #include <linux/capability.h>
24 #include <linux/inetdevice.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>
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>
41 * Indexed by dont-fragment bit.
42 * It is the only constant value in the fingerprint.
44 static struct list_head xt_osf_fingers[2];
46 static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
47 [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) },
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)
55 struct xt_osf_user_finger *f;
56 struct xt_osf_finger *kf = NULL, *sf;
59 if (!capable(CAP_NET_ADMIN))
62 if (!osf_attrs[OSF_ATTR_FINGER])
65 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
68 f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
70 kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
74 memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
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)))
83 if (nlh->nlmsg_flags & NLM_F_EXCL)
89 * We are protected by nfnl mutex.
92 list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
97 static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
99 const struct nlmsghdr *nlh,
100 const struct nlattr * const osf_attrs[],
101 struct netlink_ext_ack *extack)
103 struct xt_osf_user_finger *f;
104 struct xt_osf_finger *sf;
107 if (!capable(CAP_NET_ADMIN))
110 if (!osf_attrs[OSF_ATTR_FINGER])
113 f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
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)))
120 * We are protected by nfnl mutex.
122 list_del_rcu(&sf->finger_entry);
123 kfree_rcu(sf, rcu_head);
132 static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
134 .call = xt_osf_add_callback,
135 .attr_count = OSF_ATTR_MAX,
136 .policy = xt_osf_policy,
139 .call = xt_osf_remove_callback,
140 .attr_count = OSF_ATTR_MAX,
141 .policy = xt_osf_policy,
145 static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
147 .subsys_id = NFNL_SUBSYS_OSF,
148 .cb_count = OSF_MSG_MAX,
149 .cb = xt_osf_nfnetlink_callbacks,
153 xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
155 const struct xt_osf_info *info = p->matchinfo;
156 struct net *net = xt_net(p);
161 return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p),
162 xt_out(p), info, net, xt_osf_fingers);
165 static struct xt_match xt_osf_match = {
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),
178 static int __init xt_osf_init(void)
183 for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
184 INIT_LIST_HEAD(&xt_osf_fingers[i]);
186 err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
188 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
192 err = xt_register_match(&xt_osf_match);
194 pr_err("Failed to register OS fingerprint "
195 "matching module (%d)\n", err);
202 nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
207 static void __exit xt_osf_fini(void)
209 struct xt_osf_finger *f;
212 nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
213 xt_unregister_match(&xt_osf_match);
216 for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
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);
228 module_init(xt_osf_init);
229 module_exit(xt_osf_fini);
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);