Merge branch 'devel'
cargo devel CI / cargo CI (push) Successful in 2m59s Details

This commit is contained in:
Christoph J. Scherr 2024-01-24 16:29:25 +01:00
commit 26521989be
Signed by: cscherrNT
GPG Key ID: 8E2B45BC51A27EA7
30 changed files with 827 additions and 174 deletions

View File

@ -1,6 +1,7 @@
workspace = { members = ["spammer"] }
[package]
name = "netpong"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
publish = true
authors = ["Christoph J. Scherr <software@cscherr.de>"]
@ -17,11 +18,13 @@ anyhow = "1.0.79"
clap = "4.4.18"
clap-num = "1.0.2"
clap-verbosity-flag = "2.1.2"
libpt = { version = "0.3.10", features = ["net"] }
libpt = { version = "0.3.11", features = ["net"] }
thiserror = "1.0.56"
threadpool = { version = "1.8.1", optional = true }
tokio = { version = "1.35.1", features = ["net", "rt", "macros"] }
rustls-pemfile = "2.0.0"
tokio-rustls = "0.25.0"
webpki-roots = "0.26.0"
[features]
default = ["server"]
server = ["dep:threadpool"]
server = []

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgITfl3NbK3jOj2V0yehJ0VkuBWlvDANBgkqhkiG9w0BAQsF
ADCBmTELMAkGA1UEBhMCREUxHTAbBgNVBAgMFEJhZGVuIFfDg8K8cnR0ZW1iZXJn
MREwDwYDVQQHDAhNYW5uaGVpbTEVMBMGA1UECgwMTmV0cG9uZyBUZWFtMR0wGwYD
VQQDDBROZXRwb25nLVRlc3QtQ0EgUm9vdDEiMCAGCSqGSIb3DQEJARYTc29mdHdh
cmVAY3NjaGVyci5kZTAeFw0yNDAxMjQxNDM3NTdaFw0zNDAxMjExNDM3NTdaMIGZ
MQswCQYDVQQGEwJERTEdMBsGA1UECAwUQmFkZW4gV8ODwrxydHRlbWJlcmcxETAP
BgNVBAcMCE1hbm5oZWltMRUwEwYDVQQKDAxOZXRwb25nIFRlYW0xHTAbBgNVBAMM
FE5ldHBvbmctVGVzdC1DQSBSb290MSIwIAYJKoZIhvcNAQkBFhNzb2Z0d2FyZUBj
c2NoZXJyLmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjc443jjU
YZP4aVC0vD0WRpzC6G50wva3lLX2vOf6x1xAE/sVQ7F3j25s/oUUzHSf4/F4H3rC
R5ZmpyOBiW/1ZuQVb48HxzE7Vh/QQenTUVcPEdZcqf0vLogDzaSrq9uMXvmWHWgQ
IE0yYbEBd2/bE0k530EW5QZpKdUZI6m+Tf6k60Fk65skC4IZ684M6ahB9AQiBY0c
6DzJPN6AV33s6HjHqLJUeWwiEFXx7v/I3Fo81NHnoRZQw9bNel3rRa1Ovn1FIUz3
rKygXb3/Zcl3TKh2eRXb7bJmG35dh+Cx9OtPlYSiU45w5Kxa7+c1n2H+rDv5QlcH
tsUR2ONDDRG4MwIDAQABo1MwUTAdBgNVHQ4EFgQUj4dOxujhWUGrCG5xJNhrCXM0
JWEwHwYDVR0jBBgwFoAUj4dOxujhWUGrCG5xJNhrCXM0JWEwDwYDVR0TAQH/BAUw
AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcR6c5RMuEqO01TKfzXq0b2J8Rfqxe9WJ
6tgc7/3DatCYkytCq+fucZ2hUg/IxZ8wRpe1UyaK5iLd0kC8ag5RT5pl9ybHnVZZ
DsQNYlal71DaCwId+VhiZpqGVERruln7nBifNDrqbRy9U2da/q7ZoMlxkIOgUiBd
r4Ecv/J6l6LprIIjxGRQ6dC0TN0kDkJ5UFS7IMsM13eDtejA/mfHOamN6Ty0PzaY
HI9IeKzlFz0yzRyaYL/VrpBmiQF1goRpeIfEZw5F09hatkhSgzmV+GcMjTAnIVCU
h/s9q/mFKeWVWUA8endIx+3YXtIdMK6H16DGYNOIyzmc7XwpQkDqvg==
-----END CERTIFICATE-----

View File

@ -0,0 +1 @@
V 340121145241Z 00 unknown /C=DE/ST=Baden W\xC3\x83\xC2\xBCrttemberg/O=Netpong Team/CN=localhost

View File

@ -0,0 +1 @@
unique_subject = yes

View File

View File

@ -0,0 +1,93 @@
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=DE, ST=Baden W\xC3\x83\xC2\xBCrttemberg, L=Mannheim, O=Netpong Team, CN=Netpong-Test-CA Root/emailAddress=software@cscherr.de
Validity
Not Before: Jan 24 14:52:41 2024 GMT
Not After : Jan 21 14:52:41 2034 GMT
Subject: C=DE, ST=Baden W\xC3\x83\xC2\xBCrttemberg, O=Netpong Team, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:d5:e6:a4:18:a1:c2:a6:c6:f1:22:d7:c5:66:a6:
90:68:f6:2f:0e:2f:41:8c:9b:2e:f2:e4:64:9b:e1:
5f:28:64:4f:ea:a6:b5:68:67:e2:09:93:11:93:3d:
d8:0b:e7:06:50:38:1e:6c:fa:70:2c:32:fb:64:ba:
d3:43:8c:16:b0:78:39:e4:6f:05:da:e1:7b:c0:8c:
e0:79:90:4d:60:85:0e:13:5c:2b:03:a9:38:c9:20:
48:1b:41:a7:70:95:d2:ae:e9:96:5e:55:d7:a1:9b:
75:51:de:65:75:7c:0f:1f:71:29:88:6d:ca:82:d5:
9e:e6:09:78:4a:d3:10:f7:13:69:c8:3e:4e:7e:1f:
9b:9c:6b:a3:f6:da:2a:65:3d:41:e9:41:62:41:a7:
aa:5e:9e:5a:1b:e9:a0:ca:35:c4:7e:a0:93:48:0c:
cc:54:98:79:4b:97:20:0d:48:9f:9a:fb:24:16:6e:
ba:ad:04:5e:83:0c:a6:da:de:59:6a:29:c0:fd:77:
3b:d4:d1:f2:a7:a0:a1:64:66:32:52:11:08:5f:17:
35:14:11:ab:9a:ac:69:df:82:d0:05:7e:78:7e:45:
20:ea:da:0e:18:3b:22:72:e3:d6:ef:4a:00:aa:2a:
3d:42:3a:03:ae:6a:e6:cc:2a:fb:6c:eb:e0:13:3e:
ca:1d:a6:92:ed:14:25:a3:c3:d9:03:60:13:48:be:
32:c4:b3:09:df:68:b5:b3:7f:cd:13:c6:af:e0:49:
d2:91:40:d3:9d:6f:53:a5:08:23:5e:fb:b1:d6:20:
8f:a0:66:b1:ce:7d:8e:97:79:9c:ec:73:94:ca:60:
71:48:8e:0f:92:b7:5b:99:83:24:02:13:a3:f3:64:
92:25:2e:74:00:0d:b6:e4:85:41:95:12:af:93:39:
ed:ed:73:9e:00:a5:c6:1b:8a:3f:19:73:e8:e4:01:
4a:a4:f5:a6:3c:f8:ee:e3:74:21:fd:ab:53:17:2c:
72:74:b0:7e:87:23:b5:f2:dd:67:24:d1:8c:8d:75:
4b:d9:5b:d1:10:55:c0:6b:2d:22:7c:7f:a1:42:15:
12:4f:fd:70:b3:18:f5:78:a9:56:f7:2f:f2:91:54:
57:38:9f:11:31:20:dd:79:aa:fb:b6:8d:fc:58:25:
07:2b:b9:c7:8b:85:e3:39:77:6f:8e:51:fa:9c:6b:
c7:2a:ba:1e:59:28:e9:b8:07:1f:50:bc:89:3e:61:
55:9a:c5:c6:6d:54:09:9a:96:ec:97:d9:16:5b:4b:
60:d5:37:bf:9d:ad:72:09:4c:fc:c0:df:05:5c:2a:
51:92:e2:79:b0:c6:8c:91:26:a9:cb:3d:f9:1e:dd:
7f:19:e3
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
3f:00:bc:70:77:c1:4d:f5:d2:f5:ea:23:7a:1d:ee:90:3a:1e:
16:3a:2b:25:56:8c:13:78:4e:a1:6c:32:49:68:3e:0e:9a:43:
e1:45:bf:85:a1:36:88:5f:9a:e1:9b:04:40:f8:a4:77:5f:cf:
a3:29:c5:fb:b0:2b:d1:cc:2b:97:04:d1:9e:4d:32:7d:bd:ff:
49:7b:b1:38:c7:77:be:74:73:2f:f2:e5:f8:af:34:05:f2:5e:
75:40:2a:d3:8f:d7:4f:aa:17:7d:09:f1:16:3e:1c:f7:e6:e9:
7a:bb:98:92:83:5a:b4:71:08:97:fc:6e:97:cf:07:73:48:de:
23:f6:58:06:b4:c9:c9:a7:11:8b:95:50:f0:2e:cb:25:85:b1:
30:79:6c:61:84:ee:b4:ea:1f:b1:a7:80:c5:09:2c:e3:ae:83:
f8:0a:3c:ef:d1:b8:fb:1e:2e:91:03:21:65:62:fe:fe:a6:c7:
cd:cf:7f:31:d4:99:cf:6e:39:63:df:1a:f2:fd:55:33:22:ef:
a8:26:2f:15:f6:d9:63:a2:ac:bb:f1:bf:e9:c1:c7:88:d1:4f:
d8:19:38:ce:8c:d3:bc:a8:15:32:ba:05:58:74:f5:8c:fa:aa:
9f:52:42:67:2e:73:57:04:ec:57:ca:6c:a6:f5:f2:84:b5:0d:
09:09:1a:64
-----BEGIN CERTIFICATE-----
MIIEZTCCA00CAQAwDQYJKoZIhvcNAQELBQAwgZkxCzAJBgNVBAYTAkRFMR0wGwYD
VQQIDBRCYWRlbiBXw4PCvHJ0dGVtYmVyZzERMA8GA1UEBwwITWFubmhlaW0xFTAT
BgNVBAoMDE5ldHBvbmcgVGVhbTEdMBsGA1UEAwwUTmV0cG9uZy1UZXN0LUNBIFJv
b3QxIjAgBgkqhkiG9w0BCQEWE3NvZnR3YXJlQGNzY2hlcnIuZGUwHhcNMjQwMTI0
MTQ1MjQxWhcNMzQwMTIxMTQ1MjQxWjBXMQswCQYDVQQGEwJERTEdMBsGA1UECAwU
QmFkZW4gV8ODwrxydHRlbWJlcmcxFTATBgNVBAoMDE5ldHBvbmcgVGVhbTESMBAG
A1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
1eakGKHCpsbxItfFZqaQaPYvDi9BjJsu8uRkm+FfKGRP6qa1aGfiCZMRkz3YC+cG
UDgebPpwLDL7ZLrTQ4wWsHg55G8F2uF7wIzgeZBNYIUOE1wrA6k4ySBIG0GncJXS
rumWXlXXoZt1Ud5ldXwPH3EpiG3KgtWe5gl4StMQ9xNpyD5Ofh+bnGuj9toqZT1B
6UFiQaeqXp5aG+mgyjXEfqCTSAzMVJh5S5cgDUifmvskFm66rQRegwym2t5ZainA
/Xc71NHyp6ChZGYyUhEIXxc1FBGrmqxp34LQBX54fkUg6toOGDsicuPW70oAqio9
QjoDrmrmzCr7bOvgEz7KHaaS7RQlo8PZA2ATSL4yxLMJ32i1s3/NE8av4EnSkUDT
nW9TpQgjXvux1iCPoGaxzn2Ol3mc7HOUymBxSI4PkrdbmYMkAhOj82SSJS50AA22
5IVBlRKvkznt7XOeAKXGG4o/GXPo5AFKpPWmPPju43Qh/atTFyxydLB+hyO18t1n
JNGMjXVL2VvREFXAay0ifH+hQhUST/1wsxj1eKlW9y/ykVRXOJ8RMSDdear7to38
WCUHK7nHi4XjOXdvjlH6nGvHKroeWSjpuAcfULyJPmFVmsXGbVQJmpbsl9kWW0tg
1Te/na1yCUz8wN8FXCpRkuJ5sMaMkSapyz35Ht1/GeMCAwEAATANBgkqhkiG9w0B
AQsFAAOCAQEAPwC8cHfBTfXS9eojeh3ukDoeFjorJVaME3hOoWwySWg+DppD4UW/
haE2iF+a4ZsEQPikd1/PoynF+7Ar0cwrlwTRnk0yfb3/SXuxOMd3vnRzL/Ll+K80
BfJedUAq04/XT6oXfQnxFj4c9+bperuYkoNatHEIl/xul88Hc0jeI/ZYBrTJyacR
i5VQ8C7LJYWxMHlsYYTutOofsaeAxQks466D+Ao879G4+x4ukQMhZWL+/qbHzc9/
MdSZz245Y98a8v1VMyLvqCYvFfbZY6Ksu/G/6cHHiNFP2Bk4zozTvKgVMroFWHT1
jPqqn1JCZy5zVwTsV8pspvXyhLUNCQkaZA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE1DCCArwCAQAwgY4xCzAJBgNVBAYTAkRFMR0wGwYDVQQIDBRCYWRlbiBXw4PC
vHJ0dGVtYmVyZzERMA8GA1UEBwwITWFubmhlaW0xFTATBgNVBAoMDE5ldHBvbmcg
VGVhbTESMBAGA1UEAwwJbG9jYWxob3N0MSIwIAYJKoZIhvcNAQkBFhNzb2Z0d2Fy
ZUBjc2NoZXJyLmRlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1eak
GKHCpsbxItfFZqaQaPYvDi9BjJsu8uRkm+FfKGRP6qa1aGfiCZMRkz3YC+cGUDge
bPpwLDL7ZLrTQ4wWsHg55G8F2uF7wIzgeZBNYIUOE1wrA6k4ySBIG0GncJXSrumW
XlXXoZt1Ud5ldXwPH3EpiG3KgtWe5gl4StMQ9xNpyD5Ofh+bnGuj9toqZT1B6UFi
QaeqXp5aG+mgyjXEfqCTSAzMVJh5S5cgDUifmvskFm66rQRegwym2t5ZainA/Xc7
1NHyp6ChZGYyUhEIXxc1FBGrmqxp34LQBX54fkUg6toOGDsicuPW70oAqio9QjoD
rmrmzCr7bOvgEz7KHaaS7RQlo8PZA2ATSL4yxLMJ32i1s3/NE8av4EnSkUDTnW9T
pQgjXvux1iCPoGaxzn2Ol3mc7HOUymBxSI4PkrdbmYMkAhOj82SSJS50AA225IVB
lRKvkznt7XOeAKXGG4o/GXPo5AFKpPWmPPju43Qh/atTFyxydLB+hyO18t1nJNGM
jXVL2VvREFXAay0ifH+hQhUST/1wsxj1eKlW9y/ykVRXOJ8RMSDdear7to38WCUH
K7nHi4XjOXdvjlH6nGvHKroeWSjpuAcfULyJPmFVmsXGbVQJmpbsl9kWW0tg1Te/
na1yCUz8wN8FXCpRkuJ5sMaMkSapyz35Ht1/GeMCAwEAAaAAMA0GCSqGSIb3DQEB
CwUAA4ICAQBfGAE9+31BxgHeUbmC96QtOjEhpy5YkONNQWB8M8588NVExV4WBAmj
bqEdGf5/KnDEqEMctzxYt7vSCPT5p1OALAkExWI+tz0uup6pjoKq8Ar9A/Va9tfn
4Bw3Nyvg1LJ55j0dhCCT8APljGhlHV5eVeLuFX4zTXHt+MJj/Laaip/k6J2+PuJk
pRPA/f/A2zswhgrWU/4ovyYB6f8MjJFvh65wlBva1j4Bs9siV5VpNdORswEBVXK+
4JUvdSabitn3uFWDCnEW+z7xi9Kl5aqo6VmYC6W58k8qJw8PhGODYIgKE0MhBLsd
CrfU9luUOpmrjvczZfkLuuuJxdZClrfW0kWyOlkx1rB9OFDmJVGgm0Px+dTUv53A
MojK3fhVdP2aUzHMrCpkINmpvChRNHKWYPDgBeqHNuMq/qlGXeDPuKGSN3KI3Srk
LhiDOTfRMDYNgi9V8kZywv8iLiHYke2TWDP08baUy190b5MxKr2/BnTNDpTVyx2q
4Cw7PdcvvlQsG/gpWyD93DQ3QNFsO+D4ZX6DyCbOnGFh4ff0w8Gylehp7OCiPbLB
hQrxbLrfZWEe62FrBArdJgF6aawpxycrgjXaapzFQhwaJV3BHQI+ScFrzwHaGnEG
LsSnnt+U6WrGgPuss435JhnB9QUe2hq/DSzuabeIQrpb57BrD57yuA==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,93 @@
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=DE, ST=Baden W\xC3\x83\xC2\xBCrttemberg, L=Mannheim, O=Netpong Team, CN=Netpong-Test-CA Root/emailAddress=software@cscherr.de
Validity
Not Before: Jan 24 14:52:41 2024 GMT
Not After : Jan 21 14:52:41 2034 GMT
Subject: C=DE, ST=Baden W\xC3\x83\xC2\xBCrttemberg, O=Netpong Team, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:d5:e6:a4:18:a1:c2:a6:c6:f1:22:d7:c5:66:a6:
90:68:f6:2f:0e:2f:41:8c:9b:2e:f2:e4:64:9b:e1:
5f:28:64:4f:ea:a6:b5:68:67:e2:09:93:11:93:3d:
d8:0b:e7:06:50:38:1e:6c:fa:70:2c:32:fb:64:ba:
d3:43:8c:16:b0:78:39:e4:6f:05:da:e1:7b:c0:8c:
e0:79:90:4d:60:85:0e:13:5c:2b:03:a9:38:c9:20:
48:1b:41:a7:70:95:d2:ae:e9:96:5e:55:d7:a1:9b:
75:51:de:65:75:7c:0f:1f:71:29:88:6d:ca:82:d5:
9e:e6:09:78:4a:d3:10:f7:13:69:c8:3e:4e:7e:1f:
9b:9c:6b:a3:f6:da:2a:65:3d:41:e9:41:62:41:a7:
aa:5e:9e:5a:1b:e9:a0:ca:35:c4:7e:a0:93:48:0c:
cc:54:98:79:4b:97:20:0d:48:9f:9a:fb:24:16:6e:
ba:ad:04:5e:83:0c:a6:da:de:59:6a:29:c0:fd:77:
3b:d4:d1:f2:a7:a0:a1:64:66:32:52:11:08:5f:17:
35:14:11:ab:9a:ac:69:df:82:d0:05:7e:78:7e:45:
20:ea:da:0e:18:3b:22:72:e3:d6:ef:4a:00:aa:2a:
3d:42:3a:03:ae:6a:e6:cc:2a:fb:6c:eb:e0:13:3e:
ca:1d:a6:92:ed:14:25:a3:c3:d9:03:60:13:48:be:
32:c4:b3:09:df:68:b5:b3:7f:cd:13:c6:af:e0:49:
d2:91:40:d3:9d:6f:53:a5:08:23:5e:fb:b1:d6:20:
8f:a0:66:b1:ce:7d:8e:97:79:9c:ec:73:94:ca:60:
71:48:8e:0f:92:b7:5b:99:83:24:02:13:a3:f3:64:
92:25:2e:74:00:0d:b6:e4:85:41:95:12:af:93:39:
ed:ed:73:9e:00:a5:c6:1b:8a:3f:19:73:e8:e4:01:
4a:a4:f5:a6:3c:f8:ee:e3:74:21:fd:ab:53:17:2c:
72:74:b0:7e:87:23:b5:f2:dd:67:24:d1:8c:8d:75:
4b:d9:5b:d1:10:55:c0:6b:2d:22:7c:7f:a1:42:15:
12:4f:fd:70:b3:18:f5:78:a9:56:f7:2f:f2:91:54:
57:38:9f:11:31:20:dd:79:aa:fb:b6:8d:fc:58:25:
07:2b:b9:c7:8b:85:e3:39:77:6f:8e:51:fa:9c:6b:
c7:2a:ba:1e:59:28:e9:b8:07:1f:50:bc:89:3e:61:
55:9a:c5:c6:6d:54:09:9a:96:ec:97:d9:16:5b:4b:
60:d5:37:bf:9d:ad:72:09:4c:fc:c0:df:05:5c:2a:
51:92:e2:79:b0:c6:8c:91:26:a9:cb:3d:f9:1e:dd:
7f:19:e3
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
3f:00:bc:70:77:c1:4d:f5:d2:f5:ea:23:7a:1d:ee:90:3a:1e:
16:3a:2b:25:56:8c:13:78:4e:a1:6c:32:49:68:3e:0e:9a:43:
e1:45:bf:85:a1:36:88:5f:9a:e1:9b:04:40:f8:a4:77:5f:cf:
a3:29:c5:fb:b0:2b:d1:cc:2b:97:04:d1:9e:4d:32:7d:bd:ff:
49:7b:b1:38:c7:77:be:74:73:2f:f2:e5:f8:af:34:05:f2:5e:
75:40:2a:d3:8f:d7:4f:aa:17:7d:09:f1:16:3e:1c:f7:e6:e9:
7a:bb:98:92:83:5a:b4:71:08:97:fc:6e:97:cf:07:73:48:de:
23:f6:58:06:b4:c9:c9:a7:11:8b:95:50:f0:2e:cb:25:85:b1:
30:79:6c:61:84:ee:b4:ea:1f:b1:a7:80:c5:09:2c:e3:ae:83:
f8:0a:3c:ef:d1:b8:fb:1e:2e:91:03:21:65:62:fe:fe:a6:c7:
cd:cf:7f:31:d4:99:cf:6e:39:63:df:1a:f2:fd:55:33:22:ef:
a8:26:2f:15:f6:d9:63:a2:ac:bb:f1:bf:e9:c1:c7:88:d1:4f:
d8:19:38:ce:8c:d3:bc:a8:15:32:ba:05:58:74:f5:8c:fa:aa:
9f:52:42:67:2e:73:57:04:ec:57:ca:6c:a6:f5:f2:84:b5:0d:
09:09:1a:64
-----BEGIN CERTIFICATE-----
MIIEZTCCA00CAQAwDQYJKoZIhvcNAQELBQAwgZkxCzAJBgNVBAYTAkRFMR0wGwYD
VQQIDBRCYWRlbiBXw4PCvHJ0dGVtYmVyZzERMA8GA1UEBwwITWFubmhlaW0xFTAT
BgNVBAoMDE5ldHBvbmcgVGVhbTEdMBsGA1UEAwwUTmV0cG9uZy1UZXN0LUNBIFJv
b3QxIjAgBgkqhkiG9w0BCQEWE3NvZnR3YXJlQGNzY2hlcnIuZGUwHhcNMjQwMTI0
MTQ1MjQxWhcNMzQwMTIxMTQ1MjQxWjBXMQswCQYDVQQGEwJERTEdMBsGA1UECAwU
QmFkZW4gV8ODwrxydHRlbWJlcmcxFTATBgNVBAoMDE5ldHBvbmcgVGVhbTESMBAG
A1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
1eakGKHCpsbxItfFZqaQaPYvDi9BjJsu8uRkm+FfKGRP6qa1aGfiCZMRkz3YC+cG
UDgebPpwLDL7ZLrTQ4wWsHg55G8F2uF7wIzgeZBNYIUOE1wrA6k4ySBIG0GncJXS
rumWXlXXoZt1Ud5ldXwPH3EpiG3KgtWe5gl4StMQ9xNpyD5Ofh+bnGuj9toqZT1B
6UFiQaeqXp5aG+mgyjXEfqCTSAzMVJh5S5cgDUifmvskFm66rQRegwym2t5ZainA
/Xc71NHyp6ChZGYyUhEIXxc1FBGrmqxp34LQBX54fkUg6toOGDsicuPW70oAqio9
QjoDrmrmzCr7bOvgEz7KHaaS7RQlo8PZA2ATSL4yxLMJ32i1s3/NE8av4EnSkUDT
nW9TpQgjXvux1iCPoGaxzn2Ol3mc7HOUymBxSI4PkrdbmYMkAhOj82SSJS50AA22
5IVBlRKvkznt7XOeAKXGG4o/GXPo5AFKpPWmPPju43Qh/atTFyxydLB+hyO18t1n
JNGMjXVL2VvREFXAay0ifH+hQhUST/1wsxj1eKlW9y/ykVRXOJ8RMSDdear7to38
WCUHK7nHi4XjOXdvjlH6nGvHKroeWSjpuAcfULyJPmFVmsXGbVQJmpbsl9kWW0tg
1Te/na1yCUz8wN8FXCpRkuJ5sMaMkSapyz35Ht1/GeMCAwEAATANBgkqhkiG9w0B
AQsFAAOCAQEAPwC8cHfBTfXS9eojeh3ukDoeFjorJVaME3hOoWwySWg+DppD4UW/
haE2iF+a4ZsEQPikd1/PoynF+7Ar0cwrlwTRnk0yfb3/SXuxOMd3vnRzL/Ll+K80
BfJedUAq04/XT6oXfQnxFj4c9+bperuYkoNatHEIl/xul88Hc0jeI/ZYBrTJyacR
i5VQ8C7LJYWxMHlsYYTutOofsaeAxQks466D+Ao879G4+x4ukQMhZWL+/qbHzc9/
MdSZz245Y98a8v1VMyLvqCYvFfbZY6Ksu/G/6cHHiNFP2Bk4zozTvKgVMroFWHT1
jPqqn1JCZy5zVwTsV8pspvXyhLUNCQkaZA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNzjjeONRhk/hp
ULS8PRZGnMLobnTC9reUtfa85/rHXEAT+xVDsXePbmz+hRTMdJ/j8XgfesJHlman
I4GJb/Vm5BVvjwfHMTtWH9BB6dNRVw8R1lyp/S8uiAPNpKur24xe+ZYdaBAgTTJh
sQF3b9sTSTnfQRblBmkp1Rkjqb5N/qTrQWTrmyQLghnrzgzpqEH0BCIFjRzoPMk8
3oBXfezoeMeoslR5bCIQVfHu/8jcWjzU0eehFlDD1s16XetFrU6+fUUhTPesrKBd
vf9lyXdMqHZ5FdvtsmYbfl2H4LH060+VhKJTjnDkrFrv5zWfYf6sO/lCVwe2xRHY
40MNEbgzAgMBAAECggEAIMO52wqpc8RTPM4zfFzm9TjKRhcjblrADyG+GWbGSGL1
wUgd4S6zj9X1ZBeOtzDpMqs71JYyJoVHQa4QA5f1TSk9FLIpG2qyKZOfNGOY+m3R
ow7zCSnhSXCO5Gh8a/CF7fngJ/o/457CmdTioFydc0bTktSAvDkvekVtEhLp0C5C
jTxhOYFaSznpLccHVkZtu2hYqSInTLFk3YVBi1qHO8qGbnUCj1PWSxV1wTmu/Ilo
wVw3OFyCoZhjrSN3sjNYpOFJEAV5eb9AUGCum6r+Zo7GNPiM7jDShfRidD8mjcq9
YDDkInTETHVcmr1U5CByUagDl7//ifaRBoBy5E3GPQKBgQDDKneviwuCGt2y5qbN
PPILMXHwMxja77iDIily7Mg9cbi8Cmq4fcLcPs6SEoMmHHzuAFICrWXjJJ14npfv
PR/UnIqDo95PclsjHe1dou396eqrtNGUBp5c8lt8tZGbLcLdCZMOsKqCdiPTmw1T
vaGnx4GRaQIoOVeW0N8me0J9hQKBgQC6Acr6JP/tD40s04fQb6SBMz+mTiAGPoel
R0crnh6rqb4wvomX5yoT9JRI80+i/aqVtm7COb512nq2CLc4SKSOdVSEHaRTUmOC
lLnImM9rQoP13VEwuGnL7kMv7mNc2sOZl6WHGmAnHS27zDV+e74vUIyjAdqUAUsL
C19SU5nQVwKBgQCbo7pe29wJnbM/gIF1Gy1Lj9r1W0pvDs1uhkfXxszJc2+HRidl
iaVkTxIdm3XLZtyaUNcWG4Itan3KO2+e8nf37f7ojD41zVSw5KTvD4gL/gePd1vL
WJviM8SR55p+zjegXopQJMNV1zErB3PRXGEWlBvYAo4d1dzsARZ0ccfMoQKBgB+Z
AF8f++3Mb4IG6RJqdLqR9yUMLnqBEs/r3NY3BSTKMAndxEfuuAIt0SbXVlbs2paW
KBiMcKNamu/jaSSBipq8qb/LvUd+PnNHSoweEVY6NWqFzy4ElcxTzEwPJgf3DbVA
wpjBzUW3ujYlyYyT/snQ2CM0xGnSEmps4yN8Giv/AoGALsiOvNv/jUNU/RM+OznR
93Q7WsmjZxbPFLAdpiI+Fl8zcERlSGqBKSxQSdeD7Tke5Ywzc/LHqNhTJjnDjJCY
xWzDRe/ALUHCEEc4C6dd5qPmD30T8Fb8fRX6HVFHqT3VKb3KKrpZYvkNY8ihprq6
iLDnm4a9JQ3aGrzkgV6xxlo=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDV5qQYocKmxvEi
18VmppBo9i8OL0GMmy7y5GSb4V8oZE/qprVoZ+IJkxGTPdgL5wZQOB5s+nAsMvtk
utNDjBaweDnkbwXa4XvAjOB5kE1ghQ4TXCsDqTjJIEgbQadwldKu6ZZeVdehm3VR
3mV1fA8fcSmIbcqC1Z7mCXhK0xD3E2nIPk5+H5uca6P22iplPUHpQWJBp6penlob
6aDKNcR+oJNIDMxUmHlLlyANSJ+a+yQWbrqtBF6DDKba3llqKcD9dzvU0fKnoKFk
ZjJSEQhfFzUUEauarGnfgtAFfnh+RSDq2g4YOyJy49bvSgCqKj1COgOuaubMKvts
6+ATPsodppLtFCWjw9kDYBNIvjLEswnfaLWzf80Txq/gSdKRQNOdb1OlCCNe+7HW
II+gZrHOfY6XeZzsc5TKYHFIjg+St1uZgyQCE6PzZJIlLnQADbbkhUGVEq+TOe3t
c54ApcYbij8Zc+jkAUqk9aY8+O7jdCH9q1MXLHJ0sH6HI7Xy3Wck0YyNdUvZW9EQ
VcBrLSJ8f6FCFRJP/XCzGPV4qVb3L/KRVFc4nxExIN15qvu2jfxYJQcruceLheM5
d2+OUfqca8cquh5ZKOm4Bx9QvIk+YVWaxcZtVAmaluyX2RZbS2DVN7+drXIJTPzA
3wVcKlGS4nmwxoyRJqnLPfke3X8Z4wIDAQABAoICAAq4vd7yNMSRUkLx19Y2YSSx
ulgWrE109dx88EIUAOYQaSUU6CDsnBrowUfFINAv61QYDAZgY0ED6S/6YV6QZg7A
Z/54Ri3bgY18QkA1qHs/EB6OTyWm1M7YDGU5XEA7ck0MLlpaKS3TkgThhepmpodn
77ID9tOqC4XyUZJGlCIeWf4MiXiu8ujbSGO2OcvLT0N24Irz8Yk+nLurcUDRgyDp
wZgp9BAFeIb+cz/XNRDap8tsD3Ves7IT70UnQgodP6w0zs3zHBuk5JIYwUr1yZqi
mimAXT6qh8AJWY388eM6adT7yxsR0784hmyGJBRje6CXMdoLR7hSKzohdKDiU9Uj
K2ZNxfgC1r5kDmPpdcWwP6bav15zl1pHyP3scEPqC9RX9AMWqW8mUv6YzdTd1ti3
I/VzFIv4N4Ynu5kKCojbKjKRfzT4ruL+D8AbwtZ7n799BSpvYVM5zTd0i66KAtTe
9eDTwah42GzopqyhOyFuadRwspFCYYVTsHrS+Ir2vDvudLRp2Jnu3nXurM0dW2BJ
qEFk56OdhEYZHbzUTzwft9YGc5XtrLeMJFZCNKW0K7PoiyHcFCVTncff8w7r3vHn
MkGrBiCLzNBu3kICkEVEFWjDKk6/eB7NqE3hQGZc/Zp5taP8WTS4+hD1XG4YvMbK
pi+CBDH7BIKqP1vnvdlJAoIBAQDzJXMx4dqh3yyBtw+afrRkIkKCatuN4X+qit6R
ILBBS0u4zKGEeINbzIekttW+PPmLiZPUB5/jyxNOR1nHyJuPW4yKqzrpq4PFJqqG
q3jwNJh1XmlAWVVN5Xuy7vRR+R809mgwPUMRf4eQewP93mhtl4giZL9WSmJ5D2tN
dJWSdNFxe0PmDS2xeg+Ez551kfsR6Xv2GmnBjz/nszLFGcMmBKXeKAxdicA2BsWQ
oy7WhAM//nRYzS4dziKzOmMNuYxH8Xxo2n4gjkjy0OJmo3zp9VHrvGlYrUwtEEZk
tdLY8UHcF3gu88re6KnfdkwHo+7pOgX4h53dRj+jxMTwTU+vAoIBAQDhNWhWDCkU
W3e7Tw42MohRmxPeF6DGD5ebJjLIp+BZt6uVTS+53a7VbCGwknJPo3f51oWhh/ga
nucOSVs0CSzLpiPn4+Us8V6jVhzxllJmCzYalztddemDkoQppREG7tEFMQStihnY
RDy3ksUHPXj0/HtqnZxrQPQegvDcxdm5q290R51eiZQYCNrai/mDs+naJ3GN8CTM
rudHF5JWUtWDbONBsJXAvQojgLcthiBRWZ78pMdWiPH1rDwdrTD2BdqXUIJX079z
e5nPSNRcHCoFT9p1RSvSTT6cbcWG5xH2h56iLKaz8CwGNtoGEx5iM3umkReAWKW6
0Q/KXQTRtFINAoIBAQDjSw70gn0u9MFWQRqFAgz/zkb+Q4Yai8IcWtTUNgqN/yU6
C5CxlTa2iewDPidxPu7IUkOu4bHF8ACMHIcBC7bfvGUU/ByGc58qnYqreYAEjCY5
EZiyXtAvkWahTl92gbt6dx3OenZH1T+VAGoq184nJJBOFoAG2mJTaOaV8XYhArMH
soM2evtL/R6kuLEYlu5tQCZxWR+joZXLsuiy9/JFh/LGSgnFJxBXcN0e6GzQe3fO
Sr/Yg3WoxxoJEXunSNyqJER4gEeHh3sKAdqiuBH9YybBh8+y5c1gEua7Hn2L73vx
kr72pU/wMO8bxiosukKMI4GRYrVgNFspbLftK1hhAoIBAFwvClg+fgoxLp9jSsPw
h1AwFD/SmCK6eyosxpjP7suKnRduEt0X2trNejTWnSfwF8oSf3yRNYNgC+ATMtvn
7Ygmp4fiBwsQedaOByb0iyHt8OWNheVJwJ30uVh6kq+tza08VVfbsZyOwfO6hh/i
j8JoHvSTM1XLrqFWo9Uav3Z6sBJ+xfHOiuoTpdHTffzlBhIgFyEsbUPDTDQTd/kR
ywgS6CsZZxMPzjieFVzzDAOAlc2AfX/0amZPbAQRwnrSBpntgI0GxdU1gM4SV6qk
dKbb+uYJvFhG+hv56uK/buDkvpBPiqUY6Exa43+dD9DOlgymU2Jb5urDbJ0+2hwk
nXkCggEBAJNKx7CpQXVIaYKQLTkZNu1lrlKdzq8iMuhgiF/SXqYIslZ7x6kp9Ckh
w4/YwmIYGBaQnb/Vb7PMxD4yTRw74POJNf9iy3ZvZinMiJacBIL0n3vAVh2MsEGQ
o+5G8m5DXmfAavcGfTTFe48SOYqK89V2hr6XPP8qJEMjz7lT2wpL7vS0E6JWIgR9
3Z7VsWWETbddijkcZX71zUeZWdJfm/76bJW72tM2D4iXXENvZAvzle5tMcW0cTBo
hAv7pAI9+/gye0r099K6CNx5pTBv1jGvlS//t2vMaJlJP+8eCPaIn6We2eACuJLY
nUyPrKRIgMlaQ+VkMxifhq9MzBqyB7I=
-----END PRIVATE KEY-----

