简体   繁体   中英

Perhaps a pointer problem. Linux program + libpcap + getopt_long() + C language

I'm making a network sniffer for my college project using the libpcap library. Majority of the code works without any problem, however, I'm stuck with the following issue. I've added five command line options using getopt_long() function, but one option doesn't work as expected.

The option is -d (--device_info) and is used to print the IP address and netmask associated with an interface. It takes one argument, which is the name of the interface for which the information is to be printed.

The necessary portion of the code from the program is attached below. My problem is that even though I'm explicitly assigning the name of the interface to char *device (line 35) and then passing that as an argument to print_device_info() (line 36), when print_device_info() executes, it always executes the if block (line 4) ie char *device is always equal to NULL in print_device_info() even though I pass it as an argument.

I'm a beginner programmer and this is the first "real" project I'm developing. I guess it's a pointer issue but I'm not sure.

Kindly, also suggest some method to solve it.

1)   //Prints information associated with an interface.
 2)   void print_device_info(char *device)
 3)   { 
      ...
      ...
      ...

 4)     if(device == NULL);
 5)      {
 6)       fprintf(stdout, "No interface specified \n");
 7)       exit(1);
 8)      }
      ...
      ...
      ...
 9)    }

 10)   int main(int argc, char *argv[])
 11)   { 
 12)     int next_option; // Options

 13)     char *device=NULL; // NIC to sniff packet from. 

 14)     // A string listing valid short options letters.
 15)     const char* const short_options = "ho:i:d:p";

 16)     /* An array describing valid long options. */
 17)     const struct option long_options[] = 
 18)      {
 19)       { "help",        0, NULL, 'h' },
 20)       { "output",      1, NULL, 'o' },
 21)       { "interface",   1, NULL, 'i' },
 22)       { "device_info", 1, NULL, 'd' },
 23)       { "promisc_off", 0, NULL, 'p' },
 24)       { NULL,          0, NULL,  0  } /* Required at end of array. */
 25)      };

 26)     //Check the arguments and perform their respective functions
 27)   do {
 28)     next_option = getopt_long (argc, argv, short_options,
 29)                                 long_options, NULL);
 30)     switch (next_option)
 31)     {
 32)       case 'd':    /* -d or --device_info */
 33)        /* User has requested information associated an interface. Print it to standard
 34)           output, and exit with exit code zero (normal termination). */
 35)        device = optarg;
 36)        print_device_info (device);
 37)     }
 38)     }while (next_option != -1);
       }

Edit: Here I'm posting an edited version of the original program. This edited version is a complete program in itself, so should be sufficient for any future queries.

#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

//Prints information associated with an interface.
void print_device_info(char *device)
 { 

  struct in_addr addr_struct; //Stores I.P address.

  char *ipaddr=NULL; //Points to I.P address in dotted-decimal form.

  char *netmask=NULL; //Points to  Netmask in dotted-decimal form.

  int ret; //Return code (Useful for error detection).

  bpf_u_int32 tmpip; // Stores I.P address temporarily in host-byte (little-endian) order.

  bpf_u_int32 tmpmask;// Stores Netmask temporarily in host-byte (little-endian) order.

  char errbuf[PCAP_ERRBUF_SIZE]; // Stores error messages.

   printf("%s\n",device);

  if(device==NULL);
   {
    fprintf(stdout, "No interface specified \n");
    exit(1);
   }

/*Lookup device info and store the return value in ret */
  ret = pcap_lookupnet(device, &tmpip, &tmpmask, errbuf);

//error checking
 if(ret==-1)
  {
   fprintf(stderr, "Couldn't find IP address and subnet mask: %s\n", errbuf);
   exit(1);
  }

//Calculate IP address
  addr_struct.s_addr=tmpip;
  ipaddr=inet_ntoa(addr_struct);

//error checking.
  if(ipaddr==NULL)
   {
    perror("Error in locating the I.P address");
    exit(1);
   }

//Print the IP address
  printf("IP address: %s\n",ipaddr);

//Calculate subnet mask
  addr_struct.s_addr=tmpmask;
  netmask=inet_ntoa(addr_struct);

//error checking.
  if(netmask==NULL)
   {
    perror("Error in locating the subnet mask");
    exit(1);
   }

//Print the subnet mask 
  printf("Subnet mask: %s\n",netmask);

  exit(0);
}

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

//A) Declarations -----------------------------------------------------------------------------------------------------
  int next_option; // Options

  char *device=NULL; // NIC to sniff packet from. 

  char errbuf[PCAP_ERRBUF_SIZE]; // Stores error messages.

// A string listing valid short options letters.
  const char* const short_options = "i:d:";

/* An array describing valid long options. */
  const struct option long_options[] = 
   {
    { "interface",   1, NULL, 'i' },
    { "device_info", 1, NULL, 'd' },
    { NULL,          0, NULL,  0  } /* Required at end of array. */
   };

//Check the arguments and perform their respective functions
do {
  next_option = getopt_long (argc, argv, short_options,
                              long_options, NULL);
  switch (next_option)
  {

  case 'i':    /* -i or  --interface */
     /* User has specified the NIC device to sniff from */
     device = optarg;
     break;

  case 'd':    /* -d or --device_info */
     /* User has requested information associated an interface. Print it to standard
        output, and exit with exit code zero (normal termination). */
     device = optarg;
     printf("%s\n",device);
     print_device_info (device);

  case -1:     /* Done with options.  */
     break;

  default:     /* Something else: unexpected.  */
     abort ();
  }
}
while (next_option != -1);

//B)Lookup device
  if (device == NULL)
  {
    device=pcap_lookupdev(errbuf);  

     //Check for error  
     if(device==NULL)
      {
        fprintf(stderr, "Couldn't find device %s\n",errbuf);
        return(2);
      }
  }

//Print Device
  printf("Device: %s\n", device);

}

You have a stray semicolon ( ; ) at the end of your test.

This means that the only thing controlled by the test is an empty expression and the block following the if statement is just a nested block (will always be executed).

I've modified your code to break out of arg-reading loop and it works exactly as I would expect:

$ ./longopt
(null)
$ ./longopt -d eth0
eth0

Here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>


int main(int argc, char *argv[])
{ 
    int next_option; // Options
    char *device=NULL; // NIC to sniff packet from.

    // A string listing valid short options letters.
    const char* const short_options = "ho:i:d:p";

    /* An array describing valid long options. */
    const struct option long_options[] = 
        {
            { "help",        0, NULL, 'h' },
            { "output",      1, NULL, 'o' },
            { "interface",   1, NULL, 'i' },
            { "device_info", 1, NULL, 'd' },
            { "promisc_off", 0, NULL, 'p' },
            { NULL,          0, NULL,  0  } /* Required at end of array. */
        };

    //Check the arguments and perform their respective functions
    while(1) {
        next_option = getopt_long (argc, argv, short_options,
                                   long_options, NULL);
        if (next_option == -1)
            break;


        switch (next_option)
        {
            case 'd':    /* -d or --device_info */
                /* User has requested information associated an interface. Print it to standard
                   output, and exit with exit code zero (normal termination). */
                device = optarg;


        }
    } 

    printf("%s\n", device);

    return(0);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM