
/***************************************************************************
 * NpingOps.cc -- The NpingOps class contains global options, mostly based *
 * on user-provided command-line settings.                                 *
 *                                                                         *
 ***********************IMPORTANT NMAP LICENSE TERMS************************
 *
 * The Nmap Security Scanner is (C) 1996-2026 Nmap Software LLC ("The Nmap
 * Project"). Nmap is also a registered trademark of the Nmap Project.
 *
 * This program is distributed under the terms of the Nmap Public Source
 * License (NPSL). The exact license text applying to a particular Nmap
 * release or source code control revision is contained in the LICENSE
 * file distributed with that version of Nmap or source code control
 * revision. More Nmap copyright/legal information is available from
 * https://nmap.org/book/man-legal.html, and further information on the
 * NPSL license itself can be found at https://nmap.org/npsl/ . This
 * header summarizes some key points from the Nmap license, but is no
 * substitute for the actual license text.
 *
 * Nmap is generally free for end users to download and use themselves,
 * including commercial use. It is available from https://nmap.org.
 *
 * The Nmap license generally prohibits companies from using and
 * redistributing Nmap in commercial products, but we sell a special Nmap
 * OEM Edition with a more permissive license and special features for
 * this purpose. See https://nmap.org/oem/
 *
 * If you have received a written Nmap license agreement or contract
 * stating terms other than these (such as an Nmap OEM license), you may
 * choose to use and redistribute Nmap under those terms instead.
 *
 * The official Nmap Windows builds include the Npcap software
 * (https://npcap.com) for packet capture and transmission. It is under
 * separate license terms which forbid redistribution without special
 * permission. So the official Nmap Windows builds may not be redistributed
 * without special permission (such as an Nmap OEM license).
 *
 * Source is provided to this software because we believe users have a
 * right to know exactly what a program is going to do before they run it.
 * This also allows you to audit the software for security holes.
 *
 * Source code also allows you to port Nmap to new platforms, fix bugs, and
 * add new features. You are highly encouraged to submit your changes as a
 * Github PR or by email to the dev@nmap.org mailing list for possible
 * incorporation into the main distribution. Unless you specify otherwise, it
 * is understood that you are offering us very broad rights to use your
 * submissions as described in the Nmap Public Source License Contributor
 * Agreement. This is important because we fund the project by selling licenses
 * with various terms, and also because the inability to relicense code has
 * caused devastating problems for other Free Software projects (such as KDE
 * and NASM).
 *
 * The free version of Nmap 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. Warranties,
 * indemnification and commercial support are all available through the
 * Npcap OEM program--see https://nmap.org/oem/
 *
 ***************************************************************************/

#ifdef WIN32
#include "winfix.h"
#endif

#include "nping.h"
#include "nbase.h"
#include "NpingOps.h"
#include "utils.h"
#include "utils_net.h"
#include "ArgParser.h"
#include "output.h"
#include "common.h"
#include <climits>


/******************************************************************************
 *  Constructors and destructors                                              *
 ******************************************************************************/

/* Constructor */
NpingOps::NpingOps() {

    /* Probe modes */
    mode=0;
    mode_set=false;

    traceroute=false;
    traceroute_set=false;

    /* Output */
    vb=DEFAULT_VERBOSITY;
    vb_set=false;

    dbg=DEFAULT_DEBUGGING;
    dbg_set=false;

    show_sent_pkts=true;
    show_sent_pkts_set=false;

    /* Operation and Performance */
    pcount=0;
    pcount_set=false;

    sendpref=0;
    sendpref_set=false;

    send_eth=false;

    delay=0;
    delay_set=false;

    memset(device, 0, MAX_DEV_LEN);
    device_set=false;

    spoofsource=false;
    spoofsource_set=false;

    bpf_filter_spec=NULL;
    bpf_filter_spec_set=false;

    current_round=0;

    have_pcap=true;

    disable_packet_capture=false;
    disable_packet_capture_set=false;

    /* Privileges */
/* If user did not specify --privileged or --unprivileged explicitly, try to
 * determine if has root privileges. */
#if defined WIN32 || defined __amigaos__
    /* TODO: Check this because although nmap does exactly the same, it has a this->have_pcap that may affect to this */
    isr00t=true;
#else
  if (getenv("NMAP_PRIVILEGED") || getenv("NPING_PRIVILEGED"))
    isr00t=true;
  else if (getenv("NMAP_UNPRIVILEGED") || getenv("NPING_UNPRIVILEGED"))
    isr00t=false;
  else
    isr00t = !(geteuid());
#endif

    /* Payloads */
    payload_type=PL_NONE;
    payload_type_set=false;

    payload_buff=NULL;
    payload_buff_set=false;

    payload_len=0;
    payload_len_set=false;

    /* Roles */
    role=0;
    role_set=false;

    /* IP */
    ttl=0;
    ttl_set=false;

    tos=0;
    tos_set=false;

    identification=0;
    identification_set=false;

    mf=false;
    mf_set=false;

    df=false;
    df_set=false;

    mtu=0;
    mtu_set=false;

    badsum_ip=false;
    badsum_ip_set=false;

    ipversion=0;
    ipversion_set=false;

    memset(&ipv4_src_address, 0, sizeof(struct in_addr));
    ipv4_src_address_set=false;

    ip_options=NULL;
    ip_options_set=false;

    /* IPv6 */
    ipv6_tclass=0;
    ipv6_tclass_set=false;

    ipv6_flowlabel=0;
    ipv6_flowlabel_set=false;

    memset(&ipv6_src_address, 0, sizeof(struct in6_addr));
    ipv6_src_address_set=false;

    /* TCP / UDP */
    target_ports=NULL;
    tportcount=0;
    target_ports_set=false;

    source_port=0;
    source_port_set=false;

    tcpseq=0;
    tcpseq_set=false;

    memset(tcpflags, 0, 8);
    tcpflags_set=false;

    tcpack=0;
    tcpack_set=false;

    tcpwin=0;
    tcpwin_set=false;

    badsum=false;
    badsum_set=false;

    /* ICMP */
    icmp_type=0;
    icmp_type_set=false;

    icmp_code=0;
    icmp_code_set=false;

    badsum_icmp=false;
    badsum_icmp_set=false;

    icmp_redir_addr.s_addr=0;
    icmp_redir_addr_set=false;

    icmp_paramprob_pnt=0;
    icmp_paramprob_pnt_set=false;

    icmp_routeadv_ltime=0;
    icmp_routeadv_ltime_set=false;

    icmp_id=0;
    icmp_id_set=false;

    icmp_seq=0;
    icmp_seq_set=false;

    icmp_orig_time=0;
    icmp_orig_time_set=false;

    icmp_recv_time=0;
    icmp_recv_time_set=false;

    icmp_trans_time=0;
    icmp_trans_time_set=false;

    memset( icmp_advert_entry_addr, 0, sizeof(struct in_addr)*MAX_ICMP_ADVERT_ENTRIES );
    memset( icmp_advert_entry_pref, 0, sizeof(u32)*MAX_ICMP_ADVERT_ENTRIES );
    icmp_advert_entry_count=0;
    icmp_advert_entry_set=false;

    /* Ethernet */
    memset(src_mac, 0, 6);
    src_mac_set=false;

    memset(dst_mac, 0, 6);
    dst_mac_set=false;

    eth_type=0;
    eth_type_set=false;

    arp_htype=0;
    arp_htype_set=false;

    /* ARP/RARP */
    arp_ptype=0;
    arp_ptype_set=false;

    arp_hlen=0;
    arp_hlen_set=false;

    arp_plen=0;
    arp_plen_set=false;

    arp_opcode=0;
    arp_opcode_set=false;

    memset(arp_sha, 0, 6);
    arp_sha_set=false;

    memset(arp_tha, 0, 6);
    arp_tha_set=false;

    arp_spa.s_addr=0;
    arp_spa_set=false;

    arp_tpa.s_addr=0;
    arp_tpa_set=false;

    /* Echo mode */
    echo_port=DEFAULT_ECHO_PORT;
    echo_port_set=false;

    do_crypto=true;

    echo_payload=false;

    echo_server_once=false;
    echo_server_once_set=false;

    memset(echo_passphrase, 0, sizeof(echo_passphrase));
    echo_passphrase_set=false;

    memset(&last_sent_pkt_time, 0, sizeof(struct timeval));

    delayed_rcvd_str=NULL;
    delayed_rcvd_str_set=false;

} /* End of NpingOps() */


/* Destructor */
NpingOps::~NpingOps() {
 if (payload_buff!=NULL)
    free(payload_buff);
 if ( ip_options!=NULL )
    free(ip_options);
 if ( target_ports!=NULL )
    free(target_ports);
 if (delayed_rcvd_str_set)
   free(delayed_rcvd_str);
 return;
} /* End of ~NpingOps() */


/******************************************************************************
 *  Nping probe modes                                                         *
 ******************************************************************************/

/** Sets attribute "mode". Mode must be one of: TCP_CONNECT TCP, UDP, ICMP,
 *  ARP
 *  @return OP_SUCCESS on success.
 *  @return OP_FAILURE in case of error. */
int NpingOps::setMode(int md) {
  if ( md!=TCP_CONNECT && md!=TCP && md!=UDP && md!=UDP_UNPRIV && md!=ICMP && md!=ARP )
    return OP_FAILURE;
  else{
    this->mode=md;
    this->mode_set=true;
  }
  return OP_SUCCESS;
} /* End of setMode() */


/** Returns value of attribute "mode". The value returned is supposed to be
 *  one of : TCP_CONNECT, TCP, UDP, UDP_UNPRIV, ICMP, ARP */
int NpingOps::getMode() {
  return mode;
} /* End of getMode() */


/* Returns true if option has been set */
bool NpingOps::issetMode(){
  return this->mode_set;
} /* End of isset() */


/** Takes a probe mode and returns an ASCII string with the name of the mode.
 *  @warning Returned pointer is a static buffer that subsequent calls
 *            will overwrite.
 *  @return Pointer to the appropriate string on success and pointer to a
 *          string containing "Unknown probe" in case of failure.
 * */
char * NpingOps::mode2Ascii(int md) {
  static char buff[24];

  switch( md ){
    case TCP_CONNECT:
        sprintf(buff, "TCP-Connect");
    break;

    case TCP:
        sprintf(buff, "TCP");
    break;

    case UDP:
        sprintf(buff, "UDP");
    break;

    case UDP_UNPRIV:
        sprintf(buff, "UDP-Unprivileged");
    break;

    case ICMP:
        sprintf(buff, "ICMP");
    break;

    case ARP:
        sprintf(buff, "ARP");
    break;

    default:
        sprintf(buff, "Unknown mode");
    break;
 }
 return buff;
} /* End of mode2Ascii() */


/** Returns value of attribute "traceroute" */
bool NpingOps::getTraceroute() {
  return traceroute;
} /* End of getTraceroute() */


/** Sets attribute traceroute to "true".
 *  @return previous value of the attribute. */
bool NpingOps::enableTraceroute() {
  bool prev = traceroute;
  this->traceroute=true;
  this->traceroute_set=true;
  return prev;
} /* End of enableTraceroute() */


/** Sets attribute traceroute to "false".
 *  @return previous value of the attribute. */
bool NpingOps::disableTraceroute() {
  bool prev = traceroute;
  this->traceroute=false;
  this->traceroute_set=true;
  return prev;
} /* End of disableTraceroute() */


/* Returns true if option has been set */
bool NpingOps::issetTraceroute(){
  return this->traceroute_set;
} /* End of issetTraceroute() */


/******************************************************************************
 * Output                                                                     *
 ******************************************************************************/

/** Sets verbosity level. Supplied level must be an integer between -4 and
 *  4. Check man pages for details.
 *
 *  The thing here is that what the argument parser gets from the user is
 *  number in the range [-4, 4]. However, in NpingOps we don't store negative
 *  verbosity values, we just convert the supplied level into our internal
 *  levels (QT_4, QT_3, ... , VB_0, VB_1, ..., VB_4)
 *  So the rest of the code in Nping should check for these defines, rather
 *  than checking for numbers. Check nping.h for more information on how to
 *  handle verbosity levels.
 *
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setVerbosity(int level){
   if( level < -4 || level > 4 ){
        nping_fatal(QT_3,"setVerbosity(): Invalid verbosity level supplied\n");
        return OP_FAILURE;
   }else{
        switch(level){
            case -4:  vb=QT_4;  break;
            case -3:  vb=QT_3;  break;
            case -2:  vb=QT_2;  break;
            case -1:  vb=QT_1;  break;
            case  0:  vb=VB_0;  break;
            case  1:  vb=VB_1;  break;
            case  2:  vb=VB_2;  break;
            case  3:  vb=VB_3;  break;
            case  4:  vb=VB_4;  break;
            default:
                nping_fatal(QT_3,"setVerbosity():2: Invalid verbosity level supplied\n");
            break;
        }
    }
    this->vb_set=true;
    return OP_SUCCESS;
} /* End of setVerbosity() */


/** Returns value of attribute vb (current verbosity level) */
int NpingOps::getVerbosity(){
  return vb;
} /* End of getVerbosity() */



/* Returns true if option has been set */
bool NpingOps::issetVerbosity(){
  return this->vb_set;
} /* End of issetVerbosity() */


/** Increments verbosity level by one. (When it reaches VB_4 it stops
  * getting incremented)
  * @return previous verbosity level */
int NpingOps::increaseVerbosity(){
  this->vb_set=true;
  if (vb < VB_4){
    vb++;
    return vb-1;
  }else{
    return vb;
  }
} /* End of increaseVerbosity() */


/** Decreases verbosity level by one. (When it reaches QT_4 it stops
  * getting incremented)
  * @return previous verbosity level */
int NpingOps::decreaseVerbosity(){
  this->vb_set=true;
  if (vb > QT_4){
    vb--;
    return vb+1;
  }else{
    return vb;
  }
} /* End of decreaseVerbosity() */


/** Sets debugging level. Supplied level must be an integer between DBG_0 and
 *  DBG_9. Check file nping.h for details
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setDebugging(int level){
  if( level < 0 || level > 9){
    nping_fatal(QT_3,"setDebugging(): Invalid debugging level supplied\n");
    return OP_FAILURE;
  }else{
    this->dbg= DBG_0  + level;
  }
  this->dbg_set=true;
  return OP_SUCCESS;
} /* End of setDebugging() */


/** Returns value of attribute dbg (current debugging level) */
int NpingOps::getDebugging(){
  return dbg;
} /* End of getDebugging() */


/** Increments debugging level by one. (When it reaches DBG_9 it stops
  * getting incremented)
  *   * @return previous verbosity level */
int NpingOps::increaseDebugging(){
  this->dbg_set=true;
  if (dbg < DBG_9){
    dbg++;
    return dbg-1;
  }else{
    return dbg;
  }
} /* End of increaseDebugging() */


/* Returns true if option has been set */
bool NpingOps::issetDebugging(){
    return this->dbg_set;
} /* End of issetDebugging() */


/** Sets ShowSentPackets.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setShowSentPackets(bool val){
  this->show_sent_pkts=val;
  this->show_sent_pkts_set=true;
  return OP_SUCCESS;
} /* End of setShowSentPackets() */


/** Returns value of attribute show_sent_pkts */
bool NpingOps::showSentPackets(){
  return this->show_sent_pkts;
} /* End of showSentPackets() */


/* Returns true if option has been set */
bool NpingOps::issetShowSentPackets(){
  return this->show_sent_pkts_set;
} /* End of issetShowSentPackets() */



/******************************************************************************
 *  Operation and Performance                                                 *
 ******************************************************************************/

/** Sets packet count (number of packets that should be sent to each target)
 *  Supplied parameter must be a non-negative integer.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setPacketCount(u32 val){
  /* If zero is supplied, use the highest possible value */
  if( val==0 )
    this->pcount=0xFFFFFFFF;
  else
    pcount=val;
  this->pcount_set=true;
  return OP_SUCCESS;
} /* End of setPacketCount() */


/** Returns value of attribute pcount (number of packets that should be sent
 *  to each target)  */
u32 NpingOps::getPacketCount(){
  return this->pcount;
} /* End of getPacketCount() */


/* Returns true if option has been set */
bool NpingOps::issetPacketCount(){
  return this->pcount_set;
} /* End of issetPacketCount() */


/** Sets attribute sendpref which defines user's preference for packet
 *  sending. Supplied parameter must be an integer with one of these values:
 *  PACKET_SEND_NOPREF, PACKET_SEND_ETH_WEAK, PACKET_SEND_ETH_STRONG,
 *  PACKET_SEND_ETH, PACKET_SEND_IP_WEAK, PACKET_SEND_IP_STRONG, PACKET_SEND_IP
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setSendPreference(int v){
  // Validate: no extra bits set
  if( (v & ~(PACKET_SEND_ETH | PACKET_SEND_IP))
      // Validate: both ETH and IP cannot be STRONG
      || ((v & PACKET_SEND_ETH_STRONG) && (v & PACKET_SEND_IP_STRONG))) {
        nping_fatal(QT_3,"setSendPreference(): Invalid value supplied\n");
        return OP_FAILURE;
    }else{
        sendpref=v;
    }
    this->sendpref_set=true;
    return OP_SUCCESS;
} /* End of setSendPreference() */


/** Returns value of attribute sendpref */
int NpingOps::getSendPreference(){
  return this->sendpref;
} /* End of getSendPreference() */


/* Returns true if option has been set */
bool NpingOps::issetSendPreference(){
  return this->sendpref_set;
} /* End of issetSendPreference() */


/* Returns true if send preference is Ethernet */
bool NpingOps::sendPreferenceEthernet(){
  return (this->sendpref & PACKET_SEND_ETH);
} /* End of sendPreferenceEthernet() */


/* Returns true if send preference is Ethernet */
bool NpingOps::sendPreferenceIP(){
  return (this->sendpref & PACKET_SEND_IP);
} /* End of sendPreferenceIP() */


/** Sets SendEth.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setSendEth(bool val){
  this->sendpref = PACKET_SEND_ETH;
  this->sendpref_set = true;
  return OP_SUCCESS;
} /* End of setSendEth() */


/** Returns value of attribute send_eth */
bool NpingOps::sendEth(){
  return (this->sendpref & PACKET_SEND_ETH_STRONG);
} /* End of getSendEth() */


/** Sets inter-probe delay. Supplied parameter is assumed to be in milliseconds
 *  and must be a long integer greater than zero.
 *  @warning timeout is assumed to be in milliseconds. Use tval2msecs() from
 *           nbase to obtain a proper value.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setDelay(long t){
  if( t < 0 )
    nping_fatal(QT_3,"setDelay(): Invalid time supplied\n");
  this->delay=t;
  this->delay_set=true;
  return OP_SUCCESS;
} /* End of setDelay() */


/** Returns value of attribute delay */
long NpingOps::getDelay(){
  return delay;
} /* End of getDelay() */


/* Returns true if option has been set */
bool NpingOps::issetDelay(){
  return this->delay_set;
} /* End of issetDelay() */


/** Sets network device. Supplied parameter must be a valid network interface
 *  name.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setDevice(char *n){
  if( n==NULL ){
    nping_fatal(QT_3,"setDevice(): Invalid value supplied\n");
  }else{
    Strncpy(this->device, n, MAX_DEV_LEN-1);
  }
  this->device_set=true;
  return OP_SUCCESS;
} /* End of setDevice() */


char *NpingOps::getDevice(){
  return this->device;
} /* End of getDevice() */


/* Returns true if option has been set */
bool NpingOps::issetDevice(){
  return this->device_set;
} /* End of issetDevice() */


/** Returns true if user requested explicitly that he wants IP source
 *  spoofing */
bool NpingOps::spoofSource(){
  return this->spoofsource;
} /* End of spoofSource() */


bool NpingOps::getSpoofSource(){
  return this->spoofsource;
} /* End of getSpoofSource() */


int NpingOps::setSpoofSource(){
  this->spoofsource=true;
  this->spoofsource_set=true;
  return OP_SUCCESS;
} /* End of spoofSource() */


/* Returns true if option has been set */
bool NpingOps::issetSpoofSource(){
  return this->spoofsource_set;
} /* End of issetSpoofSource() */


/** Sets BPFFilterSpec.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setBPFFilterSpec(char *val){
  this->bpf_filter_spec=val;
  this->bpf_filter_spec_set=true;
  return OP_SUCCESS;
} /* End of setBPFFilterSpec() */


/** Returns value of attribute bpf_filter_spec */
char *NpingOps::getBPFFilterSpec(){
  return this->bpf_filter_spec;
} /* End of getBPFFilterSpec() */


/* Returns true if option has been set */
bool NpingOps::issetBPFFilterSpec(){
  return this->bpf_filter_spec_set;
} /* End of issetBPFFilterSpec() */


/** Sets CurrentRound.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setCurrentRound(int val){
  this->current_round=val;
  return OP_SUCCESS;
} /* End of setCurrentRound() */


/** Returns value of attribute current_round */
int NpingOps::getCurrentRound(){
  return this->current_round;
} /* End of getCurrentRound() */


bool NpingOps::havePcap(){
  return this->have_pcap;
} /* End of havePcap() */


int NpingOps::setHavePcap(bool val){
  this->have_pcap=val;
  return OP_SUCCESS;
} /* End of setHavePcap() */


/** Sets DisablePacketCapture.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setDisablePacketCapture(bool val){
  this->disable_packet_capture=val;
  this->disable_packet_capture_set=true;
  return OP_SUCCESS;
} /* End of setDisablePacketCapture() */


/** Returns value of attribute disable_packet_capture */
bool NpingOps::disablePacketCapture(){
  return this->disable_packet_capture;
} /* End of disablePacketCapture() */


/* Returns true if option has been set */
bool NpingOps::issetDisablePacketCapture(){
  return this->disable_packet_capture_set;
} /* End of issetDisablePacketCapture() */

/** Sets the IP version that will be used in all packets. Supplied parameter
 *  must be either IP_VERSION_4 or IP_VERSION_&.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setIPVersion(u8 val){
  if( val!=IP_VERSION_4 && val!=IP_VERSION_6 ){
    nping_fatal(QT_3,"setIPVersion(): Invalid value supplied\n");
    return OP_FAILURE;
  }else{
    this-> ipversion=val;
  }
  this->ipversion_set=true;
  return OP_SUCCESS;
} /* End of setIPVersion() */


/** Returns value of attribute ipversion. */
int NpingOps::getIPVersion(){
  return ipversion;
} /* End of getIPVersion() */


/* Returns true if option has been set */
bool NpingOps::issetIPVersion(){
  return this->ipversion_set;
} /* End of issetIPversion() */


/* Returns true if we are using IPv4 */
bool NpingOps::ipv4(){
  if( this->getIPVersion() == IP_VERSION_4 )
    return true;
  else
    return false;
} /* End of ipv4() */


/* Returns true if we are using IPv6 */
bool NpingOps::ipv6(){
  if( this->getIPVersion() == IP_VERSION_6 )
    return true;
  else
    return false;
} /* End of ipv6() */


/* Returns true if we are sending IPv6 packets at raw TCP level (using a
 * useless and boring IPv6 socket that doesn't let us include our own IPv6
 * header)*/
bool NpingOps::ipv6UsingSocket(){
  if( this->getIPVersion() == IP_VERSION_6 && this->sendEth()==false)
    return true;
  else
    return false;
} /* End of ipv6UsingSocket() */


/* Returns AF_INET or AF_INET6, depending on current configuration */
int NpingOps::af(){
  if( this->getIPVersion() == IP_VERSION_6 )
    return AF_INET6;
  else
    return AF_INET;
} /* End of af() */


/******************************************************************************
 *  User types and Privileges                                                 *
 ******************************************************************************/

/** Sets value of attribute isr00t.
 *  @returns previous isr00t value */
int NpingOps::setIsRoot(int v) {
  int prev=this->isr00t;
  this->isr00t = (v==0) ? 0 : 1;
  return prev;
} /* End of setIsRoot() */


/** Sets attribute isr00t to value 1.
 *  @returns previous isr00t value */
int NpingOps::setIsRoot() {
  int prev=this->isr00t;
  this->isr00t=1;
 return prev;
} /* End of setIsRoot() */


/* Returns the state of attribute isr00t */
bool NpingOps::isRoot() {
  return (this->isr00t);
} /* End of isRoot() */


/******************************************************************************
 *  Payloads                                                                  *
 ******************************************************************************/

/** Sets payload type. Supplied parameter must be one of: PL_RAND, PL_HEX or
 *  PL_FILE;
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setPayloadType(int t){
  if( t!=PL_RAND && t!=PL_HEX && t!=PL_FILE && t!=PL_STRING){
    nping_fatal(QT_3,"setPayloadType(): Invalid value supplied\n");
    return OP_FAILURE;
  }else{
    payload_type=t;
  }
  this->payload_type_set=true;
  return OP_SUCCESS;
} /* End of setPayloadType() */


/** Returns value of attribute payload_type */
int NpingOps::getPayloadType(){
  return payload_type;
} /* End of getPayloadType() */


/* Returns true if option has been set */
bool NpingOps::issetPayloadType(){
  return this->payload_type_set;
} /* End of issetPayloadType() */


/** Sets payload buffer pointer. Supplied pointer must be a free()able
 *  non-NULL pointer; Supplied length must be a positive integer.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setPayloadBuffer(u8 *p, int len){
  if( p==NULL || len < 0 ){
    nping_fatal(QT_3,"setPayloadBuffer(): Invalid value supplied\n");
    return OP_FAILURE;
  }else{
    this->payload_buff=p;
    this->payload_len=len;
  }
  this->payload_buff_set=true;
  this->payload_len_set=true;
  return OP_SUCCESS;
} /* End of setPayloadBuffer() */


/** Returns value of attribute payload_type */
u8 *NpingOps::getPayloadBuffer(){
  return this->payload_buff;
} /* End of getPayloadBuffer() */


/* Returns true if option has been set */
bool NpingOps::issetPayloadBuffer(){
  return this->payload_buff_set;
} /* End of issetPayloadBuffer() */


/** Returns value of attribute payload_len */
int NpingOps::getPayloadLen(){
  return this->payload_len;
} /* End of getPayloadLen() */


/* Returns true if option has been set */
bool NpingOps::issetPayloadLen(){
  return this->payload_len_set;
} /* End of issetPayloadLen() */


/******************************************************************************
 *  Roles (normal, client, server... )                                        *
 ******************************************************************************/

/** Sets nping's role. Supplied argument must be one of: ROLE_NORMAL,
 *  ROLE_CLIENT or ROLE_SERVER.
 *  @return previous value of attribute "role" or OP_FAILURE in case of error.
 *  */
int NpingOps::setRole(int r){
  int prev = this->role;
  if (r!=ROLE_NORMAL && r!=ROLE_CLIENT && r!=ROLE_SERVER){
    nping_warning(QT_2,"setRoleClient(): Invalid role supplied");
    return OP_FAILURE;
  }
  else
    this->role=r;
  this->role_set=true;
  return prev;
} /* End of setRole() */


/** Sets nping's role to ROLE_CLIENT.
 *  @return previous value of attribute "role".  */
int NpingOps::setRoleClient(){
  int prev = this->role;
  this->role=ROLE_CLIENT;
  this->role_set=true;
  return prev;
} /* End of setRoleClient() */


/** Sets nping's role to ROLE_SERVER.
 *  @return previous value of attribute "role". */
int NpingOps::setRoleServer(){
  int prev = this->role;
  this->role=ROLE_SERVER;
  this->role_set=true;
  return prev;
} /* End of setRoleServer() */


/** Sets nping's role to ROLE_NORMAL.
 *  @return previous value of attribute "role". */
int NpingOps::setRoleNormal(){
  int prev = this->role;
  this->role=ROLE_NORMAL;
  this->role_set=true;
  return prev;
} /* End of setRoleNormal() */

/* Returns nping role. */
int NpingOps::getRole(){
  return this->role;
} /* End of getRole() */


/* Returns true if option has been set */
bool NpingOps::issetRole(){
  return this->role_set;
} /* End of issetRole() */



/******************************************************************************
 * Internet Protocol  Version 4                                               *
 ******************************************************************************/

/** Sets IPv4 TTL / IPv6 hop limit. Supplied parameter must be an integer
 *  between 0 and 255 (included).
 *  @return OP_SUCCESS                                                       */
int NpingOps::setTTL(u8 t){
  this->ttl=t;
  this->ttl_set=true;
  return OP_SUCCESS;
} /* End of setTTL() */


/** Sets IPv4 TTL / IPv6 hop limit. This a wrapper for setTTL(). It is provided
 *  for consistency with IPv6 option setters.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setHopLimit(u8 t){
  return setTTL(t);
} /* End of setHopLimit() */


/** Returns value of attribute ttl */
u8 NpingOps::getTTL(){
  return ttl;
} /* End of getTTL() */


/** Returns value of attribute ttl */
u8 NpingOps::getHopLimit(){
  return getTTL();
} /* End of getHopLimit() */


/* Returns true if option has been set */
bool NpingOps::issetTTL(){
  return this->ttl_set;
} /* End of issetTTL() */


/* Returns true if option has been set */
bool NpingOps::issetHopLimit(){
  return issetTTL();
} /* End of issetHopLimit() */


/** Sets IP TOS. Supplied parameter must be 0<=n<=255
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setTOS(u8 val){
  this->tos=val;
  this->tos_set=true;
  return OP_SUCCESS;
} /* End of setTOS() */


/** Returns value of attribute TOS */
u8 NpingOps::getTOS(){
  return this->tos;
} /* End of getTOS() */


/* Returns true if option has been set */
bool NpingOps::issetTOS(){
  return this->tos_set;
} /* End of isset() */


/** Sets IP Identification. Supplied parameter must be 0<=n<=255
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setIdentification(u16 val){
  this->identification=val;
  this->identification_set=true;
  return OP_SUCCESS;
} /* End of setIdentification() */


/** Returns value of attribute Identification */
u16 NpingOps::getIdentification(){
  return this->identification;
} /* End of getIdentification() */


/* Returns true if option has been set */
bool NpingOps::issetIdentification(){
  return this->identification_set;
} /* End of issetIdentification() */


int NpingOps::setMF(){
  this->mf = true;
  this->mf_set=true;
  return OP_SUCCESS;
} /* End of setMF() */


/* Get MF flag */
bool NpingOps::getMF(){
  return this->mf;
} /* End of getMF() */


/** Set DF flag */
int NpingOps::setDF(){
  this->df = true;
  this->df_set=true;
  return OP_SUCCESS;
} /* End of setDF() */


/** Get DF flag */
bool NpingOps::getDF(){
  return this->df;
} /* End of getDF() */


/** Set Reserved / Evil flag */
int NpingOps::setRF(){
  this->rf = true;
  this->rf_set = true;
  return OP_SUCCESS;
} /* End of setRF() */


/** Get Reserved / Evil flag */
bool NpingOps::getRF(){
  return this->rf;
} /* End of getRF() */


/* Returns true if option has been set */
bool NpingOps::issetMF(){
  return this->mf_set;
} /* End of isset() */


/* Returns true if option has been set */
bool NpingOps::issetDF(){
  return this->df_set;
} /* End of isset() */


/* Returns true if option has been set */
bool NpingOps::issetRF(){
  return this->rf_set;
} /* End of isset() */


/** Sets Maximum Transmission Unit length. Supplied parameter must be a positive
 *  integer and must be a multiple of 8.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setMTU(u32 t){
  if(t==0 || (t%8)!=0){
    nping_fatal(QT_3,"setMTU(): Invalid mtu supplied\n");
  }else{
    this->mtu=t;
    this->mtu_set=true;
  }
  return OP_SUCCESS;
} /* End of setMTU() */


/** Returns value of attribute mtu */
u32 NpingOps::getMTU(){
  return this->mtu;
} /* End of getMTU() */


/* Returns true if option has been set */
bool NpingOps::issetMTU(){
  return this->mtu_set;
} /* End of issetMTU() */


/** Sets attribute badsum_ip to "true". (Generate invalid checksums in IP
 *  packets)
 *  @return previous value of the attribute. */
bool NpingOps::enableBadsumIP() {
  bool prev = this->badsum_ip;
  this->badsum_ip=true;
  this->badsum_ip_set=true;
  return prev;
} /* End of enableBadsumIP() */


/** Sets attribute badsum_ip to "false". (Do NOT Generate invalid checksums
 *  in IP packets)
 *  @return previous value of the attribute. */
bool NpingOps::disableBadsumIP() {
   bool prev = badsum_ip;
   badsum_ip=false;
   this->badsum_ip_set=true;
   return prev;
} /* End of disableBadsumIP() */


/** Returns value of attribute badsum_ip */
bool NpingOps::getBadsumIP() {
   return this->badsum_ip;
} /* End of getBadsumIP() */


/* Returns true if option has been set */
bool NpingOps::issetBadsumIP(){
  return this->badsum_ip_set;
} /* End of issetBadsumIP() */


/** @warning Supplied parameter must be in NETWORK byte order */
int NpingOps::setIPv4SourceAddress(struct in_addr i){
  this->ipv4_src_address=i;
  this->ipv4_src_address_set=true;
  return OP_SUCCESS;
} /* End of setIPv4SourceAddress() */


struct in_addr NpingOps::getIPv4SourceAddress(){
  return ipv4_src_address;
} /* End of getIPv4SourceAddress() */


/* Returns true if option has been set */
bool NpingOps::issetIPv4SourceAddress(){
  return this->ipv4_src_address_set;
} /* End of issetIPv4SourceAddress() */


/** @warning  This method makes a copy of the supplied buffer. That copy will
 *  be free()ed by the NpingOps destructor.                                  */
int NpingOps::setIPOptions(char *txt){
  if (txt==NULL)
    nping_fatal(QT_3,"setIPOptions(): NULL pointer supplied\n");
  this->ip_options=strdup(txt) ;
  this->ip_options_set=true;
  return OP_SUCCESS;
} /* End of setIPOptions() */


char *NpingOps::getIPOptions(){
  return this->ip_options;
} /* End of getIPOptions() */


bool NpingOps::issetIPOptions(){
  return this->ip_options_set;
} /* End of issetIPOptions() */


/******************************************************************************
 * Internet Protocol  Version 6                                               *
 ******************************************************************************/
/** Sets TrafficClass.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setTrafficClass(u8 val){
  this->ipv6_tclass=val;
  this->ipv6_tclass_set=true;
  return OP_SUCCESS;
} /* End of setTrafficClass() */


/** Returns value of attribute ipv6_tclass */
u8 NpingOps::getTrafficClass(){
  return this->ipv6_tclass;
} /* End of getTrafficClass() */


/* Returns true if option has been set */
bool NpingOps::issetTrafficClass(){
  return this->ipv6_tclass_set;
} /* End of issetTrafficClass() */


/** Sets FlowLabel.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setFlowLabel(u32 val){
  this->ipv6_flowlabel=val;
  this->ipv6_flowlabel_set=true;
  return OP_SUCCESS;
} /* End of setFlowLabel() */


/** Returns value of attribute ipv6_flowlabel */
u32 NpingOps::getFlowLabel(){
  return this->ipv6_flowlabel;
} /* End of getFlowLabel() */


/* Returns true if option has been set */
bool NpingOps::issetFlowLabel(){
  return this->ipv6_flowlabel_set;
} /* End of issetFlowLabel() */



int NpingOps::setIPv6SourceAddress(u8 *val){
  if(val==NULL)
    nping_fatal(QT_3,"setIPv6SourceAddress(): NULL pointer supplied\n");
  memcpy(this->ipv6_src_address.s6_addr, val, 16);
  this->ipv6_src_address_set=true;
  return OP_SUCCESS;
} /* End of setIPv6SourceAddress() */


int NpingOps::setIPv6SourceAddress(struct in6_addr val){
  this->ipv6_src_address = val;
  this->ipv6_src_address_set=true;
  return OP_SUCCESS;
} /* End of setIPv6SourceAddress() */


struct in6_addr NpingOps::getIPv6SourceAddress(){
  return ipv6_src_address;
} /* End of getIPv6SourceAddress() */


/* Returns true if option has been set */
bool NpingOps::issetIPv6SourceAddress(){
  return this->ipv6_src_address_set;
} /* End of issetIPv6SourceAddress() */


/* Returns a pointer to a sockaddr_storage structure that contains the
 * source IP address. This function takes into account this->getIPVersion()
 * an returns an IPv4 sockaddr_in or an IPv6 sockaddr_in6 struct.  */
struct sockaddr_storage *NpingOps::getSourceSockAddr(){
  static struct sockaddr_storage ss;
  return getSourceSockAddr(&ss);
} /* End of getSourceSockAddr() */


/* Returns a pointer to the supplied sockaddr_storage structure that now
 * contains the source IP address. This function takes into account
 * this->getIPVersion() an returns an IPv4 sockaddr_in or an IPv6
 * sockaddr_in6 struct.  */
struct sockaddr_storage *NpingOps::getSourceSockAddr(struct sockaddr_storage *ss){
  struct sockaddr_in *s4 = (struct sockaddr_in*)ss;
  struct sockaddr_in6 *s6 = (struct sockaddr_in6*)ss;
  memset(ss, 0, sizeof(struct sockaddr_storage));
  if( this->getIPVersion() == IP_VERSION_4){
    if(this->spoofSource())
        s4->sin_addr=getIPv4SourceAddress();
    else
        s4->sin_addr.s_addr=INADDR_ANY;
    s4->sin_family=AF_INET;
    if(this->issetSourcePort())
        s4->sin_port=htons(this->getSourcePort());
    else
        s4->sin_port=0;
  }
  else if (this->getIPVersion() == IP_VERSION_6){
    if(this->spoofSource())
        s6->sin6_addr=this->getIPv6SourceAddress();
    else
        s6->sin6_addr=in6addr_any;
    s6->sin6_family=AF_INET6;
    if(this->issetSourcePort())
        s6->sin6_port=htons(this->getSourcePort());
    else
        s6->sin6_port=0;
  }else{
    nping_fatal(QT_3, "NpingOps::getSourceSockAddr(): IP version unset.");
  }
  return ss;
} /* End of getSourceSockAddr() */



/******************************************************************************
 * Transmission Control Protocol and User Datagram Protocol                   *
 ******************************************************************************/

/** @warning Returned ports are in HOST byte order */
u16 *NpingOps::getTargetPorts( int *len ){
  if( this->tportcount <= 0)
    return NULL;
  if(len!=NULL)
    *len=this->tportcount;
  return this->target_ports;
} /* End of getTargetPorts() */


/** @warning ports in the supplied array must be in HOST byte order */
int NpingOps::setTargetPorts( u16 *pnt, int n ){
  if(this->tportcount>65536 || this->tportcount<0)
    nping_fatal(QT_3, "setTargetPorts():: Invalid number of ports supplied.");
  this->target_ports=pnt;
  this->tportcount=n;
  this->target_ports_set=true;
  return OP_SUCCESS;
} /* End of setTargetPorts() */


/* Returns true if option has been set */
bool NpingOps::issetTargetPorts(){
  return this->target_ports_set;
} /* End of issetTargetPorts() */

/*Returns true if the scan type can use the -p option*/
bool NpingOps::scan_mode_uses_target_ports(int mode){
    return (mode==TCP_CONNECT || mode==TCP || mode == UDP || mode == UDP_UNPRIV);
} /*End of scan_mode_uses_target_ports*/

/** Sets TCP/UPD source port. Supplied parameter must be an integer >=0 &&
 * <=65535
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setSourcePort(u16 val){
  this->source_port=val;
  this->source_port_set=true;
  return OP_SUCCESS;
} /* End of setSourcePort() */


/** Returns value of attribute source_port */
u16 NpingOps::getSourcePort(){
  return this->source_port;
} /* End of getSourcePort() */


/* Returns true if option has been set */
bool NpingOps::issetSourcePort(){
  return this->source_port_set;
} /* End of issetSourcePort() */


/** Sets TCP Seq number. Supplied parameter must be a positive integer between
 *  0 and 2^32 -1
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setTCPSequence(u32 val){
  this->tcpseq=val;
  this->tcpseq_set=true;
  return OP_SUCCESS;
} /* End of setTCPSequence() */


/** Returns value of attribute tcpseq */
u32 NpingOps::getTCPSequence(){
  return this->tcpseq;
} /* End of getTCPSequence() */


/** Returns true if option has been set */
bool NpingOps::issetTCPSequence(){
  return this->tcpseq_set;
} /* End of issetTCPSequence() */


/** Sets TCP Ack. Supplied parameter must be a positive integer between 0 and
 *  2^32 -1
 *  @return OP_SUCCESS                                                       */
int NpingOps::setTCPAck(u32 val){
  this->tcpack=val;
  this->tcpack_set=true;
  return OP_SUCCESS;
} /* End of setTCPAck() */


/** Returns value of attribute tcpack */
u32 NpingOps::getTCPAck(){
  return this->tcpack;
} /* End of getTCPAck() */


/** Returns true if option has been set */
bool NpingOps::issetTCPAck(){
  return this->tcpack_set;
} /* End of issetTCPAck() */


int NpingOps::setFlagTCP(int flag){
  if (flag < FLAG_CWR || flag > FLAG_FIN)
    nping_fatal(QT_3,"setFlagTCP(): Invalid flag supplied\n");
  else
    this->tcpflags[flag]=1;
  this->tcpflags_set=true;
  return OP_SUCCESS;
} /* End of setFlagTCP() */


int NpingOps::setAllFlagsTCP(){
  for(int i=FLAG_CWR; i<=FLAG_FIN; i++)
    this->tcpflags[i]=1;
  this->tcpflags_set=true;
  return OP_SUCCESS;
} /* End of setFlagTCP() */


int NpingOps::unsetAllFlagsTCP(){
  for(int i=FLAG_CWR; i<=FLAG_FIN; i++)
    this->tcpflags[i]=0;
  this->tcpflags_set=true;
  return OP_SUCCESS;
} /* End of setFlagTCP() */


int NpingOps::getFlagTCP(int flag){
  if (flag < FLAG_CWR || flag > FLAG_FIN)
    nping_fatal(QT_3,"setFlagTCP(): Invalid flag supplied\n");
  return this->tcpflags[flag];
} /* End of getFlagTCP() */


u8 NpingOps::getTCPFlags(){
 u8 octet=0x00;
  if(this->getFlagTCP(FLAG_CWR))
    octet |= TH_CWR;
  if(this->getFlagTCP(FLAG_ECN))
    octet |= TH_ECN;
  if(this->getFlagTCP(FLAG_URG))
    octet |= TH_URG;
  if(this->getFlagTCP(FLAG_ACK))
    octet |= TH_ACK;
  if(this->getFlagTCP(FLAG_PSH))
    octet |= TH_PSH;
  if(this->getFlagTCP(FLAG_RST))
    octet |= TH_RST;
  if(this->getFlagTCP(FLAG_SYN))
    octet |= TH_SYN;
  if(this->getFlagTCP(FLAG_FIN))
    octet |= TH_FIN;
 return octet;
} /* End of getTCPFlags() */


/* Returns true if option has been set */
bool NpingOps::issetTCPFlags(){
  return this->tcpflags_set;
} /* End of isset() */


/** Sets TCP Window. Supplied parameter must be a positive integer between 0 and
 *  2^32 -1
 *  @return OP_SUCCESS                                                       */
int NpingOps::setTCPWindow(u16 val){
  this->tcpwin=val;
  this->tcpwin_set=true;
  return OP_SUCCESS;
} /* End of setTCPWindow() */


/** Returns value of attribute tcpwin */
u16 NpingOps::getTCPWindow(){
  return this->tcpwin;
} /* End of getTCPWindow() */


/** Returns true if option has been set */
bool NpingOps::issetTCPWindow(){
  return this->tcpwin_set;
} /* End of issetTCPWindow() */


/** Sets attribute badsum to "true". (Generate invalid checksums in UDP / TCP
 *  packets)
 *  @return previous value of the attribute. */
bool NpingOps::enableBadsum() {
  bool prev = this->badsum;
  this->badsum=true;
  this->badsum_set=true;
  return prev;
} /* End of enableBadsumTCP() */


/** Sets attribute traceroute to "false". (Do NOT Generate invalid checksums
 *  in UDP / TCP packets)
 *  @return previous value of the attribute. */
bool NpingOps::disableBadsum() {
  bool prev = this->badsum;
  this->badsum=false;
  this->badsum_set=true;
  return prev;
} /* End of disableBadsum() */


/** Returns value of attribute badsum */
bool NpingOps::getBadsum() {
  return this->badsum;
} /* End of getBadsum() */


/* Returns true if option has been set */
bool NpingOps::issetBadsum(){
  return this->badsum_set;
} /* End of issetBadsum() */



/******************************************************************************
 *  Internet Control Message Protocol                                         *
 ******************************************************************************/
/** Sets ICMPType.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPType(u8 val){
  this->icmp_type=val;
  this->icmp_type_set=true;
  return OP_SUCCESS;
} /* End of setICMPType() */


/** Returns value of attribute icmp_type */
u8 NpingOps::getICMPType(){
  return this->icmp_type;
} /* End of getICMPType() */


/* Returns true if option has been set */
bool NpingOps::issetICMPType(){
  return this->icmp_type_set;
} /* End of issetICMPType() */


/** Sets ICMPCode.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPCode(u8 val){
  this->icmp_code=val;
  this->icmp_code_set=true;
  return OP_SUCCESS;
} /* End of setICMPCode() */


/** Returns value of attribute icmp_code */
u8 NpingOps::getICMPCode(){
  return this->icmp_code;
} /* End of getICMPCode() */


/* Returns true if option has been set */
bool NpingOps::issetICMPCode(){
  return this->icmp_code_set;
} /* End of issetICMPCode() */


/** Sets attribute badsum_icmp to "true". (Generate invalid checksums in ICMP
 *  packets)
 *  @return previous value of the attribute. */
bool NpingOps::enableBadsumICMP() {
  bool prev = this->badsum_icmp;
  this->badsum_icmp=true;
  this->badsum_icmp_set=true;
  return prev;
} /* End of enableBadsumICMPTCP() */


/** Sets attribute traceroute to "false". (Do NOT Generate invalid checksums
 *  in UDP / TCP packets)
 *  @return previous value of the attribute. */
bool NpingOps::disableBadsumICMP() {
  bool prev = this->badsum_icmp;
  this->badsum_icmp=false;
  this->badsum_icmp_set=true;
  return prev;
} /* End of disableBadsumICMP() */


/** Returns value of attribute badsum_icmp */
bool NpingOps::getBadsumICMP() {
  return this->badsum_icmp;
} /* End of getBadsumICMP() */


/* Returns true if option has been set */
bool NpingOps::issetBadsumICMP(){
  return this->badsum_icmp_set;
} /* End of issetBadsumICMP() */


/** Sets ICMPRedirectAddress.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPRedirectAddress(struct in_addr val){
  this->icmp_redir_addr=val;
  this->icmp_redir_addr_set=true;
  return OP_SUCCESS;
} /* End of setICMPRedirectAddress() */


/** Returns value of attribute icmp_redir_addr */
struct in_addr NpingOps::getICMPRedirectAddress(){
  return this->icmp_redir_addr;
} /* End of getICMPRedirectAddress() */


/* Returns true if option has been set */
bool NpingOps::issetICMPRedirectAddress(){
  return this->icmp_redir_addr_set;
} /* End of issetICMPRedirectAddress() */


/** Sets ICMPParamProblemPointer.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPParamProblemPointer(u8 val){
  this->icmp_paramprob_pnt=val;
  this->icmp_paramprob_pnt_set=true;
  return OP_SUCCESS;
} /* End of setICMPParamProblemPointer() */


/** Returns value of attribute icmp_paramprob_pnt */
u8 NpingOps::getICMPParamProblemPointer(){
  return this->icmp_paramprob_pnt;
} /* End of getICMPParamProblemPointer() */


/* Returns true if option has been set */
bool NpingOps::issetICMPParamProblemPointer(){
  return this->icmp_paramprob_pnt_set;
} /* End of issetICMPParamProblemPointer() */


/** Sets ICMPRouterAdvLifetime.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPRouterAdvLifetime(u16 val){
  this->icmp_routeadv_ltime=val;
  this->icmp_routeadv_ltime_set=true;
  return OP_SUCCESS;
} /* End of setICMPRouterAdvLifetime() */


/** Returns value of attribute icmp_routeadv_ltime */
u16 NpingOps::getICMPRouterAdvLifetime(){
  return this->icmp_routeadv_ltime;
} /* End of getICMPRouterAdvLifetime() */


/* Returns true if option has been set */
bool NpingOps::issetICMPRouterAdvLifetime(){
  return this->icmp_routeadv_ltime_set;
} /* End of issetICMPRouterAdvLifetime() */


/** Sets ICMPIdentifier.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPIdentifier(u16 val){
  this->icmp_id=val;
  this->icmp_id_set=true;
  return OP_SUCCESS;
} /* End of setICMPIdentifier() */

/** Returns value of attribute icmp_id */
u16 NpingOps::getICMPIdentifier(){
  return this->icmp_id;
} /* End of getICMPIdentifier() */


/* Returns true if option has been set */
bool NpingOps::issetICMPIdentifier(){
  return this->icmp_id_set;
} /* End of issetICMPIdentifier() */


/** Sets ICMPSequence.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPSequence(u16 val){
  this->icmp_seq=val;
  this->icmp_seq_set=true;
  return OP_SUCCESS;
} /* End of setICMPSequence() */


/** Returns value of attribute icmp_seq */
u16 NpingOps::getICMPSequence(){
  return this->icmp_seq;
} /* End of getICMPSequence() */


/* Returns true if option has been set */
bool NpingOps::issetICMPSequence(){
  return this->icmp_seq_set;
} /* End of issetICMPSequence() */


/** Sets ICMPOriginateTimestamp.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPOriginateTimestamp(u32 val){
  this->icmp_orig_time=val;
  this->icmp_orig_time_set=true;
  return OP_SUCCESS;
} /* End of setICMPOriginateTimestamp() */


/** Returns value of attribute icmp_orig_time */
u32 NpingOps::getICMPOriginateTimestamp(){
  return this->icmp_orig_time;
} /* End of getICMPOriginateTimestamp() */


/* Returns true if option has been set */
bool NpingOps::issetICMPOriginateTimestamp(){
  return this->icmp_orig_time_set;
} /* End of issetICMPOriginateTimestamp() */


/** Sets ICMPReceiveTimestamp.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPReceiveTimestamp(u32 val){
  this->icmp_recv_time=val;
  this->icmp_recv_time_set=true;
  return OP_SUCCESS;
} /* End of setICMPReceiveTimestamp() */


/** Returns value of attribute icmp_recv_time */
u32 NpingOps::getICMPReceiveTimestamp(){
  return this->icmp_recv_time;
} /* End of getICMPReceiveTimestamp() */


/* Returns true if option has been set */
bool NpingOps::issetICMPReceiveTimestamp(){
  return this->icmp_recv_time_set;
} /* End of issetICMPReceiveTimestamp() */


/** Sets ICMPTransmitTimestamp.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setICMPTransmitTimestamp(u32 val){
  this->icmp_trans_time=val;
  this->icmp_trans_time_set=true;
  return OP_SUCCESS;
} /* End of setICMPTransmitTimestamp() */


/** Returns value of attribute icmp_trans_time */
u32 NpingOps::getICMPTransmitTimestamp(){
  return this->icmp_trans_time;
} /* End of getICMPTransmitTimestamp() */


/* Returns true if option has been set */
bool NpingOps::issetICMPTransmitTimestamp(){
  return this->icmp_trans_time_set;
} /* End of issetICMPTransmitTimestamp() */


int NpingOps::addICMPAdvertEntry(struct in_addr addr, u32 pref ){
  if( this->icmp_advert_entry_count >= MAX_ICMP_ADVERT_ENTRIES )
    return OP_FAILURE;
  this->icmp_advert_entry_addr[this->icmp_advert_entry_count] = addr;
  this->icmp_advert_entry_pref[this->icmp_advert_entry_count] = pref;
  this->icmp_advert_entry_count++;
  this->icmp_advert_entry_set=true;
  return OP_SUCCESS;
} /* End of addICMPAdvertEntry() */


/** @param num means that the caller wants to obtain the num-th entry.
 *  Count starts in 0 so the supplied value must be
 *  0 <= num < getICMPAdvertEntryCount() */
int NpingOps::getICMPAdvertEntry(int num, struct in_addr *addr, u32 *pref){
  if( num<0 || num>=icmp_advert_entry_count )
    nping_fatal(QT_3,"getICMPAdvertEntry(): Supplied index is out of bounds.\n");
  if( addr==NULL || pref==NULL)
    nping_fatal(QT_3,"getICMPAdvertEntry(): NULL pointer supplied\n");
  *addr =  this->icmp_advert_entry_addr[num];
  *pref =  this->icmp_advert_entry_pref[num];
  return OP_SUCCESS;
} /* End of getICMPAdvertEntry() */


int NpingOps::getICMPAdvertEntryCount(){
  return this->icmp_advert_entry_count;
} /* End of getICMPAdvertEntryCount()*/

bool NpingOps::issetICMPAdvertEntry(){
  return this->icmp_advert_entry_set;
} /* End of issetICMPAdvertEntry()*/



/******************************************************************************
 *  Ethernet                                                                  *
 ******************************************************************************/
/** Sets SourceMAC.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setSourceMAC(u8 * val){
  memcpy(this->src_mac, val, 6);
  this->src_mac_set=true;
  return OP_SUCCESS;
} /* End of setSourceMAC() */


/** Returns value of attribute src_mac */
u8 * NpingOps::getSourceMAC(){
  return this->src_mac;
} /* End of getSourceMAC() */


/* Returns true if option has been set */
bool NpingOps::issetSourceMAC(){
  return this->src_mac_set;
} /* End of issetSourceMAC() */


/** Sets DestMAC.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setDestMAC(u8 * val){
  memcpy(this->dst_mac, val, 6);
  this->dst_mac_set=true;
  return OP_SUCCESS;
} /* End of setDestMAC() */


/** Returns value of attribute dst_mac */
u8 * NpingOps::getDestMAC(){
  return this->dst_mac;
} /* End of getDestMAC() */


/* Returns true if option has been set */
bool NpingOps::issetDestMAC(){
  return this->dst_mac_set;
} /* End of issetDestMAC() */

/** Sets EtherType.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setEtherType(u16 val){
  this->eth_type=val;
  this->eth_type_set=true;
  return OP_SUCCESS;
} /* End of setEtherType() */


/** Returns value of attribute eth_type */
u16 NpingOps::getEtherType(){
  return this->eth_type;
} /* End of getEtherType() */


/* Returns true if option has been set */
bool NpingOps::issetEtherType(){
  return this->eth_type_set;
} /* End of issetEtherType() */



/******************************************************************************
 *  Address Resolution Protocol / Reverse Address Resolution Protocol         *
 ******************************************************************************/
/** Sets ARPHardwareType.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPHardwareType(u16 val){
  this->arp_htype=val;
  this->arp_htype_set=true;
  return OP_SUCCESS;
} /* End of setARPHardwareType() */


/** Returns value of attribute arp_htype */
u16 NpingOps::getARPHardwareType(){
  return this->arp_htype;
} /* End of getARPHardwareType() */


/* Returns true if option has been set */
bool NpingOps::issetARPHardwareType(){
  return this->arp_htype_set;
} /* End of issetARPHardwareType() */


/** Sets ARPProtocolType.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPProtocolType(u16 val){
  this->arp_ptype=val;
  this->arp_ptype_set=true;
  return OP_SUCCESS;
} /* End of setARPProtocolType() */


/** Returns value of attribute arp_ptype */
u16 NpingOps::getARPProtocolType(){
  return this->arp_ptype;
} /* End of getARPProtocolType() */


/* Returns true if option has been set */
bool NpingOps::issetARPProtocolType(){
  return this->arp_ptype_set;
} /* End of issetARPProtocolType() */


/** Sets ARPHwAddrLen.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPHwAddrLen(u8 val){
  this->arp_hlen=val;
  this->arp_hlen_set=true;
  return OP_SUCCESS;
} /* End of setARPHwAddrLen() */


/** Returns value of attribute arp_hlen */
u8 NpingOps::getARPHwAddrLen(){
  return this->arp_hlen;
} /* End of getARPHwAddrLen() */


/* Returns true if option has been set */
bool NpingOps::issetARPHwAddrLen(){
  return this->arp_hlen_set;
} /* End of issetARPHwAddrLen() */


/** Sets ARPProtoAddrLen.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPProtoAddrLen(u8 val){
  this->arp_plen=val;
  this->arp_plen_set=true;
  return OP_SUCCESS;
} /* End of setARPProtoAddrLen() */


/** Returns value of attribute arp_plen */
u8 NpingOps::getARPProtoAddrLen(){
  return this->arp_plen;
} /* End of getARPProtoAddrLen() */


/* Returns true if option has been set */
bool NpingOps::issetARPProtoAddrLen(){
  return this->arp_plen_set;
} /* End of issetARPProtoAddrLen() */


/** Sets ARPOpCode.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPOpCode(u16 val){
  this->arp_opcode=val;
  this->arp_opcode_set=true;
  return OP_SUCCESS;
} /* End of setARPOpCode() */


/** Returns value of attribute arp_opcode */
u16 NpingOps::getARPOpCode(){
  return this->arp_opcode;
} /* End of getARPOpCode() */


/* Returns true if option has been set */
bool NpingOps::issetARPOpCode(){
  return this->arp_opcode_set;
} /* End of issetARPOpCode() */


/** Sets ARPSenderHwAddr.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPSenderHwAddr(u8 * val){
  memcpy(this->arp_sha, val, 6); /* MAC Address (6 bytes) */
  this->arp_sha_set=true;
  return OP_SUCCESS;
} /* End of setARPSenderHwAddr() */


/** Returns value of attribute arp_sha */
u8 * NpingOps::getARPSenderHwAddr(){
  return this->arp_sha;
} /* End of getARPSenderHwAddr() */


/* Returns true if option has been set */
bool NpingOps::issetARPSenderHwAddr(){
  return this->arp_sha_set;
} /* End of issetARPSenderHwAddr() */


/** Sets ARPTargetHwAddr.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPTargetHwAddr(u8 * val){
  memcpy(this->arp_tha, val, 6); /* MAC Address (6 bytes) */
  this->arp_tha_set=true;
  return OP_SUCCESS;
} /* End of setARPTargetHwAddr() */


/** Returns value of attribute arp_tha */
u8 * NpingOps::getARPTargetHwAddr(){
  return this->arp_tha;
} /* End of getARPTargetHwAddr() */


/* Returns true if option has been set */
bool NpingOps::issetARPTargetHwAddr(){
  return this->arp_tha_set;
} /* End of issetARPTargetHwAddr() */


/** Sets ARPSenderProtoAddr.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPSenderProtoAddr(struct in_addr val){
  this->arp_spa=val;
  this->arp_spa_set=true;
  return OP_SUCCESS;
} /* End of setARPSenderProtoAddr() */


/** Returns value of attribute arp_spa */
struct in_addr NpingOps::getARPSenderProtoAddr(){
  return this->arp_spa;
} /* End of getARPSenderProtoAddr() */


/* Returns true if option has been set */
bool NpingOps::issetARPSenderProtoAddr(){
  return this->arp_spa_set;
} /* End of issetARPSenderProtoAddr() */


/** Sets ARPTargetProtoAddr.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setARPTargetProtoAddr(struct in_addr val){
  this->arp_tpa=val;
  this->arp_tpa_set=true;
  return OP_SUCCESS;
} /* End of setARPTargetProtoAddr() */


/** Returns value of attribute arp_tpa */
struct in_addr NpingOps::getARPTargetProtoAddr(){
  return this->arp_tpa;
} /* End of getARPTargetProtoAddr() */


/* Returns true if option has been set */
bool NpingOps::issetARPTargetProtoAddr(){
  return this->arp_tpa_set;
} /* End of issetARPTargetProtoAddr() */


/** Sets EchoPort.
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
int NpingOps::setEchoPort(u16 val){
  this->echo_port=val;
  this->echo_port_set=true;
  return OP_SUCCESS;
} /* End of setEchoPort() */


/** Returns value of attribute echo_port */
u16 NpingOps::getEchoPort(){
  return this->echo_port;
} /* End of getEchoPort() */


/* Returns true if option has been set */
bool NpingOps::issetEchoPort(){
  return this->echo_port_set;
} /* End of issetEchoPort() */


int NpingOps::setEchoPassphrase(const char *str){
  strncpy(this->echo_passphrase, str, sizeof(echo_passphrase)-1);
  this->echo_passphrase_set=true;
  return OP_SUCCESS;
} /* End of setEchoPassphrase() */


char *NpingOps::getEchoPassphrase(){
  return this->echo_passphrase;
} /* End of getEchoPassphrase() */


bool NpingOps::issetEchoPassphrase(){
  return this->echo_passphrase_set;
} /* End of issetEchoPassphrase() */

/** Sets value of this->echo_server_once. When true, the echo server
  * will exit after attending one client. */
int NpingOps::setOnce(bool val){
  this->echo_server_once=val;
  this->echo_server_once_set=true;
  return OP_SUCCESS;
} /* End of once() */


/** Returns value of attribute echo_port */
bool NpingOps::once(){
  return this->echo_server_once;
} /* End of once() */


/******************************************************************************
 *  Option Validation                                                         *
 ******************************************************************************/

void NpingOps::validateOptions() {

/** DETERMINE ROOT PRIVILEGES ************************************************/
const char *privreq = "root privileges";
#ifdef WIN32
    //if (!this->have_pcap)
          privreq = "Npcap, but it seems to be missing.\n\
Npcap is available from https://npcap.com. The Npcap driver service must\n\
be started by an administrator before Npcap can be used. Running nping.exe\n\
will open a UAC dialog where you can start the service if you have\n\
administrator privileges.";
#endif

if (this->havePcap()==false){
    #ifdef WIN32
        nping_fatal(QT_3, "Nping requires %s", privreq);
    #else
        nping_fatal(QT_3, "Nping requires libpcap to be installed on your system.");
    #endif
}


/** ROLE SELECTION ***********************************************************/
  /* Ensure that at least one role is selected */
  if ( !this->issetRole() ) {
      this->setRoleNormal();
  }

/** TARGET SPECIFICATION *****************************************************/
  /* Check if user entered at least one target spec */
  if( this->getRole() == ROLE_NORMAL ){
    if ( this->targets.getTargetSpecCount() <= 0 )
        nping_fatal(QT_3,"WARNING: No targets were specified, so 0 hosts pinged.");
  }else if( this->getRole() == ROLE_CLIENT ){
    if ( this->targets.getTargetSpecCount() <= 0 )
        nping_fatal(QT_3,"No echo server was specified.");
  }

/** IP VERSION ***************************************************************/
  /* Default to IP version 4 */
  if( !this->issetIPVersion() )
    this->setIPVersion( IP_VERSION_4 );


/** PROBE MODE SELECTION *****************************************************/
  /* Ensure that one probe mode is selected */
  if( !this->issetMode() ){
      if ( this->isRoot() ){
        if( !this->ipv6() )
            this->setMode(ICMP);
        else
            this->setMode(TCP);
      }
      else
        this->setMode(TCP_CONNECT);
  }

/** PACKET COUNT / ROUNDS ****************************************************/
  if( !this->issetPacketCount() ){
      /* If --traceroute is set, the packet count is higher */
      if(this->issetTraceroute() )
          this->setPacketCount( TRACEROUTE_PACKET_COUNT );
      else
          this->setPacketCount( DEFAULT_PACKET_COUNT );
  }


  if( !this->issetDelay() )
    this->setDelay( DEFAULT_DELAY );

/** UDP UNPRIVILEGED MODE? ***************************************************/
  /* If user is NOT root and specified UDP mode, check if he did not specify
   * any option that requires privileges. In that case, we enter
   * UDP-Unprivileged mode, where users can send UDP packets and read responses
   * trough a normal UDP socket.  */
  if( !this->isRoot() && this->getMode()==UDP && canRunUDPWithoutPrivileges() )
    this->setMode( UDP_UNPRIV );

/** CHECK PRIVILEGES FOR CURRENT ROLE ****************************************/
  if( !this->isRoot() && (this->getRole()==ROLE_SERVER || this->getRole()==ROLE_CLIENT) )
    nping_fatal(QT_3,"Echo mode requires %s.", privreq);

/** CHECK PRIVILEGES FOR CURRENT MODE ****************************************/
  if( !this->isRoot() && this->getMode()!=UDP_UNPRIV && this->getMode()!=TCP_CONNECT )
    nping_fatal(QT_3,"Mode %s requires %s.", this->mode2Ascii( this->getMode() ), privreq);


/** DEFAULT HEADER PARAMETERS *************************************************/
  this->setDefaultHeaderValues();

/** ARP MODE RELATED PARAMETERS *********************************************/
  if(this->getMode()==ARP && this->ipv6()) {
    nping_fatal(QT_3, "Sorry, ARP does not support IPv6 and Nping does not yet support NDP.");
  }

/** TCP CONNECT RELATED PARAMETERS *********************************************/
  if(this->getMode()==TCP_CONNECT) {
      if(this->issetPayloadBuffer())
        nping_print(VB_0, "Warning: Payload supplied in TCP Connect mode. Payload will be ignored.");
  }

/** SOURCE IP, SOURCE MAC and NETWORK DEVICE *********************************/
/* If we are in a mode where we need to craft IP packets, then we need to
 * obtain a network interface name and a source IP address. There are three
 * different possibilities:
 *  1. User did NOT specify both network interface and source IP address.
 *  2. User did specify a network interface but not a source IP address.
 *  3. User did actually supply a source IP but not a network interface name
 *
 * I know the following code is ugly but the thing is that we want to determine
 * interface and source IP without user intervention, so we try in many ways
 * until either we succeed or we run out of possibilities and fatal().
 */
if( this->getMode()!=TCP_CONNECT && this->getMode()!=UDP_UNPRIV && this->getRole()!=ROLE_SERVER){

    char devbuff[32];
    char *dev;
    struct sockaddr_storage ss, ifaddr;
    struct sockaddr_in *s4=(struct sockaddr_in *)&ifaddr;
    struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&ifaddr;
    size_t ss_len;
    char hostname[128];
    memset(&ss, 0, sizeof(struct sockaddr_storage));
    memset(&ifaddr, 0, sizeof(struct sockaddr_storage));


   /* CASE 1: User did not specify a device so we have to select one. */
    if( !this->issetDevice() ){
        if( this->ipv4() ){
            /* Ugly hack. Get the first resolvable target and determine net interface. Let's
             * hope user did not specify something that mixes localhost with
             * other targets, like "nping localhost google.com playboy.com" */
             for(int z=0; z<this->targets.getTargetSpecCount(); z++){
                if( this->targets.getNextTargetAddressAndName(&ss, &ss_len, hostname, sizeof(hostname)) == OP_SUCCESS )
                    break;
                else if( z>=(this->targets.getTargetSpecCount()-1) )
                    nping_fatal(QT_3,"Cannot find a valid target. Please make sure the specified hosts are either IP addresses in standard notation or hostnames that can be resolved with DNS");
             }
             this->targets.rewind();

             /* Try to obtain a device name from the target IP */
             if ( getNetworkInterfaceName( &ss , devbuff) != OP_SUCCESS ) {
                /* If that didn't work, ask libpcap */
                if ( (dev = this->select_network_iface()) == NULL)
                    nping_fatal(QT_3, "Cannot obtain device for packet capture");
                else
                    this->setDevice( dev );
                /* Libpcap gave us a device name, try to obtain it's IP */
                if ( devname2ipaddr(this->getDevice(), this->af(), &ifaddr) != 0 ){
                    if( this->isRoot() )
                        nping_fatal(QT_3,"Cannot figure out what source address to use for device %s, does it even exist?", this->getDevice());
                    else
                        nping_fatal(QT_3,"Cannot figure out what source address to use for device %s, are you root?", this->getDevice());
                }
                else{
                    if( s4->sin_family==AF_INET )
                        this->setIPv4SourceAddress(s4->sin_addr);
                    else if ( s6->sin6_family==AF_INET6 )
                        this->setIPv6SourceAddress(s6->sin6_addr.s6_addr);
                }
            }else{
                this->setDevice(devbuff);
            }
        }else{ /* In IPv6 we just select one in libpcap and hope is the right one */
            char *selected_iface=this->select_network_iface();
            if(selected_iface==NULL)
                nping_fatal(QT_3, "Error trying to find a suitable network interface ");
            else
                this->setDevice( selected_iface );
        }
    } /* CASE 2: User did actually supply a device name */
    else{
        nping_print(DBG_2, "Using network interface \"%s\"", this->getDevice() );
    }

/* The echo server needs to find out a network interface*/
}else if (this->getRole()==ROLE_SERVER && this->issetDevice()==false){
  char *selected_iface=this->select_network_iface();
  if(selected_iface==NULL)
    nping_fatal(QT_3, "Error trying to find a suitable network interface ");
  else
    this->setDevice( selected_iface );
  nping_print(DBG_2, "Using network interface \"%s\"", this->getDevice() );
}

/** RAW IP AND RAW ETHERNET TRANSMISSION MODES *******************************/
/* Determine if we need to send at raw ip level or at raw ethernet level */
if(this->getRole()!=ROLE_SERVER){
 if (!this->issetSendPreference()) {


    /* CASE 1: ARP requested. We have to do raw ethernet transmission */
    if(this->getMode()==ARP ){
        this->setSendEth(true);
        this->setSendPreference( PACKET_SEND_ETH_STRONG );
    }

    /* CASE 2: If we are dealing with IPv6 we have two options: send at raw
     * eth level or sent at raw transport layer level. So here, we check if the
     * user has specified some IPv6 header specific options. If he has, we then
     * have to use raw ethernet (since we cannot include our own IPv6 header in
     * raw IPv6 sockets). If he hasn't, the best way is to send at raw TCP/UDP
     * level so we disable sendEth() */
    else if (this->ipv6() ){

        /* CASE 2.A: If user did not specify custom IPv6 header or Ethernet
         * field values go for raw transport layer level transmission */
        if( this->canDoIPv6ThroughSocket() ){
            this->setSendEth(false);
            this->setSendPreference( PACKET_SEND_IP_STRONG );
        }
        /* CASE 2.B: User wants to set some IPv6 or Ethernet values. So here we
         * check if enough parameters were supplied. */
        else if (this->canDoIPv6Ethernet() ){
            this->setSendEth(true);
            this->setSendPreference( PACKET_SEND_ETH_STRONG );
        }else{
            nping_fatal(QT_3, "If you want to control some of the fields"
                         " in the IPv6 header you also have to supply source and"
                         " destination MAC address. However, you can always"
                         " choose to let the kernel create the IPv6  header"
                         " choosing not to pass --source-IP, --traffic-class"
                         " or --flow options. That should simplify things a bit");
        }
    }
    /* CASE 3: We are dealing with regular, IPv4-based modes. In this case
     * we just select transmission mode based on current OS. For Windows
     * we choose raw eth level because MS has disable raw sockets support.
     * For the rest of systems, we chose raw IP because it's easier for us
     * as we don't have to deal with all the source MAC and next-hop MAC address
     * determination process. */
    else{
         #ifdef WIN32
            this->setSendPreference( PACKET_SEND_ETH_STRONG );
            this->setSendEth(true);
         #else
            this->setSendPreference( PACKET_SEND_IP_WEAK );
            this->setSendEth(false);
         #endif
    }

 /* User did actually supplied his own sending preference. Let's check if we
  * can actually send probes the way he wants. */
 }else{

    if( this->getMode()==ARP && !this->sendPreferenceEthernet() ){
        this->setSendEth(true);
        nping_warning(QT_2, "Warning: ARP mode requires raw ethernet frame transmission. Specified preference will be ignored.");
    }
    else if( this->ipv6() ){

        /* CASE 1: User requested ethernet explicitly and supplied all
         * necessary options. */
        if( this->sendPreferenceEthernet() && this->canDoIPv6Ethernet() ){
            this->setSendEth(true);

        /* CASE 2: User requested Ethernet but did not really supplied all
         * the information we need */
        }else if( this->sendPreferenceEthernet() && !this->canDoIPv6Ethernet() ){
            nping_fatal(QT_3, "You requested raw ethernet level transmission and IPv6."
                    " In this case, you need to supply source MAC address,"
                    " destination MAC address and IPv6 source address.");

        /* CASE 3: User requested raw IP transmission and did not request
         * any special IPv6 header options. */
        }else if( this->sendPreferenceIP() && this->canDoIPv6ThroughSocket() ){
            this->setSendEth(false);

        /* CASE 4: User requested raw IP transmission but also wanted to
         * set custom IPv6 header field values. */
        }else if (this->sendPreferenceIP() && !this->canDoIPv6ThroughSocket()){
            nping_fatal(QT_3, "You requested raw IP transmission mode for IPv6."
                         " Nping does not currently allow IPv6 header manipulation"
                         " when sending packets at raw IP level due to the limitations"
                         " on raw IPv6 sockets, imposed by RFC 2292. Please"
                         " use raw Ethernet transmission (option --send-eth)");


        }
    }
    else if( this->sendPreferenceEthernet() ){
            this->setSendEth(true);
    }else{
        this->setSendEth(false);
    }
 }
 if( this->getMode()==TCP_CONNECT || this->getMode()==UDP_UNPRIV )
    nping_print(DBG_2,"Nping will send packets in unprivileged mode using regular system calls");
 else
    nping_print(DBG_2,"Nping will send packets at %s",  this->sendEth() ? "raw ethernet level" : "raw IP level" );
}

/** ECHO MODE ************************************************************/

  if(this->getRole()==ROLE_CLIENT){

    /* Make sure the nping echo client does not generate packets with tcp
     * src port or tcp dst port 9929 (or --echo-port N, if that is set),
     * because 1) the echo server does not capture those packets and 2) to
     * avoid messing with the established side-channel tcp connection. */
    if(this->getMode()==TCP){
        for(int i=0; i<tportcount; i++){
            if( this->target_ports[i]==this->getEchoPort())
                nping_fatal(QT_3, "Packets can't be sent to the same port that is used to connect to the echo server (%d)", this->getEchoPort());
            else if(this->getSourcePort()==this->getEchoPort())
                nping_fatal(QT_3, "Packets can't be sent from the same port that is used to connect to the echo server (%d)", this->getEchoPort());
        }
    }

    /* Check the echo client only produces TCP/UDP/ICMP packets */
    switch( this->getMode() ){
        case TCP:
        case UDP:
        case ICMP:
        break;

        default:
            nping_fatal(QT_3, "The echo client can't be run with protocols other than TCP, UDP or ICMP.");
        break;
    }
  }
  #ifndef HAVE_OPENSSL
  if(this->getRole()==ROLE_CLIENT || this->getRole()==ROLE_SERVER ){
    if( this->doCrypto()==true  ){
        nping_fatal(QT_3, "Nping was compiled without OpenSSL so authentications need to be transmitted as cleartext. If you wish to continue, please specify --no-crypto.");
    }
  }
  #endif

/** FRAGMENTATION ************************************************************/
#if !defined(LINUX) && !defined(OPENBSD) && !defined(FREEBSD) && !defined(NETBSD)
  if (this->issetMTU()) {
    error("Warning: Packet fragmentation selected on a host other than Linux, OpenBSD, FreeBSD, or NetBSD.  This may or may not work.");
  }
#endif

/** MISCELLANEOUS ************************************************************/
if( this->issetSourcePort() && this->getMode()==TCP_CONNECT && this->getPacketCount()>1 )
    error("Warning: Setting a source port in TCP-Connect mode with %d rounds may not work after the first round. You may want to do just one round (use --count 1).", this->getPacketCount() );
} /* End of validateOptions() */


/** Returns true if requested mode is a simple TCP connect probe mode */
bool NpingOps::canRunUDPWithoutPrivileges(){
  if( this->issetBadsumIP() ||
    this->issetTTL() ||
    this->issetHopLimit() ||
    this->issetTOS() ||
    this->issetIdentification() ||
    this->issetMF() ||
    this->issetDF() ||
    this->issetRF() ||
    this->issetIPv4SourceAddress() ||
    this->issetIPv6SourceAddress() ||
    this->issetIPOptions() ||
    this->issetMTU() ||
    this->issetSpoofSource() ||
    this->issetSourceMAC() ||
    this->issetDestMAC() ||
    this->issetEtherType() ||
    this->issetTraceroute() ||
    this->issetBPFFilterSpec()
  )
    return false;
  else
    return true;
} /* End canRunUDPWithoutPrivileges() */


/** Returns true if user did not request any special ethernet or ipv6 header
  * options */
bool NpingOps::canDoIPv6ThroughSocket(){
  if( this->issetEtherType() ||
    this->issetDestMAC() ||
    this->issetSourceMAC() ||
    this->issetHopLimit() ||
    this->issetTrafficClass() ||
    this->issetFlowLabel() ||
    this->issetIPv6SourceAddress()
  )
    return false;
  else
    return true;
} /* End canDoIPv6ThroughSocket() */


/** Returns true if user supplied all necessary options to allow IPv6 at raw
  * Ethernet level */
bool NpingOps::canDoIPv6Ethernet(){
  if( this->issetDestMAC() &&  this->issetSourceMAC() && this->issetIPv6SourceAddress() )
    return true;
  else
    return false;
} /* End canDoIPv6Ethernet() */


/******************************************************************************
 *  Miscellaneous                                                             *
 ******************************************************************************/

void NpingOps::displayNpingDoneMsg(){

  if( this->getRole()==ROLE_SERVER ){
      nping_print(QT_1, "Nping done: %lu %s served in %.2f seconds",
               (unsigned long)this->stats.getEchoClientsServed(),
               (this->stats.getEchoClientsServed() == 1)? "client" : "clients",
               this->stats.elapsedRuntime()
              );
  }else{
      nping_print(QT_1, "Nping done: %lu %s pinged in %.2f seconds",
               this->targets.getTargetsFetched(),
               (this->targets.getTargetsFetched() == 1)? "IP address" : "IP addresses",
               this->stats.elapsedRuntime()
              );
  }
} /* End of displayNpingDoneMessage() */


/** @warning This method calls targets.rewind() */
void NpingOps::displayStatistics(){
  char auxbuff[256];
  memset(auxbuff, 0, 256);
  NpingTarget *target=NULL;
  this->targets.rewind();

  nping_print(VB_0," "); /* Print newline */

    /* Per-target statistics */
    if( this->targets.getTargetsFetched() > 1){
        while( (target=this->targets.getNextTarget()) != NULL )
            target->printStats();
    }else{
        target=this->targets.getNextTarget();
        if( target!= NULL)
            target->printRTTs();
    }

#ifdef WIN32
      /* Sent/Recv/Echoed Packets */
      if(this->getRole()==ROLE_CLIENT){
          nping_print(QT_1|NO_NEWLINE, "Raw packets sent: %I64u ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getSentBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %I64u ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Lost: %I64u ", this->stats.getLostPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
          nping_print(QT_1|NO_NEWLINE,"| Echoed: %I64u ", this->stats.getEchoedPackets() );
          nping_print(QT_1,"(%s) ", format_bytecount(this->stats.getEchoedBytes(), auxbuff, 256));
      }else if(this->getRole()==ROLE_SERVER){
          nping_print(QT_1|NO_NEWLINE, "Raw packets captured: %I64u ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Echoed: %I64u ", this->stats.getEchoedPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getEchoedBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Not Matched: %I64u ", this->stats.getUnmatchedPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes()-this->stats.getEchoedBytes(), auxbuff, 256));
          nping_print(QT_1,"(%.2lf%%)", this->stats.getUnmatchedPacketPercentage100() );
      }else if(this->getMode()==TCP_CONNECT){
          nping_print(QT_1|NO_NEWLINE, "TCP connection attempts: %I64u ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Successful connections: %I64u ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Failed: %I64u ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
      } else if (this->getMode()==UDP_UNPRIV){
          nping_print(QT_1|NO_NEWLINE, "UDP packets sent: %I64u ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %I64u ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Lost: %I64u ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
      } else{
          nping_print(QT_1|NO_NEWLINE, "Raw packets sent: %I64u ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getSentBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %I64u ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Lost: %I64u ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
     }
#else
      /* Sent/Recv/Echoed Packets */
      if(this->getRole()==ROLE_CLIENT){
          nping_print(QT_1|NO_NEWLINE, "Raw packets sent: %llu ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getSentBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %llu ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Lost: %llu ", this->stats.getLostPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
          nping_print(QT_1|NO_NEWLINE,"| Echoed: %llu ", this->stats.getEchoedPackets() );
          nping_print(QT_1,"(%s) ", format_bytecount(this->stats.getEchoedBytes(), auxbuff, 256));
      }else if(this->getRole()==ROLE_SERVER){
          nping_print(QT_1|NO_NEWLINE, "Raw packets captured: %llu ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Echoed: %llu ", this->stats.getEchoedPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getEchoedBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Not Matched: %llu ", this->stats.getUnmatchedPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes()-this->stats.getEchoedBytes(), auxbuff, 256));
          nping_print(QT_1,"(%.2lf%%)", this->stats.getUnmatchedPacketPercentage100() );
      }else if(this->getMode()==TCP_CONNECT){
          nping_print(QT_1|NO_NEWLINE, "TCP connection attempts: %llu ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Successful connections: %llu ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Failed: %llu ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
      } else if (this->getMode()==UDP_UNPRIV){
          nping_print(QT_1|NO_NEWLINE, "UDP packets sent: %llu ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %llu ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"| Lost: %llu ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
      } else{
          nping_print(QT_1|NO_NEWLINE, "Raw packets sent: %llu ", this->stats.getSentPackets() );
          nping_print(QT_1|NO_NEWLINE, "(%s) ", format_bytecount(this->stats.getSentBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Rcvd: %llu ", this->stats.getRecvPackets() );
          nping_print(QT_1|NO_NEWLINE,"(%s) ", format_bytecount(this->stats.getRecvBytes(), auxbuff, 256));
          nping_print(QT_1|NO_NEWLINE,"| Lost: %llu ", this->stats.getLostPackets() );
          nping_print(QT_1,"(%.2lf%%)", this->stats.getLostPacketPercentage100() );
     }
#endif

      /* Transmission times & rates */
      nping_print(VB_1|NO_NEWLINE,"Tx time: %.5lfs ", this->stats.elapsedTx() );
      nping_print(VB_1|NO_NEWLINE,"| Tx bytes/s: %.2lf ", this->stats.getOverallTxByteRate() );
      nping_print(VB_1,"| Tx pkts/s: %.2lf", this->stats.getOverallTxPacketRate() );
      nping_print(VB_1|NO_NEWLINE,"Rx time: %.5lfs ", this->stats.elapsedRx() );
      nping_print(VB_1|NO_NEWLINE,"| Rx bytes/s: %.2lf ", this->stats.getOverallRxByteRate() );
      nping_print(VB_1,"| Rx pkts/s: %.2lf", this->stats.getOverallRxPacketRate() );

} /* End of displayStatistics() */


/* Close open files, free allocated memory, etc. */
int NpingOps::cleanup(){
  this->targets.freeTargets();
  return OP_SUCCESS;
} /* End of cleanup() */


char *NpingOps::select_network_iface(){
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t *pcap_ifaces=NULL;

    /* Vars for the current interface in the loop */
    pcap_if_t *curr=NULL;             /* Current pcap pcap_if_t element   */
    bool current_has_address=false;   /* Does it have an addr of any type? */
    bool current_has_ipv6=false;      /* Does it have an IPv6 address?     */
    bool current_has_ipv4=false;      /* Does it have an IPv4 address?     */
    bool current_is_loopback=false;   /* Is it a loopback interface?       */
    bool select_current=false;        /* Is current better than candidate? */
    struct sockaddr_in6 devaddr6;     /* We store iface's IPv6 address     */
    struct sockaddr_in devaddr4;      /* And also its IPv4 address         */

    /* Vars for our candidate interface */
    pcap_if_t *candidate=NULL;
    bool candidate_has_address=false;
    bool candidate_has_ipv6=false;
    bool candidate_has_ipv4=false;
    bool candidate_is_loopback=false;
    //struct sockaddr_in6 candidate_addr6;
    //struct sockaddr_in candidate_addr4;

    /* Ask libpcap for a list of network interfaces */
    if( pcap_findalldevs(&pcap_ifaces, errbuf) != 0 )
        nping_fatal(QT_3, "Cannot obtain device for packet capture --> %s. You may want to specify one explicitly using option -e", errbuf);

    /* Iterate over the interface list and select the best one */
    for(curr=pcap_ifaces; curr!=NULL; curr=curr->next){
        current_has_address=false;   candidate_has_ipv6=false;
        candidate_is_loopback=false; candidate_has_ipv4=false;
        select_current=false;

        if( curr->flags==PCAP_IF_LOOPBACK)
            current_is_loopback=true;

        /* Loop through the list of addresses */
        for(pcap_addr_t *curraddr=curr->addresses; curraddr!=NULL; curraddr=curraddr->next){
            current_has_address=true;
            if( curraddr->addr->sa_family==AF_INET){
                current_has_ipv4=true;
                memcpy( &devaddr4, curraddr->addr, sizeof(struct sockaddr_in));
            } else if( curraddr->addr->sa_family==AF_INET6){
                current_has_ipv6=true;
                memcpy( &devaddr6, curraddr->addr, sizeof(struct sockaddr_in6));
            }
         }

        /* If we still have no candidate, take the first one we find */
        if( candidate==NULL){
            select_current=true;
        }
        /* If we already have a candidate, check if the one we are
         * processing right now is better than the one we've already got */
        else{
            /* If our candidate does not have an IPv6 address but this one does,
             * select the new one. */
            if( candidate_has_ipv6==false && current_has_ipv6==true ){
                select_current=true;
            }
            /* If our candidate does not even have an IPv4 address but this
             * one does, select the new one. */
            else if( candidate_has_ipv4==false && candidate_has_ipv6==false && current_has_ipv4){
                select_current=true;
            }
            /* If our candidate is a loopback iface, select the new one */
            else if( candidate_is_loopback && !current_is_loopback){

                /* Select the new one only if it has an IPv6 address
                 * and the old one didn't. If our old loopback iface
                 * has an IPv6 address and this one does not, we
                 * prefer to keep the loopback one, even though the
                 * other is not loopback */
                if(current_has_ipv6==true){
                    select_current=true;
                }
                /* We also prefer IPv4 capable interfaces than  */
                else if(candidate_has_ipv6==false && current_has_ipv4==true){
                    select_current=true;
                }
            }
            /* If both are loopback, select the best one. */
            else if( candidate->flags==PCAP_IF_LOOPBACK && curr->flags==PCAP_IF_LOOPBACK){
                if( candidate_has_ipv6==false && current_has_ipv6 )
                    select_current=true;
            }
        }

        /* Did we determine that we should discard our old candidate? */
        if( select_current ){
            candidate=curr;
            candidate_has_address=current_has_address;
            candidate_has_ipv4=current_has_ipv4;
            candidate_has_ipv6=current_has_ipv6;
            candidate_is_loopback=current_is_loopback;
        }

        /* Let's see if we have the interface of our dreams... */
        if( candidate_has_address && candidate_has_ipv6 && candidate_has_ipv4 && candidate_is_loopback==false){
            break;
        }

    }
    if(candidate==NULL)
        return NULL;
    else
       return candidate->name;
} /* End of select_network_iface() */


int NpingOps::setDefaultHeaderValues(){
  if(this->ipv6()){ /* IPv6 */
    if(!this->issetTrafficClass())
        this->ipv6_tclass=DEFAULT_IPv6_TRAFFIC_CLASS;
    if(!this->issetFlowLabel())
        this->ipv6_flowlabel=(get_random_u32() % 1048575);
    if(!this->issetHopLimit() && !this->issetTraceroute())
        this->ttl=DEFAULT_IPv6_TTL;
  }else{ /* IPv4 */
    if(!this->issetTOS())
        this->tos=DEFAULT_IP_TOS;
    if(!this->issetIdentification())
        this->identification=get_random_u16();
    if(!this->issetTTL() && !this->issetTraceroute())
        this->ttl=DEFAULT_IP_TTL;

  }
  switch( this->getMode() ){
    case TCP:
        if(!this->issetTargetPorts()){
            u16 *list = (u16 *)safe_zalloc( sizeof(u16) );
            list[0]=DEFAULT_TCP_TARGET_PORT;
            this->setTargetPorts(list, 1);
        }
        if(!this->issetSourcePort()){
            /* Generate any source port higher than 1024 */
            if(this->getRole()!=ROLE_CLIENT){
                this->source_port=(1024 + ( get_random_u16()%(65535-1024) ));
            }else{
                /* For the echo client, avoid choosing the port used for the echo side channel */
                while( (this->source_port=(1024 + ( get_random_u16()%(65535-1024) )))==this->echo_port );
            }
        }
        if(!this->issetTCPSequence())
            this->tcpseq=get_random_u32();
        if(!this->issetTCPAck()){
            if(this->getFlagTCP(FLAG_ACK))
                this->tcpack=get_random_u32();
            else
                this->tcpack=0;
        }
        if(!this->issetTCPFlags())
            this->setFlagTCP(FLAG_SYN);
        if(!this->issetTCPWindow())
            this->tcpwin=DEFAULT_TCP_WINDOW_SIZE;
        /* @todo ADD urgent pointer handling here when it gets implemented */
    break;

    case UDP:
        if(!this->issetTargetPorts()){
            u16 *list = (u16 *)safe_zalloc( sizeof(u16) );
            list[0]=DEFAULT_UDP_TARGET_PORT;
            this->setTargetPorts(list, 1);
        }
        if(!this->issetSourcePort())
            this->source_port=DEFAULT_UDP_SOURCE_PORT;
    break;

    case ICMP:
        if(this->ipv6()){
            if(!this->issetICMPType()) /* Default to ICMP Echo */
                this->icmp_type=DEFAULT_ICMPv6_TYPE;
            if(!this->issetICMPCode())
                this->icmp_code=DEFAULT_ICMPv6_CODE;
        }else{
            if(!this->issetICMPType()) /* Default to ICMP Echo */
                this->icmp_type=DEFAULT_ICMP_TYPE;
            if(!this->issetICMPCode())
                this->icmp_code=DEFAULT_ICMP_CODE;
        }
    break;

    case ARP:
        if(!this->issetARPOpCode())
            this->arp_opcode=DEFAULT_ARP_OP;
    break;

    case UDP_UNPRIV:
        if(!this->issetTargetPorts()){
            u16 *list = (u16 *)safe_zalloc( sizeof(u16) );
            list[0]=DEFAULT_UDP_TARGET_PORT;
            this->setTargetPorts(list, 1);
        }
        if(!this->issetSourcePort())
            this->source_port=DEFAULT_UDP_SOURCE_PORT;
    break;

    case TCP_CONNECT:
        if( !this->issetTargetPorts() ) {
            u16 *list = (u16 *)safe_zalloc( sizeof(u16) );
            list[0]=DEFAULT_TCP_TARGET_PORT;
            this->setTargetPorts(list, 1);
        }

    default:
        return OP_FAILURE;
    break;
  }

  return OP_SUCCESS;
} /* End of setDefaultHeaderValues() */


int NpingOps::setLastPacketSentTime(struct timeval t){
  this->last_sent_pkt_time=t;
  return OP_SUCCESS;
} /* End of setLastPacketSentTime() */


struct timeval NpingOps::getLastPacketSentTime(){
  return this->last_sent_pkt_time;
} /* End of getLastPacketSentTime() */


/** Sets the RCVD output to be delayed. The supplied string is strdup()ed, so
  * the caller may safely free() it or modify after calling this function.
  * The "id" parameter is the nsock timer event scheduled for the output of
  * the RCVD string (usually scheduled by ProbeMode). It is provided to allow
  * other objects (like EchoClient) to cancel the event if they take care of
  * printing the RCVD string before the timer goes off.*/
int NpingOps::setDelayedRcvd(const char *str, nsock_event_id id){
  if(str==NULL)
    return OP_FAILURE;
  this->delayed_rcvd_str=strdup(str);
  this->delayed_rcvd_event=id;
  this->delayed_rcvd_str_set=true;
  return OP_SUCCESS;
} /* End of setDelayedRcvd() */


/** Returns a pointer to a delayed RCVD output string. It returns non-NULL 
  * strings only once per prior setDelayedRcvd() call. This is, when a string
  * has been set through a setDelayRcdv() call, the first time getDelayRcvd()
  * is called, it returns that string. Subsequent calls will return NULL until
  * another string is set, using setDelayRcdv() again.
  * The "id" parameter will be filled with the timer event that was supposed
  * to print the message. If getDelayedRcvd() is called by the timer handler
  * itself, then NULL can be passed safely since the event id is not needed.
  * If the caller is some other method that wants to print the RCVD string
  * before the timer goes off, it may use the event ID to cancel the scheduled
  * event since it's no longer necessary.
  * @warning returned string is the strdup()ed version of the string passed
  * in the call to setDelayedRcvd(), so the caller MUST free the returned
  * pointer when it's done using it.  */
char *NpingOps::getDelayedRcvd(nsock_event_id *id){
  if(delayed_rcvd_str_set==false){
    return NULL;
  }else{
    this->delayed_rcvd_str_set=false;
    char *old=this->delayed_rcvd_str;
    this->delayed_rcvd_str=NULL;
    if(id!=NULL)
        *id=this->delayed_rcvd_event;
    return old;
  }
} /* End of getDelayedRcvd() */


bool NpingOps::doCrypto(){
  return this->do_crypto;
}

int NpingOps::doCrypto(bool value){
  this->do_crypto=value;
  return OP_SUCCESS;
}

/* Returns true if the echo server is allowed to include payloads in NEP_ECHO
 * messages. */
bool NpingOps::echoPayload(){
  return this->echo_payload;
}

/* Enables or disables payload echo for the echo server. Pass true to enable
 * or false to disable. */
int NpingOps::echoPayload(bool value){
  this->echo_payload=value;
  this->echo_payload_set=true;
  return OP_SUCCESS;
}


/** Returns the total number of probes to be sent (this takes into account
  * the number of rounds, ports, and targets. It returns a positive integer
  * on success and n<=0 in case of error. */
int NpingOps::getTotalProbes(){
  int total_ports=0;
  this->getTargetPorts(&total_ports);
  u64 tmp = (u64) this->getPacketCount() * total_ports;
  if (tmp > INT_MAX) {
    return -1;
  }
  tmp *= this->targets.Targets.size();
  if (tmp > INT_MAX) {
    return -1;
  }
  return (int) tmp;
}


/******************************************************************************
 *  Code templates.                                                           *
 ******************************************************************************/

/*

Attributes for NpingOps:

        TYPE ATTRNAME;
        bool ATTRNAME_set;

Prototypes for NpingOps:

    int setMETHNAME(TYPE val);
    TYPE getMETHNAME();
    bool issetMETHNAME();

Initialization for NpingOps::NpingOps()

    ATTRNAME=0;
    ATTRNAME_set=false;
*/

/** Sets METHNAME. Supplied parameter must be XXXXXXXX
 *  @return OP_SUCCESS on success and OP_FAILURE in case of error.           */
/*int NpingOps::setMETHNAME(TYPE val){
   if( 0 ){
        nping_fatal(QT_3,"setMETHNAME(): Invalid value supplied\n");
        return OP_FAILURE;
    }else{
        ATTRNAME=val;
        ATTRNAME_set=true;
    }
    return OP_SUCCESS;
} *//* End of setMETHNAME() */



/** Returns value of attribute ATTRNAME */
/*TYPE NpingOps::getMETHNAME(){
  return this->ATTRNAME;
} *//* End of getMETHNAME() */


/* Returns true if option has been set */
/*bool NpingOps::issetMETHNAME(){
  return this->ATTRNAME_set;
} *//* End of issetMETHNAME() */