View File

@ -0,0 +1 @@
01

View File

@ -0,0 +1 @@
00

32
data/ca.conf Normal file
View File

@ -0,0 +1,32 @@
[ ca ]
default_ca = Netpong-Test-CA # The default ca section
[ Netpong-Test-CA ]
dir = ./Netpong-Test-CA # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/cakey.pem# CA private key
RANDFILE = $dir/private/.rand # random number file
default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # md to use
policy = policy_any # default policy
email_in_dn = no # Don't add the email into cert DN
name_opt = ca_default # Subject name display option
cert_opt = ca_default # Certificate display option
copy_extensions = none # Don't copy extensions from request
[ policy_any ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

27
data/just_works/README.md Normal file
View File

@ -0,0 +1,27 @@
Using openssl to generate stuff is an endless hole, that will only make you
frustrated and waste your time. Don't even bother. You have been warned.
The stuff below is stolen from [here](https://stackoverflow.com/questions/60751795/unable-to-use-self-signed-certificates-with-tokio-rustls).
It just worked, after hours of trying to set up a selfsigned pki with v3 x509
(rustls decided not to support the regular v1)
---
You probably used a CA certificate as a client certificate.
Create a CA:
openssl req -x509 -noenc -subj '/CN=example.com' -newkey rsa -keyout root.key -out root.crt
Create a certificate signing request (CSR):
openssl req -noenc -newkey rsa -keyout client.key -out client.csr -subj '/CN=example.com' -addext subjectAltName=DNS:example.com
Sign it using your CA:
openssl x509 -req -in client.csr -CA root.crt -CAkey root.key -days 365 -out client.crt -copy_extensions copy
And then you use the certificate client.crt and the key client.key. And the client should trust your root.crt.
The addext and copy_extensions flag ensure that they generated key is X509v3, otherwise webpki will start complaining. And subjectAltName is required to prevent rustls from complaining.

19
data/just_works/root.crt Normal file
View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUcD/jxH3qOc8VK/FXAeP6nimT0W4wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDEyNDE0NTYzMloXDTI0MDIy
MzE0NTYzMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAmc0kWDjYQ9073nXLsGYN2ovyxOHKjWcREFbuTLp2qf+A
CpK6j+mBFngNNKlTJvQKhrULdUf61WeBwz0zYiExibd4jlGERjzK/5Aj1z+eUKBA
TiwfmvnpHGNvsU2WrfNd9wBjiJV/FB17JDYJZVfiswpbdV+9066fzQ0LImHBj1ON
vcwSPIrxwG3oe+zPGIO9CpQHUEzaMy6S5AUgDHwtiTwQwucu5Up4xM5WA1kVCiMq
Fc9qv84RxhhSOlWbCVeRMZP1qiWzMRs2vGVOfX/D6gL21qHliVLIP2lrs1ISdqM9
OMCCxMb8MAqtIECxVCm3cNE/YeBaoA7p2JlkY0BB+wIDAQABo1MwUTAdBgNVHQ4E
FgQUKAvw/RZZKZHpaxVLWVlijc+BROwwHwYDVR0jBBgwFoAUKAvw/RZZKZHpaxVL
WVlijc+BROwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAeNmR
fTyPanTRdTYewpJZPRZ1SvROwfzAAwMu6CqMqnH1aLizG2DFNAeHoU+TezvgXb2u
lvuIqNuUdLDTUWIhZkCgL/TQhnKWfAv9jqP2h85TgRCNAzEHYgFtXuHYnTuB4KAg
AAsRsY6r5bTvr/eDBeufOn7+MIbPp795g5ffD6YFv5gRGlKDBudwA2N0upptiZT9
Vzzf6SdPyskIdtLLA4QeY0lCsqekpd3Bo0fM0D0LgIw4+R+D5iYLUNRCkYqj0ydj
tJQEOdWVKtEdbylYlFF0QFSEAtszOW9yRPbfIY7n84WC2Z9zCYTls8V0sgw9PfMs
P1J2bn37/RNoNykeTA==
-----END CERTIFICATE-----

28
data/just_works/root.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCZzSRYONhD3Tve
dcuwZg3ai/LE4cqNZxEQVu5Munap/4AKkrqP6YEWeA00qVMm9AqGtQt1R/rVZ4HD
PTNiITGJt3iOUYRGPMr/kCPXP55QoEBOLB+a+ekcY2+xTZat8133AGOIlX8UHXsk
NgllV+KzClt1X73Trp/NDQsiYcGPU429zBI8ivHAbeh77M8Yg70KlAdQTNozLpLk
BSAMfC2JPBDC5y7lSnjEzlYDWRUKIyoVz2q/zhHGGFI6VZsJV5Exk/WqJbMxGza8
ZU59f8PqAvbWoeWJUsg/aWuzUhJ2oz04wILExvwwCq0gQLFUKbdw0T9h4FqgDunY
mWRjQEH7AgMBAAECggEADkpu8Zmakre4S+PjIMliySdOz/dw9DGa9ss1CkEbLJGW
iqT2m8+lFHrkMzv2g3ySi9C/t06QYorjFkqV/yy5ZyP6mjK92S7l59gzVFlPcwto
3jqgVyyYefBNXQqqERC3bu+E0Bif/bT9j7BLsDR51owEUoQqZcRoicuH+NJfg1sp
ndoLSfS6HTewS0oVAHaXgS02BsBoWCfEmf4G5VXhJvwgRN+QHgrni8bvuXFzoD48
e+uv+LVMOYaG7bf3jOEun3kdvNtrocEVA5lsc8mIfz6ie/b703p3FsS7FuIrUUqN
raVkvwxBeqeXPf94IBRUuicn+tH0fT9g/Pwsd+zhvQKBgQC1Ku/cKxwguoHFWlwv
17rTmNYAPgEQ8PXai+05LjVBi0ZMKfRJ7jSbV/JZbZy9omGqvqo8w4rLE6uQDEXv
huKYqQP8azp6pav6mX+G/zxHw606QNw12vc98egGCQeOPRUa6O2GK8BZkbJ7OKvF
NQ0Vy0hDDAldzYOTPpGIWXTrfQKBgQDZVGy3Yb+ynB35g0qHpVxN0tLZhe29Vnrb
yyZ5Jpg0tIa1sce9vOF1eYj1W/HlnfNeKiJ4/Qd6SXZjM8MQAvuvwaRf/dsexF49
WQwTPVro+oDL7OEq/Bj3vjM7AuDs99TuEbqLk6pw+Tsrw1sSGiyNMe5hKxE4bRD4
4VKxIfks1wKBgQCjD6liZl7jylrBMeplmWtrxlVfVG+LOwZeFbGH1OJUQzIbnWtm
G4O4Cjl0amc4e+4iS4hYNrw2ulahyZos1CAhvYZ77FtvRqx7Wytga1xrT2EcXIKX
6qS8WX436GqniKz1Uo9vQvPW6n9VzxUz4+MKKbS5vBy2FCMIJbnBmprU1QKBgAwp
4XvSCLyiaDsS0hUNeEESz6JFEK1MLcwnbpvRQSuR/wgkTx2beLLufm/dGYjUck6O
5ScIYmbBvdKHjx9SS2vm1qBYwO7T5sJgPYDGKlRn0NWZCHEzcuJKzus6mgQpSs2Y
SGyPczanfFxSrsIwnNW6ObFOi8QwtoZ3df1b/Wo5AoGAFmiDM8D4G3DVkZaKwSgX
6KpyQL2Vl1lyDzFiiBMy7REqy6KruZivmxlFwepkyTFbQt7r3BtWwwEq4teZiPXx
JOdD5MnAUeoR5XvMN064IsLeC9ReTEBWrrh0XciAWTNpfsM0861V3OgX9NQIOXcc
wRZa4TAcJKBJO4+ftFKCi30=
-----END PRIVATE KEY-----

19
data/just_works/test.crt Normal file
View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDjCCAfagAwIBAgIUCa25BV6Yb+yazosg/MltJOTnuhUwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDEyNDE0NTcwOVoXDTI1MDEy
MzE0NTcwOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA8Z284xhdzPP6PfAmmy8TGtITFcRoARqWicOMBFGDuzNy
BKnU5oO/3mEt41C+ZllKgUodyx373WmKylV2l2JTQza2LZPXBVDUf/i4L7TwvqtR
Ia5w//EZ0kfozxTB0WXRutJqbxKizN/yLpzAKNgKYp73x8hOBD7cpKJ/wlZ4qFXq
cR7K+P4/HvTVCyqdnaG/UMVnnRnuOUu1XYPXhaTvsxh7Febxu7lShZeB/oyaaDCR
K9oA6eJV6lAWOqaMLWuHYfma0fjwEgr+tV3IkIVOfAdp91jo1bvgNdfoF1jxMmD5
v/0DpbkbcpOF8zQ3la+foloyQJuutx4bcj7sRfLMiwIDAQABo1gwVjAUBgNVHREE
DTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFCCuIWcRm+7YgC8qmX87aWFc3l2qMB8G
A1UdIwQYMBaAFCgL8P0WWSmR6WsVS1lZYo3PgUTsMA0GCSqGSIb3DQEBCwUAA4IB
AQAkBR4fl1Vhx1WPCXdnyM5yocCUv3SfbzKJlevOqXWYzjCXUzB3LMqNrjjCcSUA
z42BYfv9cvmKfp5G77M3LEE9sUyKL+epyNBTgh5N/d1xZdITKuHL6c2OCaIHKowg
cP7kxFWFU5QDwYKhhkn6GRYoasS+B0jxCwW+k2pgUKxsMOZMmoBWVJL+MPyPBzV4
9oeYi50s+8RFAzsjXlHan6me6egbiJIn8DmBrshUG9LJzElPC6n6aixY9Ar0E6hR
O/25jHtFApXWzMsM5CwIRfb0JPMEB46+BUk89km2XYjFqUFp3PIjJz+/AMk07qEP
vykAMiOZ9ZP3XeZryzdLCIfd
-----END CERTIFICATE-----

16
data/just_works/test.csr Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICgDCCAWgCAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA8Z284xhdzPP6PfAmmy8TGtITFcRoARqWicOMBFGD
uzNyBKnU5oO/3mEt41C+ZllKgUodyx373WmKylV2l2JTQza2LZPXBVDUf/i4L7Tw
vqtRIa5w//EZ0kfozxTB0WXRutJqbxKizN/yLpzAKNgKYp73x8hOBD7cpKJ/wlZ4
qFXqcR7K+P4/HvTVCyqdnaG/UMVnnRnuOUu1XYPXhaTvsxh7Febxu7lShZeB/oya
aDCRK9oA6eJV6lAWOqaMLWuHYfma0fjwEgr+tV3IkIVOfAdp91jo1bvgNdfoF1jx
MmD5v/0DpbkbcpOF8zQ3la+foloyQJuutx4bcj7sRfLMiwIDAQABoCcwJQYJKoZI
hvcNAQkOMRgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQAD
ggEBAH5eaWnbsbys+CFHbzzpmXpnZpvCvrkvekJEm/21WAKGfcfl0o6IbyIGXePO
ASdWtiXcHhUIQ6c8V6nNIjP26sJR5Ol5qlPpHY+rP0CfKydwhOiu0Ty2Ceqqk2qV
AMG57tIR0XDNB8s1/cqIWqqX3vO4QEooBZlzY4Cu0HZKgnKNbV1XEjE4P4KbmEq2
DJUSO0ewqgYHdY227zjWVUFxicVOWiQQ9wLHl1ICBmHYzDiROSWzIswd8IZZvAGw
2+ulMnfEXKr04NN2AKj+DgZLyi7QhRL9MqnBAAGeQqmBVZjhn8dfuHUJFo6+xKe1
kB/FW9YU50Vt8mMxhwsA4XY0BEo=
-----END CERTIFICATE REQUEST-----

28
data/just_works/test.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDxnbzjGF3M8/o9
8CabLxMa0hMVxGgBGpaJw4wEUYO7M3IEqdTmg7/eYS3jUL5mWUqBSh3LHfvdaYrK
VXaXYlNDNrYtk9cFUNR/+LgvtPC+q1EhrnD/8RnSR+jPFMHRZdG60mpvEqLM3/Iu
nMAo2ApinvfHyE4EPtykon/CVnioVepxHsr4/j8e9NULKp2dob9QxWedGe45S7Vd
g9eFpO+zGHsV5vG7uVKFl4H+jJpoMJEr2gDp4lXqUBY6powta4dh+ZrR+PASCv61
XciQhU58B2n3WOjVu+A11+gXWPEyYPm//QOluRtyk4XzNDeVr5+iWjJAm663Hhty
PuxF8syLAgMBAAECggEAd2wAJvztq/YxSzjuVAiV+E06GqmrwFPscSZCiAXkRvxc
EDsDHHalOJyuyiqoGT1sCnBgPntQ+HSIoY5RYey6+79Il0l530o+5gvAue/EiHFz
1eJ7Pr3kBd/+DZCUZdPeMGl9Ku46omnUMb7PacCyjWFGVixGh2mstAEPhbYoyAZN
TyuGU1GQMtKlGOt9bibvzt/rMZlCZvQyCINOeU//9lGpmilvUbKFIxUzE1SRevXa
a1WZn4KEIphGPOF/dbgWhGMhVuoyaiLGriTsNUtky4dT/6e+IUEus9SkPDnooo18
ZN3cuNqZKB4IIXrlfBw7bBQQ4XsILVXKq5XAMhvlVQKBgQD2REmOWCkZQvzsTNj2
CxaOo5LsUqxQK1/eB5tgMf6qQVhodRZ3nMrSZGsGjJJDvRDyc6DtN1saLqr6KWdi
qGFySTA2dcoiSupFp7QqtGA5TARgy+lYh4QOYcUjobmCHH+OJtyzxWV+vsRF/wcI
RE0nbt9PkbN6K33HVUVMKsdxBwKBgQD7KmVrnPsSEygfV1tujf4a3pn1t4rOryej
yUQzd1YDc4QAkCuTZ9e2nMx5eyf57gIqjhFfThxe873a/wtKq9veDFiaBoZyOeL/
WAaP0YS0hpnOahrtcnaF3C/hvMbiF1Z0CCmIwL9UrxsS5PeC7qlsSObAMqXalPnR
oXBg6xUbXQKBgF6tqknbgxF/O5XthYwyfx2fraDFuBGqW1UVP5sgHXR/Yunl+hlK
Yn+4s5z09lasnZNY+Qm6OoA6aOl8eY7ohW5WzP5jEq9UdfUJoK66YjQlEZnVS4UJ
tK+CzzP/vT5UjoWsUzWaMocj+Hmgrqdy+uaqLZh9v668gcLc+aNq3vqJAoGAL4ec
Xbr9QDRj2Vp8sPUp6wfI9tje6bH3vGTwBRVGL60Cg+DEfkaeaa5Oe4a0z/Ucb9Um
sHRlpgpWGUU+a8kN+H05nxwxARi3Pj74LuslQ8xc+tTVd627hCVg4kUJFev4rkiF
I53mFy5z3yV5OUvUv+sjz6dF/5FFnUgBrjWObvkCgYASOqDXKOhMey2VgrHYCEGJ
VGlYG/NOTSOhvJKeS9LEgi4IaNWwbRSeR94AB749tZKCvz9jin+VJyxZsE/StCoS
Dg8xIC/lrB5S4FVoLUD/cn9k0SSI/AsnISpW21BUZPCwzOM4NDvyf3uGhRZXPOTk
8b+Chcc4BjK6X3oKgt4ztQ==
-----END PRIVATE KEY-----

View File

@ -1,21 +0,0 @@
import socket
HOST = "127.0.0.1"
PORT = 9999
payload = b"ping\0"
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
while True:
try:
s.sendall(payload)
print("> ping")
except Exception as e:
break
reply = s.recv(1024).decode()
if reply == "":
break
print(f"< {reply}")
print("connection shut down")

5
scripts/make_cert.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
mkdir data
echo create ca
# non-interactive and 10 years expiration
openssl req -x509 -nodes -newkey rsa:4096 -keyout data/key.pem -out data/cert.pem -sha256 -days 3650 -subj '/CN=localhost'

9
spammer/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "spammer"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
threadpool = "1.8.1"

18
spammer/src/main.rs Normal file
View File

@ -0,0 +1,18 @@
use threadpool::ThreadPool;
const MAX: usize = 20;
use std::process::Command;
fn main() {
let pool = ThreadPool::new(MAX);
loop {
if pool.queued_count() < MAX {
pool.execute(|| {
let mut cmd = Command::new("/usr/bin/python3");
cmd.args(["../scripts/client.py"]);
let _ = cmd.output().unwrap();
});
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
}

View File

@ -1 +1,79 @@
#![cfg(feature = "server")]
use std::{fs::File, io::BufReader, sync::Arc};
use crate::{common::decode, Config};
use anyhow;
use libpt::log::{error, info, trace};
use rustls_pemfile::certs;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use tokio_rustls::{
rustls::{self, pki_types},
TlsConnector,
};
use webpki_roots;
const BUF_SIZE: usize = 512;
pub struct Client {
cfg: Config,
stream: TcpStream,
connector: TlsConnector,
domain: pki_types::ServerName<'static>,
}
impl Client {
pub async fn build(cfg: Config) -> anyhow::Result<Self> {
let mut root_cert_store = rustls::RootCertStore::empty();
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
if cfg.certs.is_some() {
let mut reader = BufReader::new(File::open(cfg.certs.clone().unwrap())?);
for cert in certs(&mut reader) {
trace!("found custom cert: {cert:?}");
root_cert_store.add(cert?)?
}
}
trace!("root cert store: {root_cert_store:?}");
let tls_config = rustls::ClientConfig::builder()
.with_root_certificates(root_cert_store)
.with_no_client_auth();
let connector = TlsConnector::from(Arc::new(tls_config));
let stream = TcpStream::connect(&cfg.addr).await?;
let domain = match pki_types::ServerName::try_from(cfg.hostname.clone()) {
Ok(domain) => domain,
Err(err) => {
error!("Could not resolve hostname '{}': {err:?}", cfg.hostname);
return Err(err.into());
}
};
Ok(Client {
cfg: cfg.clone(),
stream,
connector,
domain,
})
}
pub async fn run(self) -> anyhow::Result<()> {
let mut stream = self.connector.connect(self.domain, self.stream).await?;
let mut buf = [0; BUF_SIZE];
stream.write_all(b"ping").await?;
info!("> ({}) ping", self.cfg.hostname);
while stream.read(&mut buf).await? > 0 {
let response = decode(&buf)?;
info!("< ({}) {}", self.cfg.hostname, response);
if response == "You win!" {
break;
}
stream.write_all(b"ping").await?;
info!("> ({}) ping", self.cfg.hostname);
// we should wait, so that we don't spam the client
std::thread::sleep(self.cfg.delay);
}
Ok(())
}
}

View File

@ -1,10 +1,10 @@
use std::path::PathBuf;
use libpt::log::{Level, Logger};
use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use crate::common::conf::Mode;
/// short about section displayed in help
const ABOUT_ROOT: &'static str = r##"
Let your hosts play ping pong over the network
@ -46,16 +46,14 @@ pub(crate) struct Cli {
#[arg(short, long, default_value_t = false)]
pub(crate) server: bool,
// how much threads the server should use
#[cfg(feature = "server")]
#[arg(short, long, default_value_t = 4)]
pub(crate) threads: usize,
#[arg(short, long, default_value_t = Mode::Tcp, ignore_case = true)]
pub(crate) mode: Mode,
/// Address of the server
pub(crate) addr: std::net::SocketAddr,
pub(crate) host: String,
#[cfg(feature = "server")]
#[arg(short, long)]
pub key: Option<PathBuf>,
#[arg(short, long)]
pub certs: Option<PathBuf>,
}
impl Cli {
@ -72,7 +70,7 @@ impl Cli {
}
};
if cli.meta {
Logger::init(None, Some(ll)).expect("could not initialize Logger");
Logger::init(None, Some(ll), true).expect("could not initialize Logger");
} else {
// less verbose version
Logger::init_mini(Some(ll)).expect("could not initialize Logger");

View File

@ -1,65 +1,61 @@
use crate::common::args::Cli;
use clap::ValueEnum;
use std::{fmt::Display, time::Duration};
use std::{
net::{SocketAddr, ToSocketAddrs},
path::PathBuf,
time::Duration,
};
use anyhow::{anyhow, Result};
use libpt::log::{error, trace};
const DEFAULT_TIMEOUT_LEN: u64 = 5000; // ms
const DEFAULT_DELAY_LEN: u64 = 500; // ms
const DEFAULT_WIN_AFTER: usize = 20;
#[derive(Debug, Clone, Copy)]
pub enum Mode {
Tcp,
}
impl ValueEnum for Mode {
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Some(match self {
Self::Tcp => clap::builder::PossibleValue::new("tcp"),
})
}
fn value_variants<'a>() -> &'a [Self] {
&[Self::Tcp]
}
fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
let comp: String = if ignore_case {
input.to_lowercase()
} else {
input.to_string()
};
match comp.as_str() {
"tcp" => return Ok(Self::Tcp),
_ => return Err(format!("\"{input}\" is not a valid mode")),
}
}
}
impl Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let repr: String = match self {
Self::Tcp => format!("tcp"),
};
write!(f, "{}", repr)
}
}
#[derive(Clone)]
pub struct Config {
pub addr: std::net::SocketAddr,
pub mode: Mode,
pub threads: usize,
pub hostname: String,
pub timeout: Duration,
pub delay: Duration,
#[cfg(feature = "server")]
pub win_after: usize,
#[cfg(feature = "server")]
pub key: Option<PathBuf>,
pub certs: Option<PathBuf>,
}
impl Config {
pub fn new(cli: &Cli) -> Self {
Config {
addr: cli.addr.clone(),
mode: cli.mode.clone(),
threads: cli.threads,
pub fn build(cli: &Cli) -> Result<Self> {
let addr: SocketAddr = match cli.host.to_socket_addrs() {
Ok(mut addr) => addr.next().unwrap(),
Err(err) => {
error!(
"could not resolve host {:?} to a socket address: {err:?}",
cli.host.clone()
);
return Err(anyhow!(
"could not resolve host {:?} to a socket address: {err:?}",
cli.host
));
}
};
let hostname = match cli.host.split_once(':') {
Some(hostname) => hostname.0.to_string(),
None => return Err(anyhow!("malformatted host (no port specified)")),
};
trace!("config has resolved the given hostname to: {addr:?}");
Ok(Config {
addr,
hostname,
timeout: Duration::from_millis(DEFAULT_TIMEOUT_LEN),
delay: Duration::from_millis(DEFAULT_DELAY_LEN),
#[cfg(feature = "server")]
win_after: DEFAULT_WIN_AFTER,
}
#[cfg(feature = "server")]
key: cli.key.clone(),
certs: cli.certs.clone(),
})
}
}

View File

@ -1,2 +1,14 @@
use std::str::Utf8Error;
pub mod args;
pub mod conf;
#[inline]
pub fn decode(buf: &[u8]) -> Result<String, Utf8Error> {
Ok(match std::str::from_utf8(buf) {
Ok(s) => s.to_string(),
Err(err) => return Err(err.into()),
}
.trim_matches(char::from(0))
.to_string())
}

View File

@ -13,14 +13,14 @@ mod server;
use common::{args::Cli, conf::*};
use crate::server::Server;
use crate::{client::Client, server::Server};
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::cli_parse();
debug!("dumping cli args:\n{:#?}", cli);
let cfg = Config::new(&cli);
let cfg = Config::build(&cli)?;
#[cfg(feature = "server")]
if cli.server {
@ -29,5 +29,5 @@ async fn main() -> Result<()> {
}
// implicit else, so we can work without the server feature
info!("starting client");
Ok(())
return Client::build(cfg).await?.run().await;
}

View File

@ -1,4 +1,4 @@
use std::{fmt::Display, string::FromUtf8Error};
use std::{fmt::Display, str::Utf8Error};
use anyhow;
use thiserror::Error;
@ -11,7 +11,7 @@ pub enum ServerError {
Timeout(Elapsed),
Anyhow(anyhow::Error),
IO(std::io::Error),
Format(FromUtf8Error),
Format(Utf8Error),
}
impl From<anyhow::Error> for ServerError {
@ -26,8 +26,8 @@ impl From<std::io::Error> for ServerError {
}
}
impl From<FromUtf8Error> for ServerError {
fn from(value: FromUtf8Error) -> Self {
impl From<Utf8Error> for ServerError {
fn from(value: Utf8Error) -> Self {
Self::Format(value)
}
}

View File

@ -1,125 +1,189 @@
#![cfg(feature = "server")]
use std::time::Duration;
use libpt::log::{debug, info, trace, warn};
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
net::{TcpListener, TcpStream},
time::timeout,
use std::{
fs::File,
net::SocketAddr,
sync::{atomic::AtomicUsize, Arc},
time::Duration,
};
use crate::common::conf::Config;
use libpt::log::{debug, error, info, trace, warn};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use rustls_pemfile::{certs, private_key};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpStream},
time::{self},
};
use tokio_rustls::{rustls, TlsAcceptor};
use crate::common::{conf::Config, decode};
pub mod errors;
use errors::*;
const BUF_SIZE: usize = 512;
pub struct Server {
cfg: Config,
pub timeout: Option<Duration>,
server: TcpListener,
num_peers: AtomicUsize,
acceptor: TlsAcceptor,
}
impl Server {
pub async fn build(cfg: Config) -> anyhow::Result<Self> {
let certs = Self::load_certs(cfg.clone())?;
trace!("loaded certs: {:?}", certs);
let key = Self::load_key(cfg.clone())?.expect("bad key?");
trace!("loaded key: {:?}", key);
let tls_config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)?;
let acceptor = TlsAcceptor::from(Arc::new(tls_config));
let server = TcpListener::bind(cfg.addr).await?;
let timeout = Some(Duration::from_secs(5));
Ok(Server {
cfg,
timeout,
server,
num_peers: AtomicUsize::new(0),
acceptor,
})
}
pub async fn run(self) -> anyhow::Result<()> {
let rc_self = Arc::new(self);
let ref_self = rc_self.clone();
tokio::spawn(async move {
let mut interval = time::interval(Duration::from_millis(5000));
loop {
interval.tick().await;
info!(
"status: {} peers",
ref_self
.num_peers
.load(std::sync::atomic::Ordering::Relaxed)
);
}
});
loop {
let (stream, addr) = match self.server.accept().await {
let (stream, addr) = match rc_self.server.accept().await {
Ok(s) => s,
Err(err) => {
warn!("could not accept stream: {err:?}");
warn!("could not accept tcp stream: {err:?}");
continue;
}
};
match self.handle_stream(stream).await {
Ok(_) => (),
Err(err) => {
match err {
let ref_self = rc_self.clone();
// NOTE: we can only start the task now. If we start it before accepting connections
// (so that the task theoretically accepts the connection), we would create endless
// tasks in a loop.
tokio::spawn(async move {
let stream: tokio_rustls::server::TlsStream<_> =
match ref_self.acceptor.accept(stream).await {
Ok(s) => s,
Err(err) => {
warn!("could not accept tls stream: {err}");
return;
}
};
ref_self.peer_add(1);
match ref_self.handle_stream(stream, addr).await {
Ok(_) => (),
Err(err) => match err {
ServerError::Timeout(_) => {
info!("stream {:?} timed out", addr)
debug!("stream {:?} timed out", addr)
}
_ => {
warn!("error while handling stream: {:?}", err)
}
}
continue;
}
};
},
};
ref_self.peer_sub(1);
});
}
}
async fn handle_stream(&self, stream: TcpStream) -> Result<()> {
let mut pings: usize = 0;
let addr = match stream.peer_addr() {
Ok(a) => a,
Err(err) => {
debug!("could not get peer address: {:?}", err);
return Err(err.into());
}
};
info!("new peer: {:?}", addr);
let mut buf = Vec::new();
let mut reader = BufReader::new(stream);
let mut len;
loop {
len = match self.read(&mut reader, &mut buf).await {
Ok(len) => len,
Err(err) => {
match err {
ServerError::Timeout(_) => {
info!("peer {:?} timed out", addr)
}
_ => return Err(err),
}
break;
}
};
trace!("received message: {:X?}", buf);
if len == 0 {
trace!("len is apperently 0: {len:?}");
break;
} else {
let msg = self.decode(&buf)?;
info!("< {:?} : {}", addr, msg);
if msg.contains("ping") {
pings += 1;
}
if pings < self.cfg.win_after {
reader.write_all(b"pong\0").await?;
info!("> {:?} : pong", addr,);
} else {
reader.write_all(b"you win!\0").await?;
info!("> {:?} : you win!", addr,);
reader.shutdown().await?;
break;
}
buf.clear();
fn load_key(cfg: Config) -> std::io::Result<Option<PrivateKeyDer<'static>>> {
if cfg.key.is_none() {
error!("the server needs a key!");
return Err(std::io::ErrorKind::InvalidInput.into());
}
let key = private_key(&mut std::io::BufReader::new(File::open(
cfg.key.clone().unwrap(),
)?));
return key;
}
// we should wait, so that we don't spam the client
std::thread::sleep(self.cfg.delay);
fn load_certs(cfg: Config) -> std::io::Result<Vec<CertificateDer<'static>>> {
if cfg.certs.is_none() {
error!("the server needs at least one certificate!");
return Err(std::io::ErrorKind::InvalidInput.into());
}
match certs(&mut std::io::BufReader::new(File::open(
&cfg.certs.clone().unwrap(),
)?))
.collect::<std::io::Result<Vec<CertificateDer<'static>>>>()
{
Ok(v) if !v.is_empty() => Ok(v),
Ok(_) => {
error!("no certs found in provided file {:?}", cfg.certs);
return Err(std::io::ErrorKind::InvalidInput.into());
}
Err(err) => {
error!("could not load certs: {err:?}");
return Err(err);
}
}
info!("disconnected peer: {:?}", addr);
}
#[inline]
fn peer_add(&self, v: usize) {
self.num_peers.store(
self.num_peers.load(std::sync::atomic::Ordering::Relaxed) + v,
std::sync::atomic::Ordering::Relaxed,
)
}
#[inline]
fn peer_sub(&self, v: usize) {
self.num_peers.store(
self.num_peers.load(std::sync::atomic::Ordering::Relaxed) - v,
std::sync::atomic::Ordering::Relaxed,
)
}
async fn handle_stream(
&self,
mut stream: tokio_rustls::server::TlsStream<TcpStream>,
addr: SocketAddr,
) -> Result<()> {
let mut buf = [0; BUF_SIZE];
let mut pings = 0;
debug!("new peer: {:?}", addr);
while stream.read(&mut buf).await? > 0 {
let request = decode(&buf)?;
debug!(pings, "< ({})\n\"{}\"", addr, request);
if request == format!("ping") {
pings += 1;
if pings > self.cfg.win_after {
stream.write_all(b"You win!").await?;
debug!(pings, "> ({})\n\"{}\"", addr, "You win!");
info!("{} won!", addr);
stream.flush().await?;
stream.shutdown().await?;
break;
}
stream.write_all(b"pong").await?;
debug!(pings, "> ({})\n\"{}\"", addr, "pong");
} else {
stream.write_all(b"what is the magic word?").await?;
debug!(pings, "> ({})\n\"{}\"", addr, "what is the magic word?");
stream.flush().await?;
}
// we should wait, so that we don't spam the client
std::thread::sleep(self.cfg.delay);
}
debug!("disconnected peer: {:?}", addr);
Ok(())
}
#[inline]
fn decode(&self, buf: &Vec<u8>) -> Result<String> {
Ok(String::from_utf8(buf.clone())?.replace('\n', "\\n"))
}
#[inline]
async fn read(&self, reader: &mut BufReader<TcpStream>, buf: &mut Vec<u8>) -> Result<usize> {
match timeout(self.cfg.timeout, reader.read_until(0x00, buf)).await? {
Ok(len) => Ok(len),
Err(err) => Err(err.into()),
}
}
}