QuLab 2.10.10__cp313-cp313-macosx_10_13_universal2.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 (107) hide show
  1. qulab/__init__.py +33 -0
  2. qulab/__main__.py +4 -0
  3. qulab/cli/__init__.py +0 -0
  4. qulab/cli/commands.py +30 -0
  5. qulab/cli/config.py +170 -0
  6. qulab/cli/decorators.py +28 -0
  7. qulab/dicttree.py +523 -0
  8. qulab/executor/__init__.py +5 -0
  9. qulab/executor/analyze.py +188 -0
  10. qulab/executor/cli.py +434 -0
  11. qulab/executor/load.py +563 -0
  12. qulab/executor/registry.py +185 -0
  13. qulab/executor/schedule.py +543 -0
  14. qulab/executor/storage.py +615 -0
  15. qulab/executor/template.py +259 -0
  16. qulab/executor/utils.py +194 -0
  17. qulab/expression.py +827 -0
  18. qulab/fun.cpython-313-darwin.so +0 -0
  19. qulab/monitor/__init__.py +1 -0
  20. qulab/monitor/__main__.py +8 -0
  21. qulab/monitor/config.py +41 -0
  22. qulab/monitor/dataset.py +77 -0
  23. qulab/monitor/event_queue.py +54 -0
  24. qulab/monitor/mainwindow.py +234 -0
  25. qulab/monitor/monitor.py +115 -0
  26. qulab/monitor/ploter.py +123 -0
  27. qulab/monitor/qt_compat.py +16 -0
  28. qulab/monitor/toolbar.py +265 -0
  29. qulab/scan/__init__.py +2 -0
  30. qulab/scan/curd.py +221 -0
  31. qulab/scan/models.py +554 -0
  32. qulab/scan/optimize.py +76 -0
  33. qulab/scan/query.py +387 -0
  34. qulab/scan/record.py +603 -0
  35. qulab/scan/scan.py +1166 -0
  36. qulab/scan/server.py +450 -0
  37. qulab/scan/space.py +213 -0
  38. qulab/scan/utils.py +234 -0
  39. qulab/storage/__init__.py +0 -0
  40. qulab/storage/__main__.py +51 -0
  41. qulab/storage/backend/__init__.py +0 -0
  42. qulab/storage/backend/redis.py +204 -0
  43. qulab/storage/base_dataset.py +352 -0
  44. qulab/storage/chunk.py +60 -0
  45. qulab/storage/dataset.py +127 -0
  46. qulab/storage/file.py +273 -0
  47. qulab/storage/models/__init__.py +22 -0
  48. qulab/storage/models/base.py +4 -0
  49. qulab/storage/models/config.py +28 -0
  50. qulab/storage/models/file.py +89 -0
  51. qulab/storage/models/ipy.py +58 -0
  52. qulab/storage/models/models.py +88 -0
  53. qulab/storage/models/record.py +161 -0
  54. qulab/storage/models/report.py +22 -0
  55. qulab/storage/models/tag.py +93 -0
  56. qulab/storage/storage.py +95 -0
  57. qulab/sys/__init__.py +2 -0
  58. qulab/sys/chat.py +688 -0
  59. qulab/sys/device/__init__.py +3 -0
  60. qulab/sys/device/basedevice.py +255 -0
  61. qulab/sys/device/loader.py +86 -0
  62. qulab/sys/device/utils.py +79 -0
  63. qulab/sys/drivers/FakeInstrument.py +68 -0
  64. qulab/sys/drivers/__init__.py +0 -0
  65. qulab/sys/ipy_events.py +125 -0
  66. qulab/sys/net/__init__.py +0 -0
  67. qulab/sys/net/bencoder.py +205 -0
  68. qulab/sys/net/cli.py +169 -0
  69. qulab/sys/net/dhcp.py +543 -0
  70. qulab/sys/net/dhcpd.py +176 -0
  71. qulab/sys/net/kad.py +1142 -0
  72. qulab/sys/net/kcp.py +192 -0
  73. qulab/sys/net/nginx.py +194 -0
  74. qulab/sys/progress.py +190 -0
  75. qulab/sys/rpc/__init__.py +0 -0
  76. qulab/sys/rpc/client.py +0 -0
  77. qulab/sys/rpc/exceptions.py +96 -0
  78. qulab/sys/rpc/msgpack.py +1052 -0
  79. qulab/sys/rpc/msgpack.pyi +41 -0
  80. qulab/sys/rpc/router.py +35 -0
  81. qulab/sys/rpc/rpc.py +412 -0
  82. qulab/sys/rpc/serialize.py +139 -0
  83. qulab/sys/rpc/server.py +29 -0
  84. qulab/sys/rpc/socket.py +29 -0
  85. qulab/sys/rpc/utils.py +25 -0
  86. qulab/sys/rpc/worker.py +0 -0
  87. qulab/sys/rpc/zmq_socket.py +227 -0
  88. qulab/tools/__init__.py +0 -0
  89. qulab/tools/connection_helper.py +39 -0
  90. qulab/typing.py +2 -0
  91. qulab/utils.py +95 -0
  92. qulab/version.py +1 -0
  93. qulab/visualization/__init__.py +188 -0
  94. qulab/visualization/__main__.py +71 -0
  95. qulab/visualization/_autoplot.py +464 -0
  96. qulab/visualization/plot_circ.py +319 -0
  97. qulab/visualization/plot_layout.py +408 -0
  98. qulab/visualization/plot_seq.py +242 -0
  99. qulab/visualization/qdat.py +152 -0
  100. qulab/visualization/rot3d.py +23 -0
  101. qulab/visualization/widgets.py +86 -0
  102. qulab-2.10.10.dist-info/METADATA +110 -0
  103. qulab-2.10.10.dist-info/RECORD +107 -0
  104. qulab-2.10.10.dist-info/WHEEL +5 -0
  105. qulab-2.10.10.dist-info/entry_points.txt +2 -0
  106. qulab-2.10.10.dist-info/licenses/LICENSE +21 -0
  107. qulab-2.10.10.dist-info/top_level.txt +1 -0
qulab/sys/net/dhcp.py ADDED
@@ -0,0 +1,543 @@
1
+ # Packet format
2
+ # -------------
3
+ #
4
+ # Offset Length Notes
5
+ # ------ ------ -----
6
+ #
7
+ # 0 1 Operation code with 1 being request and 2 being response
8
+ # 1 1 Hardware type with 1 being "Ethernet 10Mb"
9
+ # 2 1 Hardware address length with 6 for Ethernet
10
+ # 3 1 Hops - usually 0 unless DHCP relaying in operation
11
+ # 4-7 4 Transaction ID (selected randomly by client)
12
+ # 8-9 2 Seconds - might be used by a server to prioritise requests
13
+ # 10-11 2 Flags (only most significan bit used for broadcast)
14
+ # 12-15 4 Client Internet address (might be requested by client)
15
+ # 16-19 4 Your Internet address (the IP assigned by the server)
16
+ # 20-23 4 Server Internet address (the IP of the server)
17
+ # 24-27 4 Gateway Internet address (if DHCP relaying in operation)
18
+ # 28-43 16 Client hardware address - only first 6 bytes used for Ethernet
19
+ # 44-107 64 Text name of server (optional)
20
+ # 108-235 128 Boot file name (optional - used for PXE booting)
21
+ # 236-239 4 Magic cookie (decimal values 99, 130, 83, 99 )
22
+ #
23
+
24
+ # Dynamic Host Configuration Protocol (DHCP) and Bootstrap Protocol (BOOTP) Parameters
25
+ # See http://www.iana.org/assignments/bootp-dhcp-parameters
26
+
27
+ import base64
28
+ import logging
29
+ import socket
30
+ from enum import Enum
31
+ from struct import Struct, pack, unpack
32
+ from typing import NamedTuple
33
+
34
+ MAGIC_COOKIE = b'c\x82Sc'
35
+
36
+
37
+ class DHCPOption(Enum):
38
+ PAD = 0 # 0 [RFC2132] None
39
+ SUBNET_MASK = 1 # 4 [RFC2132] Subnet Mask Value
40
+ TIME_OFFSET = 2 # 4 [RFC2132] Time Offset in Seconds from UTC (note: deprecated by 100 and 101)
41
+ ROUTER = 3 # N [RFC2132] N/4 Router addresses
42
+ TIME_SERVER = 4 # N [RFC2132] N/4 Timeserver addresses
43
+ NAME_SERVER = 5 # N [RFC2132] N/4 IEN-116 Server addresses
44
+ DOMAIN_SERVER = 6 # N [RFC2132] N/4 DNS Server addresses
45
+ LOG_SERVER = 7 # N [RFC2132] N/4 Logging Server addresses
46
+ QUOTES_SERVER = 8 # N [RFC2132] N/4 Quotes Server addresses
47
+ LPR_SERVER = 9 # N [RFC2132] N/4 Printer Server addresses
48
+ IMPRESS_SERVER = 10 # N [RFC2132] N/4 Impress Server addresses
49
+ RLP_SERVER = 11 # N [RFC2132] N/4 RLP Server addresses
50
+ HOSTNAME = 12 # N [RFC2132] Hostname string
51
+ BOOT_FILE_SIZE = 13 # 2 [RFC2132] Size of boot file in 512 byte chunks
52
+ MERIT_DUMP_FILE = 14 # N [RFC2132] Client to dump and name the file to dump it to
53
+ DOMAIN_NAME = 15 # N [RFC2132] The DNS domain name of the client
54
+ SWAP_SERVER = 16 # N [RFC2132] Swap Server address
55
+ ROOT_PATH = 17 # N [RFC2132] Path name for root disk
56
+ EXTENSION_FILE = 18 # N [RFC2132] Path name for more BOOTP info
57
+ FORWARD = 19 # 1 [RFC2132] Enable/Disable IP Forwarding
58
+ SRCRTE = 20 # 1 [RFC2132] Enable/Disable Source Routing
59
+ POLICY_FILTER = 21 # N [RFC2132] Routing Policy Filters
60
+ MAX_DG_ASSEMBLY = 22 # 2 [RFC2132] Max Datagram Reassembly Size
61
+ DEFAULT_IP_TTL = 23 # 1 [RFC2132] Default IP Time to Live
62
+ MTU_TIMEOUT = 24 # 4 [RFC2132] Path MTU Aging Timeout
63
+ MTU_PLATEAU = 25 # N [RFC2132] Path MTU Plateau Table
64
+ MTU_INTERFACE = 26 # 2 [RFC2132] Interface MTU Size
65
+ MTU_SUBNET = 27 # 1 [RFC2132] All Subnets are Local
66
+ BROADCAST_ADDRESS = 28 # 4 [RFC2132] Broadcast Address
67
+ MASK_DISCOVERY = 29 # 1 [RFC2132] Perform Mask Discovery
68
+ MASK_SUPPLIER = 30 # 1 [RFC2132] Provide Mask to Others
69
+ ROUTER_DISCOVERY = 31 # 1 [RFC2132] Perform Router Discovery
70
+ ROUTER_REQUEST = 32 # 4 [RFC2132] Router Solicitation Address
71
+ STATIC_ROUTE = 33 # N [RFC2132] Static Routing Table
72
+ TRAILERS = 34 # 1 [RFC2132] Trailer Encapsulation
73
+ ARP_TIMEOUT = 35 # 4 [RFC2132] ARP Cache Timeout
74
+ ETHERNET = 36 # 1 [RFC2132] Ethernet Encapsulation
75
+ DEFAULT_TCP_TTL = 37 # 1 [RFC2132] Default TCP Time to Live
76
+ KEEPALIVE_TIME = 38 # 4 [RFC2132] TCP Keepalive Interval
77
+ KEEPALIVE_DATA = 39 # 1 [RFC2132] TCP Keepalive Garbage
78
+ NIS_DOMAIN = 40 # N [RFC2132] NIS Domain Name
79
+ NIS_SERVERS = 41 # N [RFC2132] NIS Server Addresses
80
+ NTP_SERVERS = 42 # N [RFC2132] NTP Server Addresses
81
+ VENDOR_SPECIFIC = 43 # N [RFC2132] Vendor Specific Information
82
+ NETBIOS_NAME_SRV = 44 # N [RFC2132] NETBIOS Name Servers
83
+ NETBIOS_DIST_SRV = 45 # N [RFC2132] NETBIOS Datagram Distribution
84
+ NETBIOS_NODE_TYPE = 46 # 1 [RFC2132] NETBIOS Node Type
85
+ NETBIOS_SCOPE = 47 # N [RFC2132] NETBIOS Scope
86
+ X_WINDOW_FONT = 48 # N [RFC2132] X Window Font Server
87
+ X_WINDOW_MANAGER = 49 # N [RFC2132] X Window Display Manager
88
+ ADDRESS_REQUEST = 50 # 4 [RFC2132] Requested IP Address
89
+ IP_LEASE_TIME = 51 # 4 [RFC2132] IP Address Lease Time
90
+ OVERLOAD = 52 # 1 [RFC2132] Overload "sname" or "file"
91
+ DHCP_MSG_TYPE = 53 # 1 [RFC2132] DHCP Message Type
92
+ SERVER_ID = 54 # 4 [RFC2132] DHCP Server Identification
93
+ PARAMETER_LIST = 55 # N [RFC2132] Parameter Request List
94
+ DHCP_MESSAGE = 56 # N [RFC2132] DHCP Error Message
95
+ DHCP_MAX_MSG_SIZE = 57 # 2 [RFC2132] DHCP Maximum Message Size
96
+ RENEWAL_TIME = 58 # 4 [RFC2132] DHCP Renewal (T1) Time
97
+ REBINDING_TIME = 59 # 4 [RFC2132] DHCP Rebinding (T2) Time
98
+ CLASS_ID = 60 # N [RFC2132] Class Identifier
99
+ CLIENT_ID = 61 # N [RFC2132] Client Identifier
100
+ NETWARE_IP_DOMAIN = 62 # N [RFC2242] NetWare/IP Domain Name
101
+ NETWARE_IP_OPTION = 63 # N [RFC2242] NetWare/IP sub Options
102
+ NIS_DOMAIN_NAME = 64 # N [RFC2132] NIS+ v3 Client Domain Name
103
+ NIS_SERVER_ADDR = 65 # N [RFC2132] NIS+ v3 Server Addresses
104
+ SERVER_NAME = 66 # N [RFC2132] TFTP Server Name
105
+ BOOTFILE_NAME = 67 # N [RFC2132] Boot File Name
106
+ HOME_AGENT_ADDRS = 68 # N [RFC2132] Home Agent Addresses
107
+ SMTP_SERVER = 69 # N [RFC2132] Simple Mail Server Addresses
108
+ POP3_SERVER = 70 # N [RFC2132] Post Office Server Addresses
109
+ NNTP_SERVER = 71 # N [RFC2132] Network News Server Addresses
110
+ WWW_SERVER = 72 # N [RFC2132] WWW Server Addresses
111
+ FINGER_SERVER = 73 # N [RFC2132] Finger Server Addresses
112
+ IRC_SERVER = 74 # N [RFC2132] Chat Server Addresses
113
+ STREETTALK_SERVER = 75 # N [RFC2132] StreetTalk Server Addresses
114
+ STDA_SERVER = 76 # N [RFC2132] ST Directory Assist. Addresses
115
+ USER_CLASS = 77 # N [RFC3004] User Class Information
116
+ DIRECTORY_AGENT = 78 # N [RFC2610] directory agent information
117
+ SERVICE_SCOPE = 79 # N [RFC2610] service location agent scope
118
+ RAPID_COMMIT = 80 # 0 [RFC4039] Rapid Commit
119
+ CLIENT_FQDN = 81 # N [RFC4702] Fully Qualified Domain Name
120
+ RELAY_AGENT_INFORMATION = 82 # N [RFC3046] Relay Agent Information
121
+ ISNS = 83 # N [RFC4174] Internet Storage Name Service
122
+ # 84 REMOVED/Unassigned [RFC3679]
123
+ NDS_SERVERS = 85 # N [RFC2241] Novell Directory Services
124
+ NDS_TREE_NAME = 86 # N [RFC2241] Novell Directory Services
125
+ NDS_CONTEXT = 87 # N [RFC2241] Novell Directory Services
126
+ BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88 # [RFC4280]
127
+ BCMCS_CONTROLLER_IPV4_ADDRESS_OPTION = 89 # [RFC4280]
128
+ AUTHENTICATION = 90 # N [RFC3118] Authentication
129
+ CLIENT_LAST_TRANSACTION_TIME_OPTION = 91 # [RFC4388]
130
+ ASSOCIATED_IP_OPTION = 92 # [RFC4388]
131
+ CLIENT_SYSTEM = 93 # N [RFC4578] Client System Architecture
132
+ CLIENT_NDI = 94 # N [RFC4578] Client Network Device Interface
133
+ LDAP = 95 # N [RFC3679] Lightweight Directory Access Protocol
134
+ # 96 REMOVED/Unassigned [RFC3679]
135
+ UUID = 97 # N [RFC4578] UUID/GUID-based Client Identifier
136
+ USER_AUTH = 98 # N [RFC2485] Open Group's User Authentication
137
+ GEOCONF_CIVIC = 99 # [RFC4776]
138
+ PCODE = 100 # N [RFC4833] IEEE 1003.1 TZ String
139
+ TCODE = 101 # N [RFC4833] Reference to the TZ Database
140
+ # 102-107 REMOVED/Unassigned [RFC3679]
141
+ IPV6_ONLY_PREFERRED = 108 # 4 [RFC8925] Number of seconds that DHCPv4 should be disabled
142
+ OPTION_DHCP4O6_S46_SADDR = 109 # 16 [RFC8539] DHCPv4 over DHCPv6 Softwire Source Address Option
143
+ # 110 REMOVED/Unassigned [RFC3679]
144
+ # 111 Unassigned [RFC3679]
145
+ NETINFO_ADDRESS = 112 # N [RFC3679] NetInfo Parent Server Address
146
+ NETINFO_TAG = 113 # N [RFC3679] NetInfo Parent Server Tag
147
+ DHCP_CAPTIVE_PORTAL = 114 # N [RFC8910] DHCP Captive-Portal
148
+ # 115 REMOVED/Unassigned [RFC3679]
149
+ AUTO_CONFIG = 116 # N [RFC2563] DHCP Auto-Configuration
150
+ NAME_SERVICE_SEARCH = 117 # N [RFC2937] Name Service Search
151
+ SUBNET_SELECTION_OPTION = 118 # 4 [RFC3011] Subnet Selection Option
152
+ DOMAIN_SEARCH = 119 # N [RFC3397] DNS domain search list
153
+ SIP_SERVERS_DHCP_OPTION = 120 # N [RFC3361] SIP Servers DHCP Option
154
+ CLASSLESS_STATIC_ROUTE_OPTION = 121 # N [RFC3442] Classless Static Route Option
155
+ CCC = 122 # N [RFC3495] CableLabs Client Configuration
156
+ GEOCONF_OPTION = 123 # 16 [RFC6225] GeoConf Option
157
+ VI_VENDOR_CLASS = 124 # [RFC3925] Vendor-Identifying Vendor Class
158
+ VI_VENDOR_SPECIFIC_INFORMATION = 125 # [RFC3925] Vendor-Identifying Vendor-Specific Information
159
+ # 128 PXE - undefined (vendor specific) [RFC4578]
160
+ # 128 Etherboot signature. 6 bytes: E4:45:74:68:00:00
161
+ # 128 DOCSIS "full security" server IP address
162
+ # 128 TFTP Server IP address (for IP Phone software load)
163
+ # 129 PXE - undefined (vendor specific) [RFC4578]
164
+ # 129 Kernel options. Variable length string
165
+ # 129 Call Server IP address
166
+ # 130 PXE - undefined (vendor specific) [RFC4578]
167
+ # 130 Ethernet interface. Variable length string.
168
+ # 130 Discrimination string (to identify vendor)
169
+ # 131 PXE - undefined (vendor specific) [RFC4578]
170
+ # 131 Remote statistics server IP address
171
+ # 132 PXE - undefined (vendor specific) [RFC4578]
172
+ # 132 IEEE 802.1Q VLAN ID
173
+ # 133 PXE - undefined (vendor specific) [RFC4578]
174
+ # 133 IEEE 802.1D/p Layer 2 Priority
175
+ # 134 PXE - undefined (vendor specific) [RFC4578]
176
+ # 134 Diffserv Code Point (DSCP) for VoIP signalling and media streams
177
+ # 135 PXE - undefined (vendor specific) [RFC4578]
178
+ # 135 HTTP Proxy for phone-specific applications
179
+ OPTION_PANA_AGENT = 136 # [RFC5192]
180
+ OPTION_V4_LOST = 137 # [RFC5223]
181
+ OPTION_CAPWAP_AC_V4 = 138 # N [RFC5417] CAPWAP Access Controller addresses
182
+ OPTION_IPV4_ADDRESS_MOS = 139 # N [RFC5678] a series of suboptions
183
+ OPTION_IPV4_FQDN_MOS = 140 # N [RFC5678] a series of suboptions
184
+ SIP_UA_CONFIGURATION_SERVICE_DOMAINS = 141 # N [RFC6011] List of domain names to search for SIP User Agent Configuration
185
+ OPTION_IPV4_ADDRESS_ANDSF = 142 # N [RFC6153] ANDSF IPv4 Address Option for DHCPv4
186
+ OPTION_V4_SZTP_REDIRECT = 143 # N [RFC8572] This option provides a list of URIs for SZTP bootstrap servers
187
+ GEOLOC = 144 # 16 [RFC6225] Geospatial Location with Uncertainty
188
+ FORCERENEW_NONCE_CAPABLE = 145 # 1 [RFC6704] Forcerenew Nonce Capable
189
+ RDNSS_SELECTION = 146 # N [RFC6731] Information for selecting RDNSS
190
+ OPTION_V4_DOTS_RI = 147 # N [RFC8973] The name of the peer DOTS agent.
191
+ OPTION_V4_DOTS_ADDRESS = 148 # N (the minimal length is 4) [RFC8973] N/4 IPv4 addresses of peer DOTS agent(s).
192
+ # 149 Unassigned [RFC3942]
193
+ TFTP_SERVER_ADDRESS = 150 # [RFC5859]
194
+ STATUS_CODE = 151 # N+1 [RFC6926] Status code and optional N byte text message describing status.
195
+ BASE_TIME = 152 # 4 [RFC6926] Absolute time (seconds since Jan 1, 1970) message was sent.
196
+ START_TIME_OF_STATE = 153 # 4 [RFC6926] Number of seconds in the past when client entered current state.
197
+ QUERY_START_TIME = 154 # 4 [RFC6926] Absolute time (seconds since Jan 1, 1970) for beginning of query.
198
+ QUERY_END_TIME = 155 # 4 [RFC6926] Absolute time (seconds since Jan 1, 1970) for end of query.
199
+ DHCP_STATE = 156 # 1 [RFC6926] State of IP address.
200
+ DATA_SOURCE = 157 # 1 [RFC6926] Indicates information came from local or remote server.
201
+ OPTION_V4_PCP_SERVER = 158 # Variable; the minimum length is 5. [RFC7291] Includes one or multiple lists of PCP server IP addresses; each list is treated as a separate PCP server.
202
+ OPTION_V4_PORTPARAMS = 159 # 4 [RFC7618] This option is used to configure a set of ports bound to a shared IPv4 address.
203
+ # 160 Unassigned [RFC7710][RFC8910] Previously assigned by [RFC7710]; known to also be used by Polycom.
204
+ OPTION_MUD_URL_V4 = 161 # N (variable) [RFC8520] Manufacturer Usage Descriptions
205
+ OPTION_V4_DNR = 162 # N [RFC-ietf-add-dnr-13] Encrypted DNS Server
206
+ # 163-174 Unassigned [RFC3942]
207
+ # ETHERBOOT = 175 # Tentatively Assigned - 2005-06-23
208
+ # IP_TELEPHONE = 176 # Tentatively Assigned - 2005-06-23
209
+ # ETHERBOOT = 177 # Tentatively Assigned - 2005-06-23
210
+ # PACKETCABLE_AND_CABLEHOME = 177 # replaced by 122
211
+ # 178-207 Unassigned [RFC3942]
212
+ PXELINUX_MAGIC = 208 # 4 [RFC5071][Deprecated] magic string = F1:00:74:7E
213
+ CONFIGURATION_FILE = 209 # N [RFC5071] Configuration file
214
+ PATH_PREFIX = 210 # N [RFC5071] Path Prefix Option
215
+ REBOOT_TIME = 211 # 4 [RFC5071] Reboot Time
216
+ OPTION_6RD = 212 # 18 + N [RFC5969] OPTION_6RD with N/4 6rd BR addresses
217
+ OPTION_V4_ACCESS_DOMAIN = 213 # N [RFC5986] Access Network Domain Name
218
+ # 214-219 Unassigned
219
+ SUBNET_ALLOCATION_OPTION = 220 # N [RFC6656] Subnet Allocation Option
220
+ VSS_OPTION = 221 # Virtual Subnet Selection (VSS) Option [RFC6607]
221
+ # 222-223 Unassigned [RFC3942]
222
+ # 224-254 Reserved (Private Use)
223
+ WPAD_PROXY_URL = 252
224
+ END = 255 # 0 [RFC2132] None
225
+
226
+
227
+ class DHCPMessageType(Enum):
228
+ # 53 Values
229
+ DISCOVER = 1 # RFC 2131
230
+ OFFER = 2 # RFC 2131
231
+ REQUEST = 3 # RFC 2131
232
+ DECLINE = 4 # RFC 2131
233
+ ACK = 5 # RFC 2131
234
+ NAK = 6 # RFC 2131
235
+ RELEASE = 7 # RFC 2131
236
+ INFORM = 8 # RFC 2131
237
+ FORCERENEW = 9 # RFC 3203
238
+ LEASEQUERY = 10 # RFC 4388
239
+ LEASEUNASSIGNED = 11 # RFC 4388
240
+ LEASEUNKNOWN = 12 # RFC 4388
241
+ LEASEACTIVE = 13 # RFC 4388
242
+ BULKLEASEQUERY = 14 # RFC 6926
243
+ LEASEQUERYDONE = 15 # RFC 6926
244
+ ACTIVELEASEQUERY = 16 # RFC 7724
245
+ LEASEQUERYSTATUS = 17 # RFC 7724
246
+ TLS = 18 # RFC 7724
247
+
248
+
249
+ class DHCPStatusCodeType(Enum):
250
+ # 151 Values
251
+ Success = 0 # RFC 6926
252
+ UnspecFail = 1 # RFC 6926
253
+ QueryTerminated = 2 # RFC 6926
254
+ MalformedQuery = 3 # RFC 6926
255
+ NotAllowed = 4 # RFC 6926
256
+ DataMissing = 5 # RFC 7724
257
+ ConnectionActive = 6 # RFC 7724
258
+ CatchUpComplete = 7 # RFC 7724
259
+ TLSConnectionRefused = 8 # RFC 7724
260
+
261
+
262
+ def mac_aton(s: str) -> bytes:
263
+ try:
264
+ haddr = [int(n, base=16) for n in s.split(':')]
265
+ if not all(0 <= x <= 0xff for x in haddr):
266
+ raise ValueError
267
+ except:
268
+ raise ValueError(f"Invalid MAC address {s!r}.")
269
+ return bytes(haddr)
270
+
271
+
272
+ def mac_ntoa(b: bytes) -> str:
273
+ return ':'.join([f"{x:02X}" for x in b])
274
+
275
+
276
+ def readable_packet(data: bytes) -> str:
277
+ bpr = 16 # bpr is Bytes Per Row
278
+ numbytes = len(data)
279
+
280
+ if numbytes == 0:
281
+ return " <empty packet>"
282
+ else:
283
+ output = ""
284
+ i = 0
285
+ while i < numbytes:
286
+ if (i % bpr) == 0:
287
+ output += f" {i:04d} :"
288
+
289
+ output += f" {data[i]:02X}"
290
+
291
+ if ((i + 1) % bpr) == 0:
292
+ output += "\n"
293
+
294
+ i = i + 1
295
+
296
+ if (numbytes % bpr) != 0:
297
+ output += "\n"
298
+
299
+ return output
300
+
301
+
302
+ def buildbytesoption(optnum, ba):
303
+ lenba = len(ba)
304
+
305
+ if (ba) == 0:
306
+ opt = bytearray(1)
307
+ opt[0] = optnum
308
+ else:
309
+ opt = bytearray(2 + lenba)
310
+ opt[0] = optnum
311
+ opt[1] = lenba
312
+ opt[2:2 + lenba] = ba
313
+
314
+ return opt
315
+
316
+
317
+ def build1byteoption(optnum, databyte):
318
+ return bytearray([optnum, 1, databyte])
319
+
320
+
321
+ def build4byteoption(optnum, d1, d2, d3, d4):
322
+ optbytes = bytearray(6)
323
+ optbytes[0] = optnum
324
+ optbytes[1] = 4
325
+ optbytes[2] = d1
326
+ optbytes[3] = d2
327
+ optbytes[4] = d3
328
+ optbytes[5] = d4
329
+
330
+ return optbytes
331
+
332
+
333
+ def buildstringoption(optnum, string):
334
+ optbytes = bytearray(2 + len(string))
335
+ optbytes[0] = optnum
336
+ optbytes[1] = len(string)
337
+ d = 2
338
+ for c in string:
339
+ optbytes[d] = ord(c)
340
+ if d == len(string) + 1:
341
+ if c == "/":
342
+ optbytes[d] = 0
343
+ d += 1
344
+
345
+ return optbytes
346
+
347
+
348
+ def buildendoption():
349
+ optbytes = bytearray(1)
350
+ optbytes[0] = 255
351
+
352
+ return optbytes
353
+
354
+
355
+ class DHCPPacket():
356
+
357
+ _format = Struct('!BBBBIHH4s4s4s4s16s64s128s4s')
358
+
359
+ def __init__(self):
360
+ self.op = 0
361
+ self.htype = 1
362
+ self.hlen = 6
363
+ self.hops = 0
364
+ self.xid = 0
365
+ self.secs = 0
366
+ self.flags = 0
367
+ self.ciaddr = '0.0.0.0'
368
+ self.yiaddr = '0.0.0.0'
369
+ self.siaddr = '0.0.0.0'
370
+ self.giaddr = '0.0.0.0'
371
+ self.chaddr = '00:00:00:00:00:00'
372
+ self.sname = ''
373
+ self.file = ''
374
+ self.options = {}
375
+ self.data = None
376
+
377
+ def encode(self):
378
+ if self.data is not None:
379
+ return self.data
380
+
381
+ buf = DHCPPacket._format.pack(self.op, self.htype, self.hlen,
382
+ self.hops, self.xid,
383
+ self.secs, self.flags,
384
+ socket.inet_aton(self.ciaddr),
385
+ socket.inet_aton(self.yiaddr),
386
+ socket.inet_aton(self.siaddr),
387
+ socket.inet_aton(self.giaddr),
388
+ mac_aton(self.chaddr),
389
+ self.sname.encode(), self.file.encode(),
390
+ MAGIC_COOKIE)
391
+
392
+ ret = [buf]
393
+ for opt, data in self.options.items():
394
+ ret.append(bytearray([opt, len(data)]))
395
+ ret.append(data)
396
+ ret.append(bytearray([DHCPOption.END.value]))
397
+ self.data = b''.join(ret)
398
+ return self.data
399
+
400
+ @classmethod
401
+ def decode(cls, data):
402
+ if len(data) < DHCPPacket._format.size:
403
+ raise ValueError("Not enough data to decode")
404
+
405
+ packet = cls()
406
+ packet.data = data
407
+
408
+ (packet.op, packet.htype, packet.hlen, packet.hops, packet.xid,
409
+ packet.secs, packet.flags, ciaddr, yiaddr, siaddr, giaddr, chaddr,
410
+ sname, file, magic_cookie) = DHCPPacket._format.unpack(
411
+ data[:DHCPPacket._format.size])
412
+
413
+ if magic_cookie != MAGIC_COOKIE:
414
+ raise ValueError("Invalid message")
415
+
416
+ packet.ciaddr = socket.inet_ntoa(ciaddr)
417
+ packet.yiaddr = socket.inet_ntoa(yiaddr)
418
+ packet.siaddr = socket.inet_ntoa(siaddr)
419
+ packet.giaddr = socket.inet_ntoa(giaddr)
420
+
421
+ packet.chaddr = mac_ntoa(chaddr[0:packet.hlen])
422
+ packet.sname = sname.decode('utf-8')
423
+ packet.file = file.decode('utf-8')
424
+
425
+ offset = DHCPPacket._format.size
426
+
427
+ while offset < len(data):
428
+ option = data[offset]
429
+ offset += 1
430
+ if option == DHCPOption.PAD.value:
431
+ continue
432
+ elif option == DHCPOption.END.value:
433
+ break
434
+ optlen = data[offset]
435
+ offset += 1
436
+ if (offset + optlen) >= len(data):
437
+ raise ValueError("Invalid option length")
438
+ packet.options[option] = data[offset:offset + optlen]
439
+ offset += optlen
440
+
441
+ return packet
442
+
443
+ def __str__(self):
444
+ DHCP_ops = {0: 'ERROR_UNDEF', 1: 'BOOTREQUEST', 2: 'BOOTREPLY'}
445
+
446
+ lines = [
447
+ "###################### Header fields ######################",
448
+ f" op : {DHCP_ops[self.op]}",
449
+ f" htype : {self.htype}",
450
+ f" hlen : {self.hlen}",
451
+ f" hops : {self.hops}",
452
+ f" xid : 0x{self.xid:08x}",
453
+ f" secs : {self.secs}",
454
+ f" flags : {self.flags}",
455
+ f" Client IP address : {self.ciaddr}",
456
+ f" Your IP address : {self.yiaddr}",
457
+ f" Server IP address : {self.siaddr}",
458
+ f" Gateway IP address : {self.giaddr}",
459
+ f" Client hardware address : {self.chaddr}",
460
+ "##################### Options fields ######################"
461
+ ]
462
+ for opt, value in self.options.items():
463
+ if opt == 53:
464
+ value = DHCPMessageType(value[0]).name
465
+ elif opt in [50, 54, 1, 3, 6]:
466
+ value = socket.inet_ntoa(value)
467
+ elif opt in [51, 58, 59]:
468
+ value = unpack('!I', value)[0]
469
+ elif opt in [57]:
470
+ value = unpack('!H', value)[0]
471
+ elif opt in [12, 15, 56]:
472
+ value = value.decode()
473
+ elif opt in [28, 33, 42]:
474
+ value = [
475
+ socket.inet_ntoa(x)
476
+ for x in [value[i:i + 4] for i in range(0, len(value), 4)]
477
+ ]
478
+ value = f'{value[0]}\n' + '\n'.join(f"{'':39s} : {x}"
479
+ for x in value[1:])
480
+ elif opt in [55]:
481
+ value = (f"({value[0]:3d}) {DHCPOption(value[0]).name}\n" +
482
+ '\n'.join(f"{'':39s} : ({x:3d}) {DHCPOption(x).name}"
483
+ for x in value[1:]))
484
+ elif opt in [61]:
485
+ value = f"{value[0]} - {mac_ntoa(value[1:])}"
486
+ else:
487
+ value = f"({len(value):2d}) {base64.b16encode(value).decode()}"
488
+ opt_name = DHCPOption(opt).name
489
+ lines.append(f" {opt_name:29s} ({opt:3d}) : {value}")
490
+
491
+ if self.data is not None:
492
+ lines.append(
493
+ "######################## Raw data #########################")
494
+ lines.append(readable_packet(self.data))
495
+ lines.append(
496
+ "###########################################################")
497
+ return '\n'.join(lines)
498
+
499
+ def set_option(self, opt: DHCPOption, value):
500
+ if opt.value in [0, 255]:
501
+ raise ValueError("Invalid option")
502
+ if opt.value == 53:
503
+ value = bytearray([value.value])
504
+ elif opt.value in [50, 54, 1, 3, 6]:
505
+ value = socket.inet_aton(value)
506
+ elif opt.value in [51, 58, 59]:
507
+ value = pack('!I', value)
508
+ elif opt.value in [57]:
509
+ value = pack('!H', value)
510
+ elif opt.value in [12, 15, 56]:
511
+ value = value.encode()
512
+ elif opt.value in [28, 33, 42]:
513
+ value = b''.join(socket.inet_aton(x) for x in value)
514
+ elif opt.value in [55]:
515
+ value = bytearray([v.value for v in value])
516
+ elif opt.value in [61]:
517
+ value = bytearray([1]) + mac_aton(value)
518
+ else:
519
+ value = bytearray(value)
520
+ self.options[opt.value] = value
521
+
522
+ def get_option(self, opt: DHCPOption):
523
+ value = self.options[opt.value]
524
+ if opt.value == 53:
525
+ value = DHCPMessageType(value[0])
526
+ elif opt.value in [50, 54, 1, 3, 6]:
527
+ value = socket.inet_ntoa(value)
528
+ elif opt.value in [51, 58, 59]:
529
+ value = unpack('!I', value)[0]
530
+ elif opt.value in [57]:
531
+ value = unpack('!H', value)[0]
532
+ elif opt.value in [12, 15, 56]:
533
+ value = value.decode()
534
+ elif opt.value in [28, 33, 42]:
535
+ value = [
536
+ socket.inet_ntoa(x)
537
+ for x in [value[i:i + 4] for i in range(0, len(value), 4)]
538
+ ]
539
+ elif opt.value in [55]:
540
+ value = [DHCPOption(x) for x in value]
541
+ elif opt.value in [61]:
542
+ value = mac_ntoa(value[1:])
543
+ return value