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 struct in_device
*in_dev
= __in_dev_get_rcu(skb
->dev
);
34 const struct iphdr
*ip
= ip_hdr(skb
);
37 if (ttl_check
== NF_OSF_TTL_TRUE
)
38 return ip
->ttl
== f_ttl
;
39 if (ttl_check
== NF_OSF_TTL_NOCHECK
)
41 else if (ip
->ttl
<= f_ttl
)
45 if (inet_ifa_match(ip
->saddr
, ifa
)) {
46 ret
= (ip
->ttl
== f_ttl
);
56 struct nf_osf_hdr_ctx
{
60 const unsigned char *optp
;
64 static bool nf_osf_match_one(const struct sk_buff
*skb
,
65 const struct nf_osf_user_finger
*f
,
67 struct nf_osf_hdr_ctx
*ctx
)
69 unsigned int check_WSS
= 0;
70 int fmatch
= FMATCH_WRONG
;
74 if (ctx
->totlen
!= f
->ss
|| !nf_osf_ttl(skb
, ttl_check
, f
->ttl
))
78 * Should not happen if userspace parser was written correctly.
80 if (f
->wss
.wc
>= OSF_WSS_MAX
)
86 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
)
87 foptsize
+= f
->opt
[optnum
].length
;
89 if (foptsize
> MAX_IPOPTLEN
||
90 ctx
->optsize
> MAX_IPOPTLEN
||
91 ctx
->optsize
!= foptsize
)
94 check_WSS
= f
->wss
.wc
;
96 for (optnum
= 0; optnum
< f
->opt_num
; ++optnum
) {
97 if (f
->opt
[optnum
].kind
== *ctx
->optp
) {
98 __u32 len
= f
->opt
[optnum
].length
;
99 const __u8
*optend
= ctx
->optp
+ len
;
103 switch (*ctx
->optp
) {
109 mss
= ntohs((__force __be16
)mss
);
117 fmatch
= FMATCH_OPT_WRONG
;
119 if (fmatch
!= FMATCH_OK
)
123 if (fmatch
!= FMATCH_OPT_WRONG
) {
124 fmatch
= FMATCH_WRONG
;
128 if (f
->wss
.val
== 0 || ctx
->window
== f
->wss
.val
)
133 * Some smart modems decrease mangle MSS to
134 * SMART_MSS_2, so we check standard, decreased
135 * and the one provided in the fingerprint MSS
138 #define SMART_MSS_1 1460
139 #define SMART_MSS_2 1448
140 if (ctx
->window
== f
->wss
.val
* mss
||
141 ctx
->window
== f
->wss
.val
* SMART_MSS_1
||
142 ctx
->window
== f
->wss
.val
* SMART_MSS_2
)
146 if (ctx
->window
== f
->wss
.val
* (mss
+ 40) ||
147 ctx
->window
== f
->wss
.val
* (SMART_MSS_1
+ 40) ||
148 ctx
->window
== f
->wss
.val
* (SMART_MSS_2
+ 40))
152 if ((ctx
->window
% f
->wss
.val
) == 0)
158 return fmatch
== FMATCH_OK
;
161 static const struct tcphdr
*nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx
*ctx
,
162 const struct sk_buff
*skb
,
163 const struct iphdr
*ip
,
166 const struct tcphdr
*tcp
;
169 tcp
= skb_header_pointer(skb
, ip_hdrlen(skb
), sizeof(struct tcphdr
), &_tcph
);
176 ctx
->totlen
= ntohs(ip
->tot_len
);
177 ctx
->df
= ntohs(ip
->frag_off
) & IP_DF
;
178 ctx
->window
= ntohs(tcp
->window
);
180 if (tcp
->doff
* 4 > sizeof(struct tcphdr
)) {
181 ctx
->optsize
= tcp
->doff
* 4 - sizeof(struct tcphdr
);
183 ctx
->optp
= skb_header_pointer(skb
, ip_hdrlen(skb
) +
184 sizeof(struct tcphdr
), ctx
->optsize
, opts
);
191 nf_osf_match(const struct sk_buff
*skb
, u_int8_t family
,
192 int hooknum
, struct net_device
*in
, struct net_device
*out
,
193 const struct nf_osf_info
*info
, struct net
*net
,
194 const struct list_head
*nf_osf_fingers
)
196 const struct iphdr
*ip
= ip_hdr(skb
);
197 const struct nf_osf_user_finger
*f
;
198 unsigned char opts
[MAX_IPOPTLEN
];
199 const struct nf_osf_finger
*kf
;
200 int fcount
= 0, ttl_check
;
201 int fmatch
= FMATCH_WRONG
;
202 struct nf_osf_hdr_ctx ctx
;
203 const struct tcphdr
*tcp
;
205 memset(&ctx
, 0, sizeof(ctx
));
207 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
);
211 ttl_check
= (info
->flags
& NF_OSF_TTL
) ? info
->ttl
: 0;
213 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
217 if (!(info
->flags
& NF_OSF_LOG
) && strcmp(info
->genre
, f
->genre
))
220 if (!nf_osf_match_one(skb
, f
, ttl_check
, &ctx
))
227 if (info
->flags
& NF_OSF_LOG
)
228 nf_log_packet(net
, family
, hooknum
, skb
,
230 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
231 f
->genre
, f
->version
, f
->subtype
,
232 &ip
->saddr
, ntohs(tcp
->source
),
233 &ip
->daddr
, ntohs(tcp
->dest
),
236 if ((info
->flags
& NF_OSF_LOG
) &&
237 info
->loglevel
== NF_OSF_LOGLEVEL_FIRST
)
241 if (!fcount
&& (info
->flags
& NF_OSF_LOG
))
242 nf_log_packet(net
, family
, hooknum
, skb
, in
, out
, NULL
,
243 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
244 &ip
->saddr
, ntohs(tcp
->source
),
245 &ip
->daddr
, ntohs(tcp
->dest
));
250 return fmatch
== FMATCH_OK
;
252 EXPORT_SYMBOL_GPL(nf_osf_match
);
254 const char *nf_osf_find(const struct sk_buff
*skb
,
255 const struct list_head
*nf_osf_fingers
,
258 const struct iphdr
*ip
= ip_hdr(skb
);
259 const struct nf_osf_user_finger
*f
;
260 unsigned char opts
[MAX_IPOPTLEN
];
261 const struct nf_osf_finger
*kf
;
262 struct nf_osf_hdr_ctx ctx
;
263 const struct tcphdr
*tcp
;
264 const char *genre
= NULL
;
266 memset(&ctx
, 0, sizeof(ctx
));
268 tcp
= nf_osf_hdr_ctx_init(&ctx
, skb
, ip
, opts
);
272 list_for_each_entry_rcu(kf
, &nf_osf_fingers
[ctx
.df
], finger_entry
) {
274 if (!nf_osf_match_one(skb
, f
, ttl_check
, &ctx
))
283 EXPORT_SYMBOL_GPL(nf_osf_find
);
285 static const struct nla_policy nfnl_osf_policy
[OSF_ATTR_MAX
+ 1] = {
286 [OSF_ATTR_FINGER
] = { .len
= sizeof(struct nf_osf_user_finger
) },
289 static int nfnl_osf_add_callback(struct net
*net
, struct sock
*ctnl
,
290 struct sk_buff
*skb
, const struct nlmsghdr
*nlh
,
291 const struct nlattr
* const osf_attrs
[],
292 struct netlink_ext_ack
*extack
)
294 struct nf_osf_user_finger
*f
;
295 struct nf_osf_finger
*kf
= NULL
, *sf
;
298 if (!capable(CAP_NET_ADMIN
))
301 if (!osf_attrs
[OSF_ATTR_FINGER
])
304 if (!(nlh
->nlmsg_flags
& NLM_F_CREATE
))
307 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
309 kf
= kmalloc(sizeof(struct nf_osf_finger
), GFP_KERNEL
);
313 memcpy(&kf
->finger
, f
, sizeof(struct nf_osf_user_finger
));
315 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
316 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
322 if (nlh
->nlmsg_flags
& NLM_F_EXCL
)
328 * We are protected by nfnl mutex.
331 list_add_tail_rcu(&kf
->finger_entry
, &nf_osf_fingers
[!!f
->df
]);
336 static int nfnl_osf_remove_callback(struct net
*net
, struct sock
*ctnl
,
338 const struct nlmsghdr
*nlh
,
339 const struct nlattr
* const osf_attrs
[],
340 struct netlink_ext_ack
*extack
)
342 struct nf_osf_user_finger
*f
;
343 struct nf_osf_finger
*sf
;
346 if (!capable(CAP_NET_ADMIN
))
349 if (!osf_attrs
[OSF_ATTR_FINGER
])
352 f
= nla_data(osf_attrs
[OSF_ATTR_FINGER
]);
354 list_for_each_entry(sf
, &nf_osf_fingers
[!!f
->df
], finger_entry
) {
355 if (memcmp(&sf
->finger
, f
, sizeof(struct nf_osf_user_finger
)))
359 * We are protected by nfnl mutex.
361 list_del_rcu(&sf
->finger_entry
);
362 kfree_rcu(sf
, rcu_head
);
371 static const struct nfnl_callback nfnl_osf_callbacks
[OSF_MSG_MAX
] = {
373 .call
= nfnl_osf_add_callback
,
374 .attr_count
= OSF_ATTR_MAX
,
375 .policy
= nfnl_osf_policy
,
378 .call
= nfnl_osf_remove_callback
,
379 .attr_count
= OSF_ATTR_MAX
,
380 .policy
= nfnl_osf_policy
,
384 static const struct nfnetlink_subsystem nfnl_osf_subsys
= {
386 .subsys_id
= NFNL_SUBSYS_OSF
,
387 .cb_count
= OSF_MSG_MAX
,
388 .cb
= nfnl_osf_callbacks
,
391 static int __init
nfnl_osf_init(void)
396 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
)
397 INIT_LIST_HEAD(&nf_osf_fingers
[i
]);
399 err
= nfnetlink_subsys_register(&nfnl_osf_subsys
);
401 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err
);
410 static void __exit
nfnl_osf_fini(void)
412 struct nf_osf_finger
*f
;
415 nfnetlink_subsys_unregister(&nfnl_osf_subsys
);
418 for (i
= 0; i
< ARRAY_SIZE(nf_osf_fingers
); ++i
) {
419 list_for_each_entry_rcu(f
, &nf_osf_fingers
[i
], finger_entry
) {
420 list_del_rcu(&f
->finger_entry
);
421 kfree_rcu(f
, rcu_head
);
429 module_init(nfnl_osf_init
);
430 module_exit(nfnl_osf_fini
);
432 MODULE_LICENSE("GPL");