1 // SPDX-License-Identifier: GPL-2.0-only
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #include <linux/module.h>
4 #include <linux/kernel.h>
6 #include <linux/capability.h>
8 #include <linux/inetdevice.h>
10 #include <linux/list.h>
11 #include <linux/rculist.h>
12 #include <linux/skbuff.h>
13 #include <linux/slab.h>
14 #include <linux/tcp.h>
19 #include <linux/netfilter/nfnetlink.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <net/netfilter/nf_log.h>
22 #include <linux/netfilter/nfnetlink_osf.h>
25 * Indexed by dont-fragment bit.
26 * It is the only constant value in the fingerprint.
28 struct list_head nf_osf_fingers
[2];
29 EXPORT_SYMBOL_GPL(nf_osf_fingers
);
31 static inline int nf_osf_ttl(const struct sk_buff
*skb
,
32 int ttl_check
, unsigned char f_ttl
)
34 struct in_device
*in_dev
= __in_dev_get_rcu(skb
->dev
);
35 const struct iphdr
*ip
= ip_hdr(skb
);
38 if (ttl_check
== NF_OSF_TTL_TRUE
)
39 return ip
->ttl
== f_ttl
;
40 if (ttl_check
== NF_OSF_TTL_NOCHECK
)
42 else if (ip
->ttl
<= f_ttl
)
46 if (inet_ifa_match(ip
->saddr
, ifa
)) {
47 ret
= (ip
->ttl
== f_ttl
);
57 struct nf_osf_hdr_ctx
{
61 const unsigned char *optp
;
65 static bool nf_osf_match_one(const struct sk_buff
*skb
,
66 const struct nf_osf_user_finger
*f
,
68 struct nf_osf_hdr_ctx
*ctx
)
70 const __u8
*optpinit
= ctx
->optp
;
71 unsigned int check_WSS
= 0;
72 int fmatch
= FMATCH_WRONG
;
76 if (ctx
->totlen
!= f
->ss
|| !nf_osf_ttl(skb
, ttl_check
, f
->ttl
))
80 * Should not happen if userspace parser was written correctly.
82 if (f
->wss
.wc
>= OSF_WSS_MAX
)
88 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
)
89 foptsize
+= f
->opt
[optnum
].length
;
91 if (foptsize
> MAX_IPOPTLEN
||
92 ctx
->optsize
> MAX_IPOPTLEN
||
93 ctx
->optsize
!= foptsize
)
96 check_WSS
= f
->wss
.wc
;
98 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
) {
99 if (f
->opt
[optnum
].kind
== *ctx
->optp
) {
100 __u32 len
= f
->opt
[optnum
].length
;
101 const __u8
*optend
= ctx
->optp
+ len
;
105 switch (*ctx
->optp
) {
111 mss
= ntohs((__force __be16
)mss
);
119 fmatch
= FMATCH_OPT_WRONG
;
121 if (fmatch
!= FMATCH_OK
)
125 if (fmatch
!= FMATCH_OPT_WRONG
) {
126 fmatch
= FMATCH_WRONG
;
130 if (f
->wss
.val
== 0 || ctx
->window
== f
->wss
.val
)
135 * Some smart modems decrease mangle MSS to
136 * SMART_MSS_2, so we check standard, decreased
137 * and the one provided in the fingerprint MSS
140 #define SMART_MSS_1 1460
141 #define SMART_MSS_2 1448
142 if (ctx
->window
== f
->wss
.val
* mss
||
143 ctx
->window
== f
->wss
.val
* SMART_MSS_1
||
144 ctx
->window
== f
->wss
.val
* SMART_MSS_2
)
148 if (ctx
->window
== f
->wss
.val
* (mss
+ 40) ||
149 ctx
->window
== f
->wss
.val
* (SMART_MSS_1
+ 40) ||
150 ctx
->window
== f
->wss
.val
* (SMART_MSS_2
+ 40))
154 if ((ctx
->window
% f
->wss
.val
) == 0)
160 if (fmatch
!= FMATCH_OK
)
161 ctx
->optp
= optpinit
;
163 return fmatch
== FMATCH_OK
;
166 static const struct tcphdr
*nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx
*ctx
,
167 const struct sk_buff
*skb
,
168 const struct iphdr
*ip
,
171 const struct tcphdr
*tcp
;
174 tcp
= skb_header_pointer(skb
, ip_hdrlen(skb
), sizeof(struct tcphdr
), &_tcph
);
181 ctx
->totlen
= ntohs(ip
->tot_len
);
182 ctx
->df
= ntohs(ip
->frag_off
) & IP_DF
;
183 ctx
->window
= ntohs(tcp
->window
);
185 if (tcp
->doff
* 4 > sizeof(struct tcphdr
)) {
186 ctx
->optsize
= tcp
->doff
* 4 - sizeof(struct tcphdr
);
188 ctx
->optp
= skb_header_pointer(skb
, ip_hdrlen(skb
) +
189 sizeof(struct tcphdr
), ctx
->optsize
, opts
);
196 nf_osf_match(const struct sk_buff
*skb
, u_int8_t family
,
197 int hooknum
, struct net_device
*in
, struct net_device
*out
,
198 const struct nf_osf_info
*info
, struct net
*net
,
199 const struct list_head
*nf_osf_fingers
)
201 const struct iphdr
*ip
= ip_hdr(skb
);
202 const struct nf_osf_user_finger
*f
;
203 unsigned char opts
[MAX_IPOPTLEN
];
204 const struct nf_osf_finger
*kf
;
205 int fcount
= 0, ttl_check
;
206 int fmatch
= FMATCH_WRONG
;
207 struct nf_osf_hdr_ctx ctx
;
208 const struct tcphdr
*tcp
;
210 memset(&ctx
, 0, sizeof(ctx
));
212 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
);
216 ttl_check
= (info
->flags
& NF_OSF_TTL
) ? info
->ttl
: 0;
218 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
222 if (!(info
->flags
& NF_OSF_LOG
) && strcmp(info
->genre
, f
->genre
))
225 if (!nf_osf_match_one(skb
, f
, ttl_check
, &ctx
))
232 if (info
->flags
& NF_OSF_LOG
)
233 nf_log_packet(net
, family
, hooknum
, skb
,
235 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
236 f
->genre
, f
->version
, f
->subtype
,
237 &ip
->saddr
, ntohs(tcp
->source
),
238 &ip
->daddr
, ntohs(tcp
->dest
),
241 if ((info
->flags
& NF_OSF_LOG
) &&
242 info
->loglevel
== NF_OSF_LOGLEVEL_FIRST
)
246 if (!fcount
&& (info
->flags
& NF_OSF_LOG
))
247 nf_log_packet(net
, family
, hooknum
, skb
, in
, out
, NULL
,
248 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
249 &ip
->saddr
, ntohs(tcp
->source
),
250 &ip
->daddr
, ntohs(tcp
->dest
));
255 return fmatch
== FMATCH_OK
;
257 EXPORT_SYMBOL_GPL(nf_osf_match
);
259 bool nf_osf_find(const struct sk_buff
*skb
,
260 const struct list_head
*nf_osf_fingers
,
261 const int ttl_check
, struct nf_osf_data
*data
)
263 const struct iphdr
*ip
= ip_hdr(skb
);
264 const struct nf_osf_user_finger
*f
;
265 unsigned char opts
[MAX_IPOPTLEN
];
266 const struct nf_osf_finger
*kf
;
267 struct nf_osf_hdr_ctx ctx
;
268 const struct tcphdr
*tcp
;
270 memset(&ctx
, 0, sizeof(ctx
));
272 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
);
276 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
278 if (!nf_osf_match_one(skb
, f
, ttl_check
, &ctx
))
281 data
->genre
= f
->genre
;
282 data
->version
= f
->version
;
288 EXPORT_SYMBOL_GPL(nf_osf_find
);
290 static const struct nla_policy nfnl_osf_policy
[OSF_ATTR_MAX
+ 1] = {
291 [OSF_ATTR_FINGER
] = { .len
= sizeof(struct nf_osf_user_finger
) },
294 static int nfnl_osf_add_callback(struct net
*net
, struct sock
*ctnl
,
295 struct sk_buff
*skb
, const struct nlmsghdr
*nlh
,
296 const struct nlattr
* const osf_attrs
[],
297 struct netlink_ext_ack
*extack
)
299 struct nf_osf_user_finger
*f
;
300 struct nf_osf_finger
*kf
= NULL
, *sf
;
303 if (!capable(CAP_NET_ADMIN
))
306 if (!osf_attrs
[OSF_ATTR_FINGER
])
309 if (!(nlh
->nlmsg_flags
& NLM_F_CREATE
))
312 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
314 kf
= kmalloc(sizeof(struct nf_osf_finger
), GFP_KERNEL
);
318 memcpy(&kf
->finger
, f
, sizeof(struct nf_osf_user_finger
));
320 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
321 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
327 if (nlh
->nlmsg_flags
& NLM_F_EXCL
)
333 * We are protected by nfnl mutex.
336 list_add_tail_rcu(&kf
->finger_entry
, &nf_osf_fingers
[!!f
->df
]);
341 static int nfnl_osf_remove_callback(struct net
*net
, struct sock
*ctnl
,
343 const struct nlmsghdr
*nlh
,
344 const struct nlattr
* const osf_attrs
[],
345 struct netlink_ext_ack
*extack
)
347 struct nf_osf_user_finger
*f
;
348 struct nf_osf_finger
*sf
;
351 if (!capable(CAP_NET_ADMIN
))
354 if (!osf_attrs
[OSF_ATTR_FINGER
])
357 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
359 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
360 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
364 * We are protected by nfnl mutex.
366 list_del_rcu(&sf
->finger_entry
);
367 kfree_rcu(sf
, rcu_head
);
376 static const struct nfnl_callback nfnl_osf_callbacks
[OSF_MSG_MAX
] = {
378 .call
= nfnl_osf_add_callback
,
379 .attr_count
= OSF_ATTR_MAX
,
380 .policy
= nfnl_osf_policy
,
383 .call
= nfnl_osf_remove_callback
,
384 .attr_count
= OSF_ATTR_MAX
,
385 .policy
= nfnl_osf_policy
,
389 static const struct nfnetlink_subsystem nfnl_osf_subsys
= {
391 .subsys_id
= NFNL_SUBSYS_OSF
,
392 .cb_count
= OSF_MSG_MAX
,
393 .cb
= nfnl_osf_callbacks
,
396 static int __init
nfnl_osf_init(void)
401 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
)
402 INIT_LIST_HEAD(&nf_osf_fingers
[i
]);
404 err
= nfnetlink_subsys_register(&nfnl_osf_subsys
);
406 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err
);
415 static void __exit
nfnl_osf_fini(void)
417 struct nf_osf_finger
*f
;
420 nfnetlink_subsys_unregister(&nfnl_osf_subsys
);
423 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
) {
424 list_for_each_entry_rcu(f
, &nf_osf_fingers
[i
], finger_entry
) {
425 list_del_rcu(&f
->finger_entry
);
426 kfree_rcu(f
, rcu_head
);
434 module_init(nfnl_osf_init
);
435 module_exit(nfnl_osf_fini
);
437 MODULE_LICENSE("GPL");