Skip to content

Instantly share code, notes, and snippets.

@AtieP
Created November 7, 2022 12:43
Show Gist options
  • Save AtieP/52a0b502763d01a6e8fa9a8b493e693b to your computer and use it in GitHub Desktop.
Save AtieP/52a0b502763d01a6e8fa9a8b493e693b to your computer and use it in GitHub Desktop.
ARP scanner
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <assert.h>
#include <linux/if_arp.h>
#include <unistd.h>
int sfd;
int our_ifindex;
char our_mac[6];
in_addr_t our_ip;
char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#define ARP_REQUEST 1
#define ARP_REPLY 2
struct arp_ip {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t op;
char srcmac[6];
in_addr_t srcip;
char destmac[6];
in_addr_t destip;
} __attribute__((packed));
static void
print_mac(char *buf)
{
for (int i = 0; i < 6; i++) {
printf("%hhx%s", buf[i], i != 5 ? ":" : "");
}
}
static void
print_ip(in_addr_t ip)
{
ip = ntohl(ip);
printf("%hhu.%hhu.%hhu.%hhu", (uint8_t) (ip >> 24), (uint8_t) (ip >> 16), (uint8_t) (ip >> 8), (uint8_t) ip);
}
static void
retrieve_interface_index(const char *ifname)
{
struct ifreq req;
memset(&req, 0, sizeof(req));
strncpy(req.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sfd, SIOCGIFINDEX, &req) < 0) {
perror("ioctl(SIOCGIFINDEX)");
exit(1);
}
our_ifindex = req.ifr_ifindex;
}
static void
retrieve_interface_mac(const char *ifname)
{
struct ifreq req;
memset(&req, 0, sizeof(req));
strncpy(req.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sfd, SIOCGIFHWADDR, &req) < 0) {
perror("ioctl(SIOCGIFHWADDR)");
exit(1);
}
assert(req.ifr_hwaddr.sa_family == ARPHRD_ETHER);
memcpy(our_mac, req.ifr_hwaddr.sa_data, 6);
}
static void
retrieve_interface_ip(const char *ifname)
{
struct ifreq req;
memset(&req, 0, sizeof(req));
strncpy(req.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sfd, SIOCGIFADDR, &req) < 0) {
perror("ioctl(SIOCGIFADDR)");
exit(1);
}
assert(req.ifr_addr.sa_family == AF_INET);
memcpy(&our_ip, req.ifr_addr.sa_data + sizeof(in_port_t), 4);
}
static void
print_arp(struct arp_ip *arp)
{
printf("htype %hu ptype %hu hlen %hhu plen %hhu op %s",
ntohs(arp->htype), ntohs(arp->ptype), arp->hlen,
arp->plen, ntohs(arp->op) == ARP_REQUEST ? "ARP_REQUEST" :
(ntohs(arp->op) == ARP_REPLY ? "ARP_REPLY" : "??"));
if (arp->htype == htons(ARPHRD_ETHER) && arp->ptype == 8) {
printf(" source mac ");
print_mac(arp->srcmac);
printf(" source ip ");
print_ip(arp->srcip);
printf(" destination mac ");
print_mac(arp->destmac);
printf(" destination ip ");
print_ip(arp->destip);
printf("\n");
} else
printf("\n");
}
int
main(int argc, char **argv)
{
char *ifname;
struct arp_ip arp;
struct sockaddr_ll sll;
memset(&arp, 0, sizeof(arp));
memset(&sll, 0, sizeof(sll));
if (argc < 2) {
printf("expected interface name\n");
return 1;
}
ifname = argv[1];
/* create packet socket */
sfd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
if (sfd < 0) {
perror("socket");
return 1;
}
retrieve_interface_index(ifname);
retrieve_interface_mac(ifname);
retrieve_interface_ip(ifname);
printf("%s: idx %d mac ", ifname, our_ifindex);
print_mac(our_mac);
printf(" ip ");
print_ip(our_ip);
printf("\n");
/* tell linux where to send */
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(ETH_P_ARP);
sll.sll_ifindex = our_ifindex;
sll.sll_hatype = ARPHRD_ETHER;
sll.sll_halen = 6;
for (int i = 0; i < 6; i++)
sll.sll_addr[i] = broadcast[i];
/* craft the arp packet */
arp.htype = htons(ARPHRD_ETHER);
arp.ptype = htons(ETH_P_IP);
arp.hlen = 6;
arp.plen = 4;
arp.op = htons(ARP_REQUEST);
for (int i = 0; i < 6; i++)
arp.srcmac[i] = our_mac[i];
arp.srcip = our_ip;
for (int i = 0; i < 6; i++)
arp.destmac[i] = 0;
arp.destip = htonl((192 << 24) | (168 << 16) | (1 << 8) | 1);
print_arp(&arp);
printf("sending ARP request for 192.168.1.1 ...\n");
if (sendto(sfd, &arp, sizeof(arp), 0, (struct sockaddr *) &sll, sizeof(sll)) != sizeof(arp)) {
perror("write");
return 1;
}
if (read(sfd, &arp, sizeof(arp)) != sizeof(arp)) {
perror("read");
return 1;
}
print_arp(&arp);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment