Merge branch '2216-add-tcprelay' into tcp-relay

PR #2231
This commit is contained in:
Mike Salvatore 2022-09-06 15:57:34 -04:00
commit 4bff110f35
16 changed files with 699 additions and 177 deletions

View File

@ -1,5 +1,5 @@
import queue
from typing import Any, List, MutableMapping, TypeVar
from typing import Any, Dict, List, MutableMapping, Type, TypeVar
T = TypeVar("T")
@ -15,7 +15,7 @@ class abstractstatic(staticmethod):
class Singleton(type):
_instances = {}
_instances: Dict[Type, type] = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:

View File

@ -26,6 +26,7 @@ pefile = {version = "*", sys_platform = "== 'win32'"} # Pyinstaller requirement
paramiko = {editable = true, ref = "2.10.3.dev1", git = "https://github.com/VakarisZ/paramiko.git"}
pypubsub = "*"
pydantic = "*"
egg-timer = "*"
[dev-packages]
ldap3 = "*"

View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "7d1e1d151dbf74cf73466f7a73305efc4e5e187245fe789c0db103f4045eb722"
"sha256": "4035f0b638bdef6971dcf5c52a0aa0f2efc76310ad5a1ea853b6d21495ffa2b0"
},
"pipfile-spec": 6,
"requires": {
@ -18,11 +18,11 @@
"default": {
"aiosmb": {
"hashes": [
"sha256:2668d63ae6e6ca30a999696c444d4afc349f85a872a204994394aa6abbf5673d",
"sha256:b0b0e7068e757b8d3a8e4be2ebf2b499933d9fa7853bc3a8e198d6a57dc77131"
"sha256:0afa901093f0ad91d0b8421dec66c80bd2e9cb237a8da405984413a5d7475398",
"sha256:0e98390ba00fdc4190e698f184dfcf72b02b592cdfe9274e03cc7316ac4ee368"
],
"markers": "python_version >= '3.7'",
"version": "==0.4.0"
"version": "==0.3.8"
},
"aiowinreg": {
"hashes": [
@ -56,11 +56,11 @@
},
"asysocks": {
"hashes": [
"sha256:8f4516088ebec7f08d8c549e5e75e7a86b41e6043af920ba4895cf3f6c654150",
"sha256:d4c619c9d2e8be0cbdd21fa635a7eaf5886809edc948e2f76625b33b3cccfc47"
"sha256:23d5fcfae71a75826c3ed787bd9b1bc3b189ec37658961bce83c9e99455e354c",
"sha256:731eda25d41783c5243153d3cb4f9357fef337c7317135488afab9ecd6b7f1a1"
],
"markers": "python_version >= '3.6'",
"version": "==0.2.1"
"version": "==0.1.7"
},
"attrs": {
"hashes": [
@ -79,21 +79,20 @@
},
"bcrypt": {
"hashes": [
"sha256:0b0f0c7141622a31e9734b7f649451147c04ebb5122327ac0bd23744df84be90",
"sha256:1c3334446fac200499e8bc04a530ce3cf0b3d7151e0e4ac5c0dddd3d95e97843",
"sha256:2d0dd19aad87e4ab882ef1d12df505f4c52b28b69666ce83c528f42c07379227",
"sha256:594780b364fb45f2634c46ec8d3e61c1c0f1811c4f2da60e8eb15594ecbf93ed",
"sha256:7c7dd6c1f05bf89e65261d97ac3a6520f34c2acb369afb57e3ea4449be6ff8fd",
"sha256:845b1daf4df2dd94d2fdbc9454953ca9dd0e12970a0bfc9f3dcc6faea3fa96e4",
"sha256:8780e69f9deec9d60f947b169507d2c9816e4f11548f1f7ebee2af38b9b22ae4",
"sha256:bf413f2a9b0a2950fc750998899013f2e718d20fa4a58b85ca50b6df5ed1bbf9",
"sha256:bfb67f6a6c72dfb0a02f3df51550aa1862708e55128b22543e2b42c74f3620d7",
"sha256:c59c170fc9225faad04dde1ba61d85b413946e8ce2e5f5f5ff30dfd67283f319",
"sha256:dc6ec3dc19b1c193b2f7cf279d3e32e7caf447532fbcb7af0906fe4398900c33",
"sha256:ede0f506554571c8eda80db22b83c139303ec6b595b8f60c4c8157bdd0bdee36"
"sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521",
"sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb",
"sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e",
"sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26",
"sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a",
"sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e",
"sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa",
"sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129",
"sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb",
"sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40",
"sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"
],
"markers": "python_version >= '3.6'",
"version": "==4.0.0"
"version": "==3.2.2"
},
"certifi": {
"hashes": [
@ -182,11 +181,11 @@
},
"charset-normalizer": {
"hashes": [
"sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845",
"sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"
"sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5",
"sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"
],
"markers": "python_version >= '3.6'",
"version": "==2.1.1"
"version": "==2.1.0"
},
"click": {
"hashes": [
@ -213,35 +212,31 @@
},
"cryptography": {
"hashes": [
"sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a",
"sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f",
"sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0",
"sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407",
"sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7",
"sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6",
"sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153",
"sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750",
"sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad",
"sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6",
"sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b",
"sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5",
"sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a",
"sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d",
"sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d",
"sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294",
"sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0",
"sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a",
"sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac",
"sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61",
"sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013",
"sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e",
"sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb",
"sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9",
"sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd",
"sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"
"sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59",
"sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596",
"sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3",
"sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5",
"sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab",
"sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884",
"sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82",
"sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b",
"sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441",
"sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa",
"sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d",
"sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b",
"sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a",
"sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6",
"sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157",
"sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280",
"sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282",
"sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67",
"sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8",
"sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046",
"sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327",
"sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"
],
"markers": "python_version >= '3.6'",
"version": "==38.0.1"
"version": "==37.0.4"
},
"dnspython": {
"hashes": [
@ -251,13 +246,21 @@
"markers": "python_version >= '3.6' and python_version < '4'",
"version": "==2.2.1"
},
"egg-timer": {
"hashes": [
"sha256:125efb1fdc1582e3354dbbf3218010968a875b97bf7c10e00c8ca6010d9c18ad",
"sha256:12b789c8d17d1aab11c5b994bad336089a4c1ac5e0565e3ad2dd0470eae34939"
],
"index": "pypi",
"version": "==1.0.0.post1"
},
"flask": {
"hashes": [
"sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b",
"sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"
"sha256:3c604c48c3d5b4c63e72134044c0b4fe90ff01ef65280b9fe2d38c8860d99fe5",
"sha256:9c2b81b9b1edcc835af72d600f1955e713a065e7cb41d7e51ee762b449d9c65d"
],
"markers": "python_version >= '3.7'",
"version": "==2.2.2"
"version": "==2.2.1"
},
"future": {
"hashes": [
@ -399,6 +402,22 @@
"markers": "python_version >= '3.7'",
"version": "==2.1.1"
},
"marshmallow": {
"hashes": [
"sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb",
"sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"
],
"index": "pypi",
"version": "==3.17.0"
},
"marshmallow-enum": {
"hashes": [
"sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58",
"sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"
],
"index": "pypi",
"version": "==1.5.1"
},
"minidump": {
"hashes": [
"sha256:6a9d2152f76ae633c609e09b48b42f55bd5a6b65f920dbbec756e5d9134a6201",
@ -409,19 +428,19 @@
},
"minikerberos": {
"hashes": [
"sha256:c05cfcd846b1973b2b0d501e9e9fa2a263543d7762b052fc803fc1de849286a3",
"sha256:e912eb4bea899e1875707e7998001ed1047e1b32d5d7bf74d8b6137acf9614d3"
"sha256:3c383f67ebcf6f28105ed54f623a6a5c677a24e3f0c9ad69ed453f77e569d714",
"sha256:789f802263fa1882f701b123f6eec048b45cd731bf1b528870005daf07402047"
],
"markers": "python_version >= '3.6'",
"version": "==0.3.1"
"version": "==0.2.20"
},
"msldap": {
"hashes": [
"sha256:236eacd04b0d2886e71b2890ec6c67fc626e1b9812c93a0fe21e998697415927",
"sha256:ccb5c1f40de165141931659eb71d4bbad326665aaff7bf23dd0dccb410dfa78c"
"sha256:ac8174ed7e0162eb64b3e9dfeff13b2e1021612d0a4b2cfc6b8e5bed7c00ffe0",
"sha256:e2c22a6e396b4d7d65d73863ed44612120e8e2570ff895b5421ddf6a350085bb"
],
"markers": "python_version >= '3.7'",
"version": "==0.4.0"
"version": "==0.3.40"
},
"netifaces": {
"hashes": [
@ -473,6 +492,14 @@
],
"version": "==1.3.0"
},
"packaging": {
"hashes": [
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
],
"markers": "python_version >= '3.6'",
"version": "==21.3"
},
"paramiko": {
"editable": true,
"git": "https://github.com/VakarisZ/paramiko.git",
@ -489,54 +516,55 @@
"hashes": [
"sha256:a5488a3dd1fd021ce33f969780b88fe0f7eebb76eb20996d7318f307612a045b"
],
"index": "pypi",
"markers": "sys_platform == 'win32'",
"version": "==2022.5.30"
},
"prompt-toolkit": {
"hashes": [
"sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d",
"sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"
"sha256:859b283c50bde45f5f97829f77a4674d1c1fcd88539364f1b28a37805cfd89c0",
"sha256:d8916d3f62a7b67ab353a952ce4ced6a1d2587dfe9ef8ebc30dd7c386751f289"
],
"markers": "python_full_version >= '3.6.2'",
"version": "==3.0.31"
"version": "==3.0.30"
},
"psutil": {
"hashes": [
"sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97",
"sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84",
"sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969",
"sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf",
"sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32",
"sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12",
"sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727",
"sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06",
"sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c",
"sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9",
"sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea",
"sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8",
"sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f",
"sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c",
"sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d",
"sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339",
"sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444",
"sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab",
"sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb",
"sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b",
"sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8",
"sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec",
"sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8",
"sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d",
"sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34",
"sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85",
"sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1",
"sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9",
"sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1",
"sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d",
"sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5",
"sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"
"sha256:068935df39055bf27a29824b95c801c7a5130f118b806eee663cad28dca97685",
"sha256:0904727e0b0a038830b019551cf3204dd48ef5c6868adc776e06e93d615fc5fc",
"sha256:0f15a19a05f39a09327345bc279c1ba4a8cfb0172cc0d3c7f7d16c813b2e7d36",
"sha256:19f36c16012ba9cfc742604df189f2f28d2720e23ff7d1e81602dbe066be9fd1",
"sha256:20b27771b077dcaa0de1de3ad52d22538fe101f9946d6dc7869e6f694f079329",
"sha256:28976df6c64ddd6320d281128817f32c29b539a52bdae5e192537bc338a9ec81",
"sha256:29a442e25fab1f4d05e2655bb1b8ab6887981838d22effa2396d584b740194de",
"sha256:3054e923204b8e9c23a55b23b6df73a8089ae1d075cb0bf711d3e9da1724ded4",
"sha256:32c52611756096ae91f5d1499fe6c53b86f4a9ada147ee42db4991ba1520e574",
"sha256:3a76ad658641172d9c6e593de6fe248ddde825b5866464c3b2ee26c35da9d237",
"sha256:44d1826150d49ffd62035785a9e2c56afcea66e55b43b8b630d7706276e87f22",
"sha256:4b6750a73a9c4a4e689490ccb862d53c7b976a2a35c4e1846d049dcc3f17d83b",
"sha256:56960b9e8edcca1456f8c86a196f0c3d8e3e361320071c93378d41445ffd28b0",
"sha256:57f1819b5d9e95cdfb0c881a8a5b7d542ed0b7c522d575706a80bedc848c8954",
"sha256:58678bbadae12e0db55186dc58f2888839228ac9f41cc7848853539b70490021",
"sha256:645bd4f7bb5b8633803e0b6746ff1628724668681a434482546887d22c7a9537",
"sha256:799759d809c31aab5fe4579e50addf84565e71c1dc9f1c31258f159ff70d3f87",
"sha256:79c9108d9aa7fa6fba6e668b61b82facc067a6b81517cab34d07a84aa89f3df0",
"sha256:91c7ff2a40c373d0cc9121d54bc5f31c4fa09c346528e6a08d1845bce5771ffc",
"sha256:9272167b5f5fbfe16945be3db475b3ce8d792386907e673a209da686176552af",
"sha256:944c4b4b82dc4a1b805329c980f270f170fdc9945464223f2ec8e57563139cf4",
"sha256:a6a11e48cb93a5fa606306493f439b4aa7c56cb03fc9ace7f6bfa21aaf07c453",
"sha256:a8746bfe4e8f659528c5c7e9af5090c5a7d252f32b2e859c584ef7d8efb1e689",
"sha256:abd9246e4cdd5b554a2ddd97c157e292ac11ef3e7af25ac56b08b455c829dca8",
"sha256:b14ee12da9338f5e5b3a3ef7ca58b3cba30f5b66f7662159762932e6d0b8f680",
"sha256:b88f75005586131276634027f4219d06e0561292be8bd6bc7f2f00bdabd63c4e",
"sha256:c7be9d7f5b0d206f0bbc3794b8e16fb7dbc53ec9e40bbe8787c6f2d38efcf6c9",
"sha256:d2d006286fbcb60f0b391741f520862e9b69f4019b4d738a2a45728c7e952f1b",
"sha256:db417f0865f90bdc07fa30e1aadc69b6f4cad7f86324b02aa842034efe8d8c4d",
"sha256:e7e10454cb1ab62cc6ce776e1c135a64045a11ec4c6d254d3f7689c16eb3efd2",
"sha256:f65f9a46d984b8cd9b3750c2bdb419b2996895b005aefa6cbaba9a143b1ce2c5",
"sha256:fea896b54f3a4ae6f790ac1d017101252c93f6fe075d0e7571543510f11d2676"
],
"index": "pypi",
"version": "==5.9.2"
"version": "==5.9.1"
},
"pyasn1": {
"hashes": [
@ -620,45 +648,44 @@
},
"pydantic": {
"hashes": [
"sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42",
"sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624",
"sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e",
"sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559",
"sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709",
"sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9",
"sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d",
"sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52",
"sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda",
"sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912",
"sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c",
"sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525",
"sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe",
"sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41",
"sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b",
"sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283",
"sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965",
"sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c",
"sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410",
"sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5",
"sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116",
"sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98",
"sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f",
"sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644",
"sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13",
"sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd",
"sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254",
"sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6",
"sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488",
"sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5",
"sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c",
"sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1",
"sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a",
"sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2",
"sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d",
"sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"
"sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44",
"sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d",
"sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84",
"sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555",
"sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7",
"sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131",
"sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8",
"sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3",
"sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56",
"sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0",
"sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4",
"sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453",
"sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044",
"sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e",
"sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15",
"sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb",
"sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001",
"sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d",
"sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3",
"sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e",
"sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f",
"sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c",
"sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b",
"sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8",
"sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567",
"sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979",
"sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326",
"sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb",
"sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f",
"sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa",
"sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747",
"sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801",
"sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55",
"sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08",
"sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76"
],
"index": "pypi",
"version": "==1.10.2"
"version": "==1.9.2"
},
"pyinstaller": {
"hashes": [
@ -679,11 +706,11 @@
},
"pyinstaller-hooks-contrib": {
"hashes": [
"sha256:d1dd6ea059dc30e77813cc12a5efa8b1d228e7da8f5b884fe11775f946db1784",
"sha256:e5edd4094175e78c178ef987b61be19efff6caa23d266ade456fc753e847f62e"
"sha256:c4210fc50282c9c6a918e485e0bfae9405592390508e3be9fde19acc2213da56",
"sha256:e46f099934dd4577fb1ddcf37a99fa04027c92f8f5291c8802f326345988d001"
],
"markers": "python_version >= '3.7'",
"version": "==2022.10"
"version": "==2022.8"
},
"pymssql": {
"hashes": [
@ -784,29 +811,49 @@
},
"pyspnego": {
"hashes": [
"sha256:15cd6d3fc4d18b4b7f80259bfab1580c87dc9677d47e7cf801dad71dc23d1afc",
"sha256:210a2248060a2d789a333f7553a1a478d21812f675c507393169143cbf038d9b",
"sha256:4e967f29c099c196cbf4622587cd27e8c61f20adf78b1d3007b72596e60c9f23",
"sha256:4fab51afb757be21d543ddf78aaeb83db600a7e7daec773568db90d4b7499a2c",
"sha256:53d30afbef1255cb1a8930c14604184b07f989b6ac295a1397eac8c27fd59d8b",
"sha256:838f875ee55004a274f6470460e62b7713237ae8b66a02680a2f31e43b3b5387",
"sha256:b78a3370ace76209a52dc7816636a8c8437e323637eefe86a2193cc4ec352b3b",
"sha256:e08709c4e0838bf37d4ef8ceff2163a51abe2b071e285bb5774de5b73eab214f",
"sha256:ea8570c5363e5dd359aaf599eac6f70116e0ada734ebe557e17cc608c8bb93fc",
"sha256:fa2946ba5059f79d13cb8c47e83474de55569c16ed8f953cc47a24dda6f38f57"
"sha256:1ee612f20c843365fbc6cf7f95c526b4ee8795281641a9bb87083622a2f87939",
"sha256:284ca7a6218344bb90aeae02fb1d2ed73e5c991d6e4c16c0df404aeab5eb58a3",
"sha256:416fd2d67e82b44ba3d2d9062485056e4dde3c141630170e9190379d6b19972a",
"sha256:4c1be83e0aca12d64f5eec638259c77eaa8bf552c89ac69f0af2322a3be9afeb",
"sha256:4d1ea987b9c2539457235793014e0d9c5e4766da9e4e028d4b6b596cfbe53828",
"sha256:725df2030e5d1b1155bb696eca3d684f403164da8e6a6b0bee3eb02f8748f72b",
"sha256:7320539f45da463029e12f3742102085d2a0343bfe77ac550c11d2fdac1d34f5",
"sha256:77b86002082f278c3f5935d8b428a0d0659ea709e305537294ba95fc49907339",
"sha256:aa93d94775d01bf70d16840426d1ddd58c11a6a71c4d0d1d7e529ad541fa0a60",
"sha256:c2abca03b6d3c71d7ec9678c7b2220d99d9a29ef204b4c52549080169e586310",
"sha256:e6645107f200fb7bf6698512d04ea0790b292028861ce169eb97e5ad8eba14ed",
"sha256:f4784d9f8e9c50a36109d715a140150add1990fce16805a56217e8ccaf69d234"
],
"markers": "python_version >= '3.7'",
"version": "==0.6.0"
"markers": "python_version >= '3.6'",
"version": "==0.5.3"
},
"pywin32": {
"sys_platform": "== 'win32'",
"version": "*"
"hashes": [
"sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc",
"sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269",
"sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3",
"sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48",
"sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4",
"sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96",
"sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df",
"sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1",
"sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43",
"sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9",
"sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f",
"sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988",
"sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e",
"sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"
],
"index": "pypi",
"markers": "sys_platform == 'win32'",
"version": "==304"
},
"pywin32-ctypes": {
"hashes": [
"sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
"sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
],
"index": "pypi",
"markers": "sys_platform == 'win32'",
"version": "==0.2.0"
},
@ -827,11 +874,11 @@
},
"setuptools": {
"hashes": [
"sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82",
"sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"
"sha256:7c7854ee1429a240090297628dc9f75b35318d193537968e2dc14010ee2f5bca",
"sha256:dc2662692f47d99cb8ae15a784529adeed535bcd7c277fee0beccf961522baf6"
],
"markers": "python_version >= '3.7'",
"version": "==65.3.0"
"version": "==63.4.1"
},
"six": {
"hashes": [
@ -843,11 +890,11 @@
},
"tqdm": {
"hashes": [
"sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4",
"sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"
"sha256:40be55d30e200777a307a7585aee69e4eabb46b4ec6a4b4a5f2d9f11e7d5408d",
"sha256:74a2cdefe14d11442cedf3ba4e21a3b84ff9a2dbdc6cfae2c34addb2a14a5ea6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==4.64.1"
"version": "==4.64.0"
},
"twisted": {
"extras": [
@ -860,6 +907,24 @@
"markers": "python_full_version >= '3.6.7'",
"version": "==22.4.0"
},
"twisted-iocpsupport": {
"hashes": [
"sha256:306becd6e22ab6e8e4f36b6bdafd9c92e867c98a5ce517b27fdd27760ee7ae41",
"sha256:3c61742cb0bc6c1ac117a7e5f422c129832f0c295af49e01d8a6066df8cfc04d",
"sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9",
"sha256:7d972cfa8439bdcb35a7be78b7ef86d73b34b808c74be56dfa785c8a93b851bf",
"sha256:81b3abe3527b367da0220482820cb12a16c661672b7bcfcde328902890d63323",
"sha256:851b3735ca7e8102e661872390e3bce88f8901bece95c25a0c8bb9ecb8a23d32",
"sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4",
"sha256:9dbb8823b49f06d4de52721b47de4d3b3026064ef4788ce62b1a21c57c3fff6f",
"sha256:b435857b9efcbfc12f8c326ef0383f26416272260455bbca2cd8d8eca470c546",
"sha256:b76b4eed9b27fd63ddb0877efdd2d15835fdcb6baa745cb85b66e5d016ac2878",
"sha256:b9fed67cf0f951573f06d560ac2f10f2a4bbdc6697770113a2fc396ea2cb2565",
"sha256:bf4133139d77fc706d8f572e6b7d82871d82ec7ef25d685c2351bdacfb701415"
],
"markers": "platform_system == 'Windows'",
"version": "==1.0.2"
},
"typing-extensions": {
"hashes": [
"sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02",
@ -870,11 +935,11 @@
},
"unicrypto": {
"hashes": [
"sha256:4d1de0f0a379bb4c213302ae61d927eb8f98179bde9a0ffb8e120998a0c882a6",
"sha256:9d5dd858ad5ad608fa524987b17e8855d64d6d2450ca0ca11638f4d92fc6c80b"
"sha256:0487f9dd9009c326ee9531a79412ae18ad673425a1c800d64947b96fdeb04cdf",
"sha256:fab49ee41926bb31be49552aa135f7aedc04436b49c8fe326d7b6a823810575e"
],
"markers": "python_version >= '3.6'",
"version": "==0.0.9"
"version": "==0.0.8"
},
"urllib3": {
"hashes": [
@ -893,11 +958,11 @@
},
"werkzeug": {
"hashes": [
"sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f",
"sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"
"sha256:4d7013ef96fd197d1cdeb03e066c6c5a491ccb44758a5b2b91137319383e5a5a",
"sha256:7e1db6a5ba6b9a8be061e47e900456355b8714c0f238b0313f53afce1a55a79a"
],
"markers": "python_version >= '3.7'",
"version": "==2.2.2"
"version": "==2.2.1"
},
"winacl": {
"hashes": [
@ -907,6 +972,14 @@
"markers": "python_version >= '3.6'",
"version": "==0.1.3"
},
"winsspi": {
"hashes": [
"sha256:2f5a8d2c4b9f459144426909e26a74e550512e23b6cf9af52c2a00003c7c3fdb",
"sha256:59b7c7595f91414528cfd80c6cfc77ec6f5e4e28185ebd6418f8368ddc7aca82"
],
"markers": "python_version >= '3.6'",
"version": "==0.0.10"
},
"winsys-3.x": {
"hashes": [
"sha256:cef3df1dce2a5a71efa46446e6007ad9f7dbae31e83ffcc2ea3485c00c914cc3"

View File

@ -0,0 +1,5 @@
from .relay_connection_handler import RelayConnectionHandler, RELAY_CONTROL_MESSAGE
from .relay_user_handler import RelayUser, RelayUserHandler
from .sockets_pipe import SocketsPipe
from .tcp_connection_handler import TCPConnectionHandler
from .tcp_pipe_spawner import TCPPipeSpawner

View File

@ -0,0 +1,32 @@
import socket
from ipaddress import IPv4Address
from .relay_user_handler import RelayUserHandler
from .tcp_pipe_spawner import TCPPipeSpawner
RELAY_CONTROL_MESSAGE = b"infection-monkey-relay-control-message: -"
class RelayConnectionHandler:
"""Handles new relay connections."""
def __init__(self, pipe_spawner: TCPPipeSpawner, relay_user_handler: RelayUserHandler):
self._pipe_spawner = pipe_spawner
self._relay_user_handler = relay_user_handler
def handle_new_connection(self, sock: socket.socket):
"""
Spawn a new pipe, or remove the user if the user requested to disconnect.
:param sock: The socket for the new connection.
"""
addr, _ = sock.getpeername()
addr = IPv4Address(addr)
control_message = sock.recv(socket.MSG_PEEK)
if control_message.startswith(RELAY_CONTROL_MESSAGE):
self._relay_user_handler.disconnect_user(addr)
else:
self._relay_user_handler.add_relay_user(addr)
self._pipe_spawner.spawn_pipe(sock)

View File

@ -0,0 +1,76 @@
from dataclasses import dataclass
from ipaddress import IPv4Address
from threading import Lock
from typing import Dict
from egg_timer import EggTimer
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from common.utils.code_utils import del_key
# Wait for potential new clients to connect
DEFAULT_NEW_CLIENT_TIMEOUT = 2.5 * MEDIUM_REQUEST_TIMEOUT
@dataclass
class RelayUser:
address: IPv4Address
timer: EggTimer
class RelayUserHandler:
"""Manages membership to a network relay."""
def __init__(self, new_client_timeout: float = DEFAULT_NEW_CLIENT_TIMEOUT):
self._new_client_timeout = new_client_timeout
self._relay_users: Dict[IPv4Address, RelayUser] = {}
self._potential_users: Dict[IPv4Address, RelayUser] = {}
self._lock = Lock()
def add_relay_user(self, user_address: IPv4Address):
"""
Handle new user connection.
:param source_socket: A source socket
:param user_address: An address defining RelayUser which will be added to the relay
"""
with self._lock:
if user_address in self._potential_users:
del_key(self._potential_users, user_address)
timer = EggTimer()
self._relay_users[user_address] = RelayUser(user_address, timer)
def add_potential_user(self, user_address: IPv4Address):
"""
Notify RelayUserHandler that a new user may try and connect.
:param user_address: An address defining potential RelayUser
that tries to connect to the relay
"""
with self._lock:
timer = EggTimer()
timer.set(self._new_client_timeout)
self._potential_users[user_address] = RelayUser(user_address, timer)
def disconnect_user(self, user_address: IPv4Address):
"""
Handle when a user disconnects.
:param user_address: The address of the disconnecting user.
"""
with self._lock:
if user_address in self._relay_users:
del_key(self._relay_users, user_address)
def has_potential_users(self) -> bool:
"""
Return whether or not we have any potential users.
"""
self._potential_users = dict(
filter(lambda ru: not ru[1].timer.is_expired(), self._potential_users.items())
)
return len(self._potential_users) > 0

View File

@ -0,0 +1,62 @@
from __future__ import annotations
import select
from logging import getLogger
from threading import Thread
from typing import Callable
READ_BUFFER_SIZE = 8192
SOCKET_READ_TIMEOUT = 10
logger = getLogger(__name__)
class SocketsPipe(Thread):
"""Manages a pipe between two sockets."""
def __init__(
self,
source,
dest,
pipe_closed: Callable[[SocketsPipe], None],
timeout=SOCKET_READ_TIMEOUT,
):
self.source = source
self.dest = dest
self.timeout = timeout
super().__init__(name=f"SocketsPipeThread-{self.ident}", daemon=True)
self._pipe_closed = pipe_closed
def _pipe(self):
sockets = [self.source, self.dest]
while True:
read_list, _, except_list = select.select(sockets, [], sockets, self.timeout)
if except_list:
raise Exception("select() failed on sockets {except_list}")
if not read_list:
raise TimeoutError("pipe did not receive data for {self.timeout} seconds")
for r in read_list:
other = self.dest if r is self.source else self.source
data = r.recv(READ_BUFFER_SIZE)
if data:
other.sendall(data)
def run(self):
try:
self._pipe()
except Exception as err:
logger.debug(err)
try:
self.source.close()
except Exception as err:
logger.debug(f"Error while closing source socket: {err}")
try:
self.dest.close()
except Exception as err:
logger.debug(f"Error while closing destination socket: {err}")
self._pipe_closed(self)

View File

@ -0,0 +1,41 @@
import socket
from threading import Thread
from typing import Callable, List
from infection_monkey.utils.threading import InterruptableThreadMixin
PROXY_TIMEOUT = 2.5
class TCPConnectionHandler(Thread, InterruptableThreadMixin):
"""Accepts connections on a TCP socket."""
def __init__(
self,
bind_host: str,
bind_port: int,
client_connected: List[Callable[[socket.socket], None]] = [],
):
self.bind_host = bind_host
self.bind_port = bind_port
self._client_connected = client_connected
Thread.__init__(self, name="TCPConnectionHandler", daemon=True)
InterruptableThreadMixin.__init__(self)
def run(self):
l_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
l_socket.bind((self.bind_host, self.bind_port))
l_socket.settimeout(PROXY_TIMEOUT)
l_socket.listen(5)
while not self._interrupted.is_set():
try:
source, _ = l_socket.accept()
except socket.timeout:
continue
for notify_client_connected in self._client_connected:
notify_client_connected(source)
l_socket.close()

View File

@ -0,0 +1,51 @@
import socket
from ipaddress import IPv4Address
from threading import Lock
from typing import Set
from .sockets_pipe import SocketsPipe
class TCPPipeSpawner:
"""
Creates bi-directional pipes between the configured client and other clients.
"""
def __init__(self, target_addr: IPv4Address, target_port: int):
self._target_addr = target_addr
self._target_port = target_port
self._pipes: Set[SocketsPipe] = set()
self._lock = Lock()
def spawn_pipe(self, source: socket.socket):
"""
Attempt to create a pipe on between the configured client and the provided socket
:param source: A socket to the connecting client.
:raises socket.error: If a socket to the configured client could not be created.
"""
dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
dest.connect((self._target_addr, self._target_port))
except socket.error as err:
source.close()
dest.close()
raise err
pipe = SocketsPipe(source, dest, self._handle_pipe_closed)
with self._lock:
self._pipes.add(pipe)
pipe.run()
def has_open_pipes(self) -> bool:
"""Return whether or not the TCPPipeSpawner has any open pipes."""
with self._lock:
for p in self._pipes:
if p.is_alive():
return True
return False
def _handle_pipe_closed(self, pipe: SocketsPipe):
with self._lock:
self._pipes.discard(pipe)

View File

@ -0,0 +1,47 @@
from threading import Lock, Thread
from time import sleep
from infection_monkey.network.relay import RelayUserHandler, TCPConnectionHandler, TCPPipeSpawner
from infection_monkey.utils.threading import InterruptableThreadMixin
class TCPRelay(Thread, InterruptableThreadMixin):
"""
Provides and manages a TCP proxy connection.
"""
def __init__(
self,
relay_user_handler: RelayUserHandler,
connection_handler: TCPConnectionHandler,
pipe_spawner: TCPPipeSpawner,
):
self._user_handler = relay_user_handler
self._connection_handler = connection_handler
self._pipe_spawner = pipe_spawner
super().__init__(name="MonkeyTcpRelayThread", daemon=True)
self._lock = Lock()
def run(self):
self._connection_handler.start()
self._interrupted.wait()
self._wait_for_users_to_disconnect()
self._connection_handler.stop()
self._connection_handler.join()
self._wait_for_pipes_to_close()
def _wait_for_users_to_disconnect(self):
"""
Blocks until the users disconnect or the timeout has elapsed.
"""
while self._user_handler.has_potential_users():
sleep(0.5)
def _wait_for_pipes_to_close(self):
"""
Blocks until the pipes have closed.
"""
while self._pipe_spawner.has_open_pipes():
sleep(0.5)

View File

@ -1,5 +1,7 @@
from functools import singledispatch
from ipaddress import IPv4Address
from infection_monkey.network.relay.tcp_relay import TCPRelay
from infection_monkey.telemetry.exploit_telem import ExploitTelem
from infection_monkey.telemetry.i_telem import ITelem
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
@ -7,26 +9,39 @@ from infection_monkey.tunnel import MonkeyTunnel
class ExploitInterceptingTelemetryMessenger(ITelemetryMessenger):
def __init__(self, telemetry_messenger: ITelemetryMessenger, tunnel: MonkeyTunnel):
def __init__(
self, telemetry_messenger: ITelemetryMessenger, tunnel: MonkeyTunnel, relay: TCPRelay
):
self._telemetry_messenger = telemetry_messenger
self._tunnel = tunnel
self._relay = relay
def send_telemetry(self, telemetry: ITelem):
_send_telemetry(telemetry, self._telemetry_messenger, self._tunnel)
_send_telemetry(telemetry, self._telemetry_messenger, self._tunnel, self._relay)
# Note: We can use @singledispatchmethod instead of @singledispatch if we migrate to Python 3.8 or
# later.
@singledispatch
def _send_telemetry(
telemetry: ITelem, telemetry_messenger: ITelemetryMessenger, tunnel: MonkeyTunnel
telemetry: ITelem,
telemetry_messenger: ITelemetryMessenger,
tunnel: MonkeyTunnel,
relay: TCPRelay,
):
telemetry_messenger.send_telemetry(telemetry)
@_send_telemetry.register
def _(telemetry: ExploitTelem, telemetry_messenger: ITelemetryMessenger, tunnel: MonkeyTunnel):
def _(
telemetry: ExploitTelem,
telemetry_messenger: ITelemetryMessenger,
tunnel: MonkeyTunnel,
relay: TCPRelay,
):
if telemetry.propagation_result is True:
tunnel.set_wait_for_exploited_machines()
if relay:
relay.add_potential_user(IPv4Address(telemetry.host["ip_addr"]))
telemetry_messenger.send_telemetry(telemetry)

View File

@ -107,3 +107,12 @@ def interruptible_function(*, msg: Optional[str] = None, default_return_value: A
return _wrapper
return _decorator
class InterruptableThreadMixin:
def __init__(self):
self._interrupted = Event()
def stop(self):
"""Stop a running thread."""
self._interrupted.set()

View File

@ -0,0 +1,64 @@
import socket
from ipaddress import IPv4Address
from unittest.mock import MagicMock
import pytest
from monkey.infection_monkey.network.relay import (
RELAY_CONTROL_MESSAGE,
RelayConnectionHandler,
RelayUserHandler,
TCPPipeSpawner,
)
USER_ADDRESS = "0.0.0.1"
@pytest.fixture
def pipe_spawner():
return MagicMock(spec=TCPPipeSpawner)
@pytest.fixture
def relay_user_handler():
return MagicMock(spec=RelayUserHandler)
@pytest.fixture
def close_socket():
sock = MagicMock(spec=socket.socket)
sock.recv.return_value = RELAY_CONTROL_MESSAGE
sock.getpeername.return_value = (USER_ADDRESS, 12345)
return sock
@pytest.fixture
def data_socket():
sock = MagicMock(spec=socket.socket)
sock.recv.return_value = b"some data"
sock.getpeername.return_value = (USER_ADDRESS, 12345)
return sock
def test_control_message_disconnects_user(pipe_spawner, relay_user_handler, close_socket):
connection_handler = RelayConnectionHandler(pipe_spawner, relay_user_handler)
connection_handler.handle_new_connection(close_socket)
relay_user_handler.disconnect_user.assert_called_once_with(IPv4Address(USER_ADDRESS))
def test_connection_spawns_pipe(pipe_spawner, relay_user_handler, data_socket):
connection_handler = RelayConnectionHandler(pipe_spawner, relay_user_handler)
connection_handler.handle_new_connection(data_socket)
pipe_spawner.spawn_pipe.assert_called_once_with(data_socket)
def test_connection_adds_user(pipe_spawner, relay_user_handler, data_socket):
connection_handler = RelayConnectionHandler(pipe_spawner, relay_user_handler)
connection_handler.handle_new_connection(data_socket)
relay_user_handler.add_relay_user.assert_called_once_with(IPv4Address(USER_ADDRESS))

View File

@ -0,0 +1,35 @@
from ipaddress import IPv4Address
from time import sleep
import pytest
from monkey.infection_monkey.network.relay import RelayUserHandler
USER_ADDRESS = IPv4Address("0.0.0.0")
@pytest.fixture
def handler():
return RelayUserHandler()
def test_potential_users_added(handler):
assert not handler.has_potential_users()
handler.add_potential_user(USER_ADDRESS)
assert handler.has_potential_users()
def test_potential_user_removed_on_matching_user_added(handler):
handler.add_potential_user(USER_ADDRESS)
handler.add_relay_user(USER_ADDRESS)
assert not handler.has_potential_users()
def test_potential_users_time_out():
handler = RelayUserHandler(new_client_timeout=0.001)
handler.add_potential_user(USER_ADDRESS)
sleep(0.003)
assert not handler.has_potential_users()

View File

@ -8,7 +8,7 @@ from infection_monkey.telemetry.messengers.exploit_intercepting_telemetry_messen
)
class MockExpliotTelem(ExploitTelem):
class MockExploitTelem(ExploitTelem):
def __init__(self, propagation_success):
erd = ExploiterResultData()
erd.propagation_success = propagation_success
@ -21,42 +21,48 @@ class MockExpliotTelem(ExploitTelem):
def test_generic_telemetry(TestTelem):
mock_telemetry_messenger = MagicMock()
mock_tunnel = MagicMock()
mock_relay = MagicMock()
telemetry_messenger = ExploitInterceptingTelemetryMessenger(
mock_telemetry_messenger, mock_tunnel
mock_telemetry_messenger, mock_tunnel, mock_relay
)
telemetry_messenger.send_telemetry(TestTelem())
assert mock_telemetry_messenger.send_telemetry.called
assert not mock_tunnel.set_wait_for_exploited_machines.called
assert not mock_relay.add_potential_user.called
def test_propagation_successful_expliot_telemetry():
def test_propagation_successful_exploit_telemetry():
mock_telemetry_messenger = MagicMock()
mock_tunnel = MagicMock()
mock_expliot_telem = MockExpliotTelem(True)
mock_relay = MagicMock()
mock_exploit_telem = MockExploitTelem(True)
telemetry_messenger = ExploitInterceptingTelemetryMessenger(
mock_telemetry_messenger, mock_tunnel
mock_telemetry_messenger, mock_tunnel, mock_relay
)
telemetry_messenger.send_telemetry(mock_expliot_telem)
telemetry_messenger.send_telemetry(mock_exploit_telem)
assert mock_telemetry_messenger.send_telemetry.called
assert mock_tunnel.set_wait_for_exploited_machines.called
assert mock_relay.add_potential_user.called
def test_propagation_failed_expliot_telemetry():
def test_propagation_failed_exploit_telemetry():
mock_telemetry_messenger = MagicMock()
mock_tunnel = MagicMock()
mock_expliot_telem = MockExpliotTelem(False)
mock_relay = MagicMock()
mock_exploit_telem = MockExploitTelem(False)
telemetry_messenger = ExploitInterceptingTelemetryMessenger(
mock_telemetry_messenger, mock_tunnel
mock_telemetry_messenger, mock_tunnel, mock_relay
)
telemetry_messenger.send_telemetry(mock_expliot_telem)
telemetry_messenger.send_telemetry(mock_exploit_telem)
assert mock_telemetry_messenger.send_telemetry.called
assert not mock_tunnel.set_wait_for_exploited_machines.called
assert not mock_relay.add_potential_user.called

View File

@ -299,6 +299,11 @@ event
deserialize
serialized_event
# TODO: Remove after #2231 is closed
relay_users
last_update_time
add_relay_user
# pydantic base models
underscore_attrs_are_private
extra