/*
 * TCP Toolkit
 * 
 * Simple utility for crafting TCP traffic of your choosing.
 * Allows full control over virtually every parameter you can think
 * of and makes spoofing traffic or poking holes in your favorite firewall
 * or other pieces of networking equipment a piece of cake.
 *
 * Requires:
 *      libnet >= 1.1.x (http://www.packetfactory.net/projects/libnet/)
 *      root
 *      a basic understanding what this tool does
 *
 * Compile with something like:
 *  gcc -Wall `libnet-config --defines --cflags` -o tcp-tk tcp-tk.c `libnet-config --libs`
 *
 *  This code can be found in its original form here:
 *
 *    http://spoofed.org/files/tcp-tk.c
 *
 *
 * Jon Hart <warchild@spoofed.org>
 *
 * Copyright (c) 2002, Jon Hart 
 * All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without modification, 
 *  are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the organization nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without 
 *    specific prior written permission.
 *
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Changes:
 * 10/30/2002
 *    Fixed the TTL so that it is not obviously spoofed.
 *    Use random number between 1024 and 65535 for src/dst if no port provided
 */
#include <libnet.h>
#if (SOLARIS || BSD)
#include <netinet/if_ether.h>
#else
#include <netinet/ether.h>
#endif

/* These are currently not defined by libnet or any OS that I know of... */
#ifndef TH_RES1
#define TH_RES1 0x80
#endif
#ifndef TH_RES2
#define TH_RES2 0x40
#endif

#define OPT_HELP        0
#define OPT_VERBOSE     1
#define OPT_INTERFACE   2
#define OPT_SRCIP       3
#define OPT_DSTIP       4
#define OPT_SRCETHER    5
#define OPT_DSTETHER    6
#define OPT_SRCPORTS    7
#define OPT_DSTPORTS    8
#define OPT_TCPFLAGS    9
#define OPT_PAYLOAD     10
#define OPT_TCPSEQ      11
#define OPT_TCPACK      12
#define OPT_TCPURG      13
#define OPT_TCPWIN      14
#define OPT_IPID        15
#define OPT_IPTOS       16
#define OPT_IPTTL       17


struct opt {
   char *name; /* name of this option */
   int req;    /* required? */
   int set;    /* Does it have a value? */
}; 

struct opt opts[] = {
   {"help", 0, 0},
   {"verbose", 0, 0},
   {"interface", 1, 0},
   {"source IP", 1, 0},
   {"destination IP", 1, 0},
   {"source ethernet address", 0, 0},
   {"destination ethernet address", 0, 0},
   {"source port(s)", 1, 0},
   {"destination port(s)", 1, 0},
   {"TCP flags", 1, 0},
   {"payload", 0, 0},
   {"sequence number", 1, 0},
   {"acknowledgement number", 1, 0},
   {"urgent pointer", 1, 0},
   {"TCP window size", 1, 0},
   {"IP ID number", 1, 0},
   {"TOS", 1, 0},
   {"TTL", 1, 0}
};


/* Given a string, figure out which characters
 * may represent valid TCP control flags.  These include
 * 1, 2, A, F, P, R, S and U
 */
u_char make_flags(char *string) {
   int i, j, flag_num, num_flags;
   char *flag_vals = "afprsu12";
   u_char flags = 0x00;

   /* If no value is given for the flag string, make one up. */
   if (string == NULL) {
      if ((string = malloc(8)) == NULL) {
         printf("Failed to malloc() for new flag string\n");
         exit(EXIT_FAILURE);
      }
      srand(libnet_get_prand(LIBNET_PR8));
      num_flags = (int) (8.0*rand()/(RAND_MAX + 1.0));
      for(j = 0; j < num_flags; j++) {
         /* Randomly select a flag */
         flag_num = (int) (8.0*rand()/RAND_MAX + 1.0);
         snprintf(string+j, sizeof(char *), "%c", flag_vals[flag_num]);
      }   
   }
                                                   //

   for (i = 0; i < strlen(string); i++) {
       switch (string[i]) {
           case '1':
               flags += TH_RES1;
               break;
           case '2':
               flags += TH_RES2;
               break;
           case 'a':
           case 'A':
               flags += TH_ACK;
               break;
           case 'f':
           case 'F':
               flags += TH_FIN;
               break;
           case 'p':
           case 'P':
               flags += TH_PUSH;
               break;
           case 'r':
           case 'R':
               flags += TH_RST;
               break;
           case 's':
           case 'S':
               flags += TH_SYN;
               break;
           case 'u':
           case 'U':
               flags += TH_URG;
               break;
           default:
               break;
       }  
   }

   return flags;
}

/* Generate a random string to represent an ethernet address.
 * evil. */
char *rand_ether() {
   int i;
   char *ether;
   if ((ether = malloc(17)) == NULL) {
      printf("Failed to malloc() for ether\n");
      exit(EXIT_FAILURE);
   }   
   for (i = 0; i < 16; i++) {
      snprintf(&ether[i], 2, "%lx", libnet_get_prand(LIBNET_PR8));
      if ((i + 1) % 3 == 0 && i != 0 && i != 16) {
         sprintf(&ether[i], ":");
      }
   }

   return ether;
}

/* Generate a random string to represent an ip address */

void usage() {
   fprintf(stderr, "\ttcp-tk\n\n\tA simple TCP Toolkit\n\tby Jon Hart <warchild@spoofed.org>\n");
   fprintf(stderr, "\thttp://spoofed.org/files/tcp-tk.c\n\n");
   fprintf(stderr, "Usage:\n");
   fprintf(stderr, "\t(note: the options whos description starts with a '*' will be assigned\n");
   fprintf(stderr, "\trandom values if the option is used but no value is specified.\n");
   fprintf(stderr, "\tAlso, those options *must* be specified in -option<value> form,\n");
   fprintf(stderr, "\tnot -option <value> form)\n\n");
   fprintf(stderr, "\tRequired:\n");
   fprintf(stderr, "\t-i <interface>         Specify interface\n");
   fprintf(stderr, "\t-d <dst ip>            * Destination IP\n");
   fprintf(stderr, "\n\tOptional:\n\n");
   fprintf(stderr, "\tLink Layer:\n");
   fprintf(stderr, "\t-e <src ethernet>      * Source ethernet address (default: auto)\n");
   fprintf(stderr, "\t-E <dst ethernet>      * Destination ethernet address (default: auto)\n");
   fprintf(stderr, "\tIP Layer:\n");
   fprintf(stderr, "\t-I <IP id #>           IP ID number (default: sane)\n");
   fprintf(stderr, "\t-s <src IP>            Source IP (default: auto)\n");
   fprintf(stderr, "\t-t <TTL>               IP TTL (default: 255)\n");
   fprintf(stderr, "\t-T <TOS>               IP TOS (default: 0)\n");
   fprintf(stderr, "\tTCP Layer:\n");
   fprintf(stderr, "\t-a <ack number>        * TCP Acknowledgement number (default: sane random)\n");
   fprintf(stderr, "\t-c <payload>           Packet payload (default: NULL)\n");
   fprintf(stderr, "\t-f <A|F|P|R|S|U|1|2>   * TCP Flags (default: syn)\n");
   fprintf(stderr, "\t-p <src port(s)>       Source ports (default: random)\n");
   fprintf(stderr, "\t-P <dst port(s)>       Destination ports (default: random)\n");
   fprintf(stderr, "\t-q <sequence number>   * TCP Sequence number (default: sane random)\n");
   fprintf(stderr, "\t-u <urg pointer>       * TCP Urgent pointer (default: sane)\n");
   fprintf(stderr, "\t-w <window size>       TCP Window size (default: sane)\n");
   fprintf(stderr, "\tOther:\n");   
   fprintf(stderr, "\t-h                     Help (this message)\n");
   fprintf(stderr, "\t-v                     Be verbose\n");
}

int main(int argc, char *argv[]) {
    
   int c, i;

   libnet_t *libnet;
   libnet_ptag_t tcp, ipv4, ether;

   u_long src_ip, dst_ip;
   u_short src_port, dst_port;

   u_char tcp_flags, ip_ttl, ip_tos;
   u_long tcp_ack, tcp_seq;
   u_short tcp_urg, tcp_win, ip_id;

   /* The source and destination MAC addresses
    * for the ethernet level
    */ 
   struct libnet_ether_addr *src_ether = NULL;
   struct libnet_ether_addr *dst_ether = NULL;

   char *interface;
   char *rand_ether_t;
   struct ether_addr *ether_t;
   struct servent *servent;
   u_char *tcp_payload;
   u_long tcp_payload_l;
   char errbuf[LIBNET_ERRBUF_SIZE];

   libnet_seed_prand(libnet);

   while ((c = getopt(argc, argv, "i:c:ep:s:EP:d:i:q::f::a::u::w:I:t:T:vh")) != EOF) {
      switch (c) {
         case 'h':
            usage();
            exit(EXIT_SUCCESS);
         case 'v':
            opts[OPT_VERBOSE].set = 1;
            break;
         case 'i':
            interface = optarg;
            opts[OPT_INTERFACE].set = 1;
            break;
         case 'e':
            if (optarg == NULL) {
               /* They didn't specify a source ethernet address, but 
               * they do want it set.  Pick a random one. */
               rand_ether_t = rand_ether();
               if ((ether_t = ether_aton(rand_ether_t)) == NULL) {
                  printf("Invalid random source ethernet addresss\n");
                  return(EXIT_FAILURE);
               }
               free(rand_ether_t);
            } else if ((ether_t = ether_aton(optarg)) == NULL) {
               printf("Invalid source ethernet address: %s\n", optarg);
               return(EXIT_FAILURE);
            }
            if ((src_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) {
               printf("Couldn't malloc() for src_ether\n");
               return(EXIT_FAILURE);
            }
            memcpy(src_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr));
            opts[OPT_SRCETHER].set = 1;
            break;
         case 'E':
            if (optarg == NULL) {
               /* They didn't speciy a destination ethernet address, but
               * they do want it set.  Pick a random one. */
               rand_ether_t = rand_ether();
               if ((ether_t = ether_aton(rand_ether_t)) == NULL) {
                  printf("Invalid random destination address\n");
                  return(EXIT_FAILURE);
               }
               free(rand_ether_t);
            } else if ((ether_t = ether_aton(optarg)) == NULL) {
               printf("Invalid ethernet address: %s\n", optarg);
               return(EXIT_FAILURE);
            }
            if ((dst_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) {
               printf("Couldn't malloc() for dst_ether\n");
               return(EXIT_FAILURE);
            }
            memcpy(dst_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr));
            opts[OPT_DSTETHER].set = 1;
            break;
         case 'p':
            src_port = atoi(optarg);
            opts[OPT_SRCPORTS].set = 1;
            break; 
         case 'P':
            dst_port = atoi(optarg);
            opts[OPT_DSTPORTS].set = 1;
            break;
         case 's':
            src_ip = libnet_name2addr4(libnet, (u_char *) optarg, LIBNET_RESOLVE);
            opts[OPT_SRCIP].set = 1;
            break;
         case 'd':
            dst_ip = libnet_name2addr4(libnet, (u_char *) optarg, LIBNET_RESOLVE);
            opts[OPT_DSTIP].set = 1;
            break;
         case 'q':
            /* sequence number is optional.  If no value is specified, generate a 
             * random value now.  If this option is not used, the sequence number may
             * or may not be set later on, depending on various other options.  This is 
             * useful to, say, set the sequence number randomly even if the SYN flag
             * is not set. */
            if (optarg == NULL) {
               tcp_seq = libnet_get_prand(LIBNET_PRu32);
            } else {
               tcp_seq = atol(optarg);
            }
            opts[OPT_TCPSEQ].set = 1;
            break;
         case 'a':
            /* acknowledgement number is optional.  If no value is specified, generate a
            * random value now.  If this option is not used, the acknowledgement number
            * may or may not be set later on, depending on various other options.  This is
            * useful to, say, set the acknowledgement number randomly even if the ACK flag
            * is not set. */
            if (optarg == NULL) {
               tcp_ack = libnet_get_prand(LIBNET_PRu32);
            } else {
               tcp_ack = atol(optarg);
            }
            opts[OPT_TCPACK].set = 1;
            break;
         case 'u':
            /* urgent pointer is optional.  If no value is specified, generate a random value
             * now.  If this option is not used, the acknowledgement number may or may not be
             * set later on, depending on various other options. */
            if (optarg == NULL) {
               tcp_urg = libnet_get_prand(LIBNET_PRu16);
            } else {
               tcp_urg = atol(optarg);
            }
            opts[OPT_TCPURG].set = 1;
            break;
         case 't':
            ip_ttl = atoi(optarg);
            opts[OPT_IPTTL].set = 1;
            break;
         case 'T':
            ip_tos = atoi(optarg);
            opts[OPT_IPTOS].set = 1;
            break;
         case 'w':
            tcp_win = atoi(optarg);
            opts[OPT_TCPWIN].set = 1;
            break;
         case 'f':
            if (optarg == NULL) {
               tcp_flags = make_flags(NULL);
            } else {
               tcp_flags = make_flags(optarg);
            }
            opts[OPT_TCPFLAGS].set = 1;
            break;
         case 'c':
            tcp_payload = (u_char *) optarg;
            tcp_payload_l = strlen(tcp_payload);
            opts[OPT_PAYLOAD].set = 1;
            break;
         case 'I':
            ip_id = atoi(optarg);
            opts[OPT_IPID].set = 1;
            break;
         default:
            usage();
            goto pass; 
            break;
      } 
   }

   /* Ensure that an interface is specified or have libnet guess */
   if (!opts[OPT_INTERFACE].set) {
      usage();
      goto fail;
   }

   /* Depending on whether or not they choose to pick their own MACs,
    * libnet needs to be initialized differently for some reason */
   if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) {
      if ((libnet = libnet_init(LIBNET_LINK, interface, errbuf)) == NULL) {
         fprintf(stderr, "libnet_init() failed: %s", errbuf);
         goto fail;
      }
   } else {
      if ((libnet = libnet_init(LIBNET_RAW4, interface, errbuf)) == NULL) {
         fprintf(stderr, "libnet_init() failed: %s", errbuf);
         goto fail;
      }
   }

   /* If they didn't set a source ethernet address, figure out */
   if (!opts[OPT_SRCETHER].set) {
      if ((src_ether = libnet_get_hwaddr(libnet)) == NULL) {
         fprintf(stderr, "libnet_get_hwaddr() failed: %s", errbuf);
         libnet_destroy(libnet);
         goto fail;
      }
   }

   /* If they didn't set a destination ethernet address, figure out */
   if (!opts[OPT_DSTETHER].set) {
      if ((dst_ether = libnet_get_hwaddr(libnet)) == NULL) {
         fprintf(stderr, "libnet_get_hwaddr() failed: %s", errbuf);
         libnet_destroy(libnet);
         goto fail;
      }
   }

   /* If they didn't set a source IP, have libnet figure it out */
   if (!opts[OPT_SRCIP].set) {
      src_ip = libnet_get_ipaddr4(libnet);
      opts[OPT_SRCIP].set = 1;
   } 

   /* If no source port is given, make one up */
   if (!opts[OPT_SRCPORTS].set) {
      src_port = 1024 + (libnet_get_prand(LIBNET_PRu16) % (65535 - 1024));
      opts[OPT_SRCPORTS].set = 1;
   }

   /* If no destination port is given, make one up */
   if (!opts[OPT_DSTPORTS].set) {
      dst_port = 1024 + (libnet_get_prand(LIBNET_PRu16) % (65535 - 1024)); 
      opts[OPT_DSTPORTS].set = 1;
   }

   /* If no TCP control flags are set, default to TH_SYN */
   if (!opts[OPT_TCPFLAGS].set) {
      tcp_flags = make_flags("S");
      opts[OPT_TCPFLAGS].set = 1;
   }

   /* If a control flag is set that has a corresponding control field,
    * attempt to set that too */
   if (!opts[OPT_TCPACK].set) {
      if (tcp_flags & TH_ACK) {
         tcp_ack = libnet_get_prand(LIBNET_PRu32);
      } else { tcp_ack = 0x000; }
      opts[OPT_TCPACK].set = 1;
   }

   /* If no sequence number is set and one is needed,
    * go ahead and set it. */          
   if (!opts[OPT_TCPSEQ].set) {
      if (tcp_flags & TH_SYN) {
         tcp_seq = libnet_get_prand(LIBNET_PRu32);
      } else { tcp_seq = 0x000; }
      opts[OPT_TCPSEQ].set = 1;
   }

   /* If no urgent pointer is set and one is needed, 
    * go ahead and set it. */
   if (!opts[OPT_TCPURG].set) {
      if (tcp_flags & TH_URG) {
         tcp_urg = libnet_get_prand(LIBNET_PRu16);
      } else { tcp_urg = 0x000; }
      opts[OPT_TCPURG].set = 1;
   }

   /* If no window is set, pick a random one */
   if (!opts[OPT_TCPWIN].set) {
      tcp_win = libnet_get_prand(LIBNET_PRu16);
      opts[OPT_TCPWIN].set = 1;
   }

   /* If no IP id is set, pick a random one */
   if (!opts[OPT_IPID].set) {
      ip_id = libnet_get_prand(LIBNET_PRu16);
      opts[OPT_IPID].set = 1;
   }

   /* If no IP TOS is set, pick 0 */
   if (!opts[OPT_IPTOS].set) {
      ip_tos = 0;
      opts[OPT_IPTOS].set = 1;
   }

   /* No payload? Then NULL */
   if (!opts[OPT_PAYLOAD].set) {
      tcp_payload = NULL;
      tcp_payload_l = 0;
      opts[OPT_PAYLOAD].set = 1;
   }

   /* If no TTL is set, default to something sly... */
   if (!opts[OPT_IPTTL].set) {
      ip_ttl = 200 + (libnet_get_prand(LIBNET_PR8) % 55);
      opts[OPT_IPTTL].set = 1;
   }

   /* make sure that everything that needs to be set is set... */
   for(i = 0; i < 10; i++) {
      if (opts[i].req && !opts[i].set) {
         fprintf(stderr, "No %s specified\n\n", opts[i].name);
         usage();
         libnet_destroy(libnet);
         goto fail;
      }
   }

   tcp = libnet_build_tcp(
            src_port,   /* source port */
            dst_port,   /* destination port */
            tcp_seq,    /* seq # */
            tcp_ack,    /* ack # */
            tcp_flags,  /* flags */
            tcp_win,    /* window */
            0,          /* auto checksum */ 
            tcp_urg,    /* urg pointer */
            LIBNET_TCP_H + tcp_payload_l,  /* TCP packet size */
            tcp_payload,   /* payload */
            tcp_payload_l, /* payload size */ 
            libnet,        /* libnet handle */
            0);            /* libnet id */

   if (tcp == -1) {
      fprintf(stderr, "Can't build tcp: %s\n", libnet_geterror(libnet));
      libnet_destroy(libnet);
      goto fail;
   }
        

   ipv4 = libnet_build_ipv4(
            LIBNET_IPV4_H + LIBNET_TCP_H + tcp_payload_l,  /* length */
            ip_tos,             /* TOS */
            ip_id,         /* ID */
            IP_DF,         /* Frag */
            ip_ttl,        /* TTL */
            IPPROTO_TCP,   /* Protocol */
            0,             /* Sum */
            src_ip,        /* source IP */
            dst_ip,        /* destination IP */
            NULL,          /* Payload */
            0,             /* Payload size */
            libnet,
            0); 
    
   if (ipv4 == -1) {
      fprintf(stderr, "Can't build ipv4: %s\n", libnet_geterror(libnet));
      libnet_destroy(libnet);
      goto fail;
   }

   /* If they wish to set their own src/dst ethernet addresses
    * we need to actually build the ethernet.  If they don't,
    * libnet does it automagically for us. */ 
   if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) {
      ether = libnet_build_ethernet(
               dst_ether->ether_addr_octet,      /* Destination ethernet address */
               src_ether->ether_addr_octet,      /* Source ethernet address */
               ETHERTYPE_IP,   /* Protocol type */
               NULL,           /* Payload */
               0,              /* Payload size */
               libnet,
               0);

      if (ether == -1) {
         fprintf(stderr, "Can't build ethernet: %s\n", libnet_geterror(libnet));
         libnet_destroy(libnet);
         goto fail;
      }
   } 

   if ((c = libnet_write(libnet)) == -1) {
      fprintf(stderr, "Couldn't write packet to the wire: %s\n", libnet_geterror(libnet));
   } else {
      if (opts[OPT_VERBOSE].set) { 
         if (opts[OPT_SRCETHER].set || opts[OPT_DSTETHER].set) {
            printf("Link Layer: ");
            printf("%s -> ", opts[OPT_SRCETHER].set ? ether_ntoa((struct ether_addr *) src_ether->ether_addr_octet) : interface);
            printf("%s\n",  opts[OPT_DSTETHER].set ? ether_ntoa((struct ether_addr *) dst_ether->ether_addr_octet) : "(auto)");
         }
         printf("  IP Layer: %s -> %s\n", libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE), libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE));
         printf("  IP Layer: TTL: %d TOS: 0x%X ID: %d\n", ip_ttl, ip_tos, ip_id);
         printf(" TCP Layer: SrcPort: %d (%s) ", src_port, (servent = getservbyport(htons(src_port), "udp")) != NULL ? servent->s_name : "unknown"); 
         printf("DstPort: %d (%s)\n", dst_port, (servent = getservbyport(htons(dst_port), "udp")) != NULL ? servent->s_name : "unknown");
         printf(" TCP Layer: %s%s%s%s%s%s%s%s", (tcp_flags & TH_RES1) ? "1" : "*",
                                 (tcp_flags & TH_RES2) ? "2" : "*",
                                 (tcp_flags & TH_ACK)  ? "A" : "*",
                                 (tcp_flags & TH_FIN)  ? "F" : "*",
                                 (tcp_flags & TH_PUSH) ? "P" : "*",
                                 (tcp_flags & TH_RST)  ? "R" : "*",
                                 (tcp_flags & TH_SYN)  ? "S" : "*",
                                 (tcp_flags & TH_URG)  ? "U" : "*");
         printf(" Seq: 0x%lx Ack: 0x%lx Urg: 0x%x Win: 0x%d\n", tcp_seq, tcp_ack, ntohs(tcp_urg), tcp_win);
         printf(" App Layer: %ld byte payload\n", tcp_payload_l);
      }
   }
   libnet_destroy(libnet);
   goto pass;

fail:
   if (opts[OPT_SRCETHER].set) {
      free(src_ether);
   }
   if (opts[OPT_DSTETHER].set) {
      free(dst_ether);
   }
   return(EXIT_FAILURE);

pass:
   if (opts[OPT_SRCETHER].set) {
      free(src_ether);
   }
   if (opts[OPT_DSTETHER].set) {
      free(dst_ether);
   }
   return(EXIT_SUCCESS);
}

