Skip to content

Commit

Permalink
phantap-learn: cleanup
Browse files Browse the repository at this point in the history
Replace all harcoded numbers and use already defined struct

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
  • Loading branch information
champtar committed Aug 5, 2019
1 parent 159653d commit 9849b0f
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 52 deletions.
40 changes: 40 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2019 Etienne Champetier <champetier.etienne@gmail.com>
*
* 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
100 changes: 48 additions & 52 deletions src/phantap-learn.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.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]))

#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:"

Expand All @@ -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;

Expand All @@ -64,26 +42,30 @@ static void usage(void)
fprintf(stderr, "phantap-learn <options>\n");
fprintf(stderr, " -i <listen-interface>\tthe interface to listen on\n");
fprintf(stderr, " -v <debug-level>\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);
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 9849b0f

Please sign in to comment.