Example #1
0
void print_addrinfo( struct addrinfo* ai ) {
   if( LOGGER_LEVEL_INFO <= logger_get_level() ) {
      if( NULL != ai )
      {
         LOGGER_info("FAMILY:    0x%02x", ai->ai_family);
         LOGGER_info("SOCKTYPE:  0x%02x", ai->ai_socktype);
         LOGGER_info("PROTOCOL:  0x%02x", ai->ai_protocol);
         LOGGER_info("FLAGS:     0x%02x", ai->ai_flags);
         LOGGER_info("CANONNAME: %s", ai->ai_canonname);
         LOGGER_info("ADDR_LEN:  %d", ai->ai_addrlen);
         switch( ai->ai_addr->sa_family ) {
            case AF_INET:
               LOGGER_info("ADDR_FAMILY: 0x%02x (INET)", ai->ai_addr->sa_family);
               print_array(LOGGER_LEVEL_INFO, "ADDR_DATA:   %s", ai->ai_addr->sa_data, ai->ai_addrlen);
            break;
            case AF_INET6:
               LOGGER_info("ADDR_FAMILY: 0x%02x (INET6)", ai->ai_addr->sa_family);
               print_array(LOGGER_LEVEL_INFO, "ADDR_DATA:   %s", ai->ai_addr->sa_data, ai->ai_addrlen);
            break;
            default:
               LOGGER_info("ADDR_FAMILY: 0x%02x (other)", ai->ai_addr->sa_family);
               print_array(LOGGER_LEVEL_INFO, "ADDR_DATA:   %s", ai->ai_addr->sa_data, ai->ai_addrlen);
            break;
         }
         LOGGER_info("--------------");

         print_addrinfo( ai->ai_next );
      }
   }
   return;
}
Example #2
0
int main(int argc, char *argv[]) {
	struct addrinfo *ailist, *aip;
	struct addrinfo hint;
	struct sockaddr_in *sinp;
	const char *addr;
	int err;

	if (argc != 3) {
		fprintf(stderr, "usage: %s nodename service\n", argv[0]);
		exit(1);
	}

	hint.ai_flags = AI_CANONNAME;
	hint.ai_family = 0;
	hint.ai_socktype = 0;
	hint.ai_protocol = 0;
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	if (err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) {
		fprintf(stderr, "getaddrinfo: %s", gai_strerror(err));
		exit(1);
	}
	for (aip = ailist; aip; aip = aip->ai_next) {
		print_addrinfo(aip);
	}

	exit(0);
}
Example #3
0
/*
 * test_addrinfo ip port
 */
int main(int argc, char *argv[])
{
	struct addrinfo hint_ai, *serv_ai, *p;
	char * ip;
	char *port;

	if (argc < 3) {
		return 1;
	}

	ip = argv[1];
	port = argv[2];

	memset(&hint_ai, 0x00, sizeof(struct addrinfo));
	hint_ai.ai_family = AF_INET;
	hint_ai.ai_socktype = SOCK_STREAM;

	if (getaddrinfo(ip, port, &hint_ai, &serv_ai) != 0) {
		fprintf(stderr, "error calling getaddrinfo [%s]\n", (char*)gai_strerror(errno));
		return 1;
	}

	p = serv_ai;
	while (p) {
		print_addrinfo(p);
		p = p->ai_next;			
	}

	freeaddrinfo(serv_ai);
	
	return 0;
}
Example #4
0
static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
{
	struct ifaddrmsg *ifa = NLMSG_DATA(n);

	printf("if%d:\n", ifa->ifa_index);
	print_addrinfo(NULL, n, stdout);
	return 0;
}
int accept_msg(const struct sockaddr_nl *who,
	       struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;

	if (timestamp)
		print_timestamp(fp);

	if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
		print_route(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
		ll_remember_index(who, n, NULL);
		print_linkinfo(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
		print_addrinfo(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH) {
		print_neigh(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWPREFIX) {
		print_prefix(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
		print_rule(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == 15) {
		char *tstr;
		time_t secs = ((__u32*)NLMSG_DATA(n))[0];
		long usecs = ((__u32*)NLMSG_DATA(n))[1];
		tstr = asctime(localtime(&secs));
		tstr[strlen(tstr)-1] = 0;
		fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWQDISC ||
	    n->nlmsg_type == RTM_DELQDISC ||
	    n->nlmsg_type == RTM_NEWTCLASS ||
	    n->nlmsg_type == RTM_DELTCLASS ||
	    n->nlmsg_type == RTM_NEWTFILTER ||
	    n->nlmsg_type == RTM_DELTFILTER)
		return 0;
	if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
	    n->nlmsg_type != NLMSG_DONE) {
		fprintf(fp, "Unknown message: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
	}
	return 0;
}
Example #6
0
static int print_addrinfo_secondary(const struct sockaddr_nl *who,
				    struct nlmsghdr *n, void *arg)
{
	struct ifaddrmsg *ifa = NLMSG_DATA(n);

	if (!(ifa->ifa_flags & IFA_F_SECONDARY))
		return 0;

	return print_addrinfo(who, n, arg);
}
Example #7
0
static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
{
	for (; ainfo; ainfo = ainfo->next) {
		struct nlmsghdr *n = &ainfo->h;
		struct ifaddrmsg *ifa = NLMSG_DATA(n);

		if (n->nlmsg_type != RTM_NEWADDR)
			continue;

		if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
			return -1;

		if (ifa->ifa_index != ifindex ||
		    (filter.family && filter.family != ifa->ifa_family))
			continue;

		print_addrinfo(NULL, n, fp);
	}
	return 0;
}
Example #8
0
int
main(int argc, char **argv)
{
	static const struct option longopts[] = {
		{ "help", 0, 0, 'h' },
		{ "verbose", 0, 0, 'v' },
		{ "node", 1, 0, 'n' },
		{ "host", 1, 0, 'n' },
		{ "service", 0, 0, 's' },
		{ "ipv4", 0, 0, '4' },
		{ "ipv6", 0, 0, '6' },
		{ "raw", 0, 0, 'R' },
		{ "stream", 0, 0, 'S' },
		{ "dgram", 0, 0, 'D' },
		{ "datagram", 0, 0, 'D' },
		{ "tcp", 0, 0, 'T' },
		{ "udp", 0, 0, 'U' },
		{ "passive", 0, 0, 'p' },
		{ "addrconfig", 0, 0, 'a' },
		{ "canonname", 0, 0, 'c' },
		{ NULL, 0, 0, 0 }
	};
	static const char *opts = "hvn:s:46RSDTUpac";
	int opt, idx = 0;
	char *nodename = NULL, *servname = NULL;
	struct addrinfo hints = { 0 };
	struct addrinfo *result;

	while ((opt = getopt_long(argc, argv, opts, longopts, &idx)) != -1) {
		switch (opt) {
		case 'h':
			fprintf(stderr,
					"-h,--help -- help\n"
					"-n,--node <nodename> -- node name\n"
					"-s,--service <servname> -- service name\n"
					"-4,--ipv4 -- IPv4 only query\n"
					"-6,--ipv6 -- IPv6 only query\n"
					"--raw -- raw socket type (SOCK_RAW)\n"
					"--stream -- stream socket type (SOCK_STREAM)\n"
					"--dgram -- datagram socket type (SOCK_DGRAM)\n"
					"--tcp -- TCP protocol (IPPROTO_TCP)\n"
					"--udp -- UDP protocol (IPPROTO_UDP)\n"
					"--passive -- AI_PASSIVE\n"
					"--addrconfig -- AI_ADDRCONFIG\n"
					"--canonname -- AI_CANONNAME\n");
			exit(EXIT_SUCCESS);
		case 'n':
			nodename = optarg;
			break;
		case 's':
			servname = optarg;
			break;
		case '4':
			hints.ai_family = AF_INET;
			break;
		case '6':
			hints.ai_family = AF_INET6;
			break;
		case 'R':
			hints.ai_socktype = SOCK_RAW;
			break;
		case 'S':
			hints.ai_socktype = SOCK_STREAM;
			break;
		case 'D':
			hints.ai_socktype = SOCK_DGRAM;
			break;
		case 'T':
			hints.ai_protocol = IPPROTO_TCP;
			break;
		case 'U':
			hints.ai_protocol = IPPROTO_UDP;
			break;
		case 'p':
			hints.ai_flags |= AI_PASSIVE;
			break;
		case 'a':
			hints.ai_flags |= AI_ADDRCONFIG;
			break;
		case 'c':
			hints.ai_flags |= AI_CANONNAME;
			break;
		default:
			exit(EXIT_FAILURE);
		}
	}

	if (argv[optind])
		nodename = argv[optind++];
	if (argv[optind])
		servname = argv[optind++];
	if (argv[optind]) {
		fprintf(stderr, "Too many arguments.");
		exit(1);
	}

	printf("query:\n");
	printf("  nodename = %s\n", nodename);
	printf("  servname = %s\n", servname);
	print_addrinfo(&hints);

	int status = getaddrinfo(nodename, servname, &hints, &result);

	printf("status = %d\n", status);
	if (status)
		exit(1);
	int count = 0;
	for (struct addrinfo *item = result; item; item = item->ai_next) {
		printf("#%d:\n", count++);
		print_addrinfo(item);
	}

	freeaddrinfo(result);
}
Example #9
0
void open_socket_inet(device_dev_t* if_device, options_t *options) {

   // TODO: not yet ready !!!
   ip_port_t        srv_addr; // address to connect the probe to
   struct addrinfo* a_res;    // address results
   struct addrinfo  a_hint;   // address results

   // parse address input string '<ip>:<port>'
   srv_addr = parse_ip_port(if_device->device_name);
   LOGGER_info("INET socket: '%s:%s'", srv_addr.ip, srv_addr.port);

   // TODO: IPv4 support IPv6 is added later
   memset( &a_hint, 0, sizeof(a_hint) );
   a_hint.ai_family   = options->ai_family; //AF_INET; // AF_INET6;
   //a_hint.ai_socktype = SOCK_STREAM; //SOCK_DGRAM;
   a_hint.ai_socktype = SOCK_DGRAM; //SOCK_STREAM;
   a_hint.ai_flags    = AI_PASSIVE;  // server socket
   //a_hint.ai_flags    |= AI_ADDRCONFIG;
   //a_hint.ai_flags    |= AI_V4MAPPED;
   a_hint.ai_protocol = IPPROTO_UDP; // udp protocol

   // get all availabe address for the given ip port
   //int rv = getaddrinfo(srv_addr.ip, srv_addr.port, &a_hint, &a_res);
   int rv = getaddrinfo(NULL, srv_addr.port, &a_hint, &a_res);
   if( 0 != rv ) {
      perror( "Socket error in getaddrinfo()" );
      perror( gai_strerror(rv) );
      exit(1);
   }

   // print the return addresses
   print_addrinfo( a_res );

   if( NULL != a_res ) {
      //LOGGER_info( "connect" );
      LOGGER_info( "bind" );

      int socket = -1;

      // create a socket for the returned service
      //if_device->device_handle.socket = create_connect( a_res );
      socket = create_bind( a_res );
      if(-1 == socket ) {
         //perror("socket create_connect error");
         perror("socket create_bind error");
         exit(1);
      }

      if_device->device_handle.socket = socket;
      if_device->dh.fd = socket;
      if_device->dispatch = socket_dispatch_inet;

      // send 'hello' TODO: for test only
      //write( if_device->device_handle.socket, "HELLO!", 6 );
      //write( if_device->device_handle.socket, "", 1 );

      // TODO: some rework is still needed
      // register read handling to ev_handler
      LOGGER_debug("Register io handling for interface: %s", if_device->device_name);

      setNONBlocking(if_device);

      int fd = get_file_desc(if_device);
      LOGGER_debug("File Descriptor: %d", fd);

      /* storing a reference of packet device to
       be passed via watcher on a packet event so
       we know which device to read the packet from */
      // TODO: implement an own packet watcher callback
      LOGGER_info("register event io: read inet socket interface (%s)", if_device->device_name);
      ev_watcher* watcher = event_register_io_r(EV_DEFAULT_ packet_watcher_cb, fd);
      watcher->data = (device_dev_t *) if_device;
   }

   // TODO: for UDP send initial message ?
   return;
}
Example #10
0
static int accept_msg(const struct sockaddr_nl *who,
		      struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;

	if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
		struct rtmsg *r = NLMSG_DATA(n);
		int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));

		if (len < 0) {
			fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
			return -1;
		}

		if (r->rtm_flags & RTM_F_CLONED)
			return 0;

		if (timestamp)
			print_timestamp(fp);

		if (r->rtm_family == RTNL_FAMILY_IPMR ||
		    r->rtm_family == RTNL_FAMILY_IP6MR) {
			if (prefix_banner)
				fprintf(fp, "[MROUTE]");
			print_mroute(who, n, arg);
			return 0;
		} else {
			if (prefix_banner)
				fprintf(fp, "[ROUTE]");
			print_route(who, n, arg);
			return 0;
		}
	}

	if (timestamp)
		print_timestamp(fp);

	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
		ll_remember_index(who, n, NULL);
		if (prefix_banner)
			fprintf(fp, "[LINK]");
		print_linkinfo(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
		if (prefix_banner)
			fprintf(fp, "[ADDR]");
		print_addrinfo(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
		if (prefix_banner)
			fprintf(fp, "[ADDRLABEL]");
		print_addrlabel(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH ||
	    n->nlmsg_type == RTM_GETNEIGH) {
		if (preferred_family) {
			struct ndmsg *r = NLMSG_DATA(n);

			if (r->ndm_family != preferred_family)
				return 0;
		}

		if (prefix_banner)
			fprintf(fp, "[NEIGH]");
		print_neigh(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWPREFIX) {
		if (prefix_banner)
			fprintf(fp, "[PREFIX]");
		print_prefix(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
		if (prefix_banner)
			fprintf(fp, "[RULE]");
		print_rule(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == RTM_NEWNETCONF) {
		if (prefix_banner)
			fprintf(fp, "[NETCONF]");
		print_netconf(who, n, arg);
		return 0;
	}
	if (n->nlmsg_type == NLMSG_TSTAMP) {
		print_nlmsg_timestamp(fp, n);
		return 0;
	}
	if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
	    n->nlmsg_type != NLMSG_DONE) {
		fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)"
			"len=0x%08x(%d)\n", n->nlmsg_type, n->nlmsg_type,
			n->nlmsg_flags, n->nlmsg_flags, n->nlmsg_len,
			n->nlmsg_len);
	}
	return 0;
}
Example #11
0
int
main(int argc, char *argv[])
{
    const char     *allowed_args =
#ifndef VAL_NO_ASYNC
        "a"
#endif
        "hco:s:Vv:r:i:";
    char           *node = NULL;
    char           *service = NULL;
    struct addrinfo hints;
    struct addrinfo *val_ainfo = NULL;
    int             retval;
    int             getcanonname = 0;
    int             portspecified = 0;
    int             async = 0;
    val_log_t      *logp;
    val_status_t val_status;

    // Parse the command line
    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, allowed_args,
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, allowed_args);
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 's':
            portspecified = 1;
            service = optarg;
            break;
        case 'c':
            getcanonname = 1;
            break;

#ifndef VAL_NO_ASYNC
        case 'a':
            async = 1;
            break;
#endif

        case 'v':
            dnsval_conf_set(optarg);
            break;

        case 'i':
            root_hints_set(optarg);
            break;

        case 'r':
            resolv_conf_set(optarg);
            break;

        case 'V':
            version();
            return 0;
        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    memset(&hints, 0, sizeof(struct addrinfo));
    if (getcanonname) {
        hints.ai_flags |= AI_CANONNAME;
    }

    if (!async) {
        retval = val_getaddrinfo(NULL, node, service, &hints, &val_ainfo, &val_status);
    }
    else {
#ifdef VAL_NO_ASYNC
        fprintf(stderr, "async support not available\n");
#else
        struct getaddr_s cb_data = { &retval, &val_ainfo, &val_status, 0 };
        val_gai_callback my_cb = &_callback;
        val_gai_status *status = NULL;
        struct timeval tv;
        val_context_t *context;
        /*
         * create a new context
         */
        val_create_context("getaddr", &context);
        if (context == NULL)
            return -1;
        /*
         * submit request
         */
        retval = val_getaddrinfo_submit(context, node, service, &hints,
                                        my_cb, &cb_data, 0, &status);
        /*
         * wait for it to complete
         */
        while(0 == cb_data.done) {
            tv.tv_sec = 4;
            tv.tv_usec = 567;
            val_async_check_wait(context, NULL, NULL, &tv, 0);
        }
        val_free_context(context);
#endif
    }

    printf("Return code = %d\n", retval);
    printf("Validator status code = %d (%s)\n", val_status,
           p_val_status(val_status));

    if (retval != 0) {
#ifdef HAVE_GAI_STRERROR
        printf("Error in val_getaddrinfo(): %s\n", gai_strerror(retval));
#else
        printf("Error in val_getaddrinfo(): %d\n", retval);
#endif
        return -1;
    }

    print_addrinfo(VAL_ADDRINFO_TYPE, val_ainfo);

    /*
     * cleanup 
     */
    val_freeaddrinfo(val_ainfo);
    if (val_isvalidated(val_status)) {
        return 2; 
    } 
    if (val_istrusted(val_status)) {
        return 1; 
    } 

    return 0;
}
Example #12
0
int main(int argc, char **argv)
{
    if(argc != 2)
    {
        fprintf(stderr,"usage: %s hostname\n", argv[0]);
        return 1;
    }

    signal(SIGINT, sigint_handler);

    printf("Looking up addresses for %s ...\n", argv[1]);

    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
    hints.ai_socktype = SOCK_STREAM;

    struct addrinfo *dnsres;
    int status_1 = getaddrinfo(argv[1], PORT, &hints, &dnsres);
    if(status_1 != 0)
    {
        fprintf(stderr, "dns lookup failed: %s\n", gai_strerror(status_1));
        return 2;
    }

    print_addrinfo(dnsres);

    printf("Connecting to %s ...\n", "the server");
    int sockfd = socket(dnsres->ai_family, dnsres->ai_socktype, dnsres->ai_protocol);

    if(connect(sockfd, dnsres->ai_addr, dnsres->ai_addrlen) != 0)
    {
        perror("connect");
        return 3;
    }
    printf("Connected.\n");

    freeaddrinfo(dnsres); // frees the memory that was dynamically allocated for the linked lists by getaddrinfo

    s2n_init();
    
    struct s2n_config *config = s2n_config_new();
    s2n_status_request_type type = S2N_STATUS_REQUEST_NONE;
    s2n_config_set_status_request_type(config, type);

    struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
    s2n_connection_set_config(conn, config);
    s2n_connection_set_fd(conn, sockfd);

    s2n_blocked_status blocked;
    do {
        if (s2n_negotiate(conn, &blocked) < 0) {
            fprintf(stderr, "Failed to negotiate: '%s' %d\n", s2n_strerror(s2n_errno, "EN"), s2n_connection_get_alert(conn));
            exit(1);
        }
    } while (blocked);

    int client_hello_version;
    int client_protocol_version;
    int server_protocol_version;
    int actual_protocol_version;

    if ((client_hello_version = s2n_connection_get_client_hello_version(conn)) < 0) {
        fprintf(stderr, "Could not get client hello version\n");
        exit(1);
    }
    if ((client_protocol_version = s2n_connection_get_client_protocol_version(conn)) < 0) {
        fprintf(stderr, "Could not get client protocol version\n");
        exit(1);
    }
    if ((server_protocol_version = s2n_connection_get_server_protocol_version(conn)) < 0) {
        fprintf(stderr, "Could not get server protocol version\n");
        exit(1);
    }
    if ((actual_protocol_version = s2n_connection_get_actual_protocol_version(conn)) < 0) {
        fprintf(stderr, "Could not get actual protocol version\n");
        exit(1);
    }
    printf("Client hello version: %d\n", client_hello_version);
    printf("Client protocol version: %d\n", client_protocol_version);
    printf("Server protocol version: %d\n", server_protocol_version);
    printf("Actual protocol version: %d\n", actual_protocol_version);

    if (s2n_get_server_name(conn)) {
        printf("Server name: %s\n", s2n_get_server_name(conn));
    }
    if (s2n_get_application_protocol(conn)) {
        printf("Application protocol: %s\n", s2n_get_application_protocol(conn));
    }

    uint32_t length;
    const uint8_t *status = s2n_connection_get_ocsp_response(conn, &length);
    if (status && length > 0) {
        fprintf(stderr, "OCSP response received, length %d\n", length);
    }

    printf("Cipher negotiated: %s\n", s2n_connection_get_cipher(conn));

    char buf[BUFFERSIZE + 1];
    int bytes_read, bytes_written;

    // Make sure stdin is a terminal.
    if (!isatty(STDIN_FILENO))
    {
        fprintf(stderr, "Not a terminal.\n");
        exit(EXIT_FAILURE);
    }

    // Save the terminal attributes so we can restore them later.
    tcgetattr(STDIN_FILENO, &saved_attributes);
    atexit(reset_input_mode);

    // Set the funny terminal modes.
    struct termios tattr;
    tcgetattr(STDIN_FILENO, &tattr);
    tattr.c_lflag &= ~(ICANON | ECHO); // Clear ICANON and ECHO.
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);

    fd_set master, readfds;
    FD_ZERO(&master);
    FD_SET(STDIN_FILENO, &master);
    FD_SET(sockfd, &master);

    for(;;)
    {
        readfds = master;
        select(sockfd + 1, &readfds, NULL, NULL, NULL);
        if(FD_ISSET(STDIN_FILENO, &readfds))
        {
            bytes_read = read(STDIN_FILENO, buf, BUFFERSIZE);
            if(bytes_read < 1) break;
            char *buf_ptr = buf;
            int bytes_available = bytes_read;
            do
            {
                bytes_written = s2n_send(conn, buf_ptr, bytes_available, &blocked);
                if(bytes_written < 0) break;
                bytes_available -= bytes_written;
                buf_ptr += bytes_written;
            } while(bytes_available || blocked);
        }
        if(FD_ISSET(sockfd, &readfds))
        {
            do
            {
                bytes_read = s2n_recv(conn, buf, BUFFERSIZE, &blocked);
                if(bytes_read < 1) break;
                write(STDOUT_FILENO, buf, bytes_read);
            } while(blocked);
        }
        //if(nbytes != mbytes) printf("nbytes [%d] != mbytes [%d] \n", nbytes, mbytes);
    }

    close(sockfd);
    s2n_connection_free(conn);
    s2n_config_free(config);
    s2n_cleanup();
    printf("\nBYE!\n");
    return 0;
}
int
main(int argc, char *argv[])
{
    struct addrinfo		*ai, *res, hints;
    char			*servname = NULL, *host;
    int			 i, ch;

    memset(&hints, 0, sizeof hints);

    while((ch = getopt(argc, argv, "CFHPSef:p:s:t:")) !=  -1) {
        switch(ch) {
        case 'C':
            hints.ai_flags |= AI_CANONNAME;
            break;
        case 'F':
            hints.ai_flags |= AI_FQDN;
            break;
        case 'H':
            hints.ai_flags |= AI_NUMERICHOST;
            break;
        case 'P':
            hints.ai_flags |= AI_PASSIVE;
            break;
        case 'S':
            hints.ai_flags |= AI_NUMERICSERV;
            break;
        case 'e':
            long_err += 1;
            break;
        case 'f':
            if (!strcmp(optarg, "inet"))
                hints.ai_family = AF_INET;
            else if (!strcmp(optarg, "inet6"))
                hints.ai_family = AF_INET6;
            else
                usage();
            break;
        case 'p':
            if (!strcmp(optarg, "udp"))
                hints.ai_protocol = IPPROTO_UDP;
            else if (!strcmp(optarg, "tcp"))
                hints.ai_protocol = IPPROTO_TCP;
            else if (!strcmp(optarg, "icmp"))
                hints.ai_protocol = IPPROTO_ICMP;
            else if (!strcmp(optarg, "icmpv6"))
                hints.ai_protocol = IPPROTO_ICMPV6;
            else
                usage();
            break;
        case 's':
            servname = optarg;
            break;
        case 't':
            if (!strcmp(optarg, "stream"))
                hints.ai_socktype = SOCK_STREAM;
            else if (!strcmp(optarg, "dgram"))
                hints.ai_socktype = SOCK_DGRAM;
            else if (!strcmp(optarg, "raw"))
                hints.ai_socktype = SOCK_RAW;
            else
                usage();
            break;
        default:
            usage();
            /* NOTREACHED */
        }
    }
    argc -= optind;
    argv += optind;

    for(i = 0; i < argc; i++) {

        if (i)
            printf("\n");
        printf("===> \"%s\"\n", argv[i]);
        host = gethostarg(argv[i]);

        errno = 0;
        h_errno = 0;
        gai_errno = 0;
        rrset_errno = 0;

        gai_errno = getaddrinfo(host, servname, &hints, &ai);

        print_errors();
        if (gai_errno == 0) {
            for (res = ai; res; res = res->ai_next)
                print_addrinfo(res);
            freeaddrinfo(ai);
        }
    }

    return (0);
}