// Compile: gcc mirror.c -o mirror
// By fryxar

#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>

#define MAX_LEN_PACKET  1600

char debug = 0;


void Usage (void) {
        fprintf (stderr,
                "Usage: mirror [-i interface] [-o interface] -d\n"
                "\t-i : input interface\n"
                "\t-o : output interface\n"
                "\t-d : debug\n"
        );

        exit(0);
}

void PrintPacketInHex (char *packet, int len) {
        char *p = packet;

        printf ("\n\n---------Packet---Starts----\n\n");

        while (len--) {
                printf("%.2x ", *p);
                p++;
        }

        printf ("\n\n--------Packet---Ends-----\n\n");

}


int main (int argc,char *argv[]) {
int                     rec, snd, reclen, sndlen, ifindex;
struct sockaddr_ll      recaddr,sndaddr;
char                    c, buffer[MAX_LEN_PACKET];
char                    *if_in = NULL, *if_out = NULL;
struct ifreq            ifr;

        /* Get options */

        while ((c = getopt (argc, argv, "i:o:d")) != -1)
                switch (c) {
                        case 'i':
                                if_in = optarg;
                        break;

                        case 'o':
                                if_out = optarg;
                        break;

                        case 'd':
                                debug = 1;
                        break;

                        default:
                                Usage();
                        break;
                }

        if (!if_in) {
                if_in = malloc(5);
                strcpy (if_in, "eth0");
        }

        if (!if_out) {
                if_out = malloc(5);
                strcpy (if_out, "eth1");
        }

        printf ("Mirroring interface %s to %s...\n", if_in, if_out);

        // Create Recv Socket
        if ((rec=socket (PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) == -1) {
                perror("Error Creating Recv Socket");
                exit(-1);
        }

        // Retrieve input interface index
        strncpy (ifr.ifr_name, if_in, IFNAMSIZ);
        if (ioctl (rec, SIOCGIFINDEX, &ifr) == -1) {
                perror ("SIOCGIFINDEX");
                exit (-1);
        }

        // Bind to input interface
        recaddr.sll_family = AF_PACKET;
        recaddr.sll_protocol = htons(ETH_P_ALL);
        recaddr.sll_ifindex = ifr.ifr_ifindex;
        if (bind (rec, (struct sockaddr*)&recaddr, sizeof(recaddr))==-1) {
                perror ("Binding to in interface not done");
                exit (-1);
        }

        // Create Send Socket
        if ((snd = socket (PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) == -1) {
                perror ("Error Creating Send Socket");
                exit (-1);
        }


        // Retrieve out interface index
        strncpy (ifr.ifr_name, if_out, IFNAMSIZ);
        if (ioctl (snd, SIOCGIFINDEX, &ifr) == -1) {
                perror ("SIOCGIFINDEX");
                exit(1);
        }

        // Bind to out interface
        sndaddr.sll_family = AF_PACKET;
        sndaddr.sll_protocol = htons(ETH_P_ALL);
        sndaddr.sll_ifindex = ifr.ifr_ifindex;
        if (bind (snd,(struct sockaddr*)&sndaddr,sizeof(sndaddr))==-1) {
                perror ("Binding to out inteface not done");
                return 0;
        }

        while(1) {
                // Receive from in interface
                reclen = recv (rec, buffer, sizeof(buffer), 0);

                if (debug) PrintPacketInHex (buffer, reclen);

                // Send to the out interface
                if ((sndlen = send (snd, buffer, reclen, 0)) == -1) {
                        perror("Packet not Sent");
                        return 0;
                }
        }
}