diff options
-rw-r--r-- | Kernel/Net/NetworkTask.cpp | 1 | ||||
-rw-r--r-- | Userland/Utilities/arp.cpp | 91 |
2 files changed, 80 insertions, 12 deletions
diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp index fc4fc9e82b..bb408781b2 100644 --- a/Kernel/Net/NetworkTask.cpp +++ b/Kernel/Net/NetworkTask.cpp @@ -150,7 +150,6 @@ void handle_arp(const EthernetFrameHeader& eth, size_t frame_size) if (!packet.sender_hardware_address().is_zero() && !packet.sender_protocol_address().is_zero()) { // Someone has this IPv4 address. I guess we can try to remember that. // FIXME: Protect against ARP spamming. - // FIXME: Support static ARP table entries. update_arp_table(packet.sender_protocol_address(), packet.sender_hardware_address(), UpdateArp::Set); } diff --git a/Userland/Utilities/arp.cpp b/Userland/Utilities/arp.cpp index 51c118e5c3..208b2c6f92 100644 --- a/Userland/Utilities/arp.cpp +++ b/Userland/Utilities/arp.cpp @@ -6,29 +6,98 @@ #include <AK/Assertions.h> #include <AK/ByteBuffer.h> +#include <AK/IPv4Address.h> #include <AK/JsonObject.h> +#include <AK/MACAddress.h> +#include <AK/String.h> +#include <AK/Types.h> +#include <LibCore/ArgsParser.h> #include <LibCore/File.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <sys/socket.h> -int main() +int main(int argc, char** argv) { + static bool flag_set; + static bool flag_delete; + const char* value_ipv4_address = nullptr; + const char* value_hw_address = nullptr; + + Core::ArgsParser args_parser; + args_parser.set_general_help("Display or modify the system ARP cache"); + args_parser.add_option(flag_set, "Set an ARP table entry", "set", 's'); + args_parser.add_option(flag_delete, "Delete an ARP table entry", "delete", 'd'); + args_parser.add_positional_argument(value_ipv4_address, "IPv4 protocol address", "address", Core::ArgsParser::Required::No); + args_parser.add_positional_argument(value_hw_address, "Hardware address", "hwaddress", Core::ArgsParser::Required::No); + args_parser.parse(argc, argv); + auto file = Core::File::construct("/proc/net/arp"); if (!file->open(Core::OpenMode::ReadOnly)) { warnln("Failed to open {}: {}", file->name(), file->error_string()); return 1; } - outln("Address HWaddress"); - auto file_contents = file->read_all(); - auto json = JsonValue::from_string(file_contents); - VERIFY(json.has_value()); - json.value().as_array().for_each([](auto& value) { - auto& if_object = value.as_object(); + if (!flag_set && !flag_delete) { + outln("Address HWaddress"); + auto file_contents = file->read_all(); + auto json = JsonValue::from_string(file_contents); + VERIFY(json.has_value()); + json.value().as_array().for_each([](auto& value) { + auto& if_object = value.as_object(); + + auto ip_address = if_object.get("ip_address").to_string(); + auto mac_address = if_object.get("mac_address").to_string(); + + outln("{:15} {:17}", ip_address, mac_address); + }); + } + + if (flag_set || flag_delete) { + if (!value_ipv4_address || !value_hw_address) { + warnln("No protocol address or hardware address specified."); + return 1; + } + + auto address = IPv4Address::from_string(value_ipv4_address); + if (!address.has_value()) { + warnln("Invalid IPv4 protocol address: '{}'", value_ipv4_address); + return 1; + } - auto ip_address = if_object.get("ip_address").to_string(); - auto mac_address = if_object.get("mac_address").to_string(); + auto hw_address = MACAddress::from_string(value_hw_address); + if (!hw_address.has_value()) { + warnln("Invalid MACAddress: '{}'", value_hw_address); + return 1; + } - outln("{:15} {:17}", ip_address, mac_address); - }); + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (fd < 0) { + perror("socket"); + return 1; + } + + struct arpreq arp_req; + memset(&arp_req, 0, sizeof(arp_req)); + + arp_req.arp_pa.sa_family = AF_INET; + ((sockaddr_in&)arp_req.arp_pa).sin_addr.s_addr = address.value().to_in_addr_t(); + + *(MACAddress*)&arp_req.arp_ha.sa_data[0] = hw_address.value(); + + int rc; + if (flag_set) + rc = ioctl(fd, SIOCSARP, &arp_req); + if (flag_delete) + rc = ioctl(fd, SIOCDARP, &arp_req); + + if (rc < 0) { + perror("ioctl"); + return 1; + } + } return 0; } |