GNU Linux-libre 4.19.286-gnu1
[releases.git] / net / netfilter / nfnetlink_osf.c
1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4
5 #include <linux/capability.h>
6 #include <linux/if.h>
7 #include <linux/inetdevice.h>
8 #include <linux/ip.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>
14
15 #include <net/ip.h>
16 #include <net/tcp.h>
17
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>
22
23 /*
24  * Indexed by dont-fragment bit.
25  * It is the only constant value in the fingerprint.
26  */
27 struct list_head nf_osf_fingers[2];
28 EXPORT_SYMBOL_GPL(nf_osf_fingers);
29
30 static inline int nf_osf_ttl(const struct sk_buff *skb,
31                              int ttl_check, unsigned char f_ttl)
32 {
33         const struct iphdr *ip = ip_hdr(skb);
34
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)
39                         return 1;
40                 else if (ip->ttl <= f_ttl)
41                         return 1;
42                 else {
43                         struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
44                         int ret = 0;
45
46                         for_ifa(in_dev) {
47                                 if (inet_ifa_match(ip->saddr, ifa)) {
48                                         ret = (ip->ttl == f_ttl);
49                                         break;
50                                 }
51                         }
52                         endfor_ifa(in_dev);
53
54                         return ret;
55                 }
56         }
57
58         return ip->ttl == f_ttl;
59 }
60
61 struct nf_osf_hdr_ctx {
62         bool                    df;
63         u16                     window;
64         u16                     totlen;
65         const unsigned char     *optp;
66         unsigned int            optsize;
67 };
68
69 static bool nf_osf_match_one(const struct sk_buff *skb,
70                              const struct nf_osf_user_finger *f,
71                              int ttl_check,
72                              struct nf_osf_hdr_ctx *ctx)
73 {
74         const __u8 *optpinit = ctx->optp;
75         unsigned int check_WSS = 0;
76         int fmatch = FMATCH_WRONG;
77         int foptsize, optnum;
78         u16 mss = 0;
79
80         if (ctx->totlen != f->ss || !nf_osf_ttl(skb, ttl_check, f->ttl))
81                 return false;
82
83         /*
84          * Should not happen if userspace parser was written correctly.
85          */
86         if (f->wss.wc >= OSF_WSS_MAX)
87                 return false;
88
89         /* Check options */
90
91         foptsize = 0;
92         for (optnum = 0; optnum < f->opt_num; ++optnum)
93                 foptsize += f->opt[optnum].length;
94
95         if (foptsize > MAX_IPOPTLEN ||
96             ctx->optsize > MAX_IPOPTLEN ||
97             ctx->optsize != foptsize)
98                 return false;
99
100         check_WSS = f->wss.wc;
101
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;
106
107                         fmatch = FMATCH_OK;
108
109                         switch (*ctx->optp) {
110                         case OSFOPT_MSS:
111                                 mss = ctx->optp[3];
112                                 mss <<= 8;
113                                 mss |= ctx->optp[2];
114
115                                 mss = ntohs((__force __be16)mss);
116                                 break;
117                         case OSFOPT_TS:
118                                 break;
119                         }
120
121                         ctx->optp = optend;
122                 } else
123                         fmatch = FMATCH_OPT_WRONG;
124
125                 if (fmatch != FMATCH_OK)
126                         break;
127         }
128
129         if (fmatch != FMATCH_OPT_WRONG) {
130                 fmatch = FMATCH_WRONG;
131
132                 switch (check_WSS) {
133                 case OSF_WSS_PLAIN:
134                         if (f->wss.val == 0 || ctx->window == f->wss.val)
135                                 fmatch = FMATCH_OK;
136                         break;
137                 case OSF_WSS_MSS:
138                         /*
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
142                          * values.
143                          */
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)
149                                 fmatch = FMATCH_OK;
150                         break;
151                 case OSF_WSS_MTU:
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))
155                                 fmatch = FMATCH_OK;
156                         break;
157                 case OSF_WSS_MODULO:
158                         if ((ctx->window % f->wss.val) == 0)
159                                 fmatch = FMATCH_OK;
160                         break;
161                 }
162         }
163
164         if (fmatch != FMATCH_OK)
165                 ctx->optp = optpinit;
166
167         return fmatch == FMATCH_OK;
168 }
169
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,
173                                                 unsigned char *opts,
174                                                 struct tcphdr *_tcph)
175 {
176         const struct tcphdr *tcp;
177
178         tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), _tcph);
179         if (!tcp)
180                 return NULL;
181
182         if (!tcp->syn)
183                 return NULL;
184
185         ctx->totlen = ntohs(ip->tot_len);
186         ctx->df = ntohs(ip->frag_off) & IP_DF;
187         ctx->window = ntohs(tcp->window);
188
189         if (tcp->doff * 4 > sizeof(struct tcphdr)) {
190                 ctx->optsize = tcp->doff * 4 - sizeof(struct tcphdr);
191
192                 ctx->optp = skb_header_pointer(skb, ip_hdrlen(skb) +
193                                 sizeof(struct tcphdr), ctx->optsize, opts);
194                 if (!ctx->optp)
195                         return NULL;
196         }
197
198         return tcp;
199 }
200
201 bool
202 nf_osf_match(const struct sk_buff *skb, u_int8_t family,
203              int hooknum, struct net_device *in, struct net_device *out,
204              const struct nf_osf_info *info, struct net *net,
205              const struct list_head *nf_osf_fingers)
206 {
207         const struct iphdr *ip = ip_hdr(skb);
208         const struct nf_osf_user_finger *f;
209         unsigned char opts[MAX_IPOPTLEN];
210         const struct nf_osf_finger *kf;
211         int fcount = 0, ttl_check;
212         int fmatch = FMATCH_WRONG;
213         struct nf_osf_hdr_ctx ctx;
214         const struct tcphdr *tcp;
215         struct tcphdr _tcph;
216
217         memset(&ctx, 0, sizeof(ctx));
218
219         tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts, &_tcph);
220         if (!tcp)
221                 return false;
222
223         ttl_check = (info->flags & NF_OSF_TTL) ? info->ttl : -1;
224
225         list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) {
226
227                 f = &kf->finger;
228
229                 if (!(info->flags & NF_OSF_LOG) && strcmp(info->genre, f->genre))
230                         continue;
231
232                 if (!nf_osf_match_one(skb, f, ttl_check, &ctx))
233                         continue;
234
235                 fmatch = FMATCH_OK;
236
237                 fcount++;
238
239                 if (info->flags & NF_OSF_LOG)
240                         nf_log_packet(net, family, hooknum, skb,
241                                       in, out, NULL,
242                                       "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
243                                       f->genre, f->version, f->subtype,
244                                       &ip->saddr, ntohs(tcp->source),
245                                       &ip->daddr, ntohs(tcp->dest),
246                                       f->ttl - ip->ttl);
247
248                 if ((info->flags & NF_OSF_LOG) &&
249                     info->loglevel == NF_OSF_LOGLEVEL_FIRST)
250                         break;
251         }
252
253         if (!fcount && (info->flags & NF_OSF_LOG))
254                 nf_log_packet(net, family, hooknum, skb, in, out, NULL,
255                               "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
256                               &ip->saddr, ntohs(tcp->source),
257                               &ip->daddr, ntohs(tcp->dest));
258
259         if (fcount)
260                 fmatch = FMATCH_OK;
261
262         return fmatch == FMATCH_OK;
263 }
264 EXPORT_SYMBOL_GPL(nf_osf_match);
265
266 const char *nf_osf_find(const struct sk_buff *skb,
267                         const struct list_head *nf_osf_fingers)
268 {
269         const struct iphdr *ip = ip_hdr(skb);
270         const struct nf_osf_user_finger *f;
271         unsigned char opts[MAX_IPOPTLEN];
272         const struct nf_osf_finger *kf;
273         struct nf_osf_hdr_ctx ctx;
274         const struct tcphdr *tcp;
275         const char *genre = NULL;
276         struct tcphdr _tcph;
277
278         memset(&ctx, 0, sizeof(ctx));
279
280         tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts, &_tcph);
281         if (!tcp)
282                 return NULL;
283
284         list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) {
285                 f = &kf->finger;
286                 if (!nf_osf_match_one(skb, f, -1, &ctx))
287                         continue;
288
289                 genre = f->genre;
290                 break;
291         }
292
293         return genre;
294 }
295 EXPORT_SYMBOL_GPL(nf_osf_find);
296
297 static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = {
298         [OSF_ATTR_FINGER]       = { .len = sizeof(struct nf_osf_user_finger) },
299 };
300
301 static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
302                                  struct sk_buff *skb, const struct nlmsghdr *nlh,
303                                  const struct nlattr * const osf_attrs[],
304                                  struct netlink_ext_ack *extack)
305 {
306         struct nf_osf_user_finger *f;
307         struct nf_osf_finger *kf = NULL, *sf;
308         int err = 0;
309
310         if (!capable(CAP_NET_ADMIN))
311                 return -EPERM;
312
313         if (!osf_attrs[OSF_ATTR_FINGER])
314                 return -EINVAL;
315
316         if (!(nlh->nlmsg_flags & NLM_F_CREATE))
317                 return -EINVAL;
318
319         f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
320
321         kf = kmalloc(sizeof(struct nf_osf_finger), GFP_KERNEL);
322         if (!kf)
323                 return -ENOMEM;
324
325         memcpy(&kf->finger, f, sizeof(struct nf_osf_user_finger));
326
327         list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) {
328                 if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger)))
329                         continue;
330
331                 kfree(kf);
332                 kf = NULL;
333
334                 if (nlh->nlmsg_flags & NLM_F_EXCL)
335                         err = -EEXIST;
336                 break;
337         }
338
339         /*
340          * We are protected by nfnl mutex.
341          */
342         if (kf)
343                 list_add_tail_rcu(&kf->finger_entry, &nf_osf_fingers[!!f->df]);
344
345         return err;
346 }
347
348 static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
349                                     struct sk_buff *skb,
350                                     const struct nlmsghdr *nlh,
351                                     const struct nlattr * const osf_attrs[],
352                                     struct netlink_ext_ack *extack)
353 {
354         struct nf_osf_user_finger *f;
355         struct nf_osf_finger *sf;
356         int err = -ENOENT;
357
358         if (!capable(CAP_NET_ADMIN))
359                 return -EPERM;
360
361         if (!osf_attrs[OSF_ATTR_FINGER])
362                 return -EINVAL;
363
364         f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
365
366         list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) {
367                 if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger)))
368                         continue;
369
370                 /*
371                  * We are protected by nfnl mutex.
372                  */
373                 list_del_rcu(&sf->finger_entry);
374                 kfree_rcu(sf, rcu_head);
375
376                 err = 0;
377                 break;
378         }
379
380         return err;
381 }
382
383 static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = {
384         [OSF_MSG_ADD]   = {
385                 .call           = nfnl_osf_add_callback,
386                 .attr_count     = OSF_ATTR_MAX,
387                 .policy         = nfnl_osf_policy,
388         },
389         [OSF_MSG_REMOVE]        = {
390                 .call           = nfnl_osf_remove_callback,
391                 .attr_count     = OSF_ATTR_MAX,
392                 .policy         = nfnl_osf_policy,
393         },
394 };
395
396 static const struct nfnetlink_subsystem nfnl_osf_subsys = {
397         .name                   = "osf",
398         .subsys_id              = NFNL_SUBSYS_OSF,
399         .cb_count               = OSF_MSG_MAX,
400         .cb                     = nfnl_osf_callbacks,
401 };
402
403 static int __init nfnl_osf_init(void)
404 {
405         int err = -EINVAL;
406         int i;
407
408         for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i)
409                 INIT_LIST_HEAD(&nf_osf_fingers[i]);
410
411         err = nfnetlink_subsys_register(&nfnl_osf_subsys);
412         if (err < 0) {
413                 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
414                 goto err_out_exit;
415         }
416         return 0;
417
418 err_out_exit:
419         return err;
420 }
421
422 static void __exit nfnl_osf_fini(void)
423 {
424         struct nf_osf_finger *f;
425         int i;
426
427         nfnetlink_subsys_unregister(&nfnl_osf_subsys);
428
429         rcu_read_lock();
430         for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i) {
431                 list_for_each_entry_rcu(f, &nf_osf_fingers[i], finger_entry) {
432                         list_del_rcu(&f->finger_entry);
433                         kfree_rcu(f, rcu_head);
434                 }
435         }
436         rcu_read_unlock();
437
438         rcu_barrier();
439 }
440
441 module_init(nfnl_osf_init);
442 module_exit(nfnl_osf_fini);
443
444 MODULE_LICENSE("GPL");