pf_osfp.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /* $OpenBSD: pf_osfp.c,v 1.31 2015/07/18 19:19:00 sashan Exp $ */
  2. /*
  3. * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. *
  17. */
  18. #include <sys/param.h>
  19. #include <sys/socket.h>
  20. #ifdef _KERNEL
  21. # include <sys/systm.h>
  22. #include <sys/pool.h>
  23. #endif /* _KERNEL */
  24. #include <sys/mbuf.h>
  25. #include <sys/syslog.h>
  26. #include <netinet/in.h>
  27. #include <netinet/ip.h>
  28. #include <netinet/tcp.h>
  29. #include <net/if.h>
  30. #include <net/pfvar.h>
  31. #include <netinet/ip6.h>
  32. #ifdef _KERNEL
  33. typedef struct pool pool_t;
  34. #else /* !_KERNEL */
  35. /* Userland equivalents so we can lend code to tcpdump et al. */
  36. # include <arpa/inet.h>
  37. # include <errno.h>
  38. # include <stdio.h>
  39. # include <stdlib.h>
  40. # include <string.h>
  41. # include <netdb.h>
  42. # define pool_t int
  43. # define pool_get(pool, flags) malloc(*(pool))
  44. # define pool_put(pool, item) free(item)
  45. # define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size)
  46. # ifdef PFDEBUG
  47. # include <sys/stdarg.h> /* for DPFPRINTF() */
  48. # endif /* PFDEBUG */
  49. #endif /* _KERNEL */
  50. SLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list;
  51. pool_t pf_osfp_entry_pl;
  52. pool_t pf_osfp_pl;
  53. struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *,
  54. struct pf_os_fingerprint *, u_int8_t);
  55. struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *,
  56. struct pf_os_fingerprint *);
  57. void pf_osfp_insert(struct pf_osfp_list *,
  58. struct pf_os_fingerprint *);
  59. #ifdef _KERNEL
  60. /*
  61. * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only)
  62. * Returns the list of possible OSes.
  63. */
  64. struct pf_osfp_enlist *
  65. pf_osfp_fingerprint(struct pf_pdesc *pd)
  66. {
  67. struct tcphdr *th = pd->hdr.tcp;
  68. struct ip *ip = NULL;
  69. struct ip6_hdr *ip6 = NULL;
  70. char hdr[60];
  71. if (pd->proto != IPPROTO_TCP)
  72. return (NULL);
  73. switch (pd->af) {
  74. case AF_INET:
  75. ip = mtod(pd->m, struct ip *);
  76. break;
  77. case AF_INET6:
  78. ip6 = mtod(pd->m, struct ip6_hdr *);
  79. break;
  80. }
  81. if (!pf_pull_hdr(pd->m, pd->off, hdr, th->th_off << 2, NULL, NULL,
  82. pd->af))
  83. return (NULL);
  84. return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
  85. }
  86. #endif /* _KERNEL */
  87. struct pf_osfp_enlist *
  88. pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6,
  89. const struct tcphdr *tcp)
  90. {
  91. struct pf_os_fingerprint fp, *fpresult;
  92. int cnt, optlen = 0;
  93. const u_int8_t *optp;
  94. #ifdef _KERNEL
  95. char srcname[128];
  96. #else /* !_KERNEL */
  97. char srcname[NI_MAXHOST];
  98. #endif /* _KERNEL */
  99. if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
  100. return (NULL);
  101. if (ip) {
  102. if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
  103. return (NULL);
  104. }
  105. memset(&fp, 0, sizeof(fp));
  106. if (ip) {
  107. #ifndef _KERNEL
  108. struct sockaddr_in sin;
  109. #endif /* _KERNEL */
  110. fp.fp_psize = ntohs(ip->ip_len);
  111. fp.fp_ttl = ip->ip_ttl;
  112. if (ip->ip_off & htons(IP_DF))
  113. fp.fp_flags |= PF_OSFP_DF;
  114. #ifdef _KERNEL
  115. inet_ntop(AF_INET, &ip->ip_src, srcname, sizeof(srcname));
  116. #else /* !_KERNEL */
  117. memset(&sin, 0, sizeof(sin));
  118. sin.sin_family = AF_INET;
  119. sin.sin_len = sizeof(struct sockaddr_in);
  120. sin.sin_addr = ip->ip_src;
  121. (void)getnameinfo((struct sockaddr *)&sin,
  122. sizeof(struct sockaddr_in), srcname, sizeof(srcname),
  123. NULL, 0, NI_NUMERICHOST);
  124. #endif /* _KERNEL */
  125. }
  126. #ifdef INET6
  127. else if (ip6) {
  128. #ifndef _KERNEL
  129. struct sockaddr_in6 sin6;
  130. #endif /* !_KERNEL */
  131. /* jumbo payload? */
  132. fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
  133. fp.fp_ttl = ip6->ip6_hlim;
  134. fp.fp_flags |= PF_OSFP_DF;
  135. fp.fp_flags |= PF_OSFP_INET6;
  136. #ifdef _KERNEL
  137. inet_ntop(AF_INET6, &ip6->ip6_src, srcname, sizeof(srcname));
  138. #else /* !_KERNEL */
  139. memset(&sin6, 0, sizeof(sin6));
  140. sin6.sin6_family = AF_INET6;
  141. sin6.sin6_len = sizeof(struct sockaddr_in6);
  142. sin6.sin6_addr = ip6->ip6_src;
  143. (void)getnameinfo((struct sockaddr *)&sin6,
  144. sizeof(struct sockaddr_in6), srcname, sizeof(srcname),
  145. NULL, 0, NI_NUMERICHOST);
  146. #endif /* !_KERNEL */
  147. }
  148. #endif /* INET6 */
  149. else
  150. return (NULL);
  151. fp.fp_wsize = ntohs(tcp->th_win);
  152. cnt = (tcp->th_off << 2) - sizeof(*tcp);
  153. optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp));
  154. for (; cnt > 0; cnt -= optlen, optp += optlen) {
  155. if (*optp == TCPOPT_EOL)
  156. break;
  157. fp.fp_optcnt++;
  158. if (*optp == TCPOPT_NOP) {
  159. fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) |
  160. PF_OSFP_TCPOPT_NOP;
  161. optlen = 1;
  162. } else {
  163. if (cnt < 2)
  164. return (NULL);
  165. optlen = optp[1];
  166. if (optlen > cnt || optlen < 2)
  167. return (NULL);
  168. switch (*optp) {
  169. case TCPOPT_MAXSEG:
  170. if (optlen >= TCPOLEN_MAXSEG)
  171. memcpy(&fp.fp_mss, &optp[2],
  172. sizeof(fp.fp_mss));
  173. fp.fp_tcpopts = (fp.fp_tcpopts <<
  174. PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS;
  175. fp.fp_mss = ntohs(fp.fp_mss);
  176. break;
  177. case TCPOPT_WINDOW:
  178. if (optlen >= TCPOLEN_WINDOW)
  179. memcpy(&fp.fp_wscale, &optp[2],
  180. sizeof(fp.fp_wscale));
  181. fp.fp_tcpopts = (fp.fp_tcpopts <<
  182. PF_OSFP_TCPOPT_BITS) |
  183. PF_OSFP_TCPOPT_WSCALE;
  184. break;
  185. case TCPOPT_SACK_PERMITTED:
  186. fp.fp_tcpopts = (fp.fp_tcpopts <<
  187. PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK;
  188. break;
  189. case TCPOPT_TIMESTAMP:
  190. if (optlen >= TCPOLEN_TIMESTAMP) {
  191. u_int32_t ts;
  192. memcpy(&ts, &optp[2], sizeof(ts));
  193. if (ts == 0)
  194. fp.fp_flags |= PF_OSFP_TS0;
  195. }
  196. fp.fp_tcpopts = (fp.fp_tcpopts <<
  197. PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS;
  198. break;
  199. default:
  200. return (NULL);
  201. }
  202. }
  203. optlen = MAX(optlen, 1); /* paranoia */
  204. }
  205. DPFPRINTF(LOG_NOTICE,
  206. "fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
  207. "(TS=%s,M=%s%d,W=%s%d)",
  208. srcname, ntohs(tcp->th_sport),
  209. fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
  210. fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
  211. (fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
  212. (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
  213. (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
  214. fp.fp_mss,
  215. (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
  216. (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
  217. fp.fp_wscale);
  218. if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp,
  219. PF_OSFP_MAXTTL_OFFSET)))
  220. return (&fpresult->fp_oses);
  221. return (NULL);
  222. }
  223. /* Match a fingerprint ID against a list of OSes */
  224. int
  225. pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
  226. {
  227. struct pf_osfp_entry *entry;
  228. int os_class, os_version, os_subtype;
  229. int en_class, en_version, en_subtype;
  230. if (os == PF_OSFP_ANY)
  231. return (1);
  232. if (list == NULL) {
  233. DPFPRINTF(LOG_NOTICE, "osfp no match against %x", os);
  234. return (os == PF_OSFP_UNKNOWN);
  235. }
  236. PF_OSFP_UNPACK(os, os_class, os_version, os_subtype);
  237. SLIST_FOREACH(entry, list, fp_entry) {
  238. PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype);
  239. if ((os_class == PF_OSFP_ANY || en_class == os_class) &&
  240. (os_version == PF_OSFP_ANY || en_version == os_version) &&
  241. (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) {
  242. DPFPRINTF(LOG_NOTICE,
  243. "osfp matched %s %s %s %x==%x",
  244. entry->fp_class_nm, entry->fp_version_nm,
  245. entry->fp_subtype_nm, os, entry->fp_os);
  246. return (1);
  247. }
  248. }
  249. DPFPRINTF(LOG_NOTICE, "fingerprint 0x%x didn't match", os);
  250. return (0);
  251. }
  252. /* Initialize the OS fingerprint system */
  253. void
  254. pf_osfp_initialize(void)
  255. {
  256. pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
  257. "pfosfpen", &pool_allocator_nointr);
  258. pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
  259. "pfosfp", &pool_allocator_nointr);
  260. SLIST_INIT(&pf_osfp_list);
  261. }
  262. /* Flush the fingerprint list */
  263. void
  264. pf_osfp_flush(void)
  265. {
  266. struct pf_os_fingerprint *fp;
  267. struct pf_osfp_entry *entry;
  268. while ((fp = SLIST_FIRST(&pf_osfp_list))) {
  269. SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next);
  270. while ((entry = SLIST_FIRST(&fp->fp_oses))) {
  271. SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry);
  272. pool_put(&pf_osfp_entry_pl, entry);
  273. }
  274. pool_put(&pf_osfp_pl, fp);
  275. }
  276. }
  277. /* Add a fingerprint */
  278. int
  279. pf_osfp_add(struct pf_osfp_ioctl *fpioc)
  280. {
  281. struct pf_os_fingerprint *fp, fpadd;
  282. struct pf_osfp_entry *entry;
  283. memset(&fpadd, 0, sizeof(fpadd));
  284. fpadd.fp_tcpopts = fpioc->fp_tcpopts;
  285. fpadd.fp_wsize = fpioc->fp_wsize;
  286. fpadd.fp_psize = fpioc->fp_psize;
  287. fpadd.fp_mss = fpioc->fp_mss;
  288. fpadd.fp_flags = fpioc->fp_flags;
  289. fpadd.fp_optcnt = fpioc->fp_optcnt;
  290. fpadd.fp_wscale = fpioc->fp_wscale;
  291. fpadd.fp_ttl = fpioc->fp_ttl;
  292. DPFPRINTF(LOG_DEBUG,
  293. "adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d "
  294. "(TS=%s,M=%s%d,W=%s%d) %x",
  295. fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm,
  296. fpioc->fp_os.fp_subtype_nm,
  297. (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" :
  298. (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" :
  299. (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" :
  300. (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "",
  301. fpadd.fp_wsize,
  302. fpadd.fp_ttl,
  303. (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0,
  304. (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" :
  305. (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "",
  306. fpadd.fp_psize,
  307. (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt,
  308. (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "",
  309. (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
  310. (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
  311. fpadd.fp_mss,
  312. (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
  313. (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
  314. fpadd.fp_wscale,
  315. fpioc->fp_os.fp_os);
  316. if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) {
  317. SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
  318. if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os))
  319. return (EEXIST);
  320. }
  321. if ((entry = pool_get(&pf_osfp_entry_pl,
  322. PR_WAITOK|PR_LIMITFAIL)) == NULL)
  323. return (ENOMEM);
  324. } else {
  325. if ((fp = pool_get(&pf_osfp_pl,
  326. PR_WAITOK|PR_ZERO|PR_LIMITFAIL)) == NULL)
  327. return (ENOMEM);
  328. fp->fp_tcpopts = fpioc->fp_tcpopts;
  329. fp->fp_wsize = fpioc->fp_wsize;
  330. fp->fp_psize = fpioc->fp_psize;
  331. fp->fp_mss = fpioc->fp_mss;
  332. fp->fp_flags = fpioc->fp_flags;
  333. fp->fp_optcnt = fpioc->fp_optcnt;
  334. fp->fp_wscale = fpioc->fp_wscale;
  335. fp->fp_ttl = fpioc->fp_ttl;
  336. SLIST_INIT(&fp->fp_oses);
  337. if ((entry = pool_get(&pf_osfp_entry_pl,
  338. PR_WAITOK|PR_LIMITFAIL)) == NULL) {
  339. pool_put(&pf_osfp_pl, fp);
  340. return (ENOMEM);
  341. }
  342. pf_osfp_insert(&pf_osfp_list, fp);
  343. }
  344. memcpy(entry, &fpioc->fp_os, sizeof(*entry));
  345. /* Make sure the strings are NUL terminated */
  346. entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0';
  347. entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0';
  348. entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0';
  349. SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry);
  350. #ifdef PFDEBUG
  351. if ((fp = pf_osfp_validate()))
  352. DPFPRINTF(LOG_NOTICE,
  353. "Invalid fingerprint list");
  354. #endif /* PFDEBUG */
  355. return (0);
  356. }
  357. /* Find a fingerprint in the list */
  358. struct pf_os_fingerprint *
  359. pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find,
  360. u_int8_t ttldiff)
  361. {
  362. struct pf_os_fingerprint *f;
  363. #define MATCH_INT(_MOD, _DC, _field) \
  364. if ((f->fp_flags & _DC) == 0) { \
  365. if ((f->fp_flags & _MOD) == 0) { \
  366. if (f->_field != find->_field) \
  367. continue; \
  368. } else { \
  369. if (f->_field == 0 || find->_field % f->_field) \
  370. continue; \
  371. } \
  372. }
  373. SLIST_FOREACH(f, list, fp_next) {
  374. if (f->fp_tcpopts != find->fp_tcpopts ||
  375. f->fp_optcnt != find->fp_optcnt ||
  376. f->fp_ttl < find->fp_ttl ||
  377. f->fp_ttl - find->fp_ttl > ttldiff ||
  378. (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) !=
  379. (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)))
  380. continue;
  381. MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize)
  382. MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss)
  383. MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale)
  384. if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) {
  385. if (f->fp_flags & PF_OSFP_WSIZE_MSS) {
  386. if (find->fp_mss == 0)
  387. continue;
  388. /* Some "smart" NAT devices and DSL routers will tweak the MSS size and
  389. * will set it to whatever is suitable for the link type.
  390. */
  391. #define SMART_MSS 1460
  392. if ((find->fp_wsize % find->fp_mss ||
  393. find->fp_wsize / find->fp_mss !=
  394. f->fp_wsize) &&
  395. (find->fp_wsize % SMART_MSS ||
  396. find->fp_wsize / SMART_MSS !=
  397. f->fp_wsize))
  398. continue;
  399. } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) {
  400. if (find->fp_mss == 0)
  401. continue;
  402. #define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr))
  403. #define SMART_MTU (SMART_MSS + MTUOFF)
  404. if ((find->fp_wsize % (find->fp_mss + MTUOFF) ||
  405. find->fp_wsize / (find->fp_mss + MTUOFF) !=
  406. f->fp_wsize) &&
  407. (find->fp_wsize % SMART_MTU ||
  408. find->fp_wsize / SMART_MTU !=
  409. f->fp_wsize))
  410. continue;
  411. } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) {
  412. if (f->fp_wsize == 0 || find->fp_wsize %
  413. f->fp_wsize)
  414. continue;
  415. } else {
  416. if (f->fp_wsize != find->fp_wsize)
  417. continue;
  418. }
  419. }
  420. return (f);
  421. }
  422. return (NULL);
  423. }
  424. /* Find an exact fingerprint in the list */
  425. struct pf_os_fingerprint *
  426. pf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find)
  427. {
  428. struct pf_os_fingerprint *f;
  429. SLIST_FOREACH(f, list, fp_next) {
  430. if (f->fp_tcpopts == find->fp_tcpopts &&
  431. f->fp_wsize == find->fp_wsize &&
  432. f->fp_psize == find->fp_psize &&
  433. f->fp_mss == find->fp_mss &&
  434. f->fp_flags == find->fp_flags &&
  435. f->fp_optcnt == find->fp_optcnt &&
  436. f->fp_wscale == find->fp_wscale &&
  437. f->fp_ttl == find->fp_ttl)
  438. return (f);
  439. }
  440. return (NULL);
  441. }
  442. /* Insert a fingerprint into the list */
  443. void
  444. pf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins)
  445. {
  446. struct pf_os_fingerprint *f, *prev = NULL;
  447. /* XXX need to go semi tree based. can key on tcp options */
  448. SLIST_FOREACH(f, list, fp_next)
  449. prev = f;
  450. if (prev)
  451. SLIST_INSERT_AFTER(prev, ins, fp_next);
  452. else
  453. SLIST_INSERT_HEAD(list, ins, fp_next);
  454. }
  455. /* Fill a fingerprint by its number (from an ioctl) */
  456. int
  457. pf_osfp_get(struct pf_osfp_ioctl *fpioc)
  458. {
  459. struct pf_os_fingerprint *fp;
  460. struct pf_osfp_entry *entry;
  461. int num = fpioc->fp_getnum;
  462. int i = 0;
  463. memset(fpioc, 0, sizeof(*fpioc));
  464. SLIST_FOREACH(fp, &pf_osfp_list, fp_next) {
  465. SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
  466. if (i++ == num) {
  467. fpioc->fp_mss = fp->fp_mss;
  468. fpioc->fp_wsize = fp->fp_wsize;
  469. fpioc->fp_flags = fp->fp_flags;
  470. fpioc->fp_psize = fp->fp_psize;
  471. fpioc->fp_ttl = fp->fp_ttl;
  472. fpioc->fp_wscale = fp->fp_wscale;
  473. fpioc->fp_getnum = num;
  474. memcpy(&fpioc->fp_os, entry,
  475. sizeof(fpioc->fp_os));
  476. return (0);
  477. }
  478. }
  479. }
  480. return (EBUSY);
  481. }
  482. /* Validate that each signature is reachable */
  483. struct pf_os_fingerprint *
  484. pf_osfp_validate(void)
  485. {
  486. struct pf_os_fingerprint *f, *f2, find;
  487. SLIST_FOREACH(f, &pf_osfp_list, fp_next) {
  488. memcpy(&find, f, sizeof(find));
  489. /* We do a few MSS/th_win percolations to make things unique */
  490. if (find.fp_mss == 0)
  491. find.fp_mss = 128;
  492. if (f->fp_flags & PF_OSFP_WSIZE_MSS)
  493. find.fp_wsize *= find.fp_mss;
  494. else if (f->fp_flags & PF_OSFP_WSIZE_MTU)
  495. find.fp_wsize *= (find.fp_mss + 40);
  496. else if (f->fp_flags & PF_OSFP_WSIZE_MOD)
  497. find.fp_wsize *= 2;
  498. if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) {
  499. if (f2)
  500. DPFPRINTF(LOG_NOTICE,
  501. "Found \"%s %s %s\" instead of "
  502. "\"%s %s %s\"\n",
  503. SLIST_FIRST(&f2->fp_oses)->fp_class_nm,
  504. SLIST_FIRST(&f2->fp_oses)->fp_version_nm,
  505. SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm,
  506. SLIST_FIRST(&f->fp_oses)->fp_class_nm,
  507. SLIST_FIRST(&f->fp_oses)->fp_version_nm,
  508. SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
  509. else
  510. DPFPRINTF(LOG_NOTICE,
  511. "Couldn't find \"%s %s %s\"\n",
  512. SLIST_FIRST(&f->fp_oses)->fp_class_nm,
  513. SLIST_FIRST(&f->fp_oses)->fp_version_nm,
  514. SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
  515. return (f);
  516. }
  517. }
  518. return (NULL);
  519. }