History

netfilter: extract Passive OS fingerprint infrastructure from xt_osf

Add nf_osf_ttl() and nf_osf_match() into nf_osf.c to prepare for nf_tables support.

Fernando Fernandez Mancera committed 8 years ago

Commit bfb15f21 parent 3f9c56a7 files · +359 −289Browse files

Unified · Split

7 files
  1. include/linux/netfilter/nf_osf.h +27 −0
  2. include/uapi/linux/netfilter/nf_osf.h +90 −0
  3. include/uapi/linux/netfilter/xt_osf.h +17 −89
  4. net/netfilter/Kconfig +4 −0
  5. net/netfilter/Makefile +1 −0
  6. net/netfilter/nf_osf.c +218 −0
  7. net/netfilter/xt_osf.c +2 −200
include/linux/netfilter/nf_osf.h+27−0
@@ -0,0 +1,27 @@
1#include <uapi/linux/netfilter/nf_osf.h>
2
3/* Initial window size option state machine: multiple of mss, mtu or
4 * plain numeric value. Can also be made as plain numeric value which
5 * is not a multiple of specified value.
6 */
7enum nf_osf_window_size_options {
8 OSF_WSS_PLAIN = 0,
9 OSF_WSS_MSS,
10 OSF_WSS_MTU,
11 OSF_WSS_MODULO,
12 OSF_WSS_MAX,
13};
14
15enum osf_fmatch_states {
16 /* Packet does not match the fingerprint */
17 FMATCH_WRONG = 0,
18 /* Packet matches the fingerprint */
19 FMATCH_OK,
20 /* Options do not match the fingerprint, but header does */
21 FMATCH_OPT_WRONG,
22};
23
24bool nf_osf_match(const struct sk_buff *skb, u_int8_t family,
25 int hooknum, struct net_device *in, struct net_device *out,
26 const struct nf_osf_info *info, struct net *net,
27 const struct list_head *nf_osf_fingers);
include/uapi/linux/netfilter/nf_osf.h+90−0
@@ -0,0 +1,90 @@
1#ifndef _NF_OSF_H
2#define _NF_OSF_H
3
4#define MAXGENRELEN 32
5
6#define NF_OSF_GENRE (1 << 0)
7#define NF_OSF_TTL (1 << 1)
8#define NF_OSF_LOG (1 << 2)
9#define NF_OSF_INVERT (1 << 3)
10
11#define NF_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */
12#define NF_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */
13#define NF_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */
14
15#define NF_OSF_TTL_TRUE 0 /* True ip and fingerprint TTL comparison */
16
17/* Do not compare ip and fingerprint TTL at all */
18#define NF_OSF_TTL_NOCHECK 2
19
20/* Wildcard MSS (kind of).
21 * It is used to implement a state machine for the different wildcard values
22 * of the MSS and window sizes.
23 */
24struct nf_osf_wc {
25 __u32 wc;
26 __u32 val;
27};
28
29/* This struct represents IANA options
30 * http://www.iana.org/assignments/tcp-parameters
31 */
32struct nf_osf_opt {
33 __u16 kind, length;
34 struct nf_osf_wc wc;
35};
36
37struct nf_osf_info {
38 char genre[MAXGENRELEN];
39 __u32 len;
40 __u32 flags;
41 __u32 loglevel;
42 __u32 ttl;
43};
44
45struct nf_osf_user_finger {
46 struct nf_osf_wc wss;
47
48 __u8 ttl, df;
49 __u16 ss, mss;
50 __u16 opt_num;
51
52 char genre[MAXGENRELEN];
53 char version[MAXGENRELEN];
54 char subtype[MAXGENRELEN];
55
56 /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */
57 struct nf_osf_opt opt[MAX_IPOPTLEN];
58};
59
60struct nf_osf_finger {
61 struct rcu_head rcu_head;
62 struct list_head finger_entry;
63 struct nf_osf_user_finger finger;
64};
65
66struct nf_osf_nlmsg {
67 struct nf_osf_user_finger f;
68 struct iphdr ip;
69 struct tcphdr tcp;
70};
71
72/* Defines for IANA option kinds */
73enum iana_options {
74 OSFOPT_EOL = 0, /* End of options */
75 OSFOPT_NOP, /* NOP */
76 OSFOPT_MSS, /* Maximum segment size */
77 OSFOPT_WSO, /* Window scale option */
78 OSFOPT_SACKP, /* SACK permitted */
79 OSFOPT_SACK, /* SACK */
80 OSFOPT_ECHO,
81 OSFOPT_ECHOREPLY,
82 OSFOPT_TS, /* Timestamp option */
83 OSFOPT_POCP, /* Partial Order Connection Permitted */
84 OSFOPT_POSP, /* Partial Order Service Profile */
85
86 /* Others are not used in the current OSF */
87 OSFOPT_EMPTY = 255,
88};
89
90#endif /* _NF_OSF_H */
include/uapi/linux/netfilter/xt_osf.h+17−89
@@ -23,101 +23,29 @@ · 22 unmodified lines
23#include <linux/types.h>23#include <linux/types.h>
24#include <linux/ip.h>24#include <linux/ip.h>
25#include <linux/tcp.h>25#include <linux/tcp.h>
26#include <linux/netfilter/nf_osf.h>
26 27
27#define MAXGENRELEN 3228#define XT_OSF_GENRE NF_OSF_GENRE
29#define XT_OSF_INVERT NF_OSF_INVERT
28 30
29#define XT_OSF_GENRE (1<<0)31#define XT_OSF_TTL NF_OSF_TTL
30#define XT_OSF_TTL (1<<1)32#define XT_OSF_LOG NF_OSF_LOG
31#define XT_OSF_LOG (1<<2)
32#define XT_OSF_INVERT (1<<3)
33 33
34#define XT_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */34#define XT_OSF_LOGLEVEL_ALL NF_OSF_LOGLEVEL_ALL
35#define XT_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */35#define XT_OSF_LOGLEVEL_FIRST NF_OSF_LOGLEVEL_FIRST
36#define XT_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */36#define XT_OSF_LOGLEVEL_ALL_KNOWN NF_OSF_LOGLEVEL_ALL_KNOWN
37 37
38#define XT_OSF_TTL_TRUE 0 /* True ip and fingerprint TTL comparison */38#define XT_OSF_TTL_TRUE NF_OSF_TTL_TRUE
39#define XT_OSF_TTL_LESS 1 /* Check if ip TTL is less than fingerprint one */39#define XT_OSF_TTL_NOCHECK NF_OSF_TTL_NOCHECK
40#define XT_OSF_TTL_NOCHECK 2 /* Do not compare ip and fingerprint TTL at all */
41 40
42struct xt_osf_info {41#define XT_OSF_TTL_LESS 1 /* Check if ip TTL is less than fingerprint one */
43 char genre[MAXGENRELEN];
44 __u32 len;
45 __u32 flags;
46 __u32 loglevel;
47 __u32 ttl;
48};
49
50/*
51 * Wildcard MSS (kind of).
52 * It is used to implement a state machine for the different wildcard values
53 * of the MSS and window sizes.
54 */
55struct xt_osf_wc {
56 __u32 wc;
57 __u32 val;
58};
59
60/*
61 * This struct represents IANA options
62 * http://www.iana.org/assignments/tcp-parameters
63 */
64struct xt_osf_opt {
65 __u16 kind, length;
66 struct xt_osf_wc wc;
67};
68
69struct xt_osf_user_finger {
70 struct xt_osf_wc wss;
71
72 __u8 ttl, df;
73 __u16 ss, mss;
74 __u16 opt_num;
75
76 char genre[MAXGENRELEN];
77 char version[MAXGENRELEN];
78 char subtype[MAXGENRELEN];
79 42
80 /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */43#define xt_osf_wc nf_osf_wc
81 struct xt_osf_opt opt[MAX_IPOPTLEN];44#define xt_osf_opt nf_osf_opt
82};45#define xt_osf_info nf_osf_info
83 46#define xt_osf_user_finger nf_osf_user_finger
84struct xt_osf_nlmsg {47#define xt_osf_finger nf_osf_finger
85 struct xt_osf_user_finger f;48#define xt_osf_nlmsg nf_osf_nlmsg
86 struct iphdr ip;
87 struct tcphdr tcp;
88};
89
90/* Defines for IANA option kinds */
91
92enum iana_options {
93 OSFOPT_EOL = 0, /* End of options */
94 OSFOPT_NOP, /* NOP */
95 OSFOPT_MSS, /* Maximum segment size */
96 OSFOPT_WSO, /* Window scale option */
97 OSFOPT_SACKP, /* SACK permitted */
98 OSFOPT_SACK, /* SACK */
99 OSFOPT_ECHO,
100 OSFOPT_ECHOREPLY,
101 OSFOPT_TS, /* Timestamp option */
102 OSFOPT_POCP, /* Partial Order Connection Permitted */
103 OSFOPT_POSP, /* Partial Order Service Profile */
104
105 /* Others are not used in the current OSF */
106 OSFOPT_EMPTY = 255,
107};
108
109/*
110 * Initial window size option state machine: multiple of mss, mtu or
111 * plain numeric value. Can also be made as plain numeric value which
112 * is not a multiple of specified value.
113 */
114enum xt_osf_window_size_options {
115 OSF_WSS_PLAIN = 0,
116 OSF_WSS_MSS,
117 OSF_WSS_MTU,
118 OSF_WSS_MODULO,
119 OSF_WSS_MAX,
120};
121 49
122/*50/*
123 * Add/remove fingerprint from the kernel.51 * Add/remove fingerprint from the kernel.
net/netfilter/Kconfig+4−0
@@ -444,6 +444,9 @@ config NETFILTER_SYNPROXY · 443 unmodified lines
444 444
445endif # NF_CONNTRACK445endif # NF_CONNTRACK
446 446
447config NF_OSF
448 tristate 'Passive OS fingerprint infrastructure'
449
447config NF_TABLES450config NF_TABLES
448 select NETFILTER_NETLINK451 select NETFILTER_NETLINK
449 tristate "Netfilter nf_tables support"452 tristate "Netfilter nf_tables support"
@@ -1358,6 +1361,7 @@ config NETFILTER_XT_MATCH_NFACCT · 908 unmodified lines
1358config NETFILTER_XT_MATCH_OSF1361config NETFILTER_XT_MATCH_OSF
1359 tristate '"osf" Passive OS fingerprint match'1362 tristate '"osf" Passive OS fingerprint match'
1360 depends on NETFILTER_ADVANCED && NETFILTER_NETLINK1363 depends on NETFILTER_ADVANCED && NETFILTER_NETLINK
1364 select NF_OSF
1361 help1365 help
1362 This option selects the Passive OS Fingerprinting match module1366 This option selects the Passive OS Fingerprinting match module
1363 that allows to passively match the remote operating system by1367 that allows to passively match the remote operating system by
net/netfilter/Makefile+1−0
@@ -101,6 +101,7 @@ obj-$(CONFIG_NFT_HASH) += nft_hash.o · 100 unmodified lines
101obj-$(CONFIG_NFT_FIB) += nft_fib.o101obj-$(CONFIG_NFT_FIB) += nft_fib.o
102obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o102obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o
103obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o103obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o
104obj-$(CONFIG_NF_OSF) += nf_osf.o
104 105
105# nf_tables netdev106# nf_tables netdev
106obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o107obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o
net/netfilter/nf_osf.c+218−0
@@ -0,0 +1,218 @@
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");
net/netfilter/xt_osf.c+2−200
@@ -37,21 +37,6 @@ · 36 unmodified lines
37#include <net/netfilter/nf_log.h>37#include <net/netfilter/nf_log.h>
38#include <linux/netfilter/xt_osf.h>38#include <linux/netfilter/xt_osf.h>
39 39
40struct xt_osf_finger {
41 struct rcu_head rcu_head;
42 struct list_head finger_entry;
43 struct xt_osf_user_finger finger;
44};
45
46enum osf_fmatch_states {
47 /* Packet does not match the fingerprint */
48 FMATCH_WRONG = 0,
49 /* Packet matches the fingerprint */
50 FMATCH_OK,
51 /* Options do not match the fingerprint, but header does */
52 FMATCH_OPT_WRONG,
53};
54
55/*40/*
56 * Indexed by dont-fragment bit.41 * Indexed by dont-fragment bit.
57 * It is the only constant value in the fingerprint.42 * It is the only constant value in the fingerprint.
@@ -164,200 +149,17 @@ static const struct nfnetlink_subsystem xt_osf_nfnetlink = { · 106 unmodified lines
164 .cb = xt_osf_nfnetlink_callbacks,149 .cb = xt_osf_nfnetlink_callbacks,
165};150};
166 151
167static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info,
168 unsigned char f_ttl)
169{
170 const struct iphdr *ip = ip_hdr(skb);
171
172 if (info->flags & XT_OSF_TTL) {
173 if (info->ttl == XT_OSF_TTL_TRUE)
174 return ip->ttl == f_ttl;
175 if (info->ttl == XT_OSF_TTL_NOCHECK)
176 return 1;
177 else if (ip->ttl <= f_ttl)
178 return 1;
179 else {
180 struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
181 int ret = 0;
182
183 for_ifa(in_dev) {
184 if (inet_ifa_match(ip->saddr, ifa)) {
185 ret = (ip->ttl == f_ttl);
186 break;
187 }
188 }
189 endfor_ifa(in_dev);
190
191 return ret;
192 }
193 }
194
195 return ip->ttl == f_ttl;
196}
197
198static bool152static bool
199xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)153xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
200{154{
201 const struct xt_osf_info *info = p->matchinfo;155 const struct xt_osf_info *info = p->matchinfo;
202 const struct iphdr *ip = ip_hdr(skb);
203 const struct tcphdr *tcp;
204 struct tcphdr _tcph;
205 int fmatch = FMATCH_WRONG, fcount = 0;
206 unsigned int optsize = 0, check_WSS = 0;
207 u16 window, totlen, mss = 0;
208 bool df;
209 const unsigned char *optp = NULL, *_optp = NULL;
210 unsigned char opts[MAX_IPOPTLEN];
211 const struct xt_osf_finger *kf;
212 const struct xt_osf_user_finger *f;
213 struct net *net = xt_net(p);156 struct net *net = xt_net(p);
214 157
215 if (!info)158 if (!info)
216 return false;159 return false;
217 160
218 tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);161 return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p),
219 if (!tcp)162 xt_out(p), info, net, xt_osf_fingers);
220 return false;
221
222 if (!tcp->syn)
223 return false;
224
225 totlen = ntohs(ip->tot_len);
226 df = ntohs(ip->frag_off) & IP_DF;
227 window = ntohs(tcp->window);
228
229 if (tcp->doff * 4 > sizeof(struct tcphdr)) {
230 optsize = tcp->doff * 4 - sizeof(struct tcphdr);
231
232 _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
233 sizeof(struct tcphdr), optsize, opts);
234 }
235
236 list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) {
237 int foptsize, optnum;
238
239 f = &kf->finger;
240
241 if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
242 continue;
243
244 optp = _optp;
245 fmatch = FMATCH_WRONG;
246
247 if (totlen != f->ss || !xt_osf_ttl(skb, info, f->ttl))
248 continue;
249
250 /*
251 * Should not happen if userspace parser was written correctly.
252 */
253 if (f->wss.wc >= OSF_WSS_MAX)
254 continue;
255
256 /* Check options */
257
258 foptsize = 0;
259 for (optnum = 0; optnum < f->opt_num; ++optnum)
260 foptsize += f->opt[optnum].length;
261
262 if (foptsize > MAX_IPOPTLEN ||
263 optsize > MAX_IPOPTLEN ||
264 optsize != foptsize)
265 continue;
266
267 check_WSS = f->wss.wc;
268
269 for (optnum = 0; optnum < f->opt_num; ++optnum) {
270 if (f->opt[optnum].kind == (*optp)) {
271 __u32 len = f->opt[optnum].length;
272 const __u8 *optend = optp + len;
273
274 fmatch = FMATCH_OK;
275
276 switch (*optp) {
277 case OSFOPT_MSS:
278 mss = optp[3];
279 mss <<= 8;
280 mss |= optp[2];
281
282 mss = ntohs((__force __be16)mss);
283 break;
284 case OSFOPT_TS:
285 break;
286 }
287
288 optp = optend;
289 } else
290 fmatch = FMATCH_OPT_WRONG;
291
292 if (fmatch != FMATCH_OK)
293 break;
294 }
295
296 if (fmatch != FMATCH_OPT_WRONG) {
297 fmatch = FMATCH_WRONG;
298
299 switch (check_WSS) {
300 case OSF_WSS_PLAIN:
301 if (f->wss.val == 0 || window == f->wss.val)
302 fmatch = FMATCH_OK;
303 break;
304 case OSF_WSS_MSS:
305 /*
306 * Some smart modems decrease mangle MSS to
307 * SMART_MSS_2, so we check standard, decreased
308 * and the one provided in the fingerprint MSS
309 * values.
310 */
311#define SMART_MSS_1 1460
312#define SMART_MSS_2 1448
313 if (window == f->wss.val * mss ||
314 window == f->wss.val * SMART_MSS_1 ||
315 window == f->wss.val * SMART_MSS_2)
316 fmatch = FMATCH_OK;
317 break;
318 case OSF_WSS_MTU:
319 if (window == f->wss.val * (mss + 40) ||
320 window == f->wss.val * (SMART_MSS_1 + 40) ||
321 window == f->wss.val * (SMART_MSS_2 + 40))
322 fmatch = FMATCH_OK;
323 break;
324 case OSF_WSS_MODULO:
325 if ((window % f->wss.val) == 0)
326 fmatch = FMATCH_OK;
327 break;
328 }
329 }
330
331 if (fmatch != FMATCH_OK)
332 continue;
333
334 fcount++;
335
336 if (info->flags & XT_OSF_LOG)
337 nf_log_packet(net, xt_family(p), xt_hooknum(p), skb,
338 xt_in(p), xt_out(p), NULL,
339 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
340 f->genre, f->version, f->subtype,
341 &ip->saddr, ntohs(tcp->source),
342 &ip->daddr, ntohs(tcp->dest),
343 f->ttl - ip->ttl);
344
345 if ((info->flags & XT_OSF_LOG) &&
346 info->loglevel == XT_OSF_LOGLEVEL_FIRST)
347 break;
348 }
349
350 if (!fcount && (info->flags & XT_OSF_LOG))
351 nf_log_packet(net, xt_family(p), xt_hooknum(p), skb, xt_in(p),
352 xt_out(p), NULL,
353 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
354 &ip->saddr, ntohs(tcp->source),
355 &ip->daddr, ntohs(tcp->dest));
356
357 if (fcount)
358 fmatch = FMATCH_OK;
359
360 return fmatch == FMATCH_OK;
361}163}
362 164
363static struct xt_match xt_osf_match = {165static struct xt_match xt_osf_match = {