Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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/nf_osf.h>
22
23static inline int nf_osf_ttl(const struct sk_buff *skb,
24 const struct nf_osf_info *info,
25 unsigned char f_ttl)
26{
27 const struct iphdr *ip = ip_hdr(skb);
28
29 if (info->flags & NF_OSF_TTL) {
30 if (info->ttl == NF_OSF_TTL_TRUE)
31 return ip->ttl == f_ttl;
32 if (info->ttl == NF_OSF_TTL_NOCHECK)
33 return 1;
34 else if (ip->ttl <= f_ttl)
35 return 1;
36 else {
37 struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
38 int ret = 0;
39
40 for_ifa(in_dev) {
41 if (inet_ifa_match(ip->saddr, ifa)) {
42 ret = (ip->ttl == f_ttl);
43 break;
44 }
45 }
46 endfor_ifa(in_dev);
47
48 return ret;
49 }
50 }
51
52 return ip->ttl == f_ttl;
53}
54
55bool
56nf_osf_match(const struct sk_buff *skb, u_int8_t family,
57 int hooknum, struct net_device *in, struct net_device *out,
58 const struct nf_osf_info *info, struct net *net,
59 const struct list_head *nf_osf_fingers)
60{
61 const unsigned char *optp = NULL, *_optp = NULL;
62 unsigned int optsize = 0, check_WSS = 0;
63 int fmatch = FMATCH_WRONG, fcount = 0;
64 const struct iphdr *ip = ip_hdr(skb);
65 const struct nf_osf_user_finger *f;
66 unsigned char opts[MAX_IPOPTLEN];
67 const struct nf_osf_finger *kf;
68 u16 window, totlen, mss = 0;
69 const struct tcphdr *tcp;
70 struct tcphdr _tcph;
71 bool df;
72
73 tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);
74 if (!tcp)
75 return false;
76
77 if (!tcp->syn)
78 return false;
79
80 totlen = ntohs(ip->tot_len);
81 df = ntohs(ip->frag_off) & IP_DF;
82 window = ntohs(tcp->window);
83
84 if (tcp->doff * 4 > sizeof(struct tcphdr)) {
85 optsize = tcp->doff * 4 - sizeof(struct tcphdr);
86
87 _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
88 sizeof(struct tcphdr), optsize, opts);
89 }
90
91 list_for_each_entry_rcu(kf, &nf_osf_fingers[df], finger_entry) {
92 int foptsize, optnum;
93
94 f = &kf->finger;
95
96 if (!(info->flags & NF_OSF_LOG) && strcmp(info->genre, f->genre))
97 continue;
98
99 optp = _optp;
100 fmatch = FMATCH_WRONG;
101
102 if (totlen != f->ss || !nf_osf_ttl(skb, info, f->ttl))
103 continue;
104
105 /*
106 * Should not happen if userspace parser was written correctly.
107 */
108 if (f->wss.wc >= OSF_WSS_MAX)
109 continue;
110
111 /* Check options */
112
113 foptsize = 0;
114 for (optnum = 0; optnum < f->opt_num; ++optnum)
115 foptsize += f->opt[optnum].length;
116
117 if (foptsize > MAX_IPOPTLEN ||
118 optsize > MAX_IPOPTLEN ||
119 optsize != foptsize)
120 continue;
121
122 check_WSS = f->wss.wc;
123
124 for (optnum = 0; optnum < f->opt_num; ++optnum) {
125 if (f->opt[optnum].kind == (*optp)) {
126 __u32 len = f->opt[optnum].length;
127 const __u8 *optend = optp + len;
128
129 fmatch = FMATCH_OK;
130
131 switch (*optp) {
132 case OSFOPT_MSS:
133 mss = optp[3];
134 mss <<= 8;
135 mss |= optp[2];
136
137 mss = ntohs((__force __be16)mss);
138 break;
139 case OSFOPT_TS:
140 break;
141 }
142
143 optp = optend;
144 } else
145 fmatch = FMATCH_OPT_WRONG;
146
147 if (fmatch != FMATCH_OK)
148 break;
149 }
150
151 if (fmatch != FMATCH_OPT_WRONG) {
152 fmatch = FMATCH_WRONG;
153
154 switch (check_WSS) {
155 case OSF_WSS_PLAIN:
156 if (f->wss.val == 0 || window == f->wss.val)
157 fmatch = FMATCH_OK;
158 break;
159 case OSF_WSS_MSS:
160 /*
161 * Some smart modems decrease mangle MSS to
162 * SMART_MSS_2, so we check standard, decreased
163 * and the one provided in the fingerprint MSS
164 * values.
165 */
166#define SMART_MSS_1 1460
167#define SMART_MSS_2 1448
168 if (window == f->wss.val * mss ||
169 window == f->wss.val * SMART_MSS_1 ||
170 window == f->wss.val * SMART_MSS_2)
171 fmatch = FMATCH_OK;
172 break;
173 case OSF_WSS_MTU:
174 if (window == f->wss.val * (mss + 40) ||
175 window == f->wss.val * (SMART_MSS_1 + 40) ||
176 window == f->wss.val * (SMART_MSS_2 + 40))
177 fmatch = FMATCH_OK;
178 break;
179 case OSF_WSS_MODULO:
180 if ((window % f->wss.val) == 0)
181 fmatch = FMATCH_OK;
182 break;
183 }
184 }
185
186 if (fmatch != FMATCH_OK)
187 continue;
188
189 fcount++;
190
191 if (info->flags & NF_OSF_LOG)
192 nf_log_packet(net, family, hooknum, skb,
193 in, out, NULL,
194 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
195 f->genre, f->version, f->subtype,
196 &ip->saddr, ntohs(tcp->source),
197 &ip->daddr, ntohs(tcp->dest),
198 f->ttl - ip->ttl);
199
200 if ((info->flags & NF_OSF_LOG) &&
201 info->loglevel == NF_OSF_LOGLEVEL_FIRST)
202 break;
203 }
204
205 if (!fcount && (info->flags & NF_OSF_LOG))
206 nf_log_packet(net, family, hooknum, skb, in, out, NULL,
207 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
208 &ip->saddr, ntohs(tcp->source),
209 &ip->daddr, ntohs(tcp->dest));
210
211 if (fcount)
212 fmatch = FMATCH_OK;
213
214 return fmatch == FMATCH_OK;
215}
216EXPORT_SYMBOL_GPL(nf_osf_match);
217
218MODULE_LICENSE("GPL");