Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Fernando Fernandez Mancera and committed by
Pablo Neira Ayuso
bfb15f2a 3f9c56a5

+359 -289
+27
include/linux/netfilter/nf_osf.h
··· 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 + */ 7 + enum 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 + 15 + enum 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 + 24 + bool 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);
+90
include/uapi/linux/netfilter/nf_osf.h
··· 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 + */ 24 + struct 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 + */ 32 + struct nf_osf_opt { 33 + __u16 kind, length; 34 + struct nf_osf_wc wc; 35 + }; 36 + 37 + struct nf_osf_info { 38 + char genre[MAXGENRELEN]; 39 + __u32 len; 40 + __u32 flags; 41 + __u32 loglevel; 42 + __u32 ttl; 43 + }; 44 + 45 + struct 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 + 60 + struct nf_osf_finger { 61 + struct rcu_head rcu_head; 62 + struct list_head finger_entry; 63 + struct nf_osf_user_finger finger; 64 + }; 65 + 66 + struct 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 */ 73 + enum 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 */
+17 -89
include/uapi/linux/netfilter/xt_osf.h
··· 23 23 #include <linux/types.h> 24 24 #include <linux/ip.h> 25 25 #include <linux/tcp.h> 26 + #include <linux/netfilter/nf_osf.h> 26 27 27 - #define MAXGENRELEN 32 28 + #define XT_OSF_GENRE NF_OSF_GENRE 29 + #define XT_OSF_INVERT NF_OSF_INVERT 28 30 29 - #define XT_OSF_GENRE (1<<0) 30 - #define XT_OSF_TTL (1<<1) 31 - #define XT_OSF_LOG (1<<2) 32 - #define XT_OSF_INVERT (1<<3) 31 + #define XT_OSF_TTL NF_OSF_TTL 32 + #define XT_OSF_LOG NF_OSF_LOG 33 33 34 - #define XT_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */ 35 - #define XT_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */ 36 - #define XT_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */ 34 + #define XT_OSF_LOGLEVEL_ALL NF_OSF_LOGLEVEL_ALL 35 + #define XT_OSF_LOGLEVEL_FIRST NF_OSF_LOGLEVEL_FIRST 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 */ 39 - #define XT_OSF_TTL_LESS 1 /* Check if ip TTL is less than fingerprint one */ 40 - #define XT_OSF_TTL_NOCHECK 2 /* Do not compare ip and fingerprint TTL at all */ 38 + #define XT_OSF_TTL_TRUE NF_OSF_TTL_TRUE 39 + #define XT_OSF_TTL_NOCHECK NF_OSF_TTL_NOCHECK 41 40 42 - struct xt_osf_info { 43 - char genre[MAXGENRELEN]; 44 - __u32 len; 45 - __u32 flags; 46 - __u32 loglevel; 47 - __u32 ttl; 48 - }; 41 + #define XT_OSF_TTL_LESS 1 /* Check if ip TTL is less than fingerprint one */ 49 42 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 - */ 55 - struct 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 - */ 64 - struct xt_osf_opt { 65 - __u16 kind, length; 66 - struct xt_osf_wc wc; 67 - }; 68 - 69 - struct 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 - 80 - /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */ 81 - struct xt_osf_opt opt[MAX_IPOPTLEN]; 82 - }; 83 - 84 - struct xt_osf_nlmsg { 85 - struct xt_osf_user_finger f; 86 - struct iphdr ip; 87 - struct tcphdr tcp; 88 - }; 89 - 90 - /* Defines for IANA option kinds */ 91 - 92 - enum 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 - */ 114 - enum 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 - }; 43 + #define xt_osf_wc nf_osf_wc 44 + #define xt_osf_opt nf_osf_opt 45 + #define xt_osf_info nf_osf_info 46 + #define xt_osf_user_finger nf_osf_user_finger 47 + #define xt_osf_finger nf_osf_finger 48 + #define xt_osf_nlmsg nf_osf_nlmsg 121 49 122 50 /* 123 51 * Add/remove fingerprint from the kernel.
+4
net/netfilter/Kconfig
··· 444 444 445 445 endif # NF_CONNTRACK 446 446 447 + config NF_OSF 448 + tristate 'Passive OS fingerprint infrastructure' 449 + 447 450 config NF_TABLES 448 451 select NETFILTER_NETLINK 449 452 tristate "Netfilter nf_tables support" ··· 1361 1358 config NETFILTER_XT_MATCH_OSF 1362 1359 tristate '"osf" Passive OS fingerprint match' 1363 1360 depends on NETFILTER_ADVANCED && NETFILTER_NETLINK 1361 + select NF_OSF 1364 1362 help 1365 1363 This option selects the Passive OS Fingerprinting match module 1366 1364 that allows to passively match the remote operating system by
+1
net/netfilter/Makefile
··· 101 101 obj-$(CONFIG_NFT_FIB) += nft_fib.o 102 102 obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o 103 103 obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o 104 + obj-$(CONFIG_NF_OSF) += nf_osf.o 104 105 105 106 # nf_tables netdev 106 107 obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o
+218
net/netfilter/nf_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/nf_osf.h> 22 + 23 + static 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 + 55 + bool 56 + nf_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 + } 216 + EXPORT_SYMBOL_GPL(nf_osf_match); 217 + 218 + MODULE_LICENSE("GPL");
+2 -200
net/netfilter/xt_osf.c
··· 37 37 #include <net/netfilter/nf_log.h> 38 38 #include <linux/netfilter/xt_osf.h> 39 39 40 - struct xt_osf_finger { 41 - struct rcu_head rcu_head; 42 - struct list_head finger_entry; 43 - struct xt_osf_user_finger finger; 44 - }; 45 - 46 - enum 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 41 * Indexed by dont-fragment bit. 57 42 * It is the only constant value in the fingerprint. ··· 149 164 .cb = xt_osf_nfnetlink_callbacks, 150 165 }; 151 166 152 - static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info, 153 - unsigned char f_ttl) 154 - { 155 - const struct iphdr *ip = ip_hdr(skb); 156 - 157 - if (info->flags & XT_OSF_TTL) { 158 - if (info->ttl == XT_OSF_TTL_TRUE) 159 - return ip->ttl == f_ttl; 160 - if (info->ttl == XT_OSF_TTL_NOCHECK) 161 - return 1; 162 - else if (ip->ttl <= f_ttl) 163 - return 1; 164 - else { 165 - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); 166 - int ret = 0; 167 - 168 - for_ifa(in_dev) { 169 - if (inet_ifa_match(ip->saddr, ifa)) { 170 - ret = (ip->ttl == f_ttl); 171 - break; 172 - } 173 - } 174 - endfor_ifa(in_dev); 175 - 176 - return ret; 177 - } 178 - } 179 - 180 - return ip->ttl == f_ttl; 181 - } 182 - 183 167 static bool 184 168 xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) 185 169 { 186 170 const struct xt_osf_info *info = p->matchinfo; 187 - const struct iphdr *ip = ip_hdr(skb); 188 - const struct tcphdr *tcp; 189 - struct tcphdr _tcph; 190 - int fmatch = FMATCH_WRONG, fcount = 0; 191 - unsigned int optsize = 0, check_WSS = 0; 192 - u16 window, totlen, mss = 0; 193 - bool df; 194 - const unsigned char *optp = NULL, *_optp = NULL; 195 - unsigned char opts[MAX_IPOPTLEN]; 196 - const struct xt_osf_finger *kf; 197 - const struct xt_osf_user_finger *f; 198 171 struct net *net = xt_net(p); 199 172 200 173 if (!info) 201 174 return false; 202 175 203 - tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph); 204 - if (!tcp) 205 - return false; 206 - 207 - if (!tcp->syn) 208 - return false; 209 - 210 - totlen = ntohs(ip->tot_len); 211 - df = ntohs(ip->frag_off) & IP_DF; 212 - window = ntohs(tcp->window); 213 - 214 - if (tcp->doff * 4 > sizeof(struct tcphdr)) { 215 - optsize = tcp->doff * 4 - sizeof(struct tcphdr); 216 - 217 - _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) + 218 - sizeof(struct tcphdr), optsize, opts); 219 - } 220 - 221 - list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) { 222 - int foptsize, optnum; 223 - 224 - f = &kf->finger; 225 - 226 - if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre)) 227 - continue; 228 - 229 - optp = _optp; 230 - fmatch = FMATCH_WRONG; 231 - 232 - if (totlen != f->ss || !xt_osf_ttl(skb, info, f->ttl)) 233 - continue; 234 - 235 - /* 236 - * Should not happen if userspace parser was written correctly. 237 - */ 238 - if (f->wss.wc >= OSF_WSS_MAX) 239 - continue; 240 - 241 - /* Check options */ 242 - 243 - foptsize = 0; 244 - for (optnum = 0; optnum < f->opt_num; ++optnum) 245 - foptsize += f->opt[optnum].length; 246 - 247 - if (foptsize > MAX_IPOPTLEN || 248 - optsize > MAX_IPOPTLEN || 249 - optsize != foptsize) 250 - continue; 251 - 252 - check_WSS = f->wss.wc; 253 - 254 - for (optnum = 0; optnum < f->opt_num; ++optnum) { 255 - if (f->opt[optnum].kind == (*optp)) { 256 - __u32 len = f->opt[optnum].length; 257 - const __u8 *optend = optp + len; 258 - 259 - fmatch = FMATCH_OK; 260 - 261 - switch (*optp) { 262 - case OSFOPT_MSS: 263 - mss = optp[3]; 264 - mss <<= 8; 265 - mss |= optp[2]; 266 - 267 - mss = ntohs((__force __be16)mss); 268 - break; 269 - case OSFOPT_TS: 270 - break; 271 - } 272 - 273 - optp = optend; 274 - } else 275 - fmatch = FMATCH_OPT_WRONG; 276 - 277 - if (fmatch != FMATCH_OK) 278 - break; 279 - } 280 - 281 - if (fmatch != FMATCH_OPT_WRONG) { 282 - fmatch = FMATCH_WRONG; 283 - 284 - switch (check_WSS) { 285 - case OSF_WSS_PLAIN: 286 - if (f->wss.val == 0 || window == f->wss.val) 287 - fmatch = FMATCH_OK; 288 - break; 289 - case OSF_WSS_MSS: 290 - /* 291 - * Some smart modems decrease mangle MSS to 292 - * SMART_MSS_2, so we check standard, decreased 293 - * and the one provided in the fingerprint MSS 294 - * values. 295 - */ 296 - #define SMART_MSS_1 1460 297 - #define SMART_MSS_2 1448 298 - if (window == f->wss.val * mss || 299 - window == f->wss.val * SMART_MSS_1 || 300 - window == f->wss.val * SMART_MSS_2) 301 - fmatch = FMATCH_OK; 302 - break; 303 - case OSF_WSS_MTU: 304 - if (window == f->wss.val * (mss + 40) || 305 - window == f->wss.val * (SMART_MSS_1 + 40) || 306 - window == f->wss.val * (SMART_MSS_2 + 40)) 307 - fmatch = FMATCH_OK; 308 - break; 309 - case OSF_WSS_MODULO: 310 - if ((window % f->wss.val) == 0) 311 - fmatch = FMATCH_OK; 312 - break; 313 - } 314 - } 315 - 316 - if (fmatch != FMATCH_OK) 317 - continue; 318 - 319 - fcount++; 320 - 321 - if (info->flags & XT_OSF_LOG) 322 - nf_log_packet(net, xt_family(p), xt_hooknum(p), skb, 323 - xt_in(p), xt_out(p), NULL, 324 - "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n", 325 - f->genre, f->version, f->subtype, 326 - &ip->saddr, ntohs(tcp->source), 327 - &ip->daddr, ntohs(tcp->dest), 328 - f->ttl - ip->ttl); 329 - 330 - if ((info->flags & XT_OSF_LOG) && 331 - info->loglevel == XT_OSF_LOGLEVEL_FIRST) 332 - break; 333 - } 334 - 335 - if (!fcount && (info->flags & XT_OSF_LOG)) 336 - nf_log_packet(net, xt_family(p), xt_hooknum(p), skb, xt_in(p), 337 - xt_out(p), NULL, 338 - "Remote OS is not known: %pI4:%u -> %pI4:%u\n", 339 - &ip->saddr, ntohs(tcp->source), 340 - &ip->daddr, ntohs(tcp->dest)); 341 - 342 - if (fcount) 343 - fmatch = FMATCH_OK; 344 - 345 - return fmatch == FMATCH_OK; 176 + return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p), 177 + xt_out(p), info, net, xt_osf_fingers); 346 178 } 347 179 348 180 static struct xt_match xt_osf_match = {