From 9849b0f516238955f2b949337858822be485272c Mon Sep 17 00:00:00 2001 From: Etienne Champetier Date: Sat, 3 Aug 2019 23:57:52 -0700 Subject: [PATCH] phantap-learn: cleanup Replace all harcoded numbers and use already defined struct Signed-off-by: Etienne Champetier --- src/common.h | 40 ++++++++++++++++++ src/phantap-learn.c | 100 +++++++++++++++++++++----------------------- 2 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 src/common.h diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..503ce91 --- /dev/null +++ b/src/common.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 Etienne Champetier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __COMMON_H +#define __COMMON_H + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0]) +#endif + +#define EO(mac) (((struct ether_addr *)mac)->ether_addr_octet) +#define ETHER_MULTICAST(mac) (EO(mac)[0] & 0x1) +#define ETHER_ZERO(mac) (!(EO(mac)[0]|EO(mac)[1]|EO(mac)[2]|EO(mac)[3]|EO(mac)[4]|EO(mac)[5])) + +extern unsigned int debug; +#define DEBUG(level, fmt, ...) \ + do \ + { \ + if (debug >= level) \ + { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define ERROR(fmt, ...) DEBUG(0, "Error: "fmt, ##__VA_ARGS__) + +// This allow us to filter route/neigh when displaying / flushing +#define PHANTAP_RTPROTO "255" + +#endif diff --git a/src/phantap-learn.c b/src/phantap-learn.c index 56060e4..cf4bf85 100644 --- a/src/phantap-learn.c +++ b/src/phantap-learn.c @@ -18,31 +18,12 @@ #include #include #include -#include #include -#include -#include +#include #include -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0]) -#endif - -#define EO(mac) (((struct ether_addr *)mac)->ether_addr_octet) -#define ETHER_MULTICAST(mac) (EO(mac)[0] & 0x1) -#define ETHER_ZERO(mac) (!(EO(mac)[0]|EO(mac)[1]|EO(mac)[2]|EO(mac)[3]|EO(mac)[4]|EO(mac)[5])) - +#include "common.h" unsigned int debug = 0; -#define DEBUG(level, fmt, ...) \ - do \ - { \ - if (debug >= level) \ - { \ - fprintf(stderr, fmt, ##__VA_ARGS__); \ - } \ - } while (0) - -#define ERROR(fmt, ...) DEBUG(0, "Error: "fmt, ##__VA_ARGS__) #define OPT_ARGS "i:v:" @@ -53,9 +34,6 @@ unsigned int debug = 0; or (ip dst net 224.0.0.0/24)\ or (ip dst net 239.255.255.0/24)" -// This allow us to filter route/neigh when displaying / flushing -#define PHANTAP_RTPROTO "255" - pcap_t *pcap_handle = NULL; char *interface = NULL; @@ -64,26 +42,30 @@ static void usage(void) fprintf(stderr, "phantap-learn \n"); fprintf(stderr, " -i \tthe interface to listen on\n"); fprintf(stderr, " -v \tprint some debug info (level > 0)\n"); - fprintf(stderr, "\nTo show/flush neigh/route\n" \ -"ip neigh show proto "PHANTAP_RTPROTO"\n" \ -"ip neigh flush nud permanent proto "PHANTAP_RTPROTO"\n" \ -"ip route show proto "PHANTAP_RTPROTO"\n" \ -"ip route flush proto "PHANTAP_RTPROTO"\n" -); + fprintf(stderr, "\nTo show/flush neigh/route\n" + "ip neigh show proto " PHANTAP_RTPROTO "\n" + "ip neigh flush nud permanent proto " PHANTAP_RTPROTO "\n" + "ip route show proto " PHANTAP_RTPROTO "\n" + "ip route flush proto " PHANTAP_RTPROTO "\n"); } char sbuf[200]; -static void add_neighboor(struct ether_addr *mac, struct in_addr *ip) +static void add_neighboor(const struct ether_addr *mac, const struct in_addr *ip) { in_addr_t iph = ntohl(ip->s_addr); - if (! (IN_MULTICAST(iph) || iph == INADDR_ANY || iph == INADDR_BROADCAST || ETHER_MULTICAST(mac) || ETHER_ZERO(mac))) { + if (!(IN_MULTICAST(iph) || iph == INADDR_ANY || iph == INADDR_BROADCAST || ETHER_MULTICAST(mac) || ETHER_ZERO(mac))) + { DEBUG(1, "MAC: %s / IP: %s\n", ether_ntoa(mac), inet_ntoa(*ip)); - snprintf(sbuf, ARRAY_SIZE(sbuf), "ip neigh replace %s dev %s lladdr %s proto "PHANTAP_RTPROTO, inet_ntoa(*ip), interface, ether_ntoa(mac)); + snprintf(sbuf, ARRAY_SIZE(sbuf), + "ip neigh replace %s dev %s lladdr %s proto " PHANTAP_RTPROTO, + inet_ntoa(*ip), interface, ether_ntoa(mac)); DEBUG(2, "Executing '%s' ...\n", sbuf); if (system(sbuf)) printf("Executing '%s' failed!!\n", sbuf); // should we add "scope link" ? "onlink" ? - snprintf(sbuf, ARRAY_SIZE(sbuf), "ip route replace %s dev %s proto "PHANTAP_RTPROTO, inet_ntoa(*ip), interface); + snprintf(sbuf, ARRAY_SIZE(sbuf), + "ip route replace %s dev %s proto " PHANTAP_RTPROTO, + inet_ntoa(*ip), interface); DEBUG(2, "Executing '%s' ...\n", sbuf); if (system(sbuf)) printf("Executing '%s' failed!!\n", sbuf); @@ -92,33 +74,47 @@ static void add_neighboor(struct ether_addr *mac, struct in_addr *ip) static void handle_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { - struct ether_header *eth_header = (struct ether_header *)packet; + if (header->caplen < sizeof(struct ether_header)) + { + ERROR("Capture too short for Ethernet (%u)\n", header->caplen); + return; + } + const struct ether_header *eth_hdr = (struct ether_header *)packet; - switch (ntohs(eth_header->ether_type)) + switch (ntohs(eth_hdr->ether_type)) { case ETHERTYPE_IP: - if (header->caplen < 34) + if (header->caplen < ETH_HLEN + sizeof(struct ip)) { - ERROR("IP capture too short %u\n", header->caplen); + ERROR("Capture too short for IP (%u)\n", header->caplen); return; } - add_neighboor((struct ether_addr *)eth_header->ether_shost, (struct in_addr *)((uint8_t *) packet + 26)); - // right now ip dest should always broadcast / multicast and be filtered out by the BPF filter - // but it's cheap to keep it - add_neighboor((struct ether_addr *)eth_header->ether_dhost, (struct in_addr *)((uint8_t *) packet + 30)); + const struct ip *ip_hdr = (struct ip *)(packet + ETH_HLEN); + add_neighboor((struct ether_addr *)eth_hdr->ether_shost, &ip_hdr->ip_src); + // right now ip_dst should always be broadcast / multicast and be filtered + // out by the BPF filter, but it's cheap to keep it + add_neighboor((struct ether_addr *)eth_hdr->ether_dhost, &ip_hdr->ip_dst); break; case ETHERTYPE_ARP: - if (header->caplen < 42) + if (header->caplen < ETH_HLEN + sizeof(struct ether_arp)) + { + ERROR("Capture too short for ARP (%u)\n", header->caplen); + return; + } + const struct ether_arp *arp = (struct ether_arp *)(packet + ETH_HLEN); + if (!(ntohs(arp->arp_hrd) == ARPHRD_ETHER && ntohs(arp->arp_pro) == ETHERTYPE_IP && + arp->arp_hln == ETH_ALEN && arp->arp_pln == sizeof(struct in_addr))) { - ERROR("ARP capture too short %u\n", header->caplen); + ERROR("ARP packet is wrong (%#06x,%#06x,%#04x,%#04x)\n", + ntohs(arp->arp_hrd), ntohs(arp->arp_pro), arp->arp_hln, arp->arp_pln); return; } - add_neighboor((struct ether_addr *)(packet + 22), (struct in_addr *)(packet + 28)); - add_neighboor((struct ether_addr *)(packet + 32), (struct in_addr *)(packet + 38)); + add_neighboor((struct ether_addr *)(arp->arp_sha), (struct in_addr *)(arp->arp_spa)); + add_neighboor((struct ether_addr *)(arp->arp_tha), (struct in_addr *)(arp->arp_tpa)); break; default: // we should never get there based of the current BPF filter - printf("Unknown ethertype %hu\n", ntohs(eth_header->ether_type)); + ERROR("Unknown ethertype %#06x\n", ntohs(eth_hdr->ether_type)); } } @@ -162,8 +158,7 @@ int main(int argc, char **argv) // Ethernet header (14) + ARP IPv4 (28) == 42 // Ethernet header (14) + IPv4 header (20) == 34 - //TODO: check if not too small - pcap_set_snaplen(pcap_handle, ETH_HLEN+28); + pcap_set_snaplen(pcap_handle, ETH_HLEN + sizeof(struct ether_arp)); // We want all the traffic we can get, in particular broadcast/multicast pcap_set_promisc(pcap_handle, 1); @@ -176,7 +171,8 @@ int main(int argc, char **argv) if ((pcapstatus = pcap_activate(pcap_handle)) != 0) { - ERROR("pcap_activate issue: %s / %s\n", pcap_statustostr(pcapstatus), pcap_geterr(pcap_handle)); + ERROR("pcap_activate issue: %s / %s\n", + pcap_statustostr(pcapstatus), pcap_geterr(pcap_handle)); goto exit_err; } @@ -209,14 +205,14 @@ int main(int argc, char **argv) } // Loop - DEBUG(1, "Before loop\n"); + DEBUG(2, "Before pcap_loop\n"); signal(SIGINT, &breakloop); if (pcap_loop(pcap_handle, -1, handle_packet, NULL) == -1) { ERROR("pcap_loop error: %s\n", pcap_geterr(pcap_handle)); goto exit_err; } - DEBUG(1, "After loop\n"); + DEBUG(2, "After pcap_loop\n"); status = EXIT_SUCCESS; exit_err: