| # Copyright (C) 2024 The Android Open Source Project | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| from ipaddress import IPv4Address | |
| from socket import inet_aton | |
| ETHER_BROADCAST_MAC_ADDRESS = "FF:FF:FF:FF:FF:FF" | |
| ARP_REQUEST_OP = 1 | |
| ARP_REPLY_OP = 2 | |
| """ | |
| This variable defines a template for constructing ARP packets in hexadecimal format. | |
| It's used to provide the common fields for ARP packet, and replaced needed fields when constructing | |
| """ | |
| ARP_TEMPLATE = ( | |
| # Ether Header (14 bytes) | |
| "{dst_mac}" + # DA | |
| "{src_mac}" + # SA | |
| "0806" + # ARP | |
| # ARP Header (28 bytes) | |
| "0001" + # Hardware type (Ethernet) | |
| "0800" + # Protocol type (IPv4) | |
| "06" + # hardware address length | |
| "04" + # protocol address length | |
| "{opcode}" + # opcode | |
| "{sender_mac}" + # sender MAC | |
| "{sender_ip}" + # sender IP | |
| "{target_mac}" + # target MAC | |
| "{target_ip}" # target IP | |
| ) | |
| def construct_arp_packet(src_mac, dst_mac, src_ip, dst_ip, op) -> str: | |
| """Constructs an ARP packet as a hexadecimal string. | |
| This function creates an ARP packet by filling in the required fields | |
| in a predefined ARP packet template. | |
| Args: | |
| src_mac: The MAC address of the sender. (e.g. "11:22:33:44:55:66") | |
| dst_mac: The MAC address of the recipient. (e.g. "aa:bb:cc:dd:ee:ff") | |
| src_ip: The IP address of the sender. (e.g. "1.1.1.1") | |
| dst_ip: The IP address of the target machine. (e.g. "2.2.2.2") | |
| op: The op code of the ARP packet, refer to ARP_*_OP | |
| Returns: | |
| A string representing the ARP packet in hexadecimal format. | |
| """ | |
| # Replace the needed fields from packet template | |
| arp_pkt = ARP_TEMPLATE.format( | |
| dst_mac=dst_mac.replace(":",""), | |
| src_mac=src_mac.replace(":",""), | |
| opcode=str(op).rjust(4, "0"), | |
| sender_mac=src_mac.replace(":",""), | |
| sender_ip=inet_aton(src_ip).hex(), | |
| target_mac=("000000000000" if op == ARP_REQUEST_OP else dst_mac.replace(":", "")), | |
| target_ip=inet_aton(dst_ip).hex() | |
| ) | |
| # always convert to upper case hex string | |
| return arp_pkt.upper() |