├── .gitignore ├── fingerprints-captures ├── capture-chrome_linux_125_0_6422_141.pcap ├── capture-chrome_linux_126_0_6478_126.pcap ├── capture-chrome_linux_126_0_6478_182.pcap ├── capture-chrome_linux_126_0_6478_55.pcap ├── capture-chrome_linux_126_0_6478_61.pcap ├── capture-chrome_linux_126_0_6478_62.pcap ├── capture-chrome_linux_126_0_6478_63.pcap ├── capture-chrome_linux_127_0_6533_119.pcap ├── capture-chrome_linux_127_0_6533_72.pcap ├── capture-chrome_linux_127_0_6533_88.pcap ├── capture-chrome_linux_127_0_6533_99.pcap ├── capture-chrome_linux_128_0_6613_119.pcap ├── capture-chrome_linux_128_0_6613_137.pcap ├── capture-chrome_linux_129_0_6668_58.pcap ├── capture-chrome_linux_129_0_6668_70.pcap ├── capture-chrome_linux_129_0_6668_89.pcap ├── capture-chrome_linux_131_0_6778_108.pcap ├── capture-chrome_linux_131_0_6778_204.pcap ├── capture-chrome_linux_131_0_6778_264.pcap ├── capture-chrome_linux_131_0_6778_85.pcap ├── capture-chrome_linux_131_0_6778_87.pcap ├── capture-chrome_linux_132_0_6834_110.pcap ├── capture-chrome_linux_132_0_6834_159.pcap ├── capture-chrome_linux_132_0_6834_83.pcap ├── capture-chrome_linux_133_0_6943_126.pcap ├── capture-chrome_linux_133_0_6943_141.pcap ├── capture-chrome_linux_133_0_6943_53.pcap ├── capture-chrome_linux_133_0_6943_98.pcap ├── capture-chrome_linux_134_0_6998_165.pcap ├── capture-chrome_linux_134_0_6998_35.pcap ├── capture-chrome_linux_134_0_6998_88.pcap ├── capture-chrome_linux_134_0_6998_90.pcap ├── capture-chrome_linux_135_0_7049_114.pcap ├── capture-chrome_linux_135_0_7049_42.pcap ├── capture-chrome_linux_135_0_7049_84.pcap ├── capture-chrome_linux_135_0_7049_95.pcap ├── capture-chrome_linux_135_0_7049_97.pcap ├── capture-chrome_linux_136_0_7103_113.pcap ├── capture-chrome_linux_136_0_7103_49.pcap ├── capture-chrome_linux_136_0_7103_92.pcap ├── capture-chrome_linux_136_0_7103_94.pcap ├── capture-chrome_linux_137_0_7151_119.pcap ├── capture-chrome_linux_137_0_7151_55.pcap ├── capture-chrome_linux_137_0_7151_68.pcap ├── capture-chrome_linux_137_0_7151_70.pcap ├── capture-chrome_linux_138_0_7204_157.pcap ├── capture-chrome_linux_138_0_7204_168.pcap ├── capture-chrome_linux_138_0_7204_183.pcap ├── capture-chrome_linux_138_0_7204_49.pcap ├── capture-chrome_linux_138_0_7204_92.pcap ├── capture-chrome_linux_138_0_7204_94.pcap ├── capture-chrome_linux_139_0_7258_138.pcap ├── capture-chrome_linux_139_0_7258_154.pcap ├── capture-chrome_linux_139_0_7258_66.pcap ├── capture-chrome_linux_139_0_7258_68.pcap ├── capture-chrome_linux_140_0_7339_185.pcap ├── capture-chrome_linux_140_0_7339_207.pcap ├── capture-chrome_linux_140_0_7339_80.pcap ├── capture-chrome_linux_140_0_7339_82.pcap ├── capture-chrome_linux_141_0_7390_122.pcap ├── capture-chrome_linux_141_0_7390_54.pcap ├── capture-chrome_linux_141_0_7390_65.pcap ├── capture-chrome_linux_141_0_7390_76.pcap ├── capture-chrome_linux_141_0_7390_78.pcap ├── capture-chrome_linux_142_0_7444_162.pcap ├── capture-chrome_linux_142_0_7444_175.pcap ├── capture-chrome_linux_142_0_7444_59.pcap ├── capture-chrome_linux_142_0_7444_61.pcap ├── capture-chrome_linux_143_0_7499_146.pcap ├── capture-chrome_linux_143_0_7499_169.pcap ├── capture-chrome_linux_143_0_7499_40.pcap ├── capture-chrome_linux_143_0_7499_42.pcap ├── capture-firefox_linux_stable_126_0_1.pcap ├── capture-firefox_linux_stable_127_0.pcap ├── capture-firefox_linux_stable_127_0_1.pcap ├── capture-firefox_linux_stable_127_0_2.pcap ├── capture-firefox_linux_stable_128_0.pcap ├── capture-firefox_linux_stable_128_0_2.pcap ├── capture-firefox_linux_stable_128_0_3.pcap ├── capture-firefox_linux_stable_129_0.pcap ├── capture-firefox_linux_stable_129_0_1.pcap ├── capture-firefox_linux_stable_130_0.pcap ├── capture-firefox_linux_stable_130_0_1.pcap ├── capture-firefox_linux_stable_131_0.pcap ├── capture-firefox_linux_stable_133_0.pcap ├── capture-firefox_linux_stable_133_0_3.pcap ├── capture-firefox_linux_stable_134_0.pcap ├── capture-firefox_linux_stable_134_0_1.pcap ├── capture-firefox_linux_stable_134_0_2.pcap ├── capture-firefox_linux_stable_135_0.pcap ├── capture-firefox_linux_stable_135_0_1.pcap ├── capture-firefox_linux_stable_136_0.pcap ├── capture-firefox_linux_stable_136_0_1.pcap ├── capture-firefox_linux_stable_136_0_2.pcap ├── capture-firefox_linux_stable_136_0_3.pcap ├── capture-firefox_linux_stable_136_0_4.pcap ├── capture-firefox_linux_stable_137_0.pcap ├── capture-firefox_linux_stable_137_0_1.pcap ├── capture-firefox_linux_stable_137_0_2.pcap ├── capture-firefox_linux_stable_138_0.pcap ├── capture-firefox_linux_stable_138_0_1.pcap ├── capture-firefox_linux_stable_138_0_3.pcap ├── capture-firefox_linux_stable_138_0_4.pcap ├── capture-firefox_linux_stable_139_0.pcap ├── capture-firefox_linux_stable_139_0_1.pcap ├── capture-firefox_linux_stable_139_0_4.pcap ├── capture-firefox_linux_stable_140_0_2.pcap ├── capture-firefox_linux_stable_140_0_4.pcap ├── capture-firefox_linux_stable_141_0.pcap ├── capture-firefox_linux_stable_141_0_2.pcap ├── capture-firefox_linux_stable_141_0_3.pcap ├── capture-firefox_linux_stable_142_0.pcap ├── capture-firefox_linux_stable_142_0_1.pcap ├── capture-firefox_linux_stable_143_0.pcap ├── capture-firefox_linux_stable_143_0_1.pcap ├── capture-firefox_linux_stable_143_0_3.pcap ├── capture-firefox_linux_stable_143_0_4.pcap ├── capture-firefox_linux_stable_144_0.pcap ├── capture-firefox_linux_stable_144_0_2.pcap ├── capture-firefox_linux_stable_145_0.pcap ├── capture-firefox_linux_stable_145_0_1.pcap ├── capture-firefox_linux_stable_145_0_2.pcap ├── capture-firefox_linux_stable_146_0.pcap ├── capture-firefox_linux_stable_146_0_1.pcap ├── capture-firefox-Mozilla_Firefox_126_0.pcap ├── capture-firefox-Mozilla_Firefox_125_0_1.pcap ├── capture-firefox-Mozilla_Firefox_125_0_2.pcap ├── capture-firefox-Mozilla_Firefox_125_0_3.pcap ├── capture-firefox-Mozilla_Firefox_126_0_1.pcap ├── capture-chrome-Google_Chrome_124_0_6367_118_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_155_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_201_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_207_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_60_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_78_unknown.pcap ├── capture-chrome-Google_Chrome_124_0_6367_91_unknown.pcap ├── capture-chrome-Google_Chrome_125_0_6422_112_unknown.pcap ├── capture-chrome-Google_Chrome_125_0_6422_141_unknown.pcap ├── capture-chrome-Google_Chrome_125_0_6422_60_unknown.pcap └── capture-chrome-Google_Chrome_125_0_6422_76_unknown.pcap ├── pkg ├── utils │ ├── util_test.go │ ├── errors.go │ ├── fake_extension.go │ ├── cipher_suite.go │ ├── utils.go │ └── keyshare.go ├── mimicry │ ├── fingerprints_test.go │ ├── errors.go │ ├── extension.go │ ├── mimic_test.go │ └── mimic_client_hello.go ├── randomize │ ├── errors.go │ ├── extension.go │ └── randomize_client_hello.go └── fingerprints │ ├── fingerprints_13.go │ └── fingerprints.go ├── go.mod ├── .github └── workflows │ ├── browser-test │ ├── download-browsers.js │ ├── package.json │ ├── steps.js │ ├── LICENSE.md │ ├── interop │ │ └── connection.test.js │ ├── webrtcclient.js │ └── webdriver.js │ ├── lint.yaml │ └── fingerprint.yaml ├── LICENSE ├── go.sum ├── README.md └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_125_0_6422_141.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_125_0_6422_141.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_126.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_126.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_182.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_182.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_55.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_55.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_61.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_61.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_62.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_62.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_126_0_6478_63.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_126_0_6478_63.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_127_0_6533_119.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_127_0_6533_119.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_127_0_6533_72.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_127_0_6533_72.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_127_0_6533_88.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_127_0_6533_88.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_127_0_6533_99.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_127_0_6533_99.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_128_0_6613_119.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_128_0_6613_119.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_128_0_6613_137.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_128_0_6613_137.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_129_0_6668_58.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_129_0_6668_58.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_129_0_6668_70.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_129_0_6668_70.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_129_0_6668_89.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_129_0_6668_89.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_131_0_6778_108.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_131_0_6778_108.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_131_0_6778_204.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_131_0_6778_204.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_131_0_6778_264.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_131_0_6778_264.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_131_0_6778_85.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_131_0_6778_85.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_131_0_6778_87.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_131_0_6778_87.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_132_0_6834_110.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_132_0_6834_110.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_132_0_6834_159.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_132_0_6834_159.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_132_0_6834_83.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_132_0_6834_83.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_133_0_6943_126.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_133_0_6943_126.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_133_0_6943_141.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_133_0_6943_141.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_133_0_6943_53.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_133_0_6943_53.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_133_0_6943_98.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_133_0_6943_98.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_134_0_6998_165.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_134_0_6998_165.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_134_0_6998_35.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_134_0_6998_35.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_134_0_6998_88.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_134_0_6998_88.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_134_0_6998_90.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_134_0_6998_90.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_135_0_7049_114.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_135_0_7049_114.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_135_0_7049_42.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_135_0_7049_42.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_135_0_7049_84.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_135_0_7049_84.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_135_0_7049_95.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_135_0_7049_95.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_135_0_7049_97.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_135_0_7049_97.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_136_0_7103_113.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_136_0_7103_113.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_136_0_7103_49.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_136_0_7103_49.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_136_0_7103_92.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_136_0_7103_92.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_136_0_7103_94.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_136_0_7103_94.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_137_0_7151_119.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_137_0_7151_119.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_137_0_7151_55.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_137_0_7151_55.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_137_0_7151_68.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_137_0_7151_68.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_137_0_7151_70.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_137_0_7151_70.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_157.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_157.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_168.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_168.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_183.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_183.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_49.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_49.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_92.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_92.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_138_0_7204_94.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_138_0_7204_94.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_139_0_7258_138.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_139_0_7258_138.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_139_0_7258_154.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_139_0_7258_154.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_139_0_7258_66.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_139_0_7258_66.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_139_0_7258_68.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_139_0_7258_68.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_140_0_7339_185.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_140_0_7339_185.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_140_0_7339_207.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_140_0_7339_207.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_140_0_7339_80.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_140_0_7339_80.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_140_0_7339_82.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_140_0_7339_82.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_141_0_7390_122.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_141_0_7390_122.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_141_0_7390_54.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_141_0_7390_54.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_141_0_7390_65.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_141_0_7390_65.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_141_0_7390_76.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_141_0_7390_76.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_141_0_7390_78.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_141_0_7390_78.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_142_0_7444_162.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_142_0_7444_162.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_142_0_7444_175.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_142_0_7444_175.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_142_0_7444_59.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_142_0_7444_59.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_142_0_7444_61.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_142_0_7444_61.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_143_0_7499_146.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_143_0_7499_146.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_143_0_7499_169.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_143_0_7499_169.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_143_0_7499_40.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_143_0_7499_40.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome_linux_143_0_7499_42.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome_linux_143_0_7499_42.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_126_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_126_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_127_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_127_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_127_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_127_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_127_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_127_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_128_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_128_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_128_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_128_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_128_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_128_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_129_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_129_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_129_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_129_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_130_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_130_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_130_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_130_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_131_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_131_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_133_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_133_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_133_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_133_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_134_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_134_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_134_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_134_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_134_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_134_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_135_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_135_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_135_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_135_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_136_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_136_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_136_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_136_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_136_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_136_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_136_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_136_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_136_0_4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_136_0_4.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_137_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_137_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_137_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_137_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_137_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_137_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_138_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_138_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_138_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_138_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_138_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_138_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_138_0_4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_138_0_4.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_139_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_139_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_139_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_139_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_139_0_4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_139_0_4.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_140_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_140_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_140_0_4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_140_0_4.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_141_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_141_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_141_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_141_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_141_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_141_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_142_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_142_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_142_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_142_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_143_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_143_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_143_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_143_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_143_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_143_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_143_0_4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_143_0_4.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_144_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_144_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_144_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_144_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_145_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_145_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_145_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_145_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_145_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_145_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_146_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_146_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox_linux_stable_146_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox_linux_stable_146_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox-Mozilla_Firefox_126_0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox-Mozilla_Firefox_126_0.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_2.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox-Mozilla_Firefox_125_0_3.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-firefox-Mozilla_Firefox_126_0_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-firefox-Mozilla_Firefox_126_0_1.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_118_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_118_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_155_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_155_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_201_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_201_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_207_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_207_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_60_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_60_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_78_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_78_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_91_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_124_0_6367_91_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_112_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_112_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_141_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_141_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_60_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_60_unknown.pcap -------------------------------------------------------------------------------- /fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_76_unknown.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodorsm/covert-dtls/HEAD/fingerprints-captures/capture-chrome-Google_Chrome_125_0_6422_76_unknown.pcap -------------------------------------------------------------------------------- /pkg/utils/util_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestShuffle(t *testing.T) { 8 | list := []int{1, 2, 3, 4, 5} 9 | for i := 1; i < 1000; i++ { 10 | shuffled := ShuffleRandomLength(list, true) 11 | if len(shuffled) == 0 { 12 | t.Fatalf("Shuffle returned a empty slice") 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/theodorsm/covert-dtls 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/google/gopacket v1.1.19 7 | github.com/pion/dtls/v3 v3.0.2 8 | ) 9 | 10 | require ( 11 | github.com/pion/logging v0.2.2 // indirect 12 | github.com/pion/transport/v3 v3.0.7 // indirect 13 | golang.org/x/crypto v0.25.0 // indirect 14 | golang.org/x/sys v0.22.0 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /pkg/utils/errors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/pion/dtls/v3/pkg/protocol" 7 | ) 8 | 9 | // Typed errors 10 | var ( 11 | errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113 12 | errLengthMismatch = &protocol.InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113 13 | ) 14 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/download-browsers.js: -------------------------------------------------------------------------------- 1 | const { buildDriver } = require('./webdriver'); 2 | // Download the browser(s). 3 | async function download() { 4 | if (process.env.BROWSER_A && process.env.BROWSER_B) { 5 | (await buildDriver(process.env.BROWSER_A)).quit(); 6 | (await buildDriver(process.env.BROWSER_B)).quit(); 7 | } else { 8 | (await buildDriver()).quit(); 9 | } 10 | } 11 | download(); 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webrtc-fingerprinting", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "jest": "node ./download-browsers.js && jest --testTimeout 5000 --maxWorkers=1 src/content/", 6 | "stylelint": "stylelint 'src/**/*.css'" 7 | }, 8 | "devDependencies": { 9 | "@puppeteer/browsers": "^2.2.0", 10 | "http-server": "^14.1.0", 11 | "jest": "^29.7.0", 12 | "selenium-webdriver": "^4.12.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pkg/mimicry/fingerprints_test.go: -------------------------------------------------------------------------------- 1 | package mimicry 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/theodorsm/covert-dtls/pkg/fingerprints" 7 | ) 8 | 9 | func TestLoadFingerprints(t *testing.T) { 10 | for _, fingerprint := range fingerprints.GetClientHelloFingerprints() { 11 | m := &MimickedClientHello{} 12 | err := m.LoadFingerprint(fingerprint) 13 | if err != nil { 14 | t.Errorf("Load failed for fingerprint: %v, with error: %v\n", fingerprint, err) 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /pkg/randomize/errors.go: -------------------------------------------------------------------------------- 1 | package randomize 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/pion/dtls/v3/pkg/protocol" 7 | ) 8 | 9 | // Typed errors 10 | var ( 11 | errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113 12 | errLengthMismatch = &protocol.InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113 13 | errCookieTooLong = &protocol.FatalError{Err: errors.New("cookie must not be longer then 255 bytes")} //nolint:goerr113 14 | ) 15 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | 7 | permissions: 8 | contents: read 9 | pull-requests: read 10 | 11 | jobs: 12 | linting: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | ref: ${{ github.event.pull_request.head.ref }} 19 | 20 | - name: Setup go 21 | uses: actions/setup-go@v5 22 | with: 23 | go-version: '1.23' 24 | 25 | - name: golangci-lint 26 | uses: golangci/golangci-lint-action@v6 27 | with: 28 | version: v1.63.4 29 | skip-cache: true 30 | skip-save-cache: true 31 | -------------------------------------------------------------------------------- /pkg/mimicry/errors.go: -------------------------------------------------------------------------------- 1 | package mimicry 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/pion/dtls/v3/pkg/protocol" 7 | ) 8 | 9 | // Typed errors. 10 | var ( 11 | errCookieTooLong = &protocol.FatalError{ 12 | Err: errors.New("cookie must not be longer then 255 bytes"), //nolint:err113 13 | } 14 | errBufferTooSmall = &protocol.TemporaryError{ 15 | Err: errors.New("buffer is too small"), //nolint:err113 16 | } 17 | errLengthMismatch = &protocol.InternalError{ 18 | Err: errors.New("data length and declared length do not match"), //nolint:err113 19 | } 20 | errNoFingerprints = errors.New("no fingerprints available") 21 | errHexstringDecode = errors.New("mimicry: failed to decode mimicry hexstring") 22 | ) 23 | -------------------------------------------------------------------------------- /pkg/utils/fake_extension.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | "github.com/pion/dtls/v3/pkg/protocol/extension" 7 | ) 8 | 9 | type FakeExt struct { 10 | FakeTypeValue extension.TypeValue 11 | Bytes []byte 12 | } 13 | 14 | func (f *FakeExt) TypeValue() extension.TypeValue { 15 | return f.FakeTypeValue 16 | } 17 | 18 | func (f *FakeExt) Marshal() ([]byte, error) { 19 | return f.Bytes, nil 20 | } 21 | 22 | func (f *FakeExt) Unmarshal(data []byte) error { 23 | if len(data) < 4 { 24 | return errBufferTooSmall 25 | } 26 | f.FakeTypeValue = extension.TypeValue(binary.BigEndian.Uint16(data)) 27 | 28 | length := int(binary.BigEndian.Uint16(data[2:])) + 4 // offset = 2 byte type + 2 byte length 29 | if length >= len(data[2:]) { 30 | return errLengthMismatch 31 | } 32 | data = data[:length] 33 | 34 | f.Bytes = data 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Theodor S. Midtlien 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/steps.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. 7 | */ 8 | const TIMEOUT = 10000; 9 | 10 | function step(drivers, cb, logMessage) { 11 | return Promise.all(drivers.map(driver => { 12 | return cb(driver); 13 | })).then(() => { 14 | if (logMessage) { 15 | console.log(logMessage); 16 | } 17 | }); 18 | } 19 | function waitNVideosExist(driver, n) { 20 | return driver.wait(() => { 21 | return driver.executeScript(n => document.querySelectorAll('video').length === n, n); 22 | }, TIMEOUT); 23 | } 24 | 25 | function waitAllVideosHaveEnoughData(driver) { 26 | return driver.wait(() => { 27 | return driver.executeScript(() => { 28 | const videos = document.querySelectorAll('video'); 29 | let ready = 0; 30 | for (let i = 0; i < videos.length; i++) { 31 | if (videos[i].readyState >= videos[i].HAVE_ENOUGH_DATA) { 32 | ready++; 33 | } 34 | } 35 | return ready === videos.length; 36 | }); 37 | }, TIMEOUT); 38 | } 39 | 40 | module.exports = { 41 | step, 42 | waitNVideosExist, 43 | waitAllVideosHaveEnoughData, 44 | }; 45 | -------------------------------------------------------------------------------- /pkg/utils/cipher_suite.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/binary" 5 | "github.com/pion/dtls/v3" 6 | ) 7 | 8 | func DecodeCipherSuiteIDs(buf []byte) ([]uint16, error) { 9 | if len(buf) < 2 { 10 | return nil, errBufferTooSmall 11 | } 12 | cipherSuitesCount := int(binary.BigEndian.Uint16(buf[0:])) / 2 13 | rtrn := make([]uint16, cipherSuitesCount) 14 | for i := 0; i < cipherSuitesCount; i++ { 15 | if len(buf) < (i*2 + 4) { 16 | return nil, errBufferTooSmall 17 | } 18 | 19 | rtrn[i] = binary.BigEndian.Uint16(buf[(i*2)+2:]) 20 | } 21 | return rtrn, nil 22 | } 23 | 24 | func EncodeCipherSuiteIDs(cipherSuiteIDs []uint16) []byte { 25 | out := []byte{0x00, 0x00} 26 | binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(cipherSuiteIDs)*2)) 27 | for _, id := range cipherSuiteIDs { 28 | out = append(out, []byte{0x00, 0x00}...) 29 | binary.BigEndian.PutUint16(out[len(out)-2:], id) 30 | } 31 | return out 32 | } 33 | 34 | func DefaultCipherSuites() []dtls.CipherSuiteID { 35 | return []dtls.CipherSuiteID{ 36 | dtls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 37 | dtls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 38 | dtls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 39 | dtls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 40 | dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 41 | dtls.TLS_ECDHE_ECDSA_WITH_AES_128_CCM, 42 | dtls.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, 43 | dtls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 44 | /* 45 | dtls.TLS_PSK_WITH_AES_128_CCM, 46 | dtls.TLS_PSK_WITH_AES_128_CCM_8, 47 | dtls.TLS_PSK_WITH_AES_256_CCM_8, 48 | dtls.TLS_PSK_WITH_AES_128_GCM_SHA256, 49 | */ 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, The WebRTC project authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | * Neither the name of Google nor the names of its contributors may 16 | be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 2 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 3 | github.com/pion/dtls/v3 v3.0.2 h1:425DEeJ/jfuTTghhUDW0GtYZYIwwMtnKKJNMcWccTX0= 4 | github.com/pion/dtls/v3 v3.0.2/go.mod h1:dfIXcFkKoujDQ+jtd8M6RgqKK3DuaUilm3YatAbGp5k= 5 | github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= 6 | github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= 7 | github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= 8 | github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= 9 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 10 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 11 | golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= 12 | golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= 13 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 14 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 15 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 16 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 17 | golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= 18 | golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= 19 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 20 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 21 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 22 | golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= 23 | golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 24 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 25 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 26 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 27 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/interop/connection.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. 7 | */ 8 | const { buildDriver } = require('../webdriver'); 9 | const { PeerConnection, MediaDevices } = require('../webrtcclient'); 10 | const steps = require('../steps'); 11 | 12 | const browserA = process.env.BROWSER_A || 'chrome'; 13 | const browserB = process.env.BROWSER_B || 'chrome'; 14 | 15 | describe(`basic interop test ${browserA} => ${browserB}`, function() { 16 | let drivers; 17 | let clients; 18 | beforeAll(async () => { 19 | const options = { 20 | version: process.env.BVER || 'stable', 21 | browserLogging: true, 22 | } 23 | drivers = [ 24 | await buildDriver(browserA, options), 25 | await buildDriver(browserB, options), 26 | ]; 27 | clients = drivers.map(driver => { 28 | return { 29 | connection: new PeerConnection(driver), 30 | mediaDevices: new MediaDevices(driver), 31 | }; 32 | }); 33 | }); 34 | afterAll(async () => { 35 | await drivers.map(driver => driver.close()); 36 | }); 37 | 38 | it('establishes a connection', async () => { 39 | await Promise.all(drivers); // timeouts in before(Each)? 40 | await steps.step(drivers, (d) => d.get('https://webrtc.github.io/samples/emptypage.html'), 'Empty page loaded'); 41 | await steps.step(clients, (client) => client.connection.create(), 'Created RTCPeerConnection'); 42 | await steps.step(clients, async (client) => { 43 | const stream = await client.mediaDevices.getUserMedia({ audio: true, video: true }); 44 | return Promise.all(stream.getTracks().map(async track => { 45 | return client.connection.addTrack(track, stream); 46 | })); 47 | }, 'Acquired and added audio/video stream'); 48 | const offerWithCandidates = await clients[0].connection.setLocalDescription(); 49 | await clients[1].connection.setRemoteDescription(offerWithCandidates); 50 | const answerWithCandidates = await clients[1].connection.setLocalDescription(); 51 | await clients[0].connection.setRemoteDescription(answerWithCandidates); 52 | 53 | await steps.step(drivers, (d) => steps.waitNVideosExist(d, 1), 'Video elements exist'); 54 | await steps.step(drivers, steps.waitAllVideosHaveEnoughData, 'Video elements have enough data'); 55 | }, 30000); 56 | }, 90000); 57 | -------------------------------------------------------------------------------- /pkg/mimicry/extension.go: -------------------------------------------------------------------------------- 1 | package mimicry 2 | 3 | import ( 4 | "encoding/binary" 5 | "github.com/pion/dtls/v3/pkg/protocol/extension" 6 | "github.com/theodorsm/covert-dtls/pkg/utils" 7 | ) 8 | 9 | // Unmarshal many extensions at once. 10 | func MimicExtensionsUnmarshal(buf []byte) ([]extension.Extension, error) { 11 | switch { 12 | case len(buf) == 0: 13 | return []extension.Extension{}, nil 14 | case len(buf) < 2: 15 | return nil, errBufferTooSmall 16 | } 17 | 18 | declaredLen := binary.BigEndian.Uint16(buf) 19 | if len(buf)-2 != int(declaredLen) { 20 | return nil, errLengthMismatch 21 | } 22 | 23 | extensions := []extension.Extension{} 24 | unmarshalAndAppend := func(data []byte, e extension.Extension) error { 25 | err := e.Unmarshal(data) 26 | if err != nil { 27 | return err 28 | } 29 | extensions = append(extensions, e) 30 | 31 | return nil 32 | } 33 | 34 | for offset := 2; offset < len(buf); { 35 | if len(buf) < (offset + 2) { 36 | return nil, errBufferTooSmall 37 | } 38 | var err error 39 | switch extension.TypeValue(binary.BigEndian.Uint16(buf[offset:])) { 40 | case extension.ServerNameTypeValue: 41 | err = unmarshalAndAppend(buf[offset:], &extension.ServerName{}) 42 | case extension.SupportedEllipticCurvesTypeValue: 43 | // Mimic 44 | err = unmarshalAndAppend(buf[offset:], &utils.FakeExt{}) 45 | case extension.SupportedPointFormatsTypeValue: 46 | err = unmarshalAndAppend(buf[offset:], &extension.SupportedPointFormats{}) 47 | case extension.SupportedSignatureAlgorithmsTypeValue: 48 | // Mimic 49 | err = unmarshalAndAppend(buf[offset:], &utils.FakeExt{}) 50 | case extension.UseSRTPTypeValue: 51 | err = unmarshalAndAppend(buf[offset:], &extension.UseSRTP{}) 52 | case extension.ALPNTypeValue: 53 | err = unmarshalAndAppend(buf[offset:], &extension.ALPN{}) 54 | case extension.UseExtendedMasterSecretTypeValue: 55 | err = unmarshalAndAppend(buf[offset:], &extension.UseExtendedMasterSecret{}) 56 | case extension.RenegotiationInfoTypeValue: 57 | err = unmarshalAndAppend(buf[offset:], &extension.RenegotiationInfo{}) 58 | case extension.ConnectionIDTypeValue: 59 | err = unmarshalAndAppend(buf[offset:], &extension.ConnectionID{}) 60 | case utils.KeyShareTypeValue: 61 | // Unmarshal mimicked KeyShare 62 | err = unmarshalAndAppend(buf[offset:], &utils.KeyShare{}) 63 | default: 64 | // Unmarshal any mimicked unimplemented extension 65 | err = unmarshalAndAppend(buf[offset:], &utils.FakeExt{}) 66 | } 67 | if err != nil { 68 | return nil, err 69 | } 70 | if len(buf) < (offset + 4) { 71 | return nil, errBufferTooSmall 72 | } 73 | extensionLength := binary.BigEndian.Uint16(buf[offset+2:]) 74 | offset += (4 + int(extensionLength)) 75 | } 76 | 77 | return extensions, nil 78 | } 79 | -------------------------------------------------------------------------------- /pkg/randomize/extension.go: -------------------------------------------------------------------------------- 1 | package randomize 2 | 3 | import ( 4 | "encoding/binary" 5 | "github.com/pion/dtls/v3/pkg/protocol/extension" 6 | "github.com/theodorsm/covert-dtls/pkg/utils" 7 | ) 8 | 9 | // Unmarshal many extensions at once, will randomize use_srtp, signature_algorithms and supported_groups. 10 | func RandomizeExtensionUnmarshal(buf []byte) ([]extension.Extension, error) { 11 | switch { 12 | case len(buf) == 0: 13 | return []extension.Extension{}, nil 14 | case len(buf) < 2: 15 | return nil, errBufferTooSmall 16 | } 17 | 18 | declaredLen := binary.BigEndian.Uint16(buf) 19 | if len(buf)-2 != int(declaredLen) { 20 | return nil, errLengthMismatch 21 | } 22 | 23 | extensions := []extension.Extension{} 24 | unmarshalAndAppend := func(data []byte, e extension.Extension) error { 25 | err := e.Unmarshal(data) 26 | if err != nil { 27 | return err 28 | } 29 | extensions = append(extensions, e) 30 | return nil 31 | } 32 | 33 | for offset := 2; offset < len(buf); { 34 | if len(buf) < (offset + 2) { 35 | return nil, errBufferTooSmall 36 | } 37 | var err error 38 | switch extension.TypeValue(binary.BigEndian.Uint16(buf[offset:])) { 39 | case extension.ServerNameTypeValue: 40 | err = unmarshalAndAppend(buf[offset:], &extension.ServerName{}) 41 | case extension.SupportedEllipticCurvesTypeValue: 42 | e := &extension.SupportedEllipticCurves{} 43 | err = e.Unmarshal(buf[offset:]) 44 | if err != nil { 45 | return nil, err 46 | } 47 | e.EllipticCurves = utils.ShuffleRandomLength(e.EllipticCurves, true) 48 | extensions = append(extensions, e) 49 | case extension.SupportedPointFormatsTypeValue: 50 | err = unmarshalAndAppend(buf[offset:], &extension.SupportedPointFormats{}) 51 | case extension.SupportedSignatureAlgorithmsTypeValue: 52 | e := &extension.SupportedSignatureAlgorithms{} 53 | err = e.Unmarshal(buf[offset:]) 54 | if err != nil { 55 | return nil, err 56 | } 57 | e.SignatureHashAlgorithms = utils.ShuffleRandomLength(e.SignatureHashAlgorithms, true) 58 | extensions = append(extensions, e) 59 | case extension.UseSRTPTypeValue: 60 | e := &extension.UseSRTP{} 61 | err = e.Unmarshal(buf[offset:]) 62 | if err != nil { 63 | return nil, err 64 | } 65 | e.ProtectionProfiles = utils.ShuffleRandomLength(e.ProtectionProfiles, true) 66 | extensions = append(extensions, e) 67 | case extension.ALPNTypeValue: 68 | err = unmarshalAndAppend(buf[offset:], &extension.ALPN{}) 69 | case extension.UseExtendedMasterSecretTypeValue: 70 | err = unmarshalAndAppend(buf[offset:], &extension.UseExtendedMasterSecret{}) 71 | case extension.RenegotiationInfoTypeValue: 72 | err = unmarshalAndAppend(buf[offset:], &extension.RenegotiationInfo{}) 73 | default: 74 | } 75 | if err != nil { 76 | return nil, err 77 | } 78 | if len(buf) < (offset + 4) { 79 | return nil, errBufferTooSmall 80 | } 81 | extensionLength := binary.BigEndian.Uint16(buf[offset+2:]) 82 | offset += (4 + int(extensionLength)) 83 | } 84 | return extensions, nil 85 | } 86 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/ecdh" 5 | "crypto/rand" 6 | "encoding/binary" 7 | "fmt" 8 | "github.com/pion/dtls/v3" 9 | "github.com/pion/dtls/v3/pkg/protocol/extension" 10 | "math/big" 11 | ) 12 | 13 | func DefaultSRTPProtectionProfiles() []dtls.SRTPProtectionProfile { 14 | return []dtls.SRTPProtectionProfile{ 15 | dtls.SRTP_AES128_CM_HMAC_SHA1_80, 16 | dtls.SRTP_AES128_CM_HMAC_SHA1_32, 17 | dtls.SRTP_AES256_CM_SHA1_80, 18 | dtls.SRTP_AES256_CM_SHA1_32, 19 | dtls.SRTP_NULL_HMAC_SHA1_80, 20 | dtls.SRTP_NULL_HMAC_SHA1_32, 21 | dtls.SRTP_AEAD_AES_128_GCM, 22 | dtls.SRTP_AEAD_AES_256_GCM, 23 | } 24 | } 25 | 26 | func RandRange(min, max int) int { 27 | bigRandomNumber, err := rand.Int(rand.Reader, big.NewInt(int64(max+1))) 28 | if err != nil { 29 | panic(err) 30 | } 31 | randomNumber := int(bigRandomNumber.Int64()) 32 | if randomNumber < min { 33 | return min 34 | } 35 | return randomNumber 36 | } 37 | 38 | var ALPNS = []string{"http/1.0", "http/1.1", "h2c", "h2", "h3", "stun.turn", "webrtc", "c-webrtc", "ftp", "pop3", "imap", "mqtt", "smb", "irc", "sip/2"} 39 | 40 | func ShuffleRandomLength[T any](s []T, randomLen bool) []T { 41 | var out = []T{} 42 | if len(s) == 0 { 43 | return s 44 | } 45 | tmp := make([]T, len(s)) 46 | _ = copy(tmp, s) 47 | var n int 48 | if randomLen { 49 | n = RandRange(1, len(tmp)) 50 | } else { 51 | n = len(tmp) 52 | } 53 | for len(out) < n { 54 | pick := RandRange(0, len(tmp)-1) 55 | out = append(out, tmp[pick]) 56 | tmp = remove(tmp, pick) 57 | } 58 | return out 59 | } 60 | 61 | func remove[T any](s []T, index int) []T { 62 | ret := make([]T, 0) 63 | ret = append(ret, s[:index]...) 64 | return append(ret, s[index+1:]...) 65 | } 66 | 67 | // GenerateRandomP256PublicKey generates a random valid secp256r1 public key 68 | func GenerateRandomP256PublicKey() (*ecdh.PublicKey, error) { 69 | curve := ecdh.P256() 70 | 71 | privateKey, err := curve.GenerateKey(rand.Reader) 72 | if err != nil { 73 | return nil, fmt.Errorf("failed to generate private key: %v", err) 74 | } 75 | 76 | return privateKey.PublicKey(), nil 77 | } 78 | 79 | // GenerateRandomPublicKey generates a random valid X25519 public key 80 | func GenerateRandomX25519PublicKey() (*ecdh.PublicKey, error) { 81 | curve := ecdh.X25519() 82 | 83 | privateKey, err := curve.GenerateKey(rand.Reader) 84 | if err != nil { 85 | return nil, fmt.Errorf("failed to generate private key: %v", err) 86 | } 87 | 88 | return privateKey.PublicKey(), nil 89 | } 90 | 91 | // Marshal many extensions at once 92 | func ExtensionMarshal(e []extension.Extension) ([]byte, error) { 93 | extensions := []byte{} 94 | for _, e := range e { 95 | raw, err := e.Marshal() 96 | if err != nil { 97 | return nil, err 98 | } 99 | extensions = append(extensions, raw...) 100 | } 101 | out := []byte{0x00, 0x00} 102 | binary.BigEndian.PutUint16(out, uint16(len(extensions))) 103 | return append(out, extensions...), nil 104 | } 105 | -------------------------------------------------------------------------------- /pkg/mimicry/mimic_test.go: -------------------------------------------------------------------------------- 1 | package mimicry 2 | 3 | import ( 4 | "fmt" 5 | "github.com/theodorsm/covert-dtls/pkg/utils" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalKeyShare(t *testing.T) { 10 | keyShareBytes := []byte{0x0, 0x33, 0x0, 0x6b, 0x0, 0x69, 0x0, 0x1d, 0x0, 0x20, 0x52, 0x61, 0xca, 0x3a, 0xa4, 0xa3, 0x2f, 0xac, 0xf3, 0xf7, 0x1e, 0xdb, 0x5e, 0xbb, 0x7f, 0xdf, 0xa8, 0x8d, 0x4, 0x31, 0x9e, 0x56, 0xe3, 0x81, 0x86, 0x32, 0x3c, 0x24, 0xe8, 0x44, 0x5e, 0xe, 0x0, 0x17, 0x0, 0x41, 0x4, 0x7b, 0xdd, 0xd9, 0xaa, 0xb2, 0xd6, 0x56, 0xb8, 0x23, 0x1e, 0xb0, 0xe3, 0x2c, 0xc7, 0xf2, 0x6a, 0xcd, 0xe0, 0x55, 0xb3, 0x3f, 0x11, 0xa2, 0x22, 0x5e, 0x93, 0xb7, 0x92, 0xbd, 0x15, 0x98, 0xae, 0x5c, 0x8a, 0xcd, 0xd2, 0x57, 0x4e, 0x50, 0x3a, 0x3f, 0x4f, 0x25, 0x82, 0x2b, 0x63, 0x25, 0xe2, 0xe0, 0xb9, 0x17, 0x27, 0x3f, 0x97, 0x77, 0x27, 0x8, 0x77, 0xe5, 0xe3, 0xb8, 0xc7, 0x73, 0x98} 11 | keyshare := utils.KeyShare{} 12 | err := keyshare.Unmarshal(keyShareBytes) 13 | if err != nil { 14 | t.Errorf("Unmarshal failed: %v\n", err) 15 | } 16 | fmt.Printf("%+v\n", keyshare) 17 | if len(keyshare.KeyShareEntries) != 2 { 18 | t.Errorf("Unmarshal failed: length %v\n", len(keyshare.KeyShareEntries)) 19 | } 20 | entry0 := keyshare.KeyShareEntries[0] 21 | expGroup := uint16(29) 22 | expKeyLength := uint16(32) 23 | if entry0.Group != expGroup || entry0.KeyLength != expKeyLength { 24 | t.Errorf("Unmarshal failed, entry #0: %v. Expected Group: %v, KeyLength: %v", entry0, expGroup, expKeyLength) 25 | } 26 | entry1 := keyshare.KeyShareEntries[1] 27 | expGroup = uint16(23) 28 | expKeyLength = uint16(65) 29 | if entry1.Group != expGroup || entry1.KeyLength != expKeyLength { 30 | t.Errorf("Unmarshal failed, entry #1: %v. Expected Group: %v, KeyLength: %v", entry1, expGroup, expKeyLength) 31 | } 32 | } 33 | 34 | func TestUnmarshalFakeExt(t *testing.T) { 35 | extBytes := []byte{0x0, 0xf6, 0x0, 0x17, 0x0, 0x0, 0xff, 0x1, 0x0, 0x1, 0x0, 0x0, 0xa, 0x0, 0xc, 0x0, 0xa, 0x0, 0x1d, 0x0, 0x17, 0x0, 0x18, 0x1, 0x0, 0x1, 0x1, 0x0, 0xb, 0x0, 0x2, 0x1, 0x0, 0x0, 0x10, 0x0, 0x12, 0x0, 0x10, 0x6, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x8, 0x63, 0x2d, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x0, 0x22, 0x0, 0xa, 0x0, 0x8, 0x4, 0x3, 0x5, 0x3, 0x6, 0x3, 0x2, 0x3, 0x0, 0x33, 0x0, 0x6b, 0x0, 0x69, 0x0, 0x1d, 0x0, 0x20, 0x52, 0x61, 0xca, 0x3a, 0xa4, 0xa3, 0x2f, 0xac, 0xf3, 0xf7, 0x1e, 0xdb, 0x5e, 0xbb, 0x7f, 0xdf, 0xa8, 0x8d, 0x4, 0x31, 0x9e, 0x56, 0xe3, 0x81, 0x86, 0x32, 0x3c, 0x24, 0xe8, 0x44, 0x5e, 0xe, 0x0, 0x17, 0x0, 0x41, 0x4, 0x7b, 0xdd, 0xd9, 0xaa, 0xb2, 0xd6, 0x56, 0xb8, 0x23, 0x1e, 0xb0, 0xe3, 0x2c, 0xc7, 0xf2, 0x6a, 0xcd, 0xe0, 0x55, 0xb3, 0x3f, 0x11, 0xa2, 0x22, 0x5e, 0x93, 0xb7, 0x92, 0xbd, 0x15, 0x98, 0xae, 0x5c, 0x8a, 0xcd, 0xd2, 0x57, 0x4e, 0x50, 0x3a, 0x3f, 0x4f, 0x25, 0x82, 0x2b, 0x63, 0x25, 0xe2, 0xe0, 0xb9, 0x17, 0x27, 0x3f, 0x97, 0x77, 0x27, 0x8, 0x77, 0xe5, 0xe3, 0xb8, 0xc7, 0x73, 0x98, 0x0, 0x2b, 0x0, 0x7, 0x6, 0xfe, 0xfc, 0xfe, 0xfd, 0x3, 0x3, 0x0, 0xd, 0x0, 0x20, 0x0, 0x1e, 0x4, 0x3, 0x5, 0x3, 0x6, 0x3, 0x2, 0x3, 0x8, 0x4, 0x8, 0x5, 0x8, 0x6, 0x4, 0x1, 0x5, 0x1, 0x6, 0x1, 0x2, 0x1, 0x4, 0x2, 0x5, 0x2, 0x6, 0x2, 0x2, 0x2, 0x0, 0x1c, 0x0, 0x2, 0x40, 0x1, 0x0, 0xe, 0x0, 0xb, 0x0, 0x8, 0x0, 0x7, 0x0, 0x8, 0x0, 0x1, 0x0, 0x2, 0x0} 36 | exts, err := MimicExtensionsUnmarshal(extBytes) 37 | if err != nil { 38 | t.Errorf("Unmarshal failed: %v\n", err) 39 | } 40 | fmt.Printf("Extensions: %+v\n", exts) 41 | out, err := utils.ExtensionMarshal(exts) 42 | if err != nil { 43 | t.Errorf("Marshal failed: %v\n", err) 44 | } 45 | fmt.Printf("length: %v, out: %#v\n", len(out), out) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/utils/keyshare.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "errors" 7 | "github.com/pion/dtls/v3/pkg/protocol/extension" 8 | ) 9 | 10 | const ( 11 | keyShareHeaderSize = 6 12 | KeyGroupP256Value = 23 13 | KeyGroupX25519Value = 29 14 | KeyShareTypeValue extension.TypeValue = 51 15 | ) 16 | 17 | var ( 18 | errKeyLength = errors.New("generated key length does not match") 19 | errRandomKey = errors.New("error while generating random key") 20 | errInvalidExtensionType = errors.New("invalid extension type") 21 | ) 22 | 23 | type KeyShareEntry struct { 24 | Group uint16 25 | KeyLength uint16 26 | Key []byte 27 | } 28 | 29 | type KeyShare struct { 30 | KeyShareEntries []KeyShareEntry 31 | } 32 | 33 | func (k *KeyShare) TypeValue() extension.TypeValue { 34 | return KeyShareTypeValue 35 | } 36 | 37 | // Marshal with fresh random keys 38 | func (k *KeyShare) Marshal() ([]byte, error) { 39 | var tmp []byte 40 | for _, entry := range k.KeyShareEntries { 41 | out := []byte{0x00, 0x00} 42 | binary.BigEndian.PutUint16(out, uint16(entry.Group)) 43 | tmp = append(tmp, out...) 44 | out = []byte{0x00, 0x00} 45 | binary.BigEndian.PutUint16(out, uint16(entry.KeyLength)) 46 | tmp = append(tmp, out...) 47 | switch entry.Group { 48 | case uint16(KeyGroupX25519Value): 49 | key, err := GenerateRandomX25519PublicKey() 50 | if err != nil { 51 | return []byte{}, err 52 | } 53 | if len(key.Bytes()) != int(entry.KeyLength) { 54 | return []byte{}, errKeyLength 55 | } 56 | tmp = append(tmp, key.Bytes()...) 57 | case uint16(KeyGroupP256Value): 58 | key, err := GenerateRandomP256PublicKey() 59 | if err != nil { 60 | return []byte{}, err 61 | } 62 | if len(key.Bytes()) != int(entry.KeyLength) { 63 | return []byte{}, errKeyLength 64 | } 65 | tmp = append(tmp, key.Bytes()...) 66 | default: 67 | key := make([]byte, entry.KeyLength) 68 | _, err := rand.Read(key) 69 | if err != nil { 70 | return []byte{}, errRandomKey 71 | } 72 | tmp = append(tmp, key...) 73 | } 74 | } 75 | 76 | var header []byte 77 | out := []byte{0x00, 0x00} 78 | binary.BigEndian.PutUint16(out, uint16(k.TypeValue())) 79 | header = append(header, out...) 80 | 81 | out = []byte{0x00, 0x00} 82 | binary.BigEndian.PutUint16(out, uint16(len(tmp)+2)) 83 | header = append(header, out...) 84 | 85 | out = []byte{0x00, 0x00} 86 | binary.BigEndian.PutUint16(out, uint16(len(tmp))) 87 | header = append(header, out...) 88 | 89 | out = append(header, tmp...) 90 | return out, nil 91 | } 92 | 93 | func (k *KeyShare) Unmarshal(data []byte) error { 94 | if len(data) <= keyShareHeaderSize { 95 | return errBufferTooSmall 96 | } else if extension.TypeValue(binary.BigEndian.Uint16(data)) != k.TypeValue() { 97 | return errInvalidExtensionType 98 | } 99 | 100 | length := int(binary.BigEndian.Uint16(data[2:])) + 4 // offset = 2 byte type + 2 byte length 101 | if length >= len(data[2:]) { 102 | return errLengthMismatch 103 | } 104 | data = data[:length] 105 | 106 | currOff := keyShareHeaderSize 107 | for currOff < len(data) { 108 | group := binary.BigEndian.Uint16(data[currOff:]) 109 | currOff += 2 110 | if currOff >= len(data) { 111 | return errLengthMismatch 112 | } 113 | keyLength := binary.BigEndian.Uint16(data[currOff:]) 114 | keyShareEntry := KeyShareEntry{Group: group, KeyLength: keyLength} 115 | k.KeyShareEntries = append(k.KeyShareEntries, keyShareEntry) 116 | currOff += 2 + int(keyLength) 117 | } 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # covertDTLS 2 | 3 | covertDTLS is a library inspired by [uTLS](https://github.com/refraction-networking/utls) for offering fingerprint-resistance features to [pion/dtls](https://github.com/pion/dtls). 4 | 5 | ## Why does this library exists? 6 | 7 | The censorship circumvention system [Snowflake](https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake) has previously been blocked by fingerprinting the DTLS handshake. This library is a module that extends the `pion/dtls` library by hooking and manipulating handshake messages to make them indistinguishable from other DTLS implementations used for WebRTC traffic. 8 | 9 | ## Fingerprint generation 10 | 11 | This repo contains a workflow ([.github/workflows/fingerprint.yaml](.github/workflows/fingerprint.yaml)) for automatically generating fresh DTLS 1.2 handshakes (fingerprints) of new browser versions (Firefox and Chrome) by using a minimal WebRTC example application and Selenium. Fresh handshakes are captured each day and stored as pcap artifacts and the [fingerprints-captures](fingerprints-captures) directory. The pcaps are further parsed and a fingerprint is added to [pkg/mimicry/fingerprints.go](pkg/mimicry/fingerprints.go). Some DTLS 1.3 fingerprints are found in [pkg/mimicry/fingerprints_13.go](pkg/mimicry/fingerprints_13.go) 12 | 13 | [main.go](main.go) contains a script for parsing pcaps, extracting the fingerprints and adding them to [pkg/mimicry/fingerprints.go](pkg/mimicry/fingerprints.go) 14 | 15 | ## Validation 16 | 17 | This library was developed as part of a Master thesis: "*[Reducing distinguishability of DTLS for usage in Snowflake](https://theodorsm.net/thesis)"*. Additionally, *[dfind](https://github.com/theodorsm/dfind)* was created for analyzing and finding passive field-based fingerprints of DTLS. *dfind* was used to validate this library, finding that mimicked *ClientHello* messages was indistinguishable from the fresh browser handshakes . Analysis also found that randomization of extensions was especially effective against fingerprinting, while randomization of ciphers has potential, but must be configured properly. To provide more effective randomization, it is recommended to use this library with **configuring as many supported ciphers as possible** (using `Config.CipherSuites`). 18 | 19 | ## Features 20 | 21 | - Mimicking/replaying *ClientHello* 22 | - key_share with fake keys (DTLS 1.3). *This feature is highly experimental and unstable: do NOT expect handshake to be completed successfully*. 23 | - Randomization of *ClientHello* 24 | - cipher suites: shuffle and random size 25 | - extensions: shuffle 26 | - `use_srtp`: shuffle and random size 27 | - `supported_groups`: shuffle and random size 28 | - `signature_algorithm`: shuffle and random size 29 | - ALPN: add random ALPN of common protocols 30 | 31 | *Note*: using these features might make handshakes unstable as unsupported features might be announced in the *ClientHello* message. 32 | 33 | ### Planned 34 | 35 | - Mimicking *ServerHello* 36 | - Mimicking *CertificateRequest* 37 | 38 | 39 | ## Examples 40 | 41 | ### Mimicry 42 | ```go 43 | import ( 44 | "github.com/pion/dtls/v2" 45 | "github.com/theodorsm/covert-dtls/pkg/fingerprints" 46 | "github.com/theodorsm/covert-dtls/pkg/mimicry" 47 | "github.com/theodorsm/covert-dtls/pkg/utils" 48 | ) 49 | 50 | // Get a specific fingerprint 51 | fingerprint := fingerprints.Mozilla_Firefox_125_0_1 52 | 53 | clientHello := mimicry.MimickedClientHello{} 54 | 55 | // If no specific fingerprint is loaded, the most recent one will be used 56 | clientHello.LoadFingerprint(fingerprint) 57 | 58 | cfg := &dtls.Config{ 59 | // SRTP needs to be enabled as the fingerprints are from webrtc traffic, thus containing the use_srtp extension. 60 | SRTPProtectionProfiles: utils.DefaultSRTPProtectionProfiles(), 61 | ClientHelloMessageHook: clientHello.Hook, 62 | } 63 | 64 | // Use config with connection... 65 | ``` 66 | 67 | ### Randomization 68 | ```go 69 | import ( 70 | "github.com/pion/dtls/v2" 71 | "github.com/theodorsm/covert-dtls/pkg/randomize" 72 | ) 73 | 74 | clientHello := randomize.RandomizedMessageClientHello{RandomALPN: true} 75 | 76 | cfg := &dtls.Config{ 77 | // Enable all ciphers for making randomization more effective. Optional step. 78 | CipherSuites: randomize.DefaultCipherSuites() , 79 | ClientHelloMessageHook: clientHello.Hook, 80 | } 81 | 82 | // Use config with connection... 83 | ``` 84 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/webrtcclient.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. 7 | */ 8 | // Disable no-undef since this file is a mix of code executed 9 | // in JS and the browser. 10 | /* eslint no-undef: 0 */ 11 | class MediaStream { 12 | constructor(tracks = []) { 13 | this.tracks = tracks; 14 | this.id = 0; 15 | } 16 | 17 | getTracks() { 18 | return this.tracks; 19 | } 20 | 21 | getAudioTracks() { 22 | return this.getTracks().filter(t => t.kind === 'audio'); 23 | } 24 | 25 | getVideoTracks() { 26 | return this.getTracks().filter(t => t.kind === 'video'); 27 | } 28 | } 29 | 30 | class MediaDevices { 31 | constructor(driver) { 32 | this.driver = driver; 33 | } 34 | 35 | getUserMedia(constraints) { 36 | return this.driver.executeAsyncScript((constraints) => { 37 | const callback = arguments[arguments.length - 1]; 38 | if (!window.localStreams) { 39 | window.localStreams = {}; 40 | } 41 | 42 | return navigator.mediaDevices.getUserMedia(constraints) 43 | .then((stream) => { 44 | window.localStreams[stream.id] = stream; 45 | callback({ 46 | id: stream.id, tracks: stream.getTracks().map((t) => { 47 | return { id: t.id, kind: t.kind }; 48 | }) 49 | }); 50 | }, (e) => callback(e)); 51 | }, constraints || { audio: true, video: true }) 52 | .then((streamObj) => { 53 | const stream = new MediaStream(streamObj.tracks); 54 | stream.id = streamObj.id; 55 | return stream; 56 | }); 57 | } 58 | } 59 | 60 | class PeerConnection { 61 | constructor(driver) { 62 | this.driver = driver; 63 | } 64 | 65 | create(rtcConfiguration) { 66 | return this.driver.executeScript(rtcConfiguration => { 67 | window.pc = new RTCPeerConnection(rtcConfiguration); 68 | }, rtcConfiguration); 69 | } 70 | 71 | addTrack(track, stream) { 72 | return this.driver.executeScript((track, stream) => { 73 | stream = localStreams[stream.id]; 74 | track = stream.getTracks().find(t => t.id === track.id); 75 | pc.addTrack(track, stream); 76 | }, track, stream); 77 | } 78 | 79 | createOffer(offerOptions) { 80 | return this.driver.executeAsyncScript((offerOptions) => { 81 | const callback = arguments[arguments.length - 1]; 82 | 83 | pc.createOffer(offerOptions) 84 | .then(callback, callback); 85 | }, offerOptions); 86 | } 87 | createAnswer() { 88 | return this.driver.executeAsyncScript(() => { 89 | const callback = arguments[arguments.length - 1]; 90 | 91 | pc.createAnswer() 92 | .then(callback, callback); 93 | }); 94 | } 95 | 96 | // resolves with non-trickle description including candidates. 97 | setLocalDescription(desc) { 98 | return this.driver.executeAsyncScript((desc) => { 99 | const callback = arguments[arguments.length - 1]; 100 | 101 | pc.onicecandidate = (event) => { 102 | console.log('candidate', event.candidate); 103 | if (!event.candidate) { 104 | pc.onicecandidate = null; 105 | callback(pc.localDescription); 106 | } 107 | }; 108 | pc.setLocalDescription(desc) 109 | .catch(callback); 110 | }, desc); 111 | } 112 | 113 | // TODO: this implicitly creates video elements, is that deseriable? 114 | setRemoteDescription(desc) { 115 | return this.driver.executeAsyncScript(function(desc) { 116 | const callback = arguments[arguments.length - 1]; 117 | 118 | pc.ontrack = function(event) { 119 | const id = event.streams[0].id; 120 | if (document.getElementById('video-' + id)) { 121 | return; 122 | } 123 | const video = document.createElement('video'); 124 | video.id = 'video-' + id; 125 | video.autoplay = true; 126 | video.srcObject = event.streams[0]; 127 | document.body.appendChild(video); 128 | }; 129 | pc.setRemoteDescription(new RTCSessionDescription(desc)) 130 | .then(callback, callback); 131 | }, desc); 132 | } 133 | } 134 | 135 | module.exports = { 136 | PeerConnection, 137 | MediaDevices, 138 | MediaStream, 139 | }; 140 | 141 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/google/gopacket" 13 | "github.com/google/gopacket/pcap" 14 | ) 15 | 16 | const OffsetContentType = 0 17 | const OffsetHandshakeType = 13 18 | const OffsetMajorVersion = 25 19 | 20 | const ClientHelloType = 1 21 | const ServerHelloType = 2 22 | const HelloVerifyRequest = 3 23 | const HandshakeType = 22 24 | 25 | func appendFingerprint(file string, fingerprint string, version string) error { 26 | var fileStrings []string 27 | 28 | readFile, err := os.Open(file) 29 | 30 | if err != nil { 31 | return err 32 | } 33 | fileScanner := bufio.NewScanner(readFile) 34 | 35 | fileScanner.Split(bufio.ScanLines) 36 | 37 | var isDone bool 38 | var hasVersion bool 39 | 40 | for fileScanner.Scan() { 41 | line := fileScanner.Text() 42 | 43 | if line == ")" && !hasVersion { 44 | fileStrings = append(fileStrings, fmt.Sprintf(" %s ClientHelloFingerprint = \"%s\" //nolint:revive,stylecheck", version, fingerprint)) 45 | } else if strings.Contains(line, "}") && !isDone && !hasVersion { 46 | fileStrings = append(fileStrings, fmt.Sprintf(" %s, //nolint:revive,stylecheck", version)) 47 | isDone = true 48 | } else if strings.Contains(line, "ClientHelloFingerprint =") { 49 | slist := strings.Split(line, "ClientHelloFingerprint") 50 | if len(slist) > 1 { 51 | fversion := slist[0] 52 | fversion = strings.Trim(fversion, " ") 53 | fversion = strings.Trim(fversion, "\t") 54 | fmt.Println(fversion) 55 | if fversion == version { 56 | hasVersion = true 57 | } 58 | } 59 | } 60 | fileStrings = append(fileStrings, line) 61 | } 62 | 63 | readFile.Close() 64 | 65 | f, err := os.Create(file) 66 | if err != nil { 67 | f.Close() 68 | return err 69 | } 70 | 71 | for _, v := range fileStrings { 72 | _, err = fmt.Fprintln(f, v) 73 | if err != nil { 74 | f.Close() 75 | return err 76 | } 77 | } 78 | err = f.Close() 79 | return err 80 | } 81 | 82 | func parsePcap(path string, filename string) error { 83 | fmt.Printf("Parsing %s\n", filename) 84 | 85 | var parsedClientHello bool 86 | 87 | tmp := strings.Split(filename, "-") 88 | version := tmp[len(tmp)-1] 89 | version = strings.TrimSuffix(version, ".pcap") 90 | version = strings.Trim(version, "_") 91 | version = strings.ToUpper(version[:1]) + version[1:] 92 | 93 | handle, err := pcap.OpenOffline(path) 94 | if err != nil { 95 | return err 96 | } 97 | defer handle.Close() 98 | 99 | packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) 100 | for packet := range packetSource.Packets() { 101 | 102 | dtls := packet.ApplicationLayer().LayerContents() 103 | 104 | if len(dtls) < OffsetContentType { 105 | return errors.New("parsed packet is empty") 106 | } 107 | if dtls[OffsetContentType] == HandshakeType { 108 | 109 | if len(dtls) < OffsetHandshakeType { 110 | return errors.New("parsed packet does not contain a handshake") 111 | } 112 | handshakeType := uint(dtls[OffsetHandshakeType]) 113 | 114 | switch handshakeType { 115 | case ClientHelloType: 116 | if len(dtls) < OffsetMajorVersion { 117 | return errors.New("parsed client hello does not have any fields") 118 | } 119 | fingerprintRaw := dtls[OffsetMajorVersion:] 120 | fingerprintString := hex.EncodeToString(fingerprintRaw) 121 | 122 | // Only parse one client hello per handshake 123 | if !parsedClientHello { 124 | var file string 125 | // supported_versions extension and DTLS 1.3 126 | if strings.Contains(fingerprintString, "002b") && strings.Contains(fingerprintString, "fefc") { 127 | file = "./pkg/fingerprints/fingerprints_13.go" 128 | } else { 129 | file = "./pkg/fingerprints/fingerprints.go" 130 | } 131 | err = appendFingerprint(file, fingerprintString, version) 132 | if err != nil { 133 | return err 134 | } 135 | parsedClientHello = true 136 | } 137 | default: 138 | } 139 | 140 | } 141 | } 142 | return nil 143 | } 144 | 145 | func main() { 146 | if len(os.Args) < 1 { 147 | fmt.Println("Please provide pcaps") 148 | os.Exit(1) 149 | } 150 | 151 | err := filepath.Walk(os.Args[1], func(path string, info os.FileInfo, err error) error { 152 | if err != nil { 153 | return err 154 | } 155 | if !info.IsDir() && strings.Contains(info.Name(), ".pcap") { 156 | err = parsePcap(path, info.Name()) 157 | if err != nil { 158 | return err 159 | } 160 | } 161 | return nil 162 | }) 163 | if err != nil { 164 | fmt.Fprintf(os.Stderr, "failed during parsing of pcap: %v\n", err) 165 | os.Exit(1) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /pkg/randomize/randomize_client_hello.go: -------------------------------------------------------------------------------- 1 | package randomize 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | "github.com/pion/dtls/v3/pkg/protocol" 7 | "github.com/pion/dtls/v3/pkg/protocol/extension" 8 | "github.com/pion/dtls/v3/pkg/protocol/handshake" 9 | "github.com/theodorsm/covert-dtls/pkg/utils" 10 | ) 11 | 12 | /* 13 | RandomizedMessageClientHello 14 | */ 15 | type RandomizedMessageClientHello struct { 16 | Version protocol.Version 17 | Random handshake.Random 18 | Cookie []byte 19 | RandomALPN bool // Add a random ALPN if there is none in the hooked message 20 | 21 | SessionID []byte 22 | 23 | CipherSuiteIDs []uint16 24 | CompressionMethods []*protocol.CompressionMethod 25 | Extensions []extension.Extension 26 | } 27 | 28 | const handshakeMessageClientHelloVariableWidthStart = 34 29 | 30 | // Type returns the Handshake Type 31 | func (m RandomizedMessageClientHello) Type() handshake.Type { 32 | return handshake.TypeClientHello 33 | } 34 | 35 | // ClientHello Hook for randomization 36 | func (m *RandomizedMessageClientHello) Hook(ch handshake.MessageClientHello) handshake.Message { 37 | buf, err := ch.Marshal() 38 | if err != nil { 39 | return &ch 40 | } 41 | err = m.Unmarshal(buf) 42 | if err != nil { 43 | return &ch 44 | } 45 | m.CipherSuiteIDs = utils.ShuffleRandomLength(m.CipherSuiteIDs, true) 46 | 47 | hasALPN := false 48 | for _, e := range m.Extensions { 49 | if e.TypeValue() == extension.TypeValue(extension.ALPNTypeValue) { 50 | hasALPN = true 51 | } 52 | } 53 | if !hasALPN && m.RandomALPN { 54 | e := &extension.ALPN{ 55 | ProtocolNameList: []string{utils.ALPNS[utils.RandRange(0, len(utils.ALPNS)-1)]}, 56 | } 57 | m.Extensions = append(m.Extensions, e) 58 | } 59 | 60 | m.Extensions = utils.ShuffleRandomLength(m.Extensions, false) 61 | return m 62 | } 63 | 64 | // Marshal encodes the Handshake 65 | func (m *RandomizedMessageClientHello) Marshal() ([]byte, error) { 66 | if len(m.Cookie) > 255 { 67 | return nil, errCookieTooLong 68 | } 69 | 70 | out := make([]byte, handshakeMessageClientHelloVariableWidthStart) 71 | out[0] = m.Version.Major 72 | out[1] = m.Version.Minor 73 | 74 | rand := m.Random.MarshalFixed() 75 | copy(out[2:], rand[:]) 76 | 77 | out = append(out, byte(len(m.SessionID))) 78 | out = append(out, m.SessionID...) 79 | 80 | out = append(out, byte(len(m.Cookie))) 81 | out = append(out, m.Cookie...) 82 | out = append(out, utils.EncodeCipherSuiteIDs(m.CipherSuiteIDs)...) 83 | out = append(out, protocol.EncodeCompressionMethods(m.CompressionMethods)...) 84 | extensions, err := utils.ExtensionMarshal(m.Extensions) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | return append(out, extensions...), nil 90 | } 91 | 92 | // Unmarshal populates the message from encoded data 93 | func (m *RandomizedMessageClientHello) Unmarshal(data []byte) error { 94 | if len(data) < 2+handshake.RandomLength { 95 | return errBufferTooSmall 96 | } 97 | 98 | m.Version.Major = data[0] 99 | m.Version.Minor = data[1] 100 | 101 | var random [handshake.RandomLength]byte 102 | copy(random[:], data[2:]) 103 | m.Random.UnmarshalFixed(random) 104 | 105 | // rest of packet has variable width sections 106 | currOffset := handshakeMessageClientHelloVariableWidthStart 107 | 108 | currOffset++ 109 | if len(data) <= currOffset { 110 | return errBufferTooSmall 111 | } 112 | n := int(data[currOffset-1]) 113 | if len(data) <= currOffset+n { 114 | return errBufferTooSmall 115 | } 116 | m.SessionID = append([]byte{}, data[currOffset:currOffset+n]...) 117 | currOffset += len(m.SessionID) 118 | 119 | currOffset++ 120 | if len(data) <= currOffset { 121 | return errBufferTooSmall 122 | } 123 | n = int(data[currOffset-1]) 124 | if len(data) <= currOffset+n { 125 | return errBufferTooSmall 126 | } 127 | m.Cookie = append([]byte{}, data[currOffset:currOffset+n]...) 128 | currOffset += len(m.Cookie) 129 | 130 | // Cipher Suites 131 | if len(data) < currOffset { 132 | return errBufferTooSmall 133 | } 134 | cipherSuiteIDs, err := utils.DecodeCipherSuiteIDs(data[currOffset:]) 135 | if err != nil { 136 | return err 137 | } 138 | m.CipherSuiteIDs = cipherSuiteIDs 139 | if len(data) < currOffset+2 { 140 | return errBufferTooSmall 141 | } 142 | currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2 143 | 144 | // Compression Methods 145 | if len(data) < currOffset { 146 | return errBufferTooSmall 147 | } 148 | compressionMethods, err := protocol.DecodeCompressionMethods(data[currOffset:]) 149 | if err != nil { 150 | return err 151 | } 152 | m.CompressionMethods = compressionMethods 153 | if len(data) < currOffset { 154 | return errBufferTooSmall 155 | } 156 | currOffset += int(data[currOffset]) + 1 157 | 158 | // Extensions 159 | extensions, err := RandomizeExtensionUnmarshal(data[currOffset:]) 160 | if err != nil { 161 | return err 162 | } 163 | m.Extensions = extensions 164 | return nil 165 | } 166 | -------------------------------------------------------------------------------- /.github/workflows/browser-test/webdriver.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. 7 | */ 8 | const os = require('os'); 9 | const path = require('path'); 10 | 11 | const webdriver = require('selenium-webdriver'); 12 | const chrome = require('selenium-webdriver/chrome'); 13 | const firefox = require('selenium-webdriver/firefox'); 14 | const safari = require('selenium-webdriver/safari'); 15 | 16 | const puppeteerBrowsers = require('@puppeteer/browsers'); 17 | 18 | async function download(browser, version, cacheDir, platform) { 19 | const buildId = await puppeteerBrowsers 20 | .resolveBuildId(browser, platform, version); 21 | await puppeteerBrowsers.install({ 22 | browser, 23 | buildId, 24 | cacheDir, 25 | platform 26 | }); 27 | return buildId; 28 | } 29 | const cacheDir = path.join(process.cwd(), 'browsers'); 30 | 31 | if (os.platform() === 'win32') { 32 | process.env.PATH += ';' + process.cwd() + '\\node_modules\\chromedriver\\lib\\chromedriver\\'; 33 | process.env.PATH += ';' + process.cwd() + '\\node_modules\\geckodriver'; 34 | } else { 35 | process.env.PATH += ':node_modules/.bin'; 36 | } 37 | 38 | function mapVersion(browser, version) { 39 | const versionMap = { 40 | chrome: { 41 | unstable: 'canary', 42 | }, 43 | firefox: { 44 | unstable: 'nightly', 45 | } 46 | }; 47 | return (versionMap[browser] || {})[version] || version; 48 | } 49 | 50 | async function buildDriver(browser = process.env.BROWSER || 'chrome', options = { version: process.env.BVER }) { 51 | const version = mapVersion(options.version); 52 | const platform = puppeteerBrowsers.detectBrowserPlatform(); 53 | 54 | const buildId = await download(browser, version || 'stable', 55 | cacheDir, platform); 56 | 57 | // Chrome options. 58 | const chromeOptions = new chrome.Options() 59 | .addArguments('no-sandbox') 60 | .addArguments('allow-insecure-localhost') 61 | .addArguments('use-fake-device-for-media-stream') 62 | .addArguments('allow-file-access-from-files'); 63 | if (options.chromeFlags) { 64 | options.chromeFlags.forEach((flag) => chromeOptions.addArguments(flag)); 65 | } 66 | if (options.chromepath) { 67 | chromeOptions.setChromeBinaryPath(options.chromepath); 68 | } else { 69 | chromeOptions.setChromeBinaryPath(puppeteerBrowsers 70 | .computeExecutablePath({ browser, buildId, cacheDir, platform })); 71 | } 72 | 73 | if (!options.devices || options.headless) { 74 | // GUM doesn't work in headless mode so we need this. See 75 | // https://bugs.chromium.org/p/chromium/issues/detail?id=776649 76 | chromeOptions.addArguments('use-fake-ui-for-media-stream'); 77 | } else { 78 | // see https://bugs.chromium.org/p/chromium/issues/detail?id=459532#c22 79 | const domain = 'https://' + (options.devices.domain || 'localhost') + ':' + (options.devices.port || 443) + ',*'; 80 | const exceptions = { 81 | media_stream_mic: {}, 82 | media_stream_camera: {}, 83 | }; 84 | 85 | exceptions.media_stream_mic[domain] = { 86 | last_used: Date.now(), 87 | setting: options.devices.audio ? 1 : 2 // 0: ask, 1: allow, 2: denied 88 | }; 89 | exceptions.media_stream_camera[domain] = { 90 | last_used: Date.now(), 91 | setting: options.devices.video ? 1 : 2 92 | }; 93 | 94 | chromeOptions.setUserPreferences({ 95 | profile: { 96 | content_settings: { 97 | exceptions: exceptions 98 | } 99 | } 100 | }); 101 | } 102 | 103 | // Safari options. 104 | const safariOptions = new safari.Options(); 105 | safariOptions.setTechnologyPreview(version === 'unstable'); 106 | 107 | // Firefox options. 108 | const firefoxOptions = new firefox.Options(); 109 | let firefoxPath = firefox.Channel.RELEASE; 110 | if (options.firefoxpath) { 111 | firefoxPath = options.firefoxpath; 112 | } else { 113 | firefoxPath = puppeteerBrowsers 114 | .computeExecutablePath({ browser, buildId, cacheDir, platform }); 115 | } 116 | if (options.headless) { 117 | firefoxOptions.addArguments('-headless'); 118 | } 119 | firefoxOptions.setBinary(firefoxPath); 120 | firefoxOptions.setPreference('media.navigator.streams.fake', true); 121 | firefoxOptions.setPreference('media.navigator.permission.disabled', true); 122 | // Force DTLS 1.2 123 | firefoxOptions.setPreference('media.peerconnection.dtls.version.max', 771); 124 | 125 | const driver = new webdriver.Builder() 126 | .setChromeOptions(chromeOptions) 127 | .setSafariOptions(safariOptions) 128 | .setFirefoxOptions(firefoxOptions) 129 | .forBrowser(browser) 130 | .setChromeService( 131 | new chrome.ServiceBuilder().addArguments('--disable-build-check') 132 | ); 133 | 134 | if (browser === 'firefox') { 135 | driver.getCapabilities().set('marionette', true); 136 | driver.getCapabilities().set('acceptInsecureCerts', true); 137 | } 138 | return driver.build(); 139 | } 140 | 141 | module.exports = { 142 | buildDriver, 143 | }; 144 | -------------------------------------------------------------------------------- /.github/workflows/fingerprint.yaml: -------------------------------------------------------------------------------- 1 | name: Fingerprinting 2 | on: 3 | push: 4 | branches: 5 | - main 6 | schedule: 7 | - cron: "0 1 * * *" 8 | 9 | 10 | jobs: 11 | handshake-capture: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 5 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | browser: [firefox, chrome] 18 | bver: [stable] 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | - name: Install tshark 23 | run: sudo apt install -y tshark 24 | 25 | - uses: actions/setup-node@v4 26 | 27 | - run: npm install 28 | working-directory: .github/workflows/browser-test/ 29 | 30 | - name: Remove preinstalled github chromedriver/geckodriver from $PATH 31 | run: sudo rm /usr/bin/chromedriver /usr/bin/geckodriver 32 | 33 | - run: Xvfb :99 & 34 | 35 | - name: Install browser version 36 | run: BROWSER_A=${{matrix.browser}} BROWSER_B=${{matrix.browser}} BVER=${{matrix.bver}} DISPLAY=:99.0 node download-browsers.js 37 | working-directory: .github/workflows/browser-test/ 38 | 39 | - name: Get browser version 40 | id: "browser" 41 | run: echo "version=$(ls ./browsers/${{matrix.browser}} | sed -e 's/ /_/g' -e 's/\./_/g' -e 's/\-/_/g')" >> $GITHUB_OUTPUT 42 | working-directory: .github/workflows/browser-test/ 43 | 44 | - name: Create directory for pcaps 45 | run: | 46 | mkdir ./captures/ 47 | touch ./captures/full-capture-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap 48 | sudo chown -R root:root ./captures 49 | ls -lga ./captures 50 | - name: Start tshark capture 51 | run: sudo tshark -i any -w ./captures/full-capture-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap -f "udp" & 52 | 53 | - name: Run webrtc applications with jest/selenium 54 | run: BROWSER_A=${{matrix.browser}} BROWSER_B=${{matrix.browser}} BVER=${{matrix.bver}} DISPLAY=:99.0 node_modules/.bin/jest --retries=3 interop 55 | working-directory: .github/workflows/browser-test/ 56 | 57 | - name: Kill tshark capture 58 | run: sudo killall tshark 1> /dev/null 2> /dev/null 59 | continue-on-error: true 60 | 61 | - name: Filter DTLS handshake in pcap 62 | run: sudo tshark -r ./captures/full-capture-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap -Y "dtls.handshake" -w ./captures/capture-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap 63 | 64 | - name: Archive pcap 65 | uses: actions/upload-artifact@v4 66 | with: 67 | name: fingerprint-pcap-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap 68 | path: ./captures/capture-${{matrix.browser}}_${{steps.browser.outputs.version}}.pcap 69 | 70 | commit-fingerprints: 71 | needs: handshake-capture 72 | runs-on: ubuntu-latest 73 | 74 | steps: 75 | - uses: actions/checkout@v3 76 | with: 77 | ref: ${{ github.event.pull_request.head.ref }} 78 | 79 | - name: Create fingerprint directory 80 | run: | 81 | mkdir -p ./fingerprints-captures 82 | mkdir -p ${{ runner.temp }}/fingerprints-captures 83 | 84 | - name: Download all artifacts 85 | uses: actions/download-artifact@v4 86 | with: 87 | path: ${{ runner.temp }}/fingerprints-captures 88 | pattern: fingerprint-pcap-* 89 | merge-multiple: true 90 | 91 | - name: Install libpcap 92 | run: sudo apt install libpcap-dev 93 | 94 | - name: Setup go 95 | uses: actions/setup-go@v5 96 | with: 97 | go-version: '1.23' 98 | 99 | - name: Run pcap fingerprint parser 100 | run: | 101 | go get . 102 | go run main.go ${{ runner.temp }}/fingerprints-captures 103 | 104 | - name: Run gofmt on fingerprints.go 105 | run: gofmt -s -w ./pkg/fingerprints/fingerprints.go ./pkg/fingerprints/fingerprints_13.go 106 | 107 | - name: golangci-lint 108 | uses: golangci/golangci-lint-action@v6 109 | with: 110 | version: v1.60.1 111 | skip-pkg-cache: true 112 | skip-build-cache: true 113 | args: $GOLANGCI_LINT_EXRA_ARGS 114 | 115 | - name: Run TestLoadFingerprints 116 | working-directory: ./pkg/mimicry 117 | run: go test -v --run TestLoadFingerprints 118 | 119 | - name: Commit fingerprints 120 | run: | 121 | git config user.name github-actions 122 | git config user.email github-actions@github.com 123 | git add ./pkg/fingerprints/fingerprints.go ./pkg/fingerprints/fingerprints_13.go 124 | ls -R ${{ runner.temp }}/fingerprints-captures 125 | ls -R ./fingerprints-captures 126 | fingerprints="" 127 | for file in ${{ runner.temp }}/fingerprints-captures/*; do 128 | if ! [[ -f ./fingerprints-captures/"${file##*/}" ]]; then 129 | mv ${{ runner.temp }}/fingerprints-captures/"${file##*/}" ./fingerprints-captures/ 130 | git add ./fingerprints-captures/"${file##*/}" 131 | fingerprint=$(echo "${file##*/}" | sed -e 's/.pcap//g' -e 's/capture-//g' -e 's/./\u&/') 132 | fingerprints="${fingerprints} ${fingerprint}" 133 | fi 134 | done 135 | git commit -m "Add fresh fingerprints" -m "$fingerprints" 136 | git push 137 | -------------------------------------------------------------------------------- /pkg/mimicry/mimic_client_hello.go: -------------------------------------------------------------------------------- 1 | package mimicry 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/hex" 6 | 7 | "github.com/pion/dtls/v3/pkg/protocol" 8 | "github.com/pion/dtls/v3/pkg/protocol/extension" 9 | "github.com/pion/dtls/v3/pkg/protocol/handshake" 10 | "github.com/theodorsm/covert-dtls/pkg/fingerprints" 11 | "github.com/theodorsm/covert-dtls/pkg/utils" 12 | ) 13 | 14 | const handshakeMessageClientHelloVariableWidthStart = 34 15 | 16 | // MimickedClientHello is to be used as a way to replay DTLS client hello messages. To be used with the Pion dtls library. 17 | type MimickedClientHello struct { 18 | clientHelloFingerprint fingerprints.ClientHelloFingerprint 19 | Version protocol.Version 20 | Random handshake.Random 21 | Cookie []byte 22 | SessionID []byte 23 | 24 | CipherSuiteIDs []uint16 25 | CompressionMethods []*protocol.CompressionMethod 26 | Extensions []extension.Extension 27 | SRTPProtectionProfiles []extension.SRTPProtectionProfile 28 | } 29 | 30 | // Hook handler, initialize client hello 31 | func (m *MimickedClientHello) Hook(ch handshake.MessageClientHello) handshake.Message { 32 | m.Random = ch.Random 33 | m.SessionID = ch.SessionID 34 | m.Cookie = ch.Cookie 35 | return m 36 | } 37 | 38 | // Type returns the Handshake Type 39 | func (m MimickedClientHello) Type() handshake.Type { 40 | return handshake.TypeClientHello 41 | } 42 | 43 | // Parses hexstring fingerprint and sets Extensions and SRTPProtectionProfiles 44 | func (m *MimickedClientHello) LoadFingerprint(fingerprint fingerprints.ClientHelloFingerprint) error { 45 | m.clientHelloFingerprint = fingerprint 46 | data, err := hex.DecodeString(string(m.clientHelloFingerprint)) 47 | if err != nil { 48 | return errHexstringDecode 49 | } 50 | err = m.Unmarshal(data) 51 | return err 52 | } 53 | 54 | // Loads a random fingerprint to mimic 55 | func (m *MimickedClientHello) LoadRandomFingerprint() error { 56 | allFingerprints := fingerprints.GetClientHelloFingerprints() 57 | length := len(allFingerprints) 58 | randomFingerprint := allFingerprints[utils.RandRange(0, length-1)] 59 | return m.LoadFingerprint(randomFingerprint) 60 | } 61 | 62 | // Marshal encodes the Handshake 63 | func (m *MimickedClientHello) Marshal() ([]byte, error) { 64 | out := make([]byte, handshakeMessageClientHelloVariableWidthStart) 65 | 66 | if string(m.clientHelloFingerprint) == "" { 67 | random := m.Random 68 | sid := m.SessionID 69 | cookie := m.Cookie 70 | fingerprints := fingerprints.GetClientHelloFingerprints() 71 | if len(fingerprints) < 1 { 72 | return out, errNoFingerprints 73 | } 74 | fingerprint := fingerprints[len(fingerprints)-1] 75 | err := m.LoadFingerprint(fingerprint) 76 | if err != nil { 77 | return out, err 78 | } 79 | m.Random = random 80 | m.SessionID = sid 81 | m.Cookie = cookie 82 | } 83 | 84 | data, err := hex.DecodeString(string(m.clientHelloFingerprint)) 85 | if err != nil { 86 | return out, errHexstringDecode 87 | } 88 | 89 | if len(data) <= 2 { 90 | return out, errBufferTooSmall 91 | } 92 | 93 | if len(m.Cookie) > 255 { 94 | return nil, errCookieTooLong 95 | } 96 | 97 | out[0] = m.Version.Major 98 | out[1] = m.Version.Minor 99 | 100 | rand := m.Random.MarshalFixed() 101 | copy(out[2:], rand[:]) 102 | 103 | out = append(out, byte(len(m.SessionID))) 104 | out = append(out, m.SessionID...) 105 | 106 | out = append(out, byte(len(m.Cookie))) 107 | out = append(out, m.Cookie...) 108 | out = append(out, utils.EncodeCipherSuiteIDs(m.CipherSuiteIDs)...) 109 | out = append(out, protocol.EncodeCompressionMethods(m.CompressionMethods)...) 110 | 111 | extensions, err := utils.ExtensionMarshal(m.Extensions) 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | return append(out, extensions...), nil 117 | } 118 | 119 | // Unmarshal populates the message from encoded data 120 | func (m *MimickedClientHello) Unmarshal(data []byte) error { 121 | if len(data) < 2+handshake.RandomLength { 122 | return errBufferTooSmall 123 | } 124 | 125 | m.Version.Major = data[0] 126 | m.Version.Minor = data[1] 127 | 128 | var random [handshake.RandomLength]byte 129 | copy(random[:], data[2:]) 130 | m.Random.UnmarshalFixed(random) 131 | 132 | // rest of packet has variable width sections 133 | currOffset := handshakeMessageClientHelloVariableWidthStart 134 | 135 | currOffset++ 136 | if len(data) <= currOffset { 137 | return errBufferTooSmall 138 | } 139 | n := int(data[currOffset-1]) 140 | if len(data) <= currOffset+n { 141 | return errBufferTooSmall 142 | } 143 | m.SessionID = append([]byte{}, data[currOffset:currOffset+n]...) 144 | currOffset += len(m.SessionID) 145 | 146 | currOffset++ 147 | if len(data) <= currOffset { 148 | return errBufferTooSmall 149 | } 150 | n = int(data[currOffset-1]) 151 | if len(data) <= currOffset+n { 152 | return errBufferTooSmall 153 | } 154 | m.Cookie = append([]byte{}, data[currOffset:currOffset+n]...) 155 | currOffset += len(m.Cookie) 156 | 157 | // Cipher Suites 158 | if len(data) < currOffset { 159 | return errBufferTooSmall 160 | } 161 | cipherSuiteIDs, err := utils.DecodeCipherSuiteIDs(data[currOffset:]) 162 | if err != nil { 163 | return err 164 | } 165 | m.CipherSuiteIDs = cipherSuiteIDs 166 | if len(data) < currOffset+2 { 167 | return errBufferTooSmall 168 | } 169 | currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2 170 | 171 | // Compression Methods 172 | if len(data) < currOffset { 173 | return errBufferTooSmall 174 | } 175 | compressionMethods, err := protocol.DecodeCompressionMethods(data[currOffset:]) 176 | if err != nil { 177 | return err 178 | } 179 | m.CompressionMethods = compressionMethods 180 | if len(data) < currOffset { 181 | return errBufferTooSmall 182 | } 183 | currOffset += int(data[currOffset]) + 1 184 | 185 | // Extensions 186 | extensions, err := MimicExtensionsUnmarshal(data[currOffset:]) 187 | if err != nil { 188 | return err 189 | } 190 | m.Extensions = extensions 191 | return nil 192 | } 193 | -------------------------------------------------------------------------------- /pkg/fingerprints/fingerprints_13.go: -------------------------------------------------------------------------------- 1 | package fingerprints 2 | 3 | /* 4 | These fingerprints are automatically generated and added by the 'fingerprint' workflow. 5 | The first byte should correspond to the DTLS version in a handshake message. 6 | All fingerprints in this file should be version 1.3. 7 | Use with caution, micking of 1.3 is not fully supported and unstable. 8 | */ 9 | 10 | const ( 11 | Firefox_linux_stable_127_0 ClientHelloFingerprint = "fefd713910e31aa451cda18c437634c566fb872731739ada472eafa74741c7d02c8c0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00209b3a0682a66a92872457a05dfd4ce6f92312ef605e960f36b8fd71f054b60540002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 12 | Firefox_linux_stable_127_0_1 ClientHelloFingerprint = "fefde650a0e526f3b0a64bb3547c83b9bb49f7c3e2dd1fb8585b8b1a30c233e30c960000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00203c07b94e15938de0e284acde46a1c7ea20da8c8b2256a3d1a04a3e86e150012a002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 13 | Firefox_linux_stable_127_0_2 ClientHelloFingerprint = "fefd25d4c2940a42cdf4f8094a9136ed8eda238e8f2b49b6220437c8ecba1363dd810000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00207d9770842d3d0284165e093b27b7e8f7102c76777cdd1fd9204580c4e620aa63002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 14 | Firefox_linux_stable_128_0 ClientHelloFingerprint = "fefd6e604b6349138a46f40357e84922b2765a5dd063291784be4679d7e5a3d79c440000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d0020c20534bdd8ed3b4b2f0ab41073c9bd1943f2c657cd8e20e9830a7324347e4b64002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 15 | Firefox_linux_stable_128_0_2 ClientHelloFingerprint = "fefd05f66093f4a729e42640d475fef0f2e249de2e163905b77640e63560377afd2b0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00201e655c04ea25c15fc667b740b853290684f826f9279426988db92f28d2109b6a002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 16 | Firefox_linux_stable_128_0_3 ClientHelloFingerprint = "fefd1c5bf73fed0023e86e70b0f806c21f805a881e0db08881fa94d0eafb51b9407c0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00203feb484830a52cdbf69af4b814c67248f2ad8de6b20c966795b8081aa792cd41002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 17 | Firefox_linux_stable_129_0 ClientHelloFingerprint = "fefdd4e89f94ca863c1cc245fa75ff5eb955989d639bc7176eda7f0965fc8c10488f0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d0020c19d69148ab471f273d110ed7c22c40731a87044b653728aca6f4c9385548a64002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 18 | Firefox_linux_stable_129_0_1 ClientHelloFingerprint = "fefdb0d31df092f435f48e76ca4a9d80ad1ddec4ed3c9442efdeacf3a342a1bf19550000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00208ddbb69aec73ce2f7a17d10785a85bda542a44c3de05011c4fe39cca0fd48d0f002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 19 | Firefox_linux_stable_130_0 ClientHelloFingerprint = "fefd756b703ad52e00975e5a7793d4af3ee5fdfeaa2aebc2a19d7513aec2fde4aabe0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d0020cd13d322ef7caa203087b220927b35087c83c3ebeae2dae37a32b2183ecfd666002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 20 | Firefox_linux_stable_130_0_1 ClientHelloFingerprint = "fefd546be4ce561fa42db5f09c21adfb9a37dc8aa0d662a80ce2823bfd2d1767736d0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d00202ffdd51b164904d0c982d474a56bd31f964437f3cbc56fe3b06907444574171f002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 21 | Firefox_linux_stable_131_0 ClientHelloFingerprint = "fefd60f3c57f94792ddcf45f57531d05b8043533d65a01509bed9a84b485a3bc4f130000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d002068fb315497b5eb24d8dfb2d4de29a32e9161ed901d1aa841ebe1c8f3ce81af0e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 22 | Firefox_linux_stable_133_0 ClientHelloFingerprint = "fefd04b8abc587ec1aa825f9e49c608780fd7967afecf6f71208a5ed71aff6bdb3f90000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d0020106d18aa5301eb1aa0bacf3e0c70b3ec15509b7b51f5ea2c3d222f7924c52d3e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 23 | Firefox_linux_stable_133_0_3 ClientHelloFingerprint = "fefd879430a815539a07e6a6b12a1645950dbdb9e37937ac335aab7150137226164c0000001413011303c02bc02fcca9cca8c00ac009c013c014010000b100170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a00080403050306030203003300260024001d0020d80a068595c22364ae53e2c99b124b8ac14d2e169c8ee1410341f3e3338d661e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 24 | Firefox_linux_stable_134_0 ClientHelloFingerprint = "fefd24cd00516b0fe60525511a7118a609117bbaa1e2d34dd4663b3dc96dc9a02cd30000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d002061b6ee807f6dce2d21f3061987ab0de030e309f78b646c1c6fda5da2e4ea2a540017004104bed4c5632e9b326eea0d7287cb1e55cf99fd92b7bbe856ad867884763af042dc92234296579bb4ed094cc0e2ee6685d0ec1e021e887d33b8d18032a14fcee94e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 25 | Firefox_linux_stable_134_0_1 ClientHelloFingerprint = "fefd2cda024937fbca13cb7e931222549dd0d605e84ff321cabe810cf7aacacec8b10000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d00200d948e8363c7250bfd7c5af64a7c83e4fd4e82b5af55bd98914ac13edc6d41440017004104984d153bfbfb019b530995f751d5ed2cad37215dedac6a7f299336e68948a6c10e70fdce26ca415d20799c8a00126469eda0b33ca20df2a49cbdac454678052e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 26 | Firefox_linux_stable_134_0_2 ClientHelloFingerprint = "fefd9bd60779d0a2643d977280c26344aeb5443237981d87debae28511852478434c0000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d0020874cab272c28094fc1a7b622bfd8ff56351f7a8e6405bea081ace223c893035f00170041049868f92a31a02b8f4e2de7b7d445a5fba92fc1df3022a28a46efc6acabeeaf4c40eb131200abfe96cc188ea72523d4a43c116418ee0b6f2888ab296499b2b1e4002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 27 | Firefox_linux_stable_135_0 ClientHelloFingerprint = "fefd08225d3db6bc211fc39c9bac9634ff0a4ed3f9b711054b309ca00fa49029571f0000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d0020c110b12e8e0a3e28f51d9a12ebb1c001f32f79bca18f8a58f2a3289fc359ba470017004104902a0553b41da6e51449de01979fc9cabc24075d1a6982211ceb24c6e13510018ab233e34ae7b2cc7f56a6a6e810d5cc4b3d033da25e6bc3ad7f7ab3b585ddac002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 28 | Firefox_linux_stable_135_0_1 ClientHelloFingerprint = "fefd7e4dc72a45d3fa9508af96b03989d61a783e55691a85b747eda0cc7040a27c4c0000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d00205261ca3aa4a32facf3f71edb5ebb7fdfa88d04319e56e38186323c24e8445e0e00170041047bddd9aab2d656b8231eb0e32cc7f26acde055b33f11a2225e93b792bd1598ae5c8acdd2574e503a3f4f25822b6325e2e0b917273f9777270877e5e3b8c77398002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 29 | Firefox_linux_stable_136_0 ClientHelloFingerprint = "fefdc7afb8de070c72fd4aadcbf576be10a3048ef04b031996d92dd022867d089d750000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d00204208bb77f94308c0779686e7dcbc22141682352d6cd14966b8edf8df76bae43d0017004104e12f12a65627f5e309084bdf73ad8c61addf2bc66df2071df74821e439abb1afc1a33c473c1658e061089318ac73d324c22041087195fce52beeb868b98c2e57002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 30 | Firefox_linux_stable_136_0_1 ClientHelloFingerprint = "fefd1b7416fdfa9149b8d9242bba32d2e06d12dcf8ce4c1fe2342a1f1fbd104eda590000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d002064551351d6927b3479ceffee0ceca7fe99d075fcf56c3696f69dbc592d4790100017004104b02be4bad04540f69c758d9c0553e209cc8bc82a75d8435240d48a14b432c422e2277f7926a1529277137f7dcad60388384dfff3938e74b1aa0fd2844addc45e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 31 | Firefox_linux_stable_136_0_2 ClientHelloFingerprint = "fefd2356eb912074497a8aa536295e59c0f80bbe93d3f4268d4cd49f595ebd8351360000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d0020259dfadbf535147ab41ffaee0ded69f92d12bae3b19b5c80b2f0020405ed6d1c0017004104638665bbed3b58bbba134cc634d2701a8bdf47c29ab215e7c948e4d430dc835abdc196503e66094d7607bbda125aee7f0c33c525a213e66901a57a94a0ae8215002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 32 | Firefox_linux_stable_136_0_3 ClientHelloFingerprint = "fefd09f6c09dabf425847bf815dbedbfb09344718e9e1ba9b59e887cfaf58ea08a5e0000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d0020dd9e3b1f77cc919cfbeb12e68021002b19067846da3f95871fed1b6d3ae0b93a0017004104f7da3eae2db58469a16b7aaf12d398400800f3b3295f2fe38b19dbf62077f2cead5617c5e37d775f72e800f07a483cf40e21097a3f3b93bb8ac17faf5b00676e002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 33 | Firefox_linux_stable_136_0_4 ClientHelloFingerprint = "fefda53227a7249031140707a495580dc26039550f65aff1ec0dfefa0bd94acb7f220000001413011303c02bc02fcca9cca8c00ac009c013c014010000f600170000ff01000100000a000c000a001d0017001801000101000b000201000010001200100677656272746308632d7765627274630022000a000804030503060302030033006b0069001d00203267f0ddad466443860284ee9b8b212c17d90cbd044febae925add13e8fa2d240017004104bdfc2fa0693286a08d95deff59f8381901360c80883963d0e9ca89048e4f78bbd3ae0ef5edacfff0e0a12264b9071ac6a3896846e6562e425f43f25f71abc044002b000706fefcfefd0303000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024001000e000b0008000700080001000200" //nolint:revive,stylecheck 34 | Chrome_linux_139_0_7258_138 ClientHelloFingerprint = "fefd8a9269790461e77503d20aa0265dfbc83e9e9a611eacf703a0c53da5d9f8639d0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000d00140012040308040401050308050501080606010201002d00020101000e0009000600010008000700ff01000100003300260024001d0020bf00face87c5477c7fc9f27164bc9f235849141f83dd3fc90124c1d62cdf3221000a00080006001d0017001800170000002b000504fefcfefd000b00020100" //nolint:revive,stylecheck 35 | Chrome_linux_139_0_7258_154 ClientHelloFingerprint = "fefd684ca81044ee49ac511389aad8d5436af310cb2414adf0118847bbb2b8c97c6c0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079002b000504fefcfefd000e000900060001000800070000170000000d00140012040308040401050308050501080606010201ff01000100000b00020100000a00080006001d00170018002d00020101003300260024001d00201ae4f5a4111ce5ed7f99e1ac9d15d6212adb3e96f34117ecb8e9708dc5dda363" //nolint:revive,stylecheck 36 | Chrome_linux_139_0_7258_66 ClientHelloFingerprint = "fefdf85e37d6f6bde402c8c43bcda2419587432f0409b7c06a1112e77084fd1d59d40000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079002d0002010100170000000e0009000600010008000700000a00080006001d00170018002b000504fefcfefd000b00020100000d00140012040308040401050308050501080606010201003300260024001d00203d3bb6007e13d8511cc326591aa66ae8a371deb83322d71e9338f03d197df10aff01000100" //nolint:revive,stylecheck 37 | Chrome_linux_139_0_7258_68 ClientHelloFingerprint = "fefd24d1169428ddae5e738f50596f51bf697467707633c5ec0e60c264d36314e74f0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079002b000504fefcfefd003300260024001d002042fc770197ccd108dcfdc38732794a848a2b856efbec1db63525bce2b50a4863000e0009000600010008000700ff01000100000b00020100000d0014001204030804040105030805050108060601020100170000000a00080006001d00170018002d00020101" //nolint:revive,stylecheck 38 | Chrome_linux_140_0_7339_185 ClientHelloFingerprint = "fefd2510b2117bc826d7f0c4e7e98270c8fa1fa5c07ca771fbbda36c8394e52840a40000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000a00080006001d00170018000e0009000600010008000700002b000504fefcfefd000b00020100002d00020101ff01000100000d00140012040308040401050308050501080606010201003300260024001d0020df7a94a70eeb8d87598abb23c9d394f3f0cf629db34a4ae305dd4c250d63110800170000" //nolint:revive,stylecheck 39 | Chrome_linux_140_0_7339_207 ClientHelloFingerprint = "fefde066d3966ed6310d0b12e6b092e9b011f01c40081b7c2e3981c1158ab42e0d110000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f00350100007900170000003300260024001d00200b1d54679eef088e54b472d1f70e50cbcc7f391a7e8e1e253cbb0a092ed7ea76002d00020101000b00020100000e0009000600010008000700000a00080006001d00170018000d00140012040308040401050308050501080606010201002b000504fefcfefdff01000100" //nolint:revive,stylecheck 40 | Chrome_linux_140_0_7339_80 ClientHelloFingerprint = "fefd084299e4ee70bb8177e8abad8911ac343ef5533d2fb12f237af7a72d4a67c3c70000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079002d00020101000d00140012040308040401050308050501080606010201002b000504fefcfefd00170000000a00080006001d00170018003300260024001d0020a8cc5af6c0f4c004e25f06144603b4674a1144754df84125875f6a53fe98056f000e0009000600010008000700000b00020100ff01000100" //nolint:revive,stylecheck 41 | Chrome_linux_140_0_7339_82 ClientHelloFingerprint = "fefdb49e04f8fe4d4b575802d18584dc387be429e1927c3e358ec86bce8cb21596450000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000b00020100000d00140012040308040401050308050501080606010201ff01000100000e0009000600010008000700002d00020101003300260024001d002004f9645bc442b0e1add2b4fae32ec979c9701242a10b39ecf8886ee2a77ceb20000a00080006001d0017001800170000002b000504fefcfefd" //nolint:revive,stylecheck 42 | Chrome_linux_141_0_7390_122 ClientHelloFingerprint = "fefd54c58224f1506280d61698466949bdfd588f81ac6f7a113d2aef25a3b747f7ba0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000d00140012040308040401050308050501080606010201003300260024001d00208418660bbe09a1387ad9c25554612c6325ccd161a43b8ac4df4dac76af96180100170000ff01000100000b00020100002b000504fefcfefd002d00020101000a00080006001d00170018000e0009000600010008000700" //nolint:revive,stylecheck 43 | Chrome_linux_141_0_7390_54 ClientHelloFingerprint = "fefd1c6282718f6016e78115631847daa3ca0451b7b6aa7729d02499862c15315f610000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000a00080006001d0017001800170000ff01000100002b000504fefcfefd000b00020100000d00140012040308040401050308050501080606010201000e0009000600010008000700003300260024001d00202925a893af36857d269aa14426753b8f6d713dc025028feb7af8c71d24716130002d00020101" //nolint:revive,stylecheck 44 | Chrome_linux_141_0_7390_65 ClientHelloFingerprint = "fefdd493862670f0b5fd4965f5037566ee4e44b16b8cf75a7c11fd697b759c9aae850000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000d00140012040308040401050308050501080606010201003300260024001d00204f4cc161b1523df6b22fd238617b151337de06ccf06d5c82c83e03b97f1bf641000a00080006001d00170018000e0009000600010008000700002d0002010100170000000b00020100ff01000100002b000504fefcfefd" //nolint:revive,stylecheck 45 | Chrome_linux_141_0_7390_76 ClientHelloFingerprint = "fefd046d4958d40be059387e8b2f9ee999135e11ee7f04b42591467486d27b776a400000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079ff0100010000170000000a00080006001d00170018002d00020101003300260024001d002040750719da4151f34b6c753d1983009f123d717e8718316158ce35674abb027b000e0009000600010008000700002b000504fefcfefd000d00140012040308040401050308050501080606010201000b00020100" //nolint:revive,stylecheck 46 | Chrome_linux_141_0_7390_78 ClientHelloFingerprint = "fefd45a2f104fda19e42aa11955c1d24a8e00c1acbe412fd07c96bbef184a8b7ac300000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000a00080006001d00170018000b00020100002d00020101003300260024001d0020c1ad92518fad1195415024597403ee08273fb62a3cd698fb1d835c2937509154ff01000100000d0014001204030804040105030805050108060601020100170000002b000504fefcfefd000e0009000600010008000700" //nolint:revive,stylecheck 47 | Chrome_linux_142_0_7444_162 ClientHelloFingerprint = "fefdce9bac5d1505dd3e785b5bcaeb8152402c38c7d6ac122ba0fb588aebaf86a98f0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000a00080006001d00170018000b00020100003300260024001d00206a20e3fffd27598605ad1ede19d9775515e5901ba9923faf2a757a7b6a169e46002b000504fefcfefd00170000ff01000100002d00020101000e0009000600010008000700000d00140012040308040401050308050501080606010201" //nolint:revive,stylecheck 48 | Chrome_linux_142_0_7444_175 ClientHelloFingerprint = "fefd532592c841ee0185ba42262301cd1fd0de092b72b0a1eae4379828237a2349340000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079ff01000100002b000504fefcfefd000b00020100002d0002010100170000000e0009000600010008000700003300260024001d0020a500d2e9f64a7a2ea6618b89b57cc961e7da13797859b233b893b6cb6734006e000d00140012040308040401050308050501080606010201000a00080006001d00170018" //nolint:revive,stylecheck 49 | Chrome_linux_142_0_7444_59 ClientHelloFingerprint = "fefd1d58aa135acc7e012f69aa092434b99b152ed3581ba1a18e10b3c4319d1d80270000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079003300260024001d00205fce8ebb2cdd05fa6dc3de6b46bc274f00f72b04d906c5f4cf6110c937b4f915ff01000100000e0009000600010008000700000a00080006001d00170018002b000504fefcfefd000d00140012040308040401050308050501080606010201000b00020100002d0002010100170000" //nolint:revive,stylecheck 50 | Chrome_linux_142_0_7444_61 ClientHelloFingerprint = "fefdd72aa14c78adecd49cd5a65dcf572e5da79fcdb6bc753f630535f0c5a63f8aab0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000a00080006001d0017001800170000002b000504fefcfefd000e0009000600010008000700002d00020101000b00020100003300260024001d002031914e2c4b361360d0ef3367c78ebc2789531d75e49f590b112e40504b7b1063ff01000100000d00140012040308040401050308050501080606010201" //nolint:revive,stylecheck 51 | Chrome_linux_143_0_7499_40 ClientHelloFingerprint = "fefdca686b3f8e60148ad067a6cfe32e6fe3e3a3123aef9389fbb854f9f62f932dce0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079000d00140012040308040401050308050501080606010201002d00020101000e000900060001000800070000170000003300260024001d0020905bb44d17a36ca6a7820faa0e5564de8d7a50a240ee5a20b04cf8381d8d776a000a00080006001d00170018ff01000100000b00020100002b000504fefcfefd" //nolint:revive,stylecheck 52 | Chrome_linux_143_0_7499_42 ClientHelloFingerprint = "fefddc9e6a1ddbcc1721c8ee0cd2eba28e63547defbfc381c557ef2dfc171b58d8080000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079003300260024001d0020115a1b7cc1f39a423df0ce81ad9f7f52a9e07e8408bbf6098688a53a5a680d7b000b00020100000a00080006001d00170018000e0009000600010008000700002b000504fefcfefdff0100010000170000000d00140012040308040401050308050501080606010201002d00020101" //nolint:revive,stylecheck 53 | Chrome_linux_143_0_7499_146 ClientHelloFingerprint = "fefd39f2fba6183e22cd653b0056343f0255f894b31f3e8a3bca4e06377920b9c8ab0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079002d00020101000e0009000600010008000700000d00140012040308040401050308050501080606010201003300260024001d00205ce46e86967925f4b378e4ad5a2e76be97282e63d9adca3509ad56fcf99f410fff01000100000a00080006001d00170018000b00020100002b000504fefcfefd00170000" //nolint:revive,stylecheck 54 | Chrome_linux_143_0_7499_169 ClientHelloFingerprint = "fefdca153f1cc581f5cc3eb398d3613f6a65253f237b768378809172570e6082807c0000001c130113021303c02bc02fcca9cca8c009c013c00ac014009c002f003501000079ff01000100000e0009000600010008000700000d00140012040308040401050308050501080606010201002b000504fefcfefd00170000000a00080006001d00170018000b00020100002d00020101003300260024001d0020c5a7fa3de872473d926a125cb6fc9f207b20af5b6f26ceddfbdf4497a01e3d33" //nolint:revive,stylecheck 55 | ) 56 | 57 | //nolint:unused,revive,stylecheck 58 | func GetDTLS13ClientHelloFingerprints() []ClientHelloFingerprint { 59 | return []ClientHelloFingerprint{ 60 | Firefox_linux_stable_127_0, //nolint:revive,stylecheck 61 | Firefox_linux_stable_127_0_1, //nolint:revive,stylecheck 62 | Firefox_linux_stable_127_0_2, //nolint:revive,stylecheck 63 | Firefox_linux_stable_128_0, //nolint:revive,stylecheck 64 | Firefox_linux_stable_128_0_2, //nolint:revive,stylecheck 65 | Firefox_linux_stable_128_0_3, //nolint:revive,stylecheck 66 | Firefox_linux_stable_129_0, //nolint:revive,stylecheck 67 | Firefox_linux_stable_129_0_1, //nolint:revive,stylecheck 68 | Firefox_linux_stable_130_0, //nolint:revive,stylecheck 69 | Firefox_linux_stable_130_0_1, //nolint:revive,stylecheck 70 | Firefox_linux_stable_131_0, //nolint:revive,stylecheck 71 | Firefox_linux_stable_133_0, //nolint:revive,stylecheck 72 | Firefox_linux_stable_133_0_3, //nolint:revive,stylecheck 73 | Firefox_linux_stable_134_0, //nolint:revive,stylecheck 74 | Firefox_linux_stable_134_0_1, //nolint:revive,stylecheck 75 | Firefox_linux_stable_134_0_2, //nolint:revive,stylecheck 76 | Firefox_linux_stable_135_0, //nolint:revive,stylecheck 77 | Firefox_linux_stable_135_0_1, //nolint:revive,stylecheck 78 | Firefox_linux_stable_136_0, //nolint:revive,stylecheck 79 | Firefox_linux_stable_136_0_1, //nolint:revive,stylecheck 80 | Firefox_linux_stable_136_0_2, //nolint:revive,stylecheck 81 | Firefox_linux_stable_136_0_3, //nolint:revive,stylecheck 82 | Firefox_linux_stable_136_0_4, //nolint:revive,stylecheck 83 | Chrome_linux_139_0_7258_138, //nolint:revive,stylecheck 84 | Chrome_linux_139_0_7258_154, //nolint:revive,stylecheck 85 | Chrome_linux_139_0_7258_66, //nolint:revive,stylecheck 86 | Chrome_linux_139_0_7258_68, //nolint:revive,stylecheck 87 | Chrome_linux_140_0_7339_185, //nolint:revive,stylecheck 88 | Chrome_linux_140_0_7339_207, //nolint:revive,stylecheck 89 | Chrome_linux_140_0_7339_80, //nolint:revive,stylecheck 90 | Chrome_linux_140_0_7339_82, //nolint:revive,stylecheck 91 | Chrome_linux_141_0_7390_122, //nolint:revive,stylecheck 92 | Chrome_linux_141_0_7390_54, //nolint:revive,stylecheck 93 | Chrome_linux_141_0_7390_65, //nolint:revive,stylecheck 94 | Chrome_linux_141_0_7390_76, //nolint:revive,stylecheck 95 | Chrome_linux_141_0_7390_78, //nolint:revive,stylecheck 96 | Chrome_linux_142_0_7444_162, //nolint:revive,stylecheck 97 | Chrome_linux_142_0_7444_175, //nolint:revive,stylecheck 98 | Chrome_linux_142_0_7444_59, //nolint:revive,stylecheck 99 | Chrome_linux_142_0_7444_61, //nolint:revive,stylecheck 100 | Chrome_linux_143_0_7499_40, //nolint:revive,stylecheck 101 | Chrome_linux_143_0_7499_42, //nolint:revive,stylecheck 102 | Chrome_linux_143_0_7499_146, //nolint:revive,stylecheck 103 | Chrome_linux_143_0_7499_169, //nolint:revive,stylecheck 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /pkg/fingerprints/fingerprints.go: -------------------------------------------------------------------------------- 1 | package fingerprints 2 | 3 | //nolint:revive,unused 4 | type ClientHelloFingerprint string 5 | 6 | // These fingerprints are automatically generated and added by the 'fingerprint' workflow 7 | // The first byte should correspond to the DTLS version in a handshake message 8 | const ( 9 | Mozilla_Firefox_125_0_1 ClientHelloFingerprint = "fefda62c8fe5497b56ad1e096f4294cf48c8fe97699406088833f3076ed35bb12b0200000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 10 | Google_Chrome_124_0_6367_60_unknown ClientHelloFingerprint = "fefdae6064bebc0381a2c7a260cd429b2f5861b9e31425b324dc1a96551bf6cae55500000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 11 | Google_Chrome_124_0_6367_78_unknown ClientHelloFingerprint = "fefdcbcec29a5919e84b7de392062196c9342da09b5bf45218a2a2d7bdab5ab61ab700000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 12 | Mozilla_Firefox_125_0_2 ClientHelloFingerprint = "fefdcbce28193f1760cf284985a99eda174720526a7346491e4a9cdff03d9febdc1600000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 13 | Google_Chrome_124_0_6367_91_unknown ClientHelloFingerprint = "fefd63c6020e585fe7787a6f56a113f10dffba4ba0360a3d727f81311d4087a2e02a00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 14 | Google_Chrome_124_0_6367_118_unknown ClientHelloFingerprint = "fefd1ab969e081af0198b1a5ef3438947d97e2a15bd879585c28512bb51672b9138700000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 15 | Mozilla_Firefox_125_0_3 ClientHelloFingerprint = "fefd58982935730115c95f06618628c3715e56cc0faf990b23ed42b52abf343aebf300000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 16 | Google_Chrome_124_0_6367_155_unknown ClientHelloFingerprint = "fefd1ad0326777ab4186c02fec9d45c3ba0dd52400bfcc40ffda54284957f7477dee00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 17 | Google_Chrome_124_0_6367_201_unknown ClientHelloFingerprint = "fefd0c6261a6f76af96b849b3cf5f7a57a092d9b1ee1226bedf02ea5bb9bec5e4a3300000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 18 | Google_Chrome_124_0_6367_207_unknown ClientHelloFingerprint = "fefde6a943ff8fd828b850f2f0ae6cc07980651688f9b8815824ff1ac15d5864201e00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 19 | Mozilla_Firefox_126_0 ClientHelloFingerprint = "fefda57091eb47f6e652ae5f081f34dbd55aeb27ef635cba4d87e17cb4e476cc8d0c00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 20 | Google_Chrome_125_0_6422_60_unknown ClientHelloFingerprint = "fefdf04150620a1e523d5d51eb63a641d37a59dc1ec9bd1a2b850bde7fe54ad4dc5200000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 21 | Google_Chrome_125_0_6422_76_unknown ClientHelloFingerprint = "fefd54fada6c8da2fe120d8466259368ba52d7c081f8753df3521dc08a0783ff8b3200000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 22 | Google_Chrome_125_0_6422_112_unknown ClientHelloFingerprint = "fefd59d836c6bebe44212c6a1abe92b7152f54a6c718940a66503307c83aa7c38fa400000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 23 | Mozilla_Firefox_126_0_1 ClientHelloFingerprint = "fefd89c2d091fdab55e258926097978a197f88fd85d1689da875e688ffe66589996000000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 24 | Google_Chrome_125_0_6422_141_unknown ClientHelloFingerprint = "fefdbbe11878d02e5cd2ba9c6c12c05845330adc294052b81d7e392ba480ad8d9dd400000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 25 | Chrome_linux_125_0_6422_141 ClientHelloFingerprint = "fefd46d25ef57649ecfd0fc17d5d933462d70770ea629a4d74a9b7567cc5714fd59500000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 26 | Firefox_linux_stable_126_0_1 ClientHelloFingerprint = "fefd456d7850288d8a38e422000b4d6b94d96af38ae82926100738c531a7b531873b00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 27 | Chrome_linux_126_0_6478_55 ClientHelloFingerprint = "fefd9460e1e8af6afd0c07728ece3350accdb7be89d2a4ebcd9a8d5dc6e780eaeb6000000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 28 | Chrome_linux_126_0_6478_61 ClientHelloFingerprint = "fefdd55ec527c484ad54a31786a4536060866e8f817605893dc5e6a9b2540ab2e38e00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 29 | Chrome_linux_126_0_6478_62 ClientHelloFingerprint = "fefd5f58909b796cbeab9075ec3239db3e9b60732044a7714180ffb3999997df7d0f00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 30 | Chrome_linux_126_0_6478_63 ClientHelloFingerprint = "fefd7ff07ea53e6848da7864b6083c5686ae82354fcf9e38cdfe20b095eaa783672b00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 31 | Chrome_linux_126_0_6478_126 ClientHelloFingerprint = "fefd06c93bd11982ae5e0ae3a93fff4dc1fac9bbf8fa354b30eaf88d10eae4ca6f2200000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 32 | Chrome_linux_126_0_6478_182 ClientHelloFingerprint = "fefd80e8f0d6d879e5d7ae9162acf93e2a65a84a9eca45b78140579c9dab066ec0ac00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 33 | Chrome_linux_127_0_6533_72 ClientHelloFingerprint = "fefd8fdf98b4e87c461e936deae7e070a7efda9a7274edbb245f6bcb7c4996c54e9c00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 34 | Chrome_linux_127_0_6533_88 ClientHelloFingerprint = "fefdc6ae8f9938c8cf30d48c7e836b5d99e1ba789700ceaf89837a6c621817681cde00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 35 | Chrome_linux_127_0_6533_99 ClientHelloFingerprint = "fefde6a1483065d8fabfa7ce7427fa9e66fc14c878635a5714bdad55c936743eb7f700000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 36 | Chrome_linux_127_0_6533_119 ClientHelloFingerprint = "fefdeaf31202bac58cc1c4c21df6ddc5305c52eb3cd0eebe09cb0850bb86f5c299c100000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 37 | Chrome_linux_128_0_6613_119 ClientHelloFingerprint = "fefde6b311ad9a353e9e8267c9f9f04bca867040bb7b420ae4fb292b0d3d7c70321400000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 38 | Chrome_linux_128_0_6613_137 ClientHelloFingerprint = "fefd9599de9f7a4baf8b3171cfa1e33a774087fdc1bb20afbe17d664a488c6c9f4ad00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400170000ff01000100000a00080006001d00170018000b0002010000230000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 39 | Chrome_linux_129_0_6668_58 ClientHelloFingerprint = "fefdbe5eb2420b729cb21c730e9cb650872c034d402ee32a98ba8f482778cc5c49dd00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004400230000000d0014001204030804040105030805050108060601020100170000000a00080006001d00170018ff01000100000e0009000600010008000700000b00020100" //nolint:revive,stylecheck 40 | Chrome_linux_129_0_6668_70 ClientHelloFingerprint = "fefd9b701235538685ac2524489957f7df25c6518b34d639bfd8f1939bc3ff9eb25700000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000044ff0100010000230000000e0009000600010008000700000a00080006001d00170018000d0014001204030804040105030805050108060601020100170000000b00020100" //nolint:revive,stylecheck 41 | Chrome_linux_129_0_6668_89 ClientHelloFingerprint = "fefd3e839587aab689b39bd3c80a66a67922cb1e77aa585e77ede3810b2cf132d18400000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000044000d00140012040308040401050308050501080606010201000e0009000600010008000700000b000201000017000000230000000a00080006001d00170018ff01000100" //nolint:revive,stylecheck 42 | Chrome_linux_131_0_6778_85 ClientHelloFingerprint = "fefde6415d56fa3c87a9039db701889649c1d6de38bca229ef967f3c1ed0cc6b50e300000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000d00140012040308040401050308050501080606010201000a00080006001d0017001800170000000e0009000600010008000700ff01000100000b00020100" //nolint:revive,stylecheck 43 | Chrome_linux_131_0_6778_204 ClientHelloFingerprint = "fefd2d0e3b43dfe577ef898823f657c09acdab81e937aeda13538a50858eb30a647300000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000d0014001204030804040105030805050108060601020100170000000a00080006001d00170018ff01000100000b00020100000e0009000600010008000700" //nolint:revive,stylecheck 44 | Chrome_linux_132_0_6834_83 ClientHelloFingerprint = "fefd734b377fcacc702a020a72786c3e6d5b12933d11f9e74cee2a68cc7c7817116a00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000a00080006001d00170018000d00140012040308040401050308050501080606010201000b00020100ff01000100000e000900060001000800070000170000" //nolint:revive,stylecheck 45 | Chrome_linux_133_0_6943_53 ClientHelloFingerprint = "fefd45063e8ceb076b7bb40823e704d78dcc9ee2dc3ced132732c5e2b44038c59c7500000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000000a00080006001d00170018000b00020100000e0009000600010008000700000d00140012040308040401050308050501080606010201ff01000100" //nolint:revive,stylecheck 46 | Chrome_linux_133_0_6943_98 ClientHelloFingerprint = "fefd073614b994fb2a664d774f60ae5b6aa31b2531956a25a76c9c2d4c5c835c763500000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000e000900060001000800070000170000000d00140012040308040401050308050501080606010201000a00080006001d00170018000b00020100ff01000100" //nolint:revive,stylecheck 47 | Chrome_linux_133_0_6943_126 ClientHelloFingerprint = "fefd14d58e58e2cbd35c413229a5a5ada96b2f0856716ba66a136ef197abf5761d3d00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000000e0009000600010008000700000d00140012040308040401050308050501080606010201000a00080006001d00170018ff01000100000b00020100" //nolint:revive,stylecheck 48 | Chrome_linux_134_0_6998_35 ClientHelloFingerprint = "fefdf1ccee895189dfeb948761ef5a329ab6b216627f676cbd508d02e4fc94eae22400000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000000b00020100000d00140012040308040401050308050501080606010201000a00080006001d00170018ff01000100000e0009000600010008000700" //nolint:revive,stylecheck 49 | Chrome_linux_134_0_6998_88 ClientHelloFingerprint = "fefdf7af5f62ee31fcec1441f7ecbf9ce0c28c5f7678b2173033ae5304b5fd4f430600000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040ff01000100000b00020100000d00140012040308040401050308050501080606010201000a00080006001d00170018000e000900060001000800070000170000" //nolint:revive,stylecheck 50 | Chrome_linux_134_0_6998_90 ClientHelloFingerprint = "fefdc3432d91aaf98ccfe1e0ac599720422da1f444d585e846bb4bc297b48d3f750f00000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000ff01000100000b00020100000d00140012040308040401050308050501080606010201000a00080006001d00170018000e0009000600010008000700" //nolint:revive,stylecheck 51 | Chrome_linux_134_0_6998_165 ClientHelloFingerprint = "fefd0a909e832282c850cb1e2e6c313f4ac0afbdcafda59603826e933182ac1dfe8400000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000000a00080006001d00170018000d00140012040308040401050308050501080606010201000b00020100ff01000100000e0009000600010008000700" //nolint:revive,stylecheck 52 | Chrome_linux_135_0_7049_42 ClientHelloFingerprint = "fefd7091dab5f02c9d975bf050e00260c1431a79be5819a995c68571c98e8d92794500000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000e000900060001000800070000170000000b00020100000a00080006001d00170018000d00140012040308040401050308050501080606010201ff01000100" //nolint:revive,stylecheck 53 | Firefox_linux_stable_137_0 ClientHelloFingerprint = "fefd6f8901b396db14cab04c20976bb2a55f21e0ca0f964d31b263a2e7d9e23da54100000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 54 | Chrome_linux_135_0_7049_84 ClientHelloFingerprint = "fefda7cdd4b6a51f024f64bd1d063e29aef15e5defe95744416b29222cb01fe864a700000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000d00140012040308040401050308050501080606010201000a00080006001d0017001800170000000b00020100000e0009000600010008000700ff01000100" //nolint:revive,stylecheck 55 | Firefox_linux_stable_137_0_1 ClientHelloFingerprint = "fefdb113d2124f32d09fd4f3276d1f74547de119ff70624e477b0e88c860bf14d82d00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 56 | Chrome_linux_135_0_7049_95 ClientHelloFingerprint = "fefd2b5100075305145d4c6084c4c6d4fe8780e96b3fff9e02eb22e784ed6189f7ad00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000b00020100000e0009000600010008000700000d00140012040308040401050308050501080606010201000a00080006001d00170018ff0100010000170000" //nolint:revive,stylecheck 57 | Firefox_linux_stable_137_0_2 ClientHelloFingerprint = "fefd3df96980b73764372c0ac76f658c42ad39f7cce533bea60ee7211bfeaec355a700000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 58 | Chrome_linux_135_0_7049_97 ClientHelloFingerprint = "fefd790ac0e2d0829b614d0823d3e6b798793c47cea355ace422255e66b3817a35fb00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000a00080006001d00170018ff0100010000170000000d00140012040308040401050308050501080606010201000e0009000600010008000700000b00020100" //nolint:revive,stylecheck 59 | Chrome_linux_135_0_7049_114 ClientHelloFingerprint = "fefd55d5479509507311441a70de800e23e71a6ac48d21a237405420fe32d9bf597800000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000a00080006001d00170018000d0014001204030804040105030805050108060601020100170000000e0009000600010008000700ff01000100000b00020100" //nolint:revive,stylecheck 60 | Chrome_linux_136_0_7103_49 ClientHelloFingerprint = "fefd2f447834d745f40a3cd53b2dafd327c56c3ac0a06bed32514ea5e1bae994734800000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040ff01000100000b00020100000e0009000600010008000700000a00080006001d00170018000d0014001204030804040105030805050108060601020100170000" //nolint:revive,stylecheck 61 | Firefox_linux_stable_138_0 ClientHelloFingerprint = "fefd4b9af357d2a97953945fe678912a857a439b7ac6693626db9f9eeee28735314f00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 62 | Firefox_linux_stable_138_0_1 ClientHelloFingerprint = "fefd050cbae5108bbad3558bdb8e09ca3f44f723c0d7e517fb1ec5ffc6c0d6fe41c200000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 63 | Chrome_linux_136_0_7103_92 ClientHelloFingerprint = "fefdc8b61395d44e2a57eb9d72ee84ee311d60e4b9d8948e79bfe838fdef0cbaf74d00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000a00080006001d00170018000d0014001204030804040105030805050108060601020100170000000b00020100000e0009000600010008000700ff01000100" //nolint:revive,stylecheck 64 | Firefox_linux_stable_138_0_3 ClientHelloFingerprint = "fefd7587b18af9d1f3d235becf4a9785030aa803598866487889eba421a7a6cde8ea00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 65 | Chrome_linux_136_0_7103_94 ClientHelloFingerprint = "fefddbae631185961cbb0f7cd1545f567ea2194aed09c9c632cca8220c038c9ffbe100000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000e0009000600010008000700000b00020100ff01000100000a00080006001d00170018000d0014001204030804040105030805050108060601020100170000" //nolint:revive,stylecheck 66 | Firefox_linux_stable_138_0_4 ClientHelloFingerprint = "fefdfdf2990d90288bb2088e6de00e188b828905bf4589812d03d01722fa945717f700000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 67 | Chrome_linux_136_0_7103_113 ClientHelloFingerprint = "fefd3086d8456a813f9e515d13c6aab6a2420b5a452dd0f361da414bc538e74a09e500000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000e0009000600010008000700000b00020100000d0014001204030804040105030805050108060601020100170000000a00080006001d00170018ff01000100" //nolint:revive,stylecheck 68 | Chrome_linux_137_0_7151_55 ClientHelloFingerprint = "fefdb849f7d2fc2897b0d8dceccd99284abf9b9d152a86c9ce89bcf8016816c3ef4400000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000d00140012040308040401050308050501080606010201000e0009000600010008000700ff01000100000a00080006001d0017001800170000000b00020100" //nolint:revive,stylecheck 69 | Firefox_linux_stable_139_0 ClientHelloFingerprint = "fefd43b068a5b1eb08fa7ca5e2dd702597a0d6feebe1d4f4fdd65f48e32dea61076200000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 70 | Firefox_linux_stable_139_0_1 ClientHelloFingerprint = "fefd03fa41b15091de242b59fe65950dd84ce721e3a444519b97a84d490d74ef6e9700000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 71 | Chrome_linux_137_0_7151_68 ClientHelloFingerprint = "fefd309e83ef12204b98ecc8096327fc92276144c3400c5a45b6546b4652a67e5dc500000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000e0009000600010008000700000a00080006001d0017001800170000000b00020100000d00140012040308040401050308050501080606010201ff01000100" //nolint:revive,stylecheck 72 | Chrome_linux_137_0_7151_70 ClientHelloFingerprint = "fefd9c57352d69904dfb38bd2c62aab4b6a83988b59757289d6c644b60877e4a708b00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000b00020100000a00080006001d00170018ff0100010000170000000d00140012040308040401050308050501080606010201000e0009000600010008000700" //nolint:revive,stylecheck 73 | Firefox_linux_stable_139_0_4 ClientHelloFingerprint = "fefd960ddf11dd800d4a3cfd1ba303a170dff15c5025ac412501b5c7c264143bd11600000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 74 | Chrome_linux_137_0_7151_119 ClientHelloFingerprint = "fefd2b81cd46cb0bdcc9ab8f2786d70d896c02fe3f46e8af7b9eaef26283bb7102c300000016c02bc02fcca9cca8c009c013c00ac014009c002f00350100004000170000000e0009000600010008000700000d00140012040308040401050308050501080606010201000a00080006001d00170018000b00020100ff01000100" //nolint:revive,stylecheck 75 | Chrome_linux_138_0_7204_49 ClientHelloFingerprint = "fefdc9af24a876e49dfed1a4ad4fd7b4c313ca954071b3a57f9ae89c0ad4e8914c8b00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040ff0100010000170000000a00080006001d00170018000e0009000600010008000700000d00140012040308040401050308050501080606010201000b00020100" //nolint:revive,stylecheck 76 | Firefox_linux_stable_140_0_2 ClientHelloFingerprint = "fefd8d662ab06722bbc69fbca0a2fd5d03207cde4bd2b18c4e9fe48a905f4289f7c200000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 77 | Chrome_linux_138_0_7204_92 ClientHelloFingerprint = "fefd0bbdf942abb4084eeb484732fe7a88e4fac8b9873ca130081d1bca7cc523178a00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040ff01000100000a00080006001d0017001800170000000d00140012040308040401050308050501080606010201000b00020100000e0009000600010008000700" //nolint:revive,stylecheck 78 | Chrome_linux_138_0_7204_94 ClientHelloFingerprint = "fefda84ff693cb898224c306065a383d239182d42fd01b1bdc44dc65b2b0de98b68f00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040ff01000100000a00080006001d00170018000d00140012040308040401050308050501080606010201000e0009000600010008000700000b0002010000170000" //nolint:revive,stylecheck 79 | Firefox_linux_stable_140_0_4 ClientHelloFingerprint = "fefd3a5c73f0dfd3199097a356131bdc833b208a4a631541a8b4616f867f16ec2dfb00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 80 | Chrome_linux_138_0_7204_157 ClientHelloFingerprint = "fefd7e1fc68df58212ce0f3348dff30a4340aadf127daa543db1dfceb4ac345a025d00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000a00080006001d00170018000e0009000600010008000700ff01000100000d00140012040308040401050308050501080606010201000b0002010000170000" //nolint:revive,stylecheck 81 | Chrome_linux_138_0_7204_168 ClientHelloFingerprint = "fefd990c48bc44f502e829f08a7d58ac75bf10bc10dc7da210ad2d04883a5242b38000000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000b00020100000d00140012040308040401050308050501080606010201000a00080006001d00170018ff01000100000e000900060001000800070000170000" //nolint:revive,stylecheck 82 | Firefox_linux_stable_141_0 ClientHelloFingerprint = "fefda4db9de931f0c9e78f33516363974b13d04879bdc2bd648888c28ac84d525d9000000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 83 | Chrome_linux_138_0_7204_183 ClientHelloFingerprint = "fefdb48e735b54c5dfc9c0394aa7cf9f0216207b8d0d3a86e77fc4874a5824d2245f00000016c02bc02fcca9cca8c009c013c00ac014009c002f003501000040000d00140012040308040401050308050501080606010201000b00020100ff01000100000a00080006001d00170018000e000900060001000800070000170000" //nolint:revive,stylecheck 84 | Firefox_linux_stable_141_0_2 ClientHelloFingerprint = "fefde4d19e5566638f635d218a07494a8b22ccd6f47d8176d760667dd89aa10554d600000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 85 | Firefox_linux_stable_141_0_3 ClientHelloFingerprint = "fefd94ac5c1deda823663f8744009f38292c12c48be0f9afcddffa6cd05ec6375e9f00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 86 | Firefox_linux_stable_142_0 ClientHelloFingerprint = "fefd1d87593201f8517a926b3fd54be3f2858c9328d1b63c72227ee24f03207fb46700000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 87 | Firefox_linux_stable_142_0_1 ClientHelloFingerprint = "fefdfee7acd5286134132399dadccc33d597ffef3dbece6889e8b64eebb61a28259e00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 88 | Firefox_linux_stable_143_0 ClientHelloFingerprint = "fefd084743198d464cd1766681f41c957dc59c91b798fc4cdbc329271b966140587000000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 89 | Firefox_linux_stable_143_0_1 ClientHelloFingerprint = "fefd7a104fe2b7c3d1886d29c621ca550d8b73ba3cca8851094aa59b1fa0c9a61e3c00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 90 | Firefox_linux_stable_143_0_3 ClientHelloFingerprint = "fefd85ad2f99ad52d2b4a08f486a8f36179a82501380d56305e9ea648ea83328151900000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 91 | Firefox_linux_stable_143_0_4 ClientHelloFingerprint = "fefd7b7b3452407e9fbbea75495b460daa67b2bcf6b1a5694c5edead9941ea7ca83600000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 92 | Firefox_linux_stable_144_0 ClientHelloFingerprint = "fefd5d67f26b89f4c41ddfb3b46043f652a9169872a99ae10083263f0d4dfd3fb18100000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 93 | Firefox_linux_stable_144_0_2 ClientHelloFingerprint = "fefde5daf0be946e538bc3d4642f8d523717e2ac498f6ecae1bcc9ab47da3942221b00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 94 | Firefox_linux_stable_145_0 ClientHelloFingerprint = "fefd5a0a0b988a843d124f1b90ad309fd1208b608cb4a6f1dc32010f0f444fe33ba200000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 95 | Firefox_linux_stable_145_0_1 ClientHelloFingerprint = "fefd93601e77f7b92cd42971e63cd77177da56d162895f4a16463ed913e939b558ad00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 96 | Firefox_linux_stable_145_0_2 ClientHelloFingerprint = "fefd55997504435e22b59398d82604b7688955fa85ec95f7a34dc44180d3cd75b86f00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 97 | Firefox_linux_stable_146_0 ClientHelloFingerprint = "fefdb0f1711508034c0e4958c5801fbef935870d3c7bea1004baa254acccd23a8eb900000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 98 | Firefox_linux_stable_146_0_1 ClientHelloFingerprint = "fefda7f8783a95b7488b63e705d5f222a7bcc9c2403c25b7481a3f3078364d73412d00000010c02bc02fcca9cca8c00ac009c013c0140100006a00170000ff01000100000a00080006001d00170018000b000201000010001200100677656272746308632d776562727463000d0020001e040305030603020308040805080604010501060102010402050206020202001c00024000000e000b0008000700080001000200" //nolint:revive,stylecheck 99 | ) 100 | 101 | //nolint:unused 102 | func GetClientHelloFingerprints() []ClientHelloFingerprint { 103 | return []ClientHelloFingerprint{ 104 | Mozilla_Firefox_125_0_1, //nolint:revive,stylecheck 105 | Google_Chrome_124_0_6367_60_unknown, //nolint:revive,stylecheck 106 | Google_Chrome_124_0_6367_78_unknown, //nolint:revive,stylecheck 107 | Mozilla_Firefox_125_0_2, //nolint:revive,stylecheck 108 | Google_Chrome_124_0_6367_91_unknown, //nolint:revive,stylecheck 109 | Google_Chrome_124_0_6367_118_unknown, //nolint:revive,stylecheck 110 | Mozilla_Firefox_125_0_3, //nolint:revive,stylecheck 111 | Google_Chrome_124_0_6367_155_unknown, //nolint:revive,stylecheck 112 | Google_Chrome_124_0_6367_201_unknown, //nolint:revive,stylecheck 113 | Google_Chrome_124_0_6367_207_unknown, //nolint:revive,stylecheck 114 | Mozilla_Firefox_126_0, //nolint:revive,stylecheck 115 | Google_Chrome_125_0_6422_60_unknown, //nolint:revive,stylecheck 116 | Google_Chrome_125_0_6422_76_unknown, //nolint:revive,stylecheck 117 | Google_Chrome_125_0_6422_112_unknown, //nolint:revive,stylecheck 118 | Mozilla_Firefox_126_0_1, //nolint:revive,stylecheck 119 | Google_Chrome_125_0_6422_141_unknown, //nolint:revive,stylecheck 120 | Chrome_linux_125_0_6422_141, //nolint:revive,stylecheck 121 | Firefox_linux_stable_126_0_1, //nolint:revive,stylecheck 122 | Chrome_linux_126_0_6478_55, //nolint:revive,stylecheck 123 | Chrome_linux_126_0_6478_61, //nolint:revive,stylecheck 124 | Chrome_linux_126_0_6478_62, //nolint:revive,stylecheck 125 | Chrome_linux_126_0_6478_62, //nolint:revive,stylecheck 126 | Chrome_linux_126_0_6478_63, //nolint:revive,stylecheck 127 | Chrome_linux_126_0_6478_126, //nolint:revive,stylecheck 128 | Chrome_linux_126_0_6478_182, //nolint:revive,stylecheck 129 | Chrome_linux_127_0_6533_72, //nolint:revive,stylecheck 130 | Chrome_linux_127_0_6533_88, //nolint:revive,stylecheck 131 | Chrome_linux_127_0_6533_99, //nolint:revive,stylecheck 132 | Chrome_linux_127_0_6533_119, //nolint:revive,stylecheck 133 | Chrome_linux_128_0_6613_119, //nolint:revive,stylecheck 134 | Chrome_linux_128_0_6613_137, //nolint:revive,stylecheck 135 | Chrome_linux_129_0_6668_58, //nolint:revive,stylecheck 136 | Chrome_linux_129_0_6668_70, //nolint:revive,stylecheck 137 | Chrome_linux_129_0_6668_89, //nolint:revive,stylecheck 138 | Chrome_linux_131_0_6778_85, //nolint:revive,stylecheck 139 | Chrome_linux_131_0_6778_204, //nolint:revive,stylecheck 140 | Chrome_linux_132_0_6834_83, //nolint:revive,stylecheck 141 | Chrome_linux_133_0_6943_53, //nolint:revive,stylecheck 142 | Chrome_linux_133_0_6943_98, //nolint:revive,stylecheck 143 | Chrome_linux_133_0_6943_126, //nolint:revive,stylecheck 144 | Chrome_linux_134_0_6998_35, //nolint:revive,stylecheck 145 | Chrome_linux_134_0_6998_88, //nolint:revive,stylecheck 146 | Chrome_linux_134_0_6998_90, //nolint:revive,stylecheck 147 | Chrome_linux_134_0_6998_165, //nolint:revive,stylecheck 148 | Chrome_linux_135_0_7049_42, //nolint:revive,stylecheck 149 | Firefox_linux_stable_137_0, //nolint:revive,stylecheck 150 | Chrome_linux_135_0_7049_84, //nolint:revive,stylecheck 151 | Firefox_linux_stable_137_0_1, //nolint:revive,stylecheck 152 | Chrome_linux_135_0_7049_95, //nolint:revive,stylecheck 153 | Firefox_linux_stable_137_0_2, //nolint:revive,stylecheck 154 | Chrome_linux_135_0_7049_97, //nolint:revive,stylecheck 155 | Chrome_linux_135_0_7049_114, //nolint:revive,stylecheck 156 | Chrome_linux_136_0_7103_49, //nolint:revive,stylecheck 157 | Firefox_linux_stable_138_0, //nolint:revive,stylecheck 158 | Firefox_linux_stable_138_0_1, //nolint:revive,stylecheck 159 | Chrome_linux_136_0_7103_92, //nolint:revive,stylecheck 160 | Firefox_linux_stable_138_0_3, //nolint:revive,stylecheck 161 | Chrome_linux_136_0_7103_94, //nolint:revive,stylecheck 162 | Firefox_linux_stable_138_0_4, //nolint:revive,stylecheck 163 | Chrome_linux_136_0_7103_113, //nolint:revive,stylecheck 164 | Chrome_linux_137_0_7151_55, //nolint:revive,stylecheck 165 | Firefox_linux_stable_139_0, //nolint:revive,stylecheck 166 | Firefox_linux_stable_139_0_1, //nolint:revive,stylecheck 167 | Chrome_linux_137_0_7151_68, //nolint:revive,stylecheck 168 | Chrome_linux_137_0_7151_70, //nolint:revive,stylecheck 169 | Firefox_linux_stable_139_0_4, //nolint:revive,stylecheck 170 | Chrome_linux_137_0_7151_119, //nolint:revive,stylecheck 171 | Chrome_linux_138_0_7204_49, //nolint:revive,stylecheck 172 | Firefox_linux_stable_140_0_2, //nolint:revive,stylecheck 173 | Chrome_linux_138_0_7204_92, //nolint:revive,stylecheck 174 | Chrome_linux_138_0_7204_94, //nolint:revive,stylecheck 175 | Firefox_linux_stable_140_0_4, //nolint:revive,stylecheck 176 | Chrome_linux_138_0_7204_157, //nolint:revive,stylecheck 177 | Chrome_linux_138_0_7204_168, //nolint:revive,stylecheck 178 | Firefox_linux_stable_141_0, //nolint:revive,stylecheck 179 | Chrome_linux_138_0_7204_183, //nolint:revive,stylecheck 180 | Firefox_linux_stable_141_0_2, //nolint:revive,stylecheck 181 | Firefox_linux_stable_141_0_3, //nolint:revive,stylecheck 182 | Firefox_linux_stable_142_0, //nolint:revive,stylecheck 183 | Firefox_linux_stable_142_0_1, //nolint:revive,stylecheck 184 | Firefox_linux_stable_143_0, //nolint:revive,stylecheck 185 | Firefox_linux_stable_143_0_1, //nolint:revive,stylecheck 186 | Firefox_linux_stable_143_0_3, //nolint:revive,stylecheck 187 | Firefox_linux_stable_143_0_4, //nolint:revive,stylecheck 188 | Firefox_linux_stable_144_0, //nolint:revive,stylecheck 189 | Firefox_linux_stable_144_0_2, //nolint:revive,stylecheck 190 | Firefox_linux_stable_145_0, //nolint:revive,stylecheck 191 | Firefox_linux_stable_145_0_1, //nolint:revive,stylecheck 192 | Firefox_linux_stable_145_0_2, //nolint:revive,stylecheck 193 | Firefox_linux_stable_146_0, //nolint:revive,stylecheck 194 | Firefox_linux_stable_146_0_1, //nolint:revive,stylecheck 195 | } 196 | } 197 | --------------------------------------------------------------------------------