printerxpl-forge 6.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. nse/README.md +204 -0
  2. nse/__init__.py +6 -0
  3. nse/install_nse.py +412 -0
  4. nse/lib/printerxpl.lua +238 -0
  5. nse/scripts/cups-info.nse +74 -0
  6. nse/scripts/cups-queue-info.nse +43 -0
  7. nse/scripts/hp-printers-cve-2022-1026.nse +121 -0
  8. nse/scripts/http-device-mac.nse +107 -0
  9. nse/scripts/http-hp-ilo-info.nse +121 -0
  10. nse/scripts/http-info-xerox-enum.nse +101 -0
  11. nse/scripts/http-vuln-cve2022-1026.nse +158 -0
  12. nse/scripts/lexmark-config.nse +89 -0
  13. nse/scripts/pjl-ready-message.nse +106 -0
  14. nse/scripts/printer-banner.nse +217 -0
  15. nse/scripts/printer-cups-rce.nse +189 -0
  16. nse/scripts/printer-cve-detect.nse +279 -0
  17. nse/scripts/printer-discover.nse +205 -0
  18. nse/scripts/printer-firmware-exposed.nse +219 -0
  19. nse/scripts/printer-hp-pjl.nse +192 -0
  20. nse/scripts/printer-http-ews.nse +293 -0
  21. nse/scripts/printer-ipp-info.nse +235 -0
  22. nse/scripts/printer-lexmark-ipp.nse +203 -0
  23. nse/scripts/printer-passback.nse +204 -0
  24. nse/scripts/printer-pjl-info.nse +146 -0
  25. nse/scripts/printer-printnightmare.nse +211 -0
  26. nse/scripts/printer-snmp-info.nse +176 -0
  27. nse/scripts/printer-vuln-check.nse +256 -0
  28. nse/scripts/snmp-device-mac.nse +93 -0
  29. nse/scripts/snmp-info.nse +146 -0
  30. nse/scripts/snmp-sysdescr.nse +70 -0
  31. printerxpl_forge-6.2.0.dist-info/METADATA +919 -0
  32. printerxpl_forge-6.2.0.dist-info/RECORD +97 -0
  33. printerxpl_forge-6.2.0.dist-info/WHEEL +5 -0
  34. printerxpl_forge-6.2.0.dist-info/entry_points.txt +4 -0
  35. printerxpl_forge-6.2.0.dist-info/licenses/LICENSE +21 -0
  36. printerxpl_forge-6.2.0.dist-info/top_level.txt +4 -0
  37. src/assets/fonts/gunplay.pfa +1671 -0
  38. src/assets/fonts/kshandwrt.pfa +315 -0
  39. src/assets/fonts/laksoner.pfa +2402 -0
  40. src/assets/fonts/paintcans.pfa +9699 -0
  41. src/assets/fonts/stencilod.pfa +4076 -0
  42. src/assets/fonts/takecover.pfa +26138 -0
  43. src/assets/fonts/topsecret.pfa +6652 -0
  44. src/assets/fonts/whoa.pfa +773 -0
  45. src/assets/mibs/HOST-RESOURCES-MIB +1540 -0
  46. src/assets/mibs/Printer-MIB +4389 -0
  47. src/assets/mibs/README.md +9 -0
  48. src/assets/mibs/SNMPv2-MIB +854 -0
  49. src/assets/overlays/hacker.eps +596 -0
  50. src/assets/overlays/smiley.eps +214 -0
  51. src/assets/overlays/smiley2.eps +240 -0
  52. src/core/attack_orchestrator.py +1025 -0
  53. src/core/capabilities.py +323 -0
  54. src/core/destructive_audit.py +430 -0
  55. src/core/discovery.py +488 -0
  56. src/core/osdetect.py +74 -0
  57. src/core/poly_runner.py +579 -0
  58. src/core/printer.py +1426 -0
  59. src/main.py +2134 -0
  60. src/modules/install_printer.py +318 -0
  61. src/modules/login_bruteforce.py +852 -0
  62. src/modules/pcl.py +506 -0
  63. src/modules/pjl.py +3575 -0
  64. src/modules/print_job.py +1290 -0
  65. src/modules/ps.py +1102 -0
  66. src/payloads/__init__.py +98 -0
  67. src/payloads/assets/overlays/notice.eps +9 -0
  68. src/protocols/__init__.py +19 -0
  69. src/protocols/firmware.py +738 -0
  70. src/protocols/ipp.py +216 -0
  71. src/protocols/ipp_attacks.py +609 -0
  72. src/protocols/lpd.py +141 -0
  73. src/protocols/network_map.py +1004 -0
  74. src/protocols/raw.py +173 -0
  75. src/protocols/smb.py +359 -0
  76. src/protocols/ssrf_pivot.py +427 -0
  77. src/protocols/storage.py +587 -0
  78. src/ui/__init__.py +6 -0
  79. src/ui/interactive.py +742 -0
  80. src/ui/spinner.py +112 -0
  81. src/ui/tables.py +132 -0
  82. src/utils/banner_grabber.py +852 -0
  83. src/utils/codebook.py +456 -0
  84. src/utils/config.py +522 -0
  85. src/utils/cve_loader.py +158 -0
  86. src/utils/default_creds.py +134 -0
  87. src/utils/discovery_online.py +1327 -0
  88. src/utils/exploit_manager.py +805 -0
  89. src/utils/fuzzer.py +220 -0
  90. src/utils/helper.py +732 -0
  91. src/utils/local_printers.py +307 -0
  92. src/utils/ml_engine.py +491 -0
  93. src/utils/operators.py +474 -0
  94. src/utils/ports.py +234 -0
  95. src/utils/vuln_scanner.py +823 -0
  96. src/utils/wordlist_loader.py +412 -0
  97. src/version.py +36 -0
src/utils/operators.py ADDED
@@ -0,0 +1,474 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ PostScript Operators Database
5
+ ===============================
6
+ This module contains a comprehensive list of PostScript operators organized by category.
7
+
8
+ Contains 400+ PostScript operators including:
9
+ - Standard operators (file, exec, run, etc.)
10
+ - Proprietary operators (Brother, HP, etc.)
11
+ - Security-relevant operators for testing
12
+ - 16 categories covering all PS functionality
13
+
14
+ PLANNED USAGE:
15
+ =======================
16
+ from utils.operators import operators
17
+
18
+ class ps(printer):
19
+ def __init__(self, args):
20
+ super().__init__(args)
21
+ self.ops = operators()
22
+
23
+ def do_enumerate_operators(self, arg):
24
+ '''Test which PostScript operators are available'''
25
+ for category, ops in self.ops.oplist.items():
26
+ print(f"\\n{category}")
27
+ for op in ops:
28
+ result = self.test_operator(op)
29
+ # Display result
30
+
31
+ SECURITY TESTING:
32
+ =================
33
+ This module enables testing for:
34
+ - File system access (file, deletefile, renamefile)
35
+ - Code execution (exec, run, cvx)
36
+ - Information disclosure (product, version, serialnumber)
37
+ - Authentication bypass (setpassword, getpassword)
38
+ - Device control (devformat, devmount, devdismount)
39
+
40
+ DO NOT REMOVE: Required for upcoming PostScript security testing module
41
+ """
42
+
43
+ # Author : Andre Henrique (@mrhenrike)
44
+ # GitHub : https://github.com/mrhenrike
45
+ # LinkedIn : https://linkedin.com/in/mrhenrike
46
+ # X/Twitter : https://x.com/mrhenrike
47
+
48
+ class operators():
49
+ '''
50
+ ┌─────────────────────────────────────┐
51
+ │ PostScript operators and categories │
52
+ └─────────────────────────────────────┘
53
+ '''
54
+ oplist = {
55
+ '01. Operand Stack Manipulation Operators':
56
+ [
57
+ 'pop',
58
+ 'exch',
59
+ 'dup',
60
+ 'copy',
61
+ 'index',
62
+ 'roll',
63
+ 'clear',
64
+ 'count',
65
+ 'mark',
66
+ 'cleartomark',
67
+ 'counttomark'
68
+ ],
69
+ '02. Arithmetic and Math Operators':
70
+ [
71
+ 'add',
72
+ 'div',
73
+ 'idiv',
74
+ 'mod',
75
+ 'mul',
76
+ 'sub',
77
+ 'abs',
78
+ 'neg',
79
+ 'ceiling',
80
+ 'floor',
81
+ 'round',
82
+ 'truncate',
83
+ 'sqrt',
84
+ 'atan',
85
+ 'cos',
86
+ 'sin',
87
+ 'exp',
88
+ 'ln',
89
+ 'log',
90
+ 'rand',
91
+ 'srand',
92
+ 'rrand'
93
+ ],
94
+ '03. Array Operators':
95
+ [
96
+ 'array',
97
+ 'length',
98
+ 'get',
99
+ 'put',
100
+ 'getinterval',
101
+ 'putinterval',
102
+ 'astore',
103
+ 'aload',
104
+ 'forall'
105
+ ],
106
+ '04. Packed Array Operators':
107
+ [
108
+ 'packedarray',
109
+ 'setpacking',
110
+ 'currentpacking'
111
+ ],
112
+ '05. Dictionary Operators':
113
+ [
114
+ 'dict ',
115
+ 'maxlength',
116
+ 'begin',
117
+ 'end',
118
+ 'def',
119
+ 'load',
120
+ 'store',
121
+ 'undef',
122
+ 'known',
123
+ 'where',
124
+ 'currentdict',
125
+ 'errordict',
126
+ '$error',
127
+ 'systemdict',
128
+ 'userdict',
129
+ 'globaldict',
130
+ 'statusdict',
131
+ 'countdictstack',
132
+ 'dictstack',
133
+ 'cleardictstack'
134
+ ],
135
+ '06. String Operators':
136
+ [
137
+ 'string',
138
+ 'anchorsearch',
139
+ 'search'
140
+ ],
141
+ '07. Relational, Boolean, and Bitwise Operators':
142
+ [
143
+ 'eq',
144
+ 'ne',
145
+ 'ge',
146
+ 'gt',
147
+ 'le',
148
+ 'lt',
149
+ 'and',
150
+ 'or',
151
+ 'xor',
152
+ 'true',
153
+ 'false',
154
+ 'bitshift'
155
+ ],
156
+ '08. Control Operators':
157
+ [
158
+ 'exec',
159
+ 'if',
160
+ 'ifelse',
161
+ 'for',
162
+ 'repeat',
163
+ 'loop',
164
+ 'exit',
165
+ 'stop',
166
+ 'stopped',
167
+ 'countexecstack',
168
+ 'execstack',
169
+ 'quit',
170
+ 'start'
171
+ ],
172
+ '09. Type, Attribute, and Conversion Operators':
173
+ [
174
+ 'type',
175
+ 'cvlit',
176
+ 'cvx',
177
+ 'xcheck',
178
+ 'executeonly',
179
+ 'noaccess',
180
+ 'readonly',
181
+ 'rcheck',
182
+ 'wcheck',
183
+ 'cvi',
184
+ 'cvn',
185
+ 'cvr',
186
+ 'cvrs',
187
+ 'cvs'
188
+ ],
189
+ '10. File Operators':
190
+ [
191
+ 'file',
192
+ 'filter',
193
+ 'closefile',
194
+ 'read',
195
+ 'write',
196
+ 'readhexstring',
197
+ 'writehexstring',
198
+ 'readstring',
199
+ 'writestring',
200
+ 'readline',
201
+ 'token',
202
+ 'bytesavailable',
203
+ 'flush',
204
+ 'flushfile',
205
+ 'resetfile',
206
+ 'status',
207
+ 'run',
208
+ 'currentfile',
209
+ 'deletefile',
210
+ 'renamefile',
211
+ 'filenameforall',
212
+ 'setfileposition',
213
+ 'fileposition',
214
+ 'print',
215
+ '=',
216
+ '==',
217
+ 'stack',
218
+ 'pstack',
219
+ 'printobject',
220
+ 'writeobject',
221
+ 'setobjectformat',
222
+ 'currentobjectformat'
223
+ ],
224
+ '11. Resource Operators':
225
+ [
226
+ 'defineresource',
227
+ 'undefineresource',
228
+ 'findresource',
229
+ 'findcolorrendering',
230
+ 'resourcestatus',
231
+ 'resourceforall'
232
+ ],
233
+ '12. Virtual Memory Operators':
234
+ [
235
+ 'save',
236
+ 'restore',
237
+ 'setglobal',
238
+ 'currentglobal',
239
+ 'gcheck',
240
+ 'startjob',
241
+ 'defineuserobject',
242
+ 'execuserobject',
243
+ 'undefineuserobject'
244
+ ],
245
+ '13. Miscellaneous Operators':
246
+ [
247
+ 'bind',
248
+ 'null',
249
+ 'version',
250
+ 'realtime',
251
+ 'usertime',
252
+ 'languagelevel',
253
+ 'product',
254
+ 'revision',
255
+ 'serialnumber',
256
+ 'executive',
257
+ 'echo',
258
+ 'prompt'
259
+ ],
260
+ '14. Device Setup and Output Operators':
261
+ [
262
+ 'showpage',
263
+ 'copypage',
264
+ 'setpagedevice',
265
+ 'currentpagedevice',
266
+ 'nulldevice'
267
+ ],
268
+ '15. Error Operators':
269
+ [
270
+ 'handleerror',
271
+ '.error'
272
+ ],
273
+ '16. Supplement and Proprietary Operators':
274
+ [
275
+ 'BiteMe',
276
+ 'brCIDCode',
277
+ 'brfindfont',
278
+ 'brGetCurrentColor',
279
+ 'brgetjpnfont',
280
+ '_BRFileExec',
281
+ '_brGetXPSPage',
282
+ '_brGetXPSThumb',
283
+ '_brpdfscan',
284
+ 'brlanguagelevel',
285
+ 'brPchk',
286
+ 'brPDFThumbPrint',
287
+ 'brPSDKey',
288
+ 'BrRegiChart',
289
+ 'brTpForm',
290
+ 'brTpPjlCheck',
291
+ 'brTpStroke',
292
+ 'buildfunction',
293
+ 'buildtime',
294
+ 'byteorder',
295
+ 'cache_memory',
296
+ 'callut',
297
+ 'cexec',
298
+ 'changeucrgcr',
299
+ 'chdir',
300
+ 'checksum',
301
+ 'cidcompat',
302
+ 'clearinterrupt',
303
+ 'command',
304
+ 'composefont',
305
+ 'cwd',
306
+ 'defaultduplexmode',
307
+ 'defaultpapertray',
308
+ 'defaultresolution',
309
+ 'defaulttimeouts',
310
+ 'defaulttrayswitch',
311
+ 'defaulttumble',
312
+ 'devcontrol',
313
+ 'devdismount',
314
+ 'devforall',
315
+ 'devformat',
316
+ 'devmount',
317
+ 'devstatus',
318
+ 'directimage',
319
+ 'disableinterrupt',
320
+ 'discardtransparencygroup',
321
+ 'diskonline',
322
+ 'diskstatus',
323
+ 'displayoperatormsg',
324
+ 'doautoformfeed',
325
+ 'doexecutive',
326
+ 'doffsuppress',
327
+ 'doinitfile',
328
+ 'dopanellock',
329
+ 'dopowersave',
330
+ 'doprinterrors',
331
+ 'doreprint',
332
+ 'dostartpage',
333
+ 'dosysstart',
334
+ 'duplexer',
335
+ 'enableinterrupt',
336
+ 'endjob',
337
+ 'endtransparencygroup',
338
+ 'endtransparencymask',
339
+ 'enginesync',
340
+ 'execdepth',
341
+ 'execn',
342
+ 'execpoolimgtable',
343
+ 'execvecttoimagetable',
344
+ 'findcolorrendering',
345
+ 'firstside',
346
+ 'fontnonzerowinding',
347
+ 'fontprivatedict',
348
+ 'gadget',
349
+ 'getedlut',
350
+ 'getenginedebug',
351
+ 'getentitydir',
352
+ 'getfinelut',
353
+ 'getjobstms',
354
+ 'getmydata',
355
+ 'getpassword',
356
+ 'getsuperfinelut',
357
+ 'gettrue1200',
358
+ 'getufstring',
359
+ 'hardwareiomode',
360
+ 'idle',
361
+ 'idlefonts',
362
+ 'ignoresize',
363
+ 'imagemasksw',
364
+ 'imagetiff',
365
+ 'initializedisk',
366
+ 'initlut',
367
+ 'inittransparencymask',
368
+ 'interrupts_clear',
369
+ 'interrupts_enabled',
370
+ 'interrupts_no',
371
+ 'interrupts_reset',
372
+ 'interrupts_yes',
373
+ 'ipdsjog',
374
+ 'jobtimeout',
375
+ 'kccreatepic',
376
+ 'kcdeletepic',
377
+ 'kcloadpic',
378
+ 'kcmakebarcode',
379
+ 'kcrevivepic',
380
+ 'kcsavepic',
381
+ 'lzwavailable',
382
+ 'malloc_verify',
383
+ 'MD5Encode',
384
+ 'newsheet',
385
+ 'pagecount',
386
+ 'pagesprinted',
387
+ 'panel',
388
+ 'paperdirectional',
389
+ 'papertray',
390
+ 'patternsearch',
391
+ 'pdfnewsheet',
392
+ 'peek',
393
+ 'poke',
394
+ 'powersavetime',
395
+ 'pragmatics',
396
+ 'printconfiguration',
397
+ 'printername',
398
+ 'printer_reset',
399
+ 'printer_status',
400
+ 'processcolors',
401
+ 'processipdserror',
402
+ 'pwd',
403
+ 'ramsize',
404
+ 'rdbytes',
405
+ 'readinputbuffer',
406
+ 'readpbstring',
407
+ 'readtotalramsize',
408
+ 'remain_memory',
409
+ 'removeall',
410
+ 'removeglyphs',
411
+ 'resolveicc',
412
+ 'sccbatch',
413
+ 'sccinteractive',
414
+ 'setbrFilename',
415
+ 'setbrTpBM',
416
+ 'setbrTpca',
417
+ 'setcoverpage',
418
+ 'setdefaultduplexmode',
419
+ 'setdefaultpapertray',
420
+ 'setdefaultresolution',
421
+ 'setdefaulttimeouts',
422
+ 'setdefaulttrayswitch',
423
+ 'setdefaulttumble',
424
+ 'setdoautoformfeed',
425
+ 'setdoffsuppress',
426
+ 'setdopanellock',
427
+ 'setdopowersave',
428
+ 'setdoprinterrors',
429
+ 'setdoreprint',
430
+ 'setdostartpage',
431
+ 'setdosysstart',
432
+ 'setedlut',
433
+ 'setenginesync',
434
+ 'setfilenameextend',
435
+ 'setfillalpha',
436
+ 'setfinelut',
437
+ 'sethardwareiomode',
438
+ 'setignoresize',
439
+ 'setipdsmode',
440
+ 'setjobname',
441
+ 'setjobtimeout',
442
+ 'setmanualduplexmode',
443
+ 'setmediatype',
444
+ 'setpantonescreen',
445
+ 'setpapertray',
446
+ 'setpassword',
447
+ 'setprintername',
448
+ 'setropmode',
449
+ 'setsccbatch',
450
+ 'setsccinteractive',
451
+ 'setsmoothness',
452
+ 'setsoftalpha',
453
+ 'setsoftwareiomode',
454
+ 'setstrokealpha',
455
+ 'setsuperfinelut',
456
+ 'setuniversalsize',
457
+ 'setusbbinary',
458
+ 'setuserdiskpercent',
459
+ 'smooth4',
460
+ 'softwareiomode',
461
+ 'statementnumber',
462
+ 'stretch',
463
+ 'tonersave',
464
+ 'train_memory',
465
+ 'transparencyshowpage',
466
+ 'ucrgcrforimage',
467
+ 'ucrgcrtable600',
468
+ 'ucrgcrtablecapt',
469
+ 'unlimit',
470
+ 'usepantonescreen',
471
+ 'userdiskpercent',
472
+ 'verify'
473
+ ] # TBD: reduce to the `interesting' ones (from a security point of view)
474
+ }
src/utils/ports.py ADDED
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ PrinterXPL-Forge — Port Configuration Utility
5
+ ==========================================
6
+ Centralised protocol-to-port mapping with user-override support.
7
+
8
+ All connection code should call `PortConfig.resolve(protocol)` instead of
9
+ using literal port numbers. This enables every module to honour custom
10
+ ports supplied by the operator without touching each module individually.
11
+
12
+ Supported protocol keys (case-insensitive):
13
+ raw — RAW/JetDirect/PJL default 9100
14
+ ipp — Internet Printing Protocol default 631
15
+ lpd — LPD/LPR default 515
16
+ snmp — SNMP default 161
17
+ ftp — FTP default 21
18
+ http — HTTP (EWS / web interface) default 80
19
+ https — HTTPS default 443
20
+ smb — SMB/CIFS default 445
21
+ telnet — Telnet management default 23
22
+ wsd — WSD (discovery) default 3702
23
+
24
+ Usage:
25
+ # One-time setup (call from main() after parsing args):
26
+ from utils.ports import PortConfig
27
+ PortConfig.configure(raw=3910, snmp=1161)
28
+
29
+ # In any module:
30
+ from utils.ports import PortConfig
31
+ port = PortConfig.resolve('raw') # returns override or 9100
32
+ port = PortConfig.resolve('snmp') # returns override or 161
33
+ port = PortConfig.resolve('ipp') # returns override or 631
34
+
35
+ # Extra probe ports (added on top of defaults for banner scan):
36
+ extras = PortConfig.extra_scan_ports() # set of int
37
+ """
38
+ # Author : Andre Henrique (@mrhenrike)
39
+ # GitHub : https://github.com/mrhenrike
40
+ # LinkedIn : https://linkedin.com/in/mrhenrike
41
+ # X/Twitter : https://x.com/mrhenrike
42
+
43
+ from __future__ import annotations
44
+
45
+ from typing import Dict, FrozenSet, Optional, Set
46
+
47
+ # ── Protocol defaults ─────────────────────────────────────────────────────────
48
+
49
+ _DEFAULTS: Dict[str, int] = {
50
+ 'raw': 9100, # RAW / JetDirect / PJL
51
+ 'ipp': 631, # Internet Printing Protocol
52
+ 'lpd': 515, # LPD/LPR
53
+ 'snmp': 161, # SNMP (UDP)
54
+ 'ftp': 21, # FTP management
55
+ 'http': 80, # HTTP embedded web server
56
+ 'https': 443, # HTTPS embedded web server
57
+ 'smb': 445, # SMB/CIFS
58
+ 'telnet': 23, # Telnet management
59
+ 'wsd': 3702, # WSD / WS-Discovery (UDP)
60
+ }
61
+
62
+ # Aliases accepted as protocol names
63
+ _ALIASES: Dict[str, str] = {
64
+ 'pjl': 'raw',
65
+ 'jetdirect': 'raw',
66
+ 'print': 'raw',
67
+ '9100': 'raw',
68
+ '631': 'ipp',
69
+ '515': 'lpd',
70
+ 'lpr': 'lpd',
71
+ '161': 'snmp',
72
+ '21': 'ftp',
73
+ '80': 'http',
74
+ '443': 'https',
75
+ '445': 'smb',
76
+ '23': 'telnet',
77
+ '3702': 'wsd',
78
+ }
79
+
80
+
81
+ class PortConfig:
82
+ """
83
+ Module-level singleton for protocol port configuration.
84
+
85
+ All state is class-level so any module importing this class sees the same
86
+ overrides without dependency injection.
87
+ """
88
+
89
+ _overrides: Dict[str, int] = {} # proto → custom port
90
+ _extra_ports: Set[int] = set() # additional scan ports
91
+
92
+ # ── Configuration (call once from main) ───────────────────────────────────
93
+
94
+ @classmethod
95
+ def configure(cls,
96
+ raw: Optional[int] = None,
97
+ ipp: Optional[int] = None,
98
+ lpd: Optional[int] = None,
99
+ snmp: Optional[int] = None,
100
+ ftp: Optional[int] = None,
101
+ http: Optional[int] = None,
102
+ https: Optional[int] = None,
103
+ smb: Optional[int] = None,
104
+ telnet: Optional[int] = None,
105
+ wsd: Optional[int] = None,
106
+ extra: Optional[Set[int]] = None) -> None:
107
+ """
108
+ Set custom ports for one or more protocols.
109
+
110
+ Args:
111
+ raw: Override RAW/PJL/JetDirect port (default 9100).
112
+ ipp: Override IPP port (default 631).
113
+ lpd: Override LPD port (default 515).
114
+ snmp: Override SNMP port (default 161).
115
+ ftp: Override FTP port (default 21).
116
+ http: Override HTTP port (default 80).
117
+ https: Override HTTPS port (default 443).
118
+ smb: Override SMB port (default 445).
119
+ telnet: Override Telnet port (default 23).
120
+ wsd: Override WSD port (default 3702).
121
+ extra: Additional ports to include in banner scan sweeps.
122
+ """
123
+ locals_ = {k: v for k, v in locals().items() if k != 'cls' and k != 'extra' and v is not None}
124
+ for proto, port in locals_.items():
125
+ if not (1 <= port <= 65535):
126
+ raise ValueError(f"Port {port} for '{proto}' is out of valid range 1-65535")
127
+ cls._overrides[proto] = int(port)
128
+
129
+ if extra:
130
+ cls._extra_ports.update(extra)
131
+
132
+ @classmethod
133
+ def configure_from_args(cls, args: object) -> None:
134
+ """
135
+ Convenience method to apply overrides from parsed argparse args.
136
+
137
+ Reads attributes: port_raw, port_ipp, port_lpd, port_snmp,
138
+ port_ftp, port_http, port_snmp, port_smb, port_telnet.
139
+ Also reads extra_ports (list of int).
140
+ """
141
+ mapping = {
142
+ 'port_raw': 'raw',
143
+ 'port_ipp': 'ipp',
144
+ 'port_lpd': 'lpd',
145
+ 'port_snmp': 'snmp',
146
+ 'port_ftp': 'ftp',
147
+ 'port_http': 'http',
148
+ 'port_https': 'https',
149
+ 'port_smb': 'smb',
150
+ 'port_telnet': 'telnet',
151
+ 'port_wsd': 'wsd',
152
+ }
153
+ for attr, proto in mapping.items():
154
+ val = getattr(args, attr, None)
155
+ if val:
156
+ try:
157
+ cls._overrides[proto] = int(val)
158
+ except (ValueError, TypeError):
159
+ pass
160
+
161
+ extra = getattr(args, 'extra_ports', None) or []
162
+ for p in extra:
163
+ try:
164
+ cls._extra_ports.add(int(p))
165
+ except (ValueError, TypeError):
166
+ pass
167
+
168
+ # ── Resolution ────────────────────────────────────────────────────────────
169
+
170
+ @classmethod
171
+ def resolve(cls, protocol: str, fallback: Optional[int] = None) -> int:
172
+ """
173
+ Return the port to use for a given protocol.
174
+
175
+ Resolution order:
176
+ 1. User override set via configure() or configure_from_args()
177
+ 2. Protocol default from _DEFAULTS
178
+ 3. Optional fallback argument
179
+ 4. 9100 (last resort)
180
+
181
+ Args:
182
+ protocol: Protocol key (e.g. 'raw', 'ipp', 'snmp') or alias.
183
+ fallback: Value to use if protocol not recognised.
184
+
185
+ Returns:
186
+ Port number as int.
187
+ """
188
+ key = _ALIASES.get(protocol.lower(), protocol.lower())
189
+ if key in cls._overrides:
190
+ return cls._overrides[key]
191
+ if key in _DEFAULTS:
192
+ return _DEFAULTS[key]
193
+ if fallback is not None:
194
+ return int(fallback)
195
+ return 9100
196
+
197
+ @classmethod
198
+ def default(cls, protocol: str) -> int:
199
+ """Return the *factory* default port for a protocol, ignoring overrides."""
200
+ key = _ALIASES.get(protocol.lower(), protocol.lower())
201
+ return _DEFAULTS.get(key, 9100)
202
+
203
+ @classmethod
204
+ def extra_scan_ports(cls) -> Set[int]:
205
+ """Return extra ports to include in banner/fingerprint sweeps."""
206
+ return set(cls._extra_ports)
207
+
208
+ @classmethod
209
+ def all_printer_ports(cls) -> Set[int]:
210
+ """
211
+ Return the full set of ports to probe during a banner scan.
212
+ Includes resolved defaults for all known printer protocols plus any extras.
213
+ """
214
+ base = {cls.resolve(p) for p in ('raw', 'ipp', 'lpd', 'snmp', 'http', 'https', 'smb', 'telnet', 'ftp')}
215
+ base.update(cls._extra_ports)
216
+ return base
217
+
218
+ @classmethod
219
+ def reset(cls) -> None:
220
+ """Clear all overrides (mainly for testing)."""
221
+ cls._overrides.clear()
222
+ cls._extra_ports.clear()
223
+
224
+ @classmethod
225
+ def summary(cls) -> str:
226
+ """Return a human-readable port mapping summary."""
227
+ lines = []
228
+ for proto, default in _DEFAULTS.items():
229
+ resolved = cls.resolve(proto)
230
+ override = f" [custom: {resolved}]" if resolved != default else ""
231
+ lines.append(f" {proto:<8} {default}{override}")
232
+ if cls._extra_ports:
233
+ lines.append(f" extra {', '.join(str(p) for p in sorted(cls._extra_ports))}")
234
+ return "\n".join(lines)