Skip to content

Commit c84b3b7

Browse files
committed
Move Python files into tooling directory and create Poetry configuration
1 parent 8b86ba7 commit c84b3b7

File tree

10 files changed

+474
-49
lines changed

10 files changed

+474
-49
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,7 @@ missing
6464
/curl_fuzzer_smtp_seed_corpus.zip
6565
/curl_fuzzer_tftp
6666
/curl_fuzzer_tftp_seed_corpus.zip
67+
68+
# Python
69+
.venv/
70+
__pycache__/

poetry.lock

Lines changed: 348 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[project]
2+
name = "curl-fuzzer-tools"
3+
version = "0.1.0"
4+
description = "Tooling for the curl-fuzzer repository"
5+
authors = [
6+
{name = "Max Dymond",email = "[email protected]"}
7+
]
8+
readme = "README.md"
9+
requires-python = "^3.9"
10+
dependencies = [
11+
"scapy (>=2.6.1,<3.0.0)"
12+
]
13+
14+
15+
[build-system]
16+
requires = ["poetry-core>=2.0.0,<3.0.0"]
17+
build-backend = "poetry.core.masonry.api"
18+
19+
[tool.poetry.group.dev.dependencies]
20+
black = "^25.1.0"
21+
flake8 = "^7.1.2"
22+
mypy = "^1.15.0"
23+
flake8-isort = "^6.1.2"
24+
25+
[tool.isort]
26+
profile = "black"
27+
28+
[tool.poetry.scripts]
29+
read_corpus = "curl_fuzzer_tools.read_corpus:main"
30+
generate_corpus = "curl_fuzzer_tools.generate_corpus:main"
31+
corpus_to_pcap = "curl_fuzzer_tools.corpus_to_pcap:main"

src/curl_fuzzer_tools/__init__.py

Whitespace-only changes.

corpus.py renamed to src/curl_fuzzer_tools/corpus.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Common corpus functions
44
import logging
55
import struct
6+
67
log = logging.getLogger(__name__)
78

89

corpus_curl_opt_http_auth.py renamed to src/curl_fuzzer_tools/corpus_curl_opt_http_auth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from enum import Enum
66

7+
78
class CurlOptHttpAuth(Enum):
89
#define CURLAUTH_NONE ((unsigned long)0)
910
CURLAUTH_NONE = 0

corpus_to_pcap.py renamed to src/curl_fuzzer_tools/corpus_to_pcap.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,38 @@
55
import argparse
66
import logging
77
import sys
8-
from scapy.all import IP, TCP, wrpcap
9-
import corpus
8+
9+
from scapy.all import wrpcap
10+
from scapy.layers.inet import IP, TCP
11+
12+
from curl_fuzzer_tools.corpus import BaseType, TLVDecoder
13+
1014
log = logging.getLogger(__name__)
1115

1216

1317
# All the responses we want to convert to pcap
1418
RESPONSES = [
15-
corpus.BaseType.TYPE_RSP0,
16-
corpus.BaseType.TYPE_RSP1,
17-
corpus.BaseType.TYPE_RSP2,
18-
corpus.BaseType.TYPE_RSP3,
19-
corpus.BaseType.TYPE_RSP4,
20-
corpus.BaseType.TYPE_RSP5,
21-
corpus.BaseType.TYPE_RSP6,
22-
corpus.BaseType.TYPE_RSP7,
23-
corpus.BaseType.TYPE_RSP8,
24-
corpus.BaseType.TYPE_RSP9,
25-
corpus.BaseType.TYPE_RSP10,
26-
corpus.BaseType.TYPE_SECRSP0,
27-
corpus.BaseType.TYPE_SECRSP1,
19+
BaseType.TYPE_RSP0,
20+
BaseType.TYPE_RSP1,
21+
BaseType.TYPE_RSP2,
22+
BaseType.TYPE_RSP3,
23+
BaseType.TYPE_RSP4,
24+
BaseType.TYPE_RSP5,
25+
BaseType.TYPE_RSP6,
26+
BaseType.TYPE_RSP7,
27+
BaseType.TYPE_RSP8,
28+
BaseType.TYPE_RSP9,
29+
BaseType.TYPE_RSP10,
30+
BaseType.TYPE_SECRSP0,
31+
BaseType.TYPE_SECRSP1,
2832
]
2933

3034

3135
def corpus_to_pcap(options):
3236
response_tlvs = {}
3337

3438
with open(options.input, "rb") as f:
35-
dec = corpus.TLVDecoder(f.read())
39+
dec = TLVDecoder(f.read())
3640
for tlv in dec:
3741
if tlv.type in RESPONSES:
3842
log.debug("Found response: %s", tlv)
@@ -49,7 +53,7 @@ def corpus_to_pcap(options):
4953
# By default generate a packet with source port 80. This hints at HTTP; in future we can be smart and
5054
# pick a port that'll influence Wireshark. But for now, you can just Decode As.. in Wireshark to get
5155
# whatever protocol you want.
52-
pkt = IP() / TCP(sport=80, flags='SA') / tlv.data
56+
pkt = IP() / TCP(sport=80, flags="SA") / tlv.data
5357
log.debug("Converted %s to packet: %s", tlv.TYPEMAP[rsp], pkt)
5458
response_packets.append(pkt)
5559

@@ -81,6 +85,7 @@ def setup_logging():
8185

8286
class ScriptRC(object):
8387
"""Enum for script return codes"""
88+
8489
SUCCESS = 0
8590
FAILURE = 1
8691
EXCEPTION = 2
@@ -107,5 +112,5 @@ def main():
107112
return rc
108113

109114

110-
if __name__ == '__main__':
115+
if __name__ == "__main__":
111116
sys.exit(main())

curl_test_data.py renamed to src/curl_fuzzer_tools/curl_test_data.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
#
2222
"""Module for extracting test data from the test data folder"""
2323

24-
from __future__ import (absolute_import, division, print_function,
25-
unicode_literals)
24+
from __future__ import absolute_import, division, print_function, unicode_literals
25+
26+
import logging
2627
import os
2728
import re
28-
import logging
2929

3030
log = logging.getLogger(__name__)
3131

generate_corpus.py renamed to src/curl_fuzzer_tools/generate_corpus.py

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,67 @@
66
import logging
77
import os
88
import sys
9-
import corpus
10-
from corpus_curl_opt_http_auth import CurlOptHttpAuth
9+
10+
from curl_fuzzer_tools.corpus import TLVEncoder
11+
from curl_fuzzer_tools.corpus_curl_opt_http_auth import CurlOptHttpAuth
12+
from curl_fuzzer_tools.curl_test_data import TestData
13+
1114
log = logging.getLogger(__name__)
1215

1316

1417
def generate_corpus(options):
1518
sys.path.append(options.curl_test_dir)
16-
import curl_test_data
1719

18-
td = curl_test_data.TestData(os.path.join(options.curl_test_dir,
19-
"data"))
20+
td = TestData(os.path.join(options.curl_test_dir, "data"))
2021

2122
with open(options.output, "wb") as f:
22-
enc = corpus.TLVEncoder(f, td)
23+
enc = TLVEncoder(f, td)
2324

2425
# Write the URL to the file.
2526
enc.write_string(enc.TYPE_URL, options.url)
2627

2728
# Write any responses to the file.
28-
enc.maybe_write_response(enc.TYPE_RSP0, options.rsp0, options.rsp0file, options.rsp0test)
29-
enc.maybe_write_response(enc.TYPE_RSP1, options.rsp1, options.rsp1file, options.rsp1test)
30-
enc.maybe_write_response(enc.TYPE_RSP2, options.rsp2, options.rsp2file, options.rsp2test)
31-
enc.maybe_write_response(enc.TYPE_RSP3, options.rsp3, options.rsp3file, options.rsp3test)
32-
enc.maybe_write_response(enc.TYPE_RSP4, options.rsp4, options.rsp4file, options.rsp4test)
33-
enc.maybe_write_response(enc.TYPE_RSP5, options.rsp5, options.rsp5file, options.rsp5test)
34-
enc.maybe_write_response(enc.TYPE_RSP6, options.rsp6, options.rsp6file, options.rsp6test)
35-
enc.maybe_write_response(enc.TYPE_RSP7, options.rsp7, options.rsp7file, options.rsp7test)
36-
enc.maybe_write_response(enc.TYPE_RSP8, options.rsp8, options.rsp8file, options.rsp8test)
37-
enc.maybe_write_response(enc.TYPE_RSP9, options.rsp9, options.rsp9file, options.rsp9test)
38-
enc.maybe_write_response(enc.TYPE_RSP10, options.rsp10, options.rsp10file, options.rsp10test)
29+
enc.maybe_write_response(
30+
enc.TYPE_RSP0, options.rsp0, options.rsp0file, options.rsp0test
31+
)
32+
enc.maybe_write_response(
33+
enc.TYPE_RSP1, options.rsp1, options.rsp1file, options.rsp1test
34+
)
35+
enc.maybe_write_response(
36+
enc.TYPE_RSP2, options.rsp2, options.rsp2file, options.rsp2test
37+
)
38+
enc.maybe_write_response(
39+
enc.TYPE_RSP3, options.rsp3, options.rsp3file, options.rsp3test
40+
)
41+
enc.maybe_write_response(
42+
enc.TYPE_RSP4, options.rsp4, options.rsp4file, options.rsp4test
43+
)
44+
enc.maybe_write_response(
45+
enc.TYPE_RSP5, options.rsp5, options.rsp5file, options.rsp5test
46+
)
47+
enc.maybe_write_response(
48+
enc.TYPE_RSP6, options.rsp6, options.rsp6file, options.rsp6test
49+
)
50+
enc.maybe_write_response(
51+
enc.TYPE_RSP7, options.rsp7, options.rsp7file, options.rsp7test
52+
)
53+
enc.maybe_write_response(
54+
enc.TYPE_RSP8, options.rsp8, options.rsp8file, options.rsp8test
55+
)
56+
enc.maybe_write_response(
57+
enc.TYPE_RSP9, options.rsp9, options.rsp9file, options.rsp9test
58+
)
59+
enc.maybe_write_response(
60+
enc.TYPE_RSP10, options.rsp10, options.rsp10file, options.rsp10test
61+
)
3962

4063
# Write any second socket responses to the file.
41-
enc.maybe_write_response(enc.TYPE_SECRSP0, options.secrsp0, options.secrsp0file, options.secrsp0test)
42-
enc.maybe_write_response(enc.TYPE_SECRSP1, options.secrsp1, options.secrsp1file, options.secrsp1test)
64+
enc.maybe_write_response(
65+
enc.TYPE_SECRSP0, options.secrsp0, options.secrsp0file, options.secrsp0test
66+
)
67+
enc.maybe_write_response(
68+
enc.TYPE_SECRSP1, options.secrsp1, options.secrsp1file, options.secrsp1test
69+
)
4370

4471
# Write other options to file.
4572
enc.maybe_write_string(enc.TYPE_USERNAME, options.username)
@@ -59,7 +86,9 @@ def generate_corpus(options):
5986
enc.maybe_write_string(enc.TYPE_XOAUTH2_BEARER, options.bearertoken)
6087
enc.maybe_write_string(enc.TYPE_USERPWD, options.user_and_pass)
6188
enc.maybe_write_string(enc.TYPE_USERAGENT, options.useragent)
62-
enc.maybe_write_string(enc.TYPE_SSH_HOST_PUBLIC_KEY_SHA256, options.hostpksha256)
89+
enc.maybe_write_string(
90+
enc.TYPE_SSH_HOST_PUBLIC_KEY_SHA256, options.hostpksha256
91+
)
6392
enc.maybe_write_string(enc.TYPE_HSTS, options.hsts)
6493

6594
enc.maybe_write_u32(enc.TYPE_OPTHEADER, options.optheader)
@@ -75,8 +104,10 @@ def generate_corpus(options):
75104
if options.httpauth:
76105
# translate a string HTTP auth name to an unsigned long bitmask
77106
# value in the format CURLOPT_HTTPAUTH expects
78-
log.debug(f"Mapping provided CURLOPT_HTTPAUTH='{options.httpauth}' "
79-
f"to {CurlOptHttpAuth[options.httpauth].value}L (ulong)")
107+
log.debug(
108+
f"Mapping provided CURLOPT_HTTPAUTH='{options.httpauth}' "
109+
f"to {CurlOptHttpAuth[options.httpauth].value}L (ulong)"
110+
)
80111
http_auth_value = CurlOptHttpAuth[options.httpauth].value
81112
enc.maybe_write_u32(enc.TYPE_HTTPAUTH, http_auth_value)
82113

@@ -150,9 +181,9 @@ def get_options():
150181
parser.add_argument("--useragent", type=str)
151182
parser.add_argument("--netrclevel", type=int)
152183
parser.add_argument("--hostpksha256", type=str)
153-
parser.add_argument("--wsoptions", action='store_true')
184+
parser.add_argument("--wsoptions", action="store_true")
154185
parser.add_argument("--connectonly", type=int)
155-
parser.add_argument("--post", action='store_true')
186+
parser.add_argument("--post", action="store_true")
156187
parser.add_argument("--hsts")
157188

158189
upload1 = parser.add_mutually_exclusive_group()
@@ -189,6 +220,7 @@ def setup_logging():
189220

190221
class ScriptRC(object):
191222
"""Enum for script return codes"""
223+
192224
SUCCESS = 0
193225
FAILURE = 1
194226
EXCEPTION = 2
@@ -215,5 +247,5 @@ def main():
215247
return rc
216248

217249

218-
if __name__ == '__main__':
250+
if __name__ == "__main__":
219251
sys.exit(main())

read_corpus.py renamed to src/curl_fuzzer_tools/read_corpus.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import argparse
66
import logging
77
import sys
8-
import corpus
8+
9+
from curl_fuzzer_tools.corpus import TLVDecoder
10+
911
log = logging.getLogger(__name__)
1012

1113

1214
def read_corpus(options):
1315
with open(options.input, "rb") as f:
14-
dec = corpus.TLVDecoder(f.read())
16+
dec = TLVDecoder(f.read())
1517
for tlv in dec:
1618
print(tlv)
1719

@@ -39,6 +41,7 @@ def setup_logging():
3941

4042
class ScriptRC(object):
4143
"""Enum for script return codes"""
44+
4245
SUCCESS = 0
4346
FAILURE = 1
4447
EXCEPTION = 2
@@ -65,5 +68,5 @@ def main():
6568
return rc
6669

6770

68-
if __name__ == '__main__':
71+
if __name__ == "__main__":
6972
sys.exit(main())

0 commit comments

Comments
 (0)