Skip to content

Instantly share code, notes, and snippets.

@syzdek
Created February 5, 2020 23:03
Show Gist options
  • Save syzdek/543843bb1abcfec99732df9c0577ddb1 to your computer and use it in GitHub Desktop.
Save syzdek/543843bb1abcfec99732df9c0577ddb1 to your computer and use it in GitHub Desktop.
/*
* Example of getaddrinfo() and inet_ntop()
* Copyright (C) 2020 David M. Syzdek <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Simple Build:
* CFLAGS='-std=gnu11 -pedantic -W -Wall -Werror -Weverything'
* gcc ${CFLAGS} -c getaddrinfo-example.c
* gcc ${CFLAGS} -o getaddrinfo-example getaddrinfo-example.o
*
* Libtool Build:
* CFLAGS='-std=gnu11 -pedantic -W -Wall -Werror -Weverything'
* libtool --mode=compile --tag=CC gcc ${CFLAGS} -c getaddrinfo-example.c
* libtool --mode=link --tag=CC gcc ${CFLAGS} -o getaddrinfo-example \
* getaddrinfo-example.lo
*
* Libtool Clean:
* libtool --mode=clean rm -f getaddrinfo-example.lo getaddrinfo-example
*/
///////////////
// //
// Headers //
// //
///////////////
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
#include <getopt.h>
//////////////////
// //
// Prototypes //
// //
//////////////////
int main(int argc, char * argv[]);
/////////////////
// //
// Functions //
// //
/////////////////
int main(int argc, char * argv[])
{
int c;
int rc;
int count;
int opt_index;
char * ptr;
const char * prog_name;
char addrstr[INET6_ADDRSTRLEN];
char * hostnam;
char * service;
struct addrinfo * res;
struct addrinfo * info;
struct addrinfo hints;
union
{
struct sockaddr * sa;
struct sockaddr_in * sin;
struct sockaddr_in6 * sin6;
struct sockaddr_storage * ss;
} sau;
static struct option long_opt[] =
{
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{NULL, 0, 0, 0 }
};
// initializes variables
hostnam = NULL;
service = NULL;
prog_name = argv[0];
if ((ptr = rindex(argv[0], '/')) != NULL)
prog_name = &ptr[1];
// innitializes hints for getaddrinfo()
bzero(&hints, sizeof(struct addrinfo));
//hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED | AI_ALL;
hints.ai_flags = AI_UNUSABLE;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
// processes CLI arguments
while((c = getopt_long(argc, argv, "46hV", long_opt, &opt_index)) != -1)
{
switch(c)
{
case -1: // no more arguments
case 0: // long options toggles
break;
case '4':
hints.ai_family = PF_INET;
break;
case '6':
hints.ai_family = PF_INET6;
break;
case 'h':
printf("Usage: %s [options] hostname [service]\n", prog_name);
printf("OPTIONS:\n");
printf(" -4 resolve IPv4 only\n");
printf(" -6 resolve IPv6 only\n");
printf(" -h, --help print this help and exit\n");
printf(" -V, --version print version number and exit\n");
printf("\n");
return(0);
case 'V':
return(0);
case '?':
fprintf(stderr, "Try `%s --help' for more information.\n", prog_name);
return(1);
default:
fprintf(stderr, "%s: unrecognized option `--%c'", prog_name, c);
fprintf(stderr, "`%s --help' for more information.\n", prog_name);
return(1);
};
};
if (optind == argc)
{
fprintf(stderr, "%s: missing required argument\n", prog_name);
fprintf(stderr, "`%s --help' for more information.\n", prog_name);
return(1);
};
hostnam = argv[optind++];
if (optind < argc)
service = argv[optind++];
// resolves specified hosts
if ((rc = getaddrinfo(hostnam, service, &hints, &res)) != 0)
{
fprintf(stderr, "%s: getaddrinfo(): %s\n", prog_name, gai_strerror(rc));
return(1);
};
// displays results
count = 0;
for(info = res; ((info)); info = info->ai_next)
{
count++;
bzero(addrstr, sizeof(addrstr));
sau.sa = info->ai_addr;
switch(sau.sa->sa_family)
{
case AF_INET:
inet_ntop(AF_INET, &sau.sin->sin_addr, addrstr, sizeof(addrstr));
printf("%i: %s:%hu\n", count, addrstr, ntohs(sau.sin->sin_port));
break;
default:
inet_ntop(AF_INET6, &sau.sin6->sin6_addr, addrstr, sizeof(addrstr));
printf("%i: [%s]:%hu\n", count, addrstr, ntohs(sau.sin6->sin6_port));
break;
};
};
// frees results
freeaddrinfo(res);
return(0);
}
/* end of source */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment