1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2 #include <linux/module.h>
3 #include <linux/kernel.h>
5 #include <linux/capability.h>
7 #include <linux/inetdevice.h>
9 #include <linux/list.h>
10 #include <linux/rculist.h>
11 #include <linux/skbuff.h>
12 #include <linux/slab.h>
13 #include <linux/tcp.h>
18 #include <linux/netfilter/nfnetlink.h>
19 #include <linux/netfilter/x_tables.h>
20 #include <net/netfilter/nf_log.h>
21 #include <linux/netfilter/nfnetlink_osf.h>
24 * Indexed by dont-fragment bit.
25 * It is the only constant value in the fingerprint.
27 struct list_head nf_osf_fingers
[2];
28 EXPORT_SYMBOL_GPL(nf_osf_fingers
);
30 static inline int nf_osf_ttl(const struct sk_buff
*skb
,
31 int ttl_check
, unsigned char f_ttl
)
33 const struct iphdr
*ip
= ip_hdr(skb
);
35 if (ttl_check
!= -1) {
36 if (ttl_check
== NF_OSF_TTL_TRUE
)
37 return ip
->ttl
== f_ttl
;
38 if (ttl_check
== NF_OSF_TTL_NOCHECK
)
40 else if (ip
->ttl
<= f_ttl
)
43 struct in_device
*in_dev
= __in_dev_get_rcu(skb
->dev
);
47 if (inet_ifa_match(ip
->saddr
, ifa
)) {
48 ret
= (ip
->ttl
== f_ttl
);
58 return ip
->ttl
== f_ttl
;
61 struct nf_osf_hdr_ctx
{
65 const unsigned char *optp
;
69 static bool nf_osf_match_one(const struct sk_buff
*skb
,
70 const struct nf_osf_user_finger
*f
,
72 struct nf_osf_hdr_ctx
*ctx
)
74 const __u8
*optpinit
= ctx
->optp
;
75 unsigned int check_WSS
= 0;
76 int fmatch
= FMATCH_WRONG
;
80 if (ctx
->totlen
!= f
->ss
|| !nf_osf_ttl(skb
, ttl_check
, f
->ttl
))
84 * Should not happen if userspace parser was written correctly.
86 if (f
->wss
.wc
>= OSF_WSS_MAX
)
92 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
)
93 foptsize
+= f
->opt
[optnum
].length
;
95 if (foptsize
> MAX_IPOPTLEN
||
96 ctx
->optsize
> MAX_IPOPTLEN
||
97 ctx
->optsize
!= foptsize
)
100 check_WSS
= f
->wss
.wc
;
102 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
) {
103 if (f
->opt
[optnum
].kind
== *ctx
->optp
) {
104 __u32 len
= f
->opt
[optnum
].length
;
105 const __u8
*optend
= ctx
->optp
+ len
;
109 switch (*ctx
->optp
) {
115 mss
= ntohs((__force __be16
)mss
);
123 fmatch
= FMATCH_OPT_WRONG
;
125 if (fmatch
!= FMATCH_OK
)
129 if (fmatch
!= FMATCH_OPT_WRONG
) {
130 fmatch
= FMATCH_WRONG
;
134 if (f
->wss
.val
== 0 || ctx
->window
== f
->wss
.val
)
139 * Some smart modems decrease mangle MSS to
140 * SMART_MSS_2, so we check standard, decreased
141 * and the one provided in the fingerprint MSS
144 #define SMART_MSS_1 1460
145 #define SMART_MSS_2 1448
146 if (ctx
->window
== f
->wss
.val
* mss
||
147 ctx
->window
== f
->wss
.val
* SMART_MSS_1
||
148 ctx
->window
== f
->wss
.val
* SMART_MSS_2
)
152 if (ctx
->window
== f
->wss
.val
* (mss
+ 40) ||
153 ctx
->window
== f
->wss
.val
* (SMART_MSS_1
+ 40) ||
154 ctx
->window
== f
->wss
.val
* (SMART_MSS_2
+ 40))
158 if ((ctx
->window
% f
->wss
.val
) == 0)
164 if (fmatch
!= FMATCH_OK
)
165 ctx
->optp
= optpinit
;
167 return fmatch
== FMATCH_OK
;
170 static const struct tcphdr
*nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx
*ctx
,
171 const struct sk_buff
*skb
,
172 const struct iphdr
*ip
,
174 struct tcphdr
*_tcph
)
176 const struct tcphdr
*tcp
;
178 tcp
= skb_header_pointer(skb
, ip_hdrlen(skb
), sizeof(struct tcphdr
), _tcph
);
185 ctx
->totlen
= ntohs(ip
->tot_len
);
186 ctx
->df
= ntohs(ip
->frag_off
) & IP_DF
;
187 ctx
->window
= ntohs(tcp
->window
);
189 if (tcp
->doff
* 4 > sizeof(struct tcphdr
)) {
190 ctx
->optsize
= tcp
->doff
* 4 - sizeof(struct tcphdr
);
192 ctx
->optp
= skb_header_pointer(skb
, ip_hdrlen(skb
) +
193 sizeof(struct tcphdr
), ctx
->optsize
, opts
);
200 nf_osf_match(const struct sk_buff
*skb
, u_int8_t family
,
201 int hooknum
, struct net_device
*in
, struct net_device
*out
,
202 const struct nf_osf_info
*info
, struct net
*net
,
203 const struct list_head
*nf_osf_fingers
)
205 const struct iphdr
*ip
= ip_hdr(skb
);
206 const struct nf_osf_user_finger
*f
;
207 unsigned char opts
[MAX_IPOPTLEN
];
208 const struct nf_osf_finger
*kf
;
209 int fcount
= 0, ttl_check
;
210 int fmatch
= FMATCH_WRONG
;
211 struct nf_osf_hdr_ctx ctx
;
212 const struct tcphdr
*tcp
;
215 memset(&ctx
, 0, sizeof(ctx
));
217 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
, &_tcph
);
221 ttl_check
= (info
->flags
& NF_OSF_TTL
) ? info
->ttl
: -1;
223 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
227 if (!(info
->flags
& NF_OSF_LOG
) && strcmp(info
->genre
, f
->genre
))
230 if (!nf_osf_match_one(skb
, f
, ttl_check
, &ctx
))
237 if (info
->flags
& NF_OSF_LOG
)
238 nf_log_packet(net
, family
, hooknum
, skb
,
240 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
241 f
->genre
, f
->version
, f
->subtype
,
242 &ip
->saddr
, ntohs(tcp
->source
),
243 &ip
->daddr
, ntohs(tcp
->dest
),
246 if ((info
->flags
& NF_OSF_LOG
) &&
247 info
->loglevel
== NF_OSF_LOGLEVEL_FIRST
)
251 if (!fcount
&& (info
->flags
& NF_OSF_LOG
))
252 nf_log_packet(net
, family
, hooknum
, skb
, in
, out
, NULL
,
253 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
254 &ip
->saddr
, ntohs(tcp
->source
),
255 &ip
->daddr
, ntohs(tcp
->dest
));
260 return fmatch
== FMATCH_OK
;
262 EXPORT_SYMBOL_GPL(nf_osf_match
);
264 const char *nf_osf_find(const struct sk_buff
*skb
,
265 const struct list_head
*nf_osf_fingers
)
267 const struct iphdr
*ip
= ip_hdr(skb
);
268 const struct nf_osf_user_finger
*f
;
269 unsigned char opts
[MAX_IPOPTLEN
];
270 const struct nf_osf_finger
*kf
;
271 struct nf_osf_hdr_ctx ctx
;
272 const struct tcphdr
*tcp
;
273 const char *genre
= NULL
;
276 memset(&ctx
, 0, sizeof(ctx
));
278 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
, &_tcph
);
282 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
284 if (!nf_osf_match_one(skb
, f
, -1, &ctx
))
293 EXPORT_SYMBOL_GPL(nf_osf_find
);
295 static const struct nla_policy nfnl_osf_policy
[OSF_ATTR_MAX
+ 1] = {
296 [OSF_ATTR_FINGER
] = { .len
= sizeof(struct nf_osf_user_finger
) },
299 static int nfnl_osf_add_callback(struct net
*net
, struct sock
*ctnl
,
300 struct sk_buff
*skb
, const struct nlmsghdr
*nlh
,
301 const struct nlattr
* const osf_attrs
[],
302 struct netlink_ext_ack
*extack
)
304 struct nf_osf_user_finger
*f
;
305 struct nf_osf_finger
*kf
= NULL
, *sf
;
308 if (!capable(CAP_NET_ADMIN
))
311 if (!osf_attrs
[OSF_ATTR_FINGER
])
314 if (!(nlh
->nlmsg_flags
& NLM_F_CREATE
))
317 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
319 kf
= kmalloc(sizeof(struct nf_osf_finger
), GFP_KERNEL
);
323 memcpy(&kf
->finger
, f
, sizeof(struct nf_osf_user_finger
));
325 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
326 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
332 if (nlh
->nlmsg_flags
& NLM_F_EXCL
)
338 * We are protected by nfnl mutex.
341 list_add_tail_rcu(&kf
->finger_entry
, &nf_osf_fingers
[!!f
->df
]);
346 static int nfnl_osf_remove_callback(struct net
*net
, struct sock
*ctnl
,
348 const struct nlmsghdr
*nlh
,
349 const struct nlattr
* const osf_attrs
[],
350 struct netlink_ext_ack
*extack
)
352 struct nf_osf_user_finger
*f
;
353 struct nf_osf_finger
*sf
;
356 if (!capable(CAP_NET_ADMIN
))
359 if (!osf_attrs
[OSF_ATTR_FINGER
])
362 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
364 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
365 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
369 * We are protected by nfnl mutex.
371 list_del_rcu(&sf
->finger_entry
);
372 kfree_rcu(sf
, rcu_head
);
381 static const struct nfnl_callback nfnl_osf_callbacks
[OSF_MSG_MAX
] = {
383 .call
= nfnl_osf_add_callback
,
384 .attr_count
= OSF_ATTR_MAX
,
385 .policy
= nfnl_osf_policy
,
388 .call
= nfnl_osf_remove_callback
,
389 .attr_count
= OSF_ATTR_MAX
,
390 .policy
= nfnl_osf_policy
,
394 static const struct nfnetlink_subsystem nfnl_osf_subsys
= {
396 .subsys_id
= NFNL_SUBSYS_OSF
,
397 .cb_count
= OSF_MSG_MAX
,
398 .cb
= nfnl_osf_callbacks
,
401 static int __init
nfnl_osf_init(void)
406 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
)
407 INIT_LIST_HEAD(&nf_osf_fingers
[i
]);
409 err
= nfnetlink_subsys_register(&nfnl_osf_subsys
);
411 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err
);
420 static void __exit
nfnl_osf_fini(void)
422 struct nf_osf_finger
*f
;
425 nfnetlink_subsys_unregister(&nfnl_osf_subsys
);
428 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
) {
429 list_for_each_entry_rcu(f
, &nf_osf_fingers
[i
], finger_entry
) {
430 list_del_rcu(&f
->finger_entry
);
431 kfree_rcu(f
, rcu_head
);
439 module_init(nfnl_osf_init
);
440 module_exit(nfnl_osf_fini
);
442 MODULE_LICENSE("GPL");