#define _SOCKADDR_LEN #include #include #include #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define NODE_SUFFIX ".eng.vmssoftware.com" /* #define NODE_SUFFIX ".com" */ #define ERROR(...) do { \ printf(__VA_ARGS__); \ error_seen = TRUE; \ error_at = __LINE__; \ } while (0) void usage( char *myname, int line ) { if (line) { printf("command error detected at line %d\n", line); printf("\n"); } printf("usage: %s [-option option-argument [-option option-argument] ... ] ... \n", myname); printf("\n"); printf("Where options & arguments are:\n"); printf("\n"); printf("-node name see nodename getaddrinfo() parameter\n"); printf("-service serv see servname getaddrinfo() parameter\n"); printf("-family unspec|inet|inet6 see hints getaddrinfo() parameter\n"); printf("-protocol tcp|udp|sctp see hints getaddrinfo() parameter\n"); printf("-flag addrconfig| see hints getaddrinfo() parameter\n"); printf(" all|canonname| multiple flags are ORed together\n"); printf(" numerichost|\n"); printf(" numericserv|\n"); printf(" passive|v4mapped|\n"); printf(" ireallymean8 (sets value of 0x8)\n"); printf("-socktype stream|dgram|seqpacket see hints getaddrinfo() parameter\n"); printf("-nodex n generated a node parameter n characters long\n"); printf("-node254 generates a node parameter 254 characters long\n"); printf("-node255 generates a node parameter 255 characters long\n"); printf("-node256 generates a node parameter 256 characters long\n"); printf("-emptyhints when no hints are supplied, pass an empty hints\n"); printf(" structure to getaddrinfo()instead of a NULL\n"); printf("-debug enabled debug output\n"); printf("-help displays this help text\n"); printf("\n"); printf("Example:\n"); printf("\n"); printf(" getaddrinfo -node vmsbug -service smtp -flag canonname -flag addrconfig\n"); printf("\n"); } char * make_hostname(int size) { char *node = NULL; int chars_needed = size - sizeof(NODE_SUFFIX) + 1; if (chars_needed > 0) { node = malloc(chars_needed + sizeof(NODE_SUFFIX)); node[chars_needed] = 0; while(chars_needed--) { /* * we could randomize this if we wanted to beat on name server, * task for another day. */ node[chars_needed] = 'x'; } strcat(node, NODE_SUFFIX); } return node; } /* * A single definition used to map both direction. */ struct name_value_equiv { char *name; int value; }; /* * Return pointer to string, or NULL indicating value not found. */ char * map_value_to_name( int value, struct name_value_equiv *table ) { int i = 0; for (; table[i].name != NULL; i++ ) { if (value == table[i].value) { break; } } return table[i].name; } /* * Return status indicating matched string, and string, or 0 if not found. */ int map_name_to_value( char *arg, struct name_value_equiv *table, int *result ) { int status = 0; int value_char_count = 0; for (int i = 0; table[i].name != NULL; i++) { if (!strcmp(arg, table[i].name)) { *result = table[i].value; status = 1; break; } } return status; } void get_equiv_list_info( int *entries, int *characters, struct name_value_equiv *table) { int character_count = 0; int i; for (i = 0; table[i].name != NULL; i++) { character_count += strlen(table[i].name); } *entries = i; *characters = character_count; return; } #define SEPARATOR " | " char * make_name_list_string( int entries, int characters, struct name_value_equiv *table) { int size_needed = characters + ((sizeof(SEPARATOR) - 1) * (entries - 1)) + 1; char *buffer = malloc(size_needed); buffer[0] = 0; /* * *** assumption *** we won't be passed any empty tables */ strcat(buffer, table[0].name); for (int i = 1; table[i].name != NULL; i++) { strcat(buffer, SEPARATOR); strcat(buffer, table[i].name); } return buffer; } char * get_option_list_string(struct name_value_equiv *table) { int entries; int characters; get_equiv_list_info(&entries, &characters, table); return make_name_list_string(entries, characters, table); } struct name_value_equiv socktype_map_table[] = { { "stream", SOCK_STREAM }, { "dgram", SOCK_DGRAM }, { "raw", SOCK_RAW }, { "rdm", SOCK_RDM }, { "seqpacket", SOCK_SEQPACKET}, { NULL, 0 } }; struct name_value_equiv protocol_map_table[] = { { "tcp", IPPROTO_TCP }, { "udp", IPPROTO_UDP }, { "sctp", IPPROTO_SCTP }, { NULL, 0 } }; struct name_value_equiv flag_bits_table[] = { { "addrconfig", AI_ADDRCONFIG }, { "all", AI_ALL }, { "canonname", AI_CANONNAME }, { "numerichost", AI_NUMERICHOST }, { "numericserv", AI_NUMERICSERV }, { "passive", AI_PASSIVE }, { "v4mapped", AI_V4MAPPED }, { "ireallymean8", 8 }, { NULL, 0 } }; struct name_value_equiv family_name_value_table[] = { { "unspec", PF_UNSPEC }, { "inet", PF_INET }, { "inet6", PF_INET6 }, { NULL, 0 } }; int debug = 0; int main(int argc, char * argv[]) { struct addrinfo hints; struct addrinfo *res_ptr = NULL; int arg = 1; char *node = NULL; char *dynamic_node = NULL; char *service = NULL; int status; int error_seen = FALSE; int error_at = 0; // int modified_hints = TRUE; int modified_hints = FALSE; if (argc == 1) { printf("Error: No arguments provided.\n"); usage("getaddrinfo", __LINE__); return 0; } memset(&hints, 0, sizeof(struct addrinfo)); while ( (!error_seen) && arg < argc ) { if (debug) fprintf(stderr, "arg: %d, argc %d\n", arg, argc); if (!strcmp("-help", argv[arg])) { error_seen = TRUE; } else if (!strcmp("-debug", argv[arg])) { printf("main: debug enabled\n"); debug = TRUE; } else if (!strcmp("-node254", argv[arg])) { dynamic_node = make_hostname(254); } else if (!strcmp("-node255", argv[arg])) { dynamic_node = make_hostname(255); } else if (!strcmp("-node256", argv[arg])) { dynamic_node = make_hostname(256); } else if (!strcmp("-node", argv[arg])) { if (++arg < argc) { node = argv[arg]; } else { ERROR("-node requires a hostname\n"); } } else if (!strcmp("-nodex", argv[arg])) { if (++arg < argc) { int size = atoi(argv[arg]); dynamic_node = make_hostname(size); if (!dynamic_node) { ERROR("-nodex size too small\n"); } } else { ERROR("-nodex requires size\n"); } } else if (!strcmp("-service", argv[arg])) { if (++arg < argc) { service = argv[arg]; } else { ERROR("-service requires a service name\n"); } } else if (!strcmp("-emptyhints", argv[arg])) { modified_hints = TRUE; } else if (!strcmp("-family", argv[arg])) { if (++arg < argc) { int result; if (map_name_to_value(argv[arg], family_name_value_table, &result)) { hints.ai_family = result; modified_hints = TRUE; } else { char *options = get_option_list_string(family_name_value_table); ERROR("-family did not match: [ %s ] \n", options); free(options); } } else { char *options = get_option_list_string(family_name_value_table); ERROR("-family did not supply: [ %s ]\n", options); free(options); } } else if (!strcmp("-protocol", argv[arg])) { if (++arg < argc) { if (!strcmp("tcp", argv[arg])) { hints.ai_protocol = IPPROTO_TCP; modified_hints = TRUE; if (debug) printf("setting protocol = IPPROTO_TCP\n"); } else if (!strcmp("udp", argv[arg])) { hints.ai_protocol = IPPROTO_UDP; modified_hints = TRUE; } else if (!strcmp("sctp", argv[arg])) { hints.ai_protocol = IPPROTO_SCTP; modified_hints = TRUE; } else { ERROR("-protocol did not match: tcp, udp, sctp\n"); } } else { ERROR("-protocol did not supply: tcp, udp, sctp\n"); } /* yes, this cried out for a table driven approach... */ } else if (!strcmp("-flag", argv[arg])) { if (++arg < argc) { int map_result; if (map_name_to_value(argv[arg], flag_bits_table, &map_result )) { hints.ai_flags |= map_result; modified_hints = TRUE; } else { ERROR("-test did not match: addrconfig, all, canonname, numerichost, numericserv, passive, v4mapped\n"); } } else { ERROR("-flag did not supply: addrconfig, all, canonname, numerichost, numericserv, passive, v4mapped\n"); } } else if (!strcmp("-socktype", argv[arg])) { if (++arg < argc) { if (!strcmp("stream", argv[arg])) { hints.ai_socktype = SOCK_STREAM; modified_hints = TRUE; }else if (!strcmp("dgram", argv[arg])) { hints.ai_socktype = SOCK_DGRAM; modified_hints = TRUE; }else if (!strcmp("seqpacket", argv[arg])) { hints.ai_socktype = SOCK_SEQPACKET; modified_hints = TRUE; } else { ERROR("-socktype did not match: stream, dgram, seqpacket\n"); } } else { ERROR("-socktype did not supply: stream, dgram, seqpacket\n"); } } else { ERROR("invalid agrument: %s\n", argv[arg]); } arg++; } if (!error_seen) { if (dynamic_node) { node = dynamic_node; } /* * Report request parameters... */ printf("\nRequest:\n"); printf(" node: %s, service: %s\n", node, service); if (modified_hints) { printf(" hints:\n"); printf(" flags: %x\n", hints.ai_flags); printf(" socktype: %x\n", hints.ai_socktype); printf(" family: %d\n", hints.ai_family); printf(" protocol: %d\n", hints.ai_protocol); } else { printf(" hints: (no values set, a NULL will be passed)\n"); } printf("\n"); /* Do it! */ status = getaddrinfo(node, service, (modified_hints ? &hints : NULL), &res_ptr); /* Dump the result */ printf("Result:\n"); printf(" Status: %d, errno: %d\n\n", status, errno); if (! status) { struct addrinfo *addr_ptr = res_ptr; char buffer[50]; void *address; char *protocol_str; char *socktype_str; while(addr_ptr) { printf("addrinfo: 0x%p, next: 0x%p\n", addr_ptr, addr_ptr->ai_next); protocol_str = map_value_to_name(addr_ptr->ai_protocol, protocol_map_table); socktype_str = map_value_to_name(addr_ptr->ai_socktype, socktype_map_table); printf(" family: %d, socktype: %d (%s), protocol: %d (%s)\n", addr_ptr->ai_family, addr_ptr->ai_socktype, socktype_str, addr_ptr->ai_protocol, protocol_str); if (addr_ptr->ai_canonname) { printf(" canonical name: %s\n", addr_ptr->ai_canonname); } /* After this point is address family sockaddr contents... */ /* XXX logic here needs work, good enough for now */ switch (addr_ptr->ai_family) { case AF_INET6: address = (void *) &((struct sockaddr_in6 *) addr_ptr->ai_addr)->sin6_addr; inet_ntop(addr_ptr->ai_family, address, buffer, sizeof(buffer)); printf(" address: %s\n", buffer); printf(" port: %hu, flowinfo: %d, scope: %d\n", ntohs(((struct sockaddr_in6 *) addr_ptr->ai_addr)->sin6_port), ((struct sockaddr_in6 *) addr_ptr->ai_addr)->sin6_flowinfo, ((struct sockaddr_in6 *) addr_ptr->ai_addr)->sin6_scope_id); break; case AF_INET: address = (void *) &((struct sockaddr_in *) addr_ptr->ai_addr)->sin_addr; inet_ntop(addr_ptr->ai_family, address, buffer, sizeof(buffer)); printf(" address: %s, port: %d\n", buffer, ntohs(((struct sockaddr_in *) addr_ptr->ai_addr)->sin_port)); break; default: printf(" family: %d address: (unknown address family, can't translate address)\n", addr_ptr->ai_family); } addr_ptr = addr_ptr->ai_next; printf("\n"); } freeaddrinfo(res_ptr); } } else { usage("getaddrinfo", error_at); } /* clean up your mess, boy! */ if (dynamic_node) free(dynamic_node); return 0; }