summaryrefslogtreecommitdiff
path: root/src/main/c/getaddrinfocli.c
blob: 3a3aa01db015ffdb222a551de88186dbdf09a539 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#ifdef USERCONFIG
USERCONFIG
#endif

#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#if __WIN32
#   include <ws2tcpip.h>
#   include <windows.h>
static WSADATA wsadat;
#else
#   include <arpa/inet.h>
#   include <netdb.h>
#endif

#define STR_QUOT_(S) #S
#define STR_QUOT(S) STR_QUOT_(S)


static void printHelp( void ){
    printf("%s%s%s", "  \n"
        "  ", strrchr(__FILE__,'/')+1, " - " STR_QUOT(PROJECT_VERSION) "\n"
        "  \n"
        "  Print result of getaddrinfo [1] to stdout.\n"
        "  \n"
        "  Example:     getaddrinfo  example.com\n"
        "  \n"
        "  [1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html\n"
        "  \n"
        "  Home:\n"
        "  https://git.hiddenalpha.ch/getaddrinfo-cli.git/tree/README.md"
        "  \n"
    );
}


int main( int argc, char**argv ){
    int err;
    const char *nodename;
    struct addrinfo hints = {0}, *res = NULL, *it;
    if( argc != 2 ){ fprintf(stderr, "EINVAL: Try --help\n"); err = -1; goto endFn; }
    if( !strcmp(argv[1], "--help") ){ printHelp(); err = 0; goto endFn; }
    nodename = argv[1]; assert(nodename != NULL);
#ifdef __WIN32
    err = WSAStartup(MAKEWORD(1, 0), &wsadat);
    if( err ) goto endFn;
#endif
    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = AI_CANONNAME;
    err = getaddrinfo(nodename, NULL, &hints, &res);
    if( err != 0 ){
        const char *ex;
        switch( err ){
        case EAI_AGAIN:      ex = "EAI_AGAIN";      break;
        case EAI_BADFLAGS:   ex = "EAI_BADFLAGS";   break;
        case EAI_FAIL:       ex = "EAI_FAIL";       break;
        case EAI_FAMILY:     ex = "EAI_FAMILY";     break;
        case EAI_MEMORY:     ex = "EAI_MEMORY";     break;
        case EAI_NONAME:     ex = "EAI_NONAME";     break;
        case EAI_SERVICE:    ex = "EAI_SERVICE";    break;
        case EAI_SOCKTYPE:   ex = "EAI_SOCKTYPE";   break;
#ifdef EAI_SYSTEM
        case EAI_SYSTEM:     ex = "EAI_SYSTEM";     break;
#endif
#ifdef EAI_ADDRFAMILY
        case EAI_ADDRFAMILY: ex = "EAI_ADDRFAMILY"; break;
#endif
#ifdef EAI_NODATA
        case EAI_NODATA:     ex = "EAI_NODATA";     break;
#endif
        default:
            assert(!fprintf(stderr,"ERROR: getaddrinfo(): %d  %s:%d\n", err, __FILE__, __LINE__));
            ex = NULL;
        }
        printf("%s: getaddrinfo(\"%s\")\n", ex, nodename);
        err = -1; goto endFn;
    }
    printf("C: %-6s  %-6s  %-5s  %-4s  %s\n", "AF", "SOCK", "PROTO", "FLGS", "ADDR");
    for( it = res ; it != NULL ; it = it->ai_next ){
        const char *afStr, *typStr, *protoStr;
        switch( it->ai_family ){
        case AF_UNIX  : afStr = "UNIX"  ; break;
        case AF_INET  : afStr = "INET"  ; break;
        case AF_INET6 : afStr = "INET6" ; break;
        case AF_UNSPEC: afStr = "UNSPEC"; break;
        default: assert(!fprintf(stderr,"TODO: ai_family %d\n", it->ai_family)); afStr = NULL;
        }
        switch( it->ai_socktype ){
        case 0          : typStr = "0"     ; break;
        case SOCK_STREAM: typStr = "STREAM"; break;
        case SOCK_DGRAM : typStr = "DGRAM" ; break;
        case SOCK_RAW   : typStr = "RAW"   ; break;
        default: assert(!fprintf(stderr, "TODO: ai_socktype %d\n", it->ai_socktype)); typStr = NULL;
        }
        switch( it->ai_protocol ){
        case 0: protoStr = "0"; break;
        case IPPROTO_TCP: protoStr = "TCP"; break;
        case IPPROTO_UDP: protoStr = "UDP"; break;
        default: assert(!fprintf(stderr, "TODO: ai_protocol %d\n", it->ai_protocol)); protoStr = NULL;
        }
        printf("R: %-6s  %-6s  %-5s  0x%02X", afStr, typStr, protoStr, it->ai_flags);
        switch( it->ai_family ){
        case AF_UNIX: /*TODO anything useful to print here?*/ break;
        case AF_INET: {
            #define ADDR4 ((struct sockaddr_in*)it->ai_addr)
            uint_fast32_t ip;
            assert(it->ai_addrlen == 16);
            assert(ADDR4->sin_family == AF_INET);
            ip = ntohl(ADDR4->sin_addr.s_addr);
            printf("  %d.%d.%d.%d", (int)(ip >> 24 & 0xFF), (int)(ip >> 16 & 0xFF),
                (int)(ip >> 8 & 0xFF), (int)(ip & 0xFF));
            break; }
            #undef ADDR4
        case AF_INET6: {
            #define ADDR6 ((struct sockaddr_in6*)it->ai_addr)
            char buf[INET6_ADDRSTRLEN + 1];
            if( inet_ntop(it->ai_family, &ADDR6->sin6_addr, buf, sizeof buf) != NULL ){
                printf("  %s", buf);
            }else{
                printf("  inet_ntop(): errno=%d", errno);
            }
            break; }
            #undef ADDR6
        default: assert(!fprintf(stderr,"TODO: ai_family %d\n", it->ai_family));
        }
        if( it->ai_canonname != NULL ) printf("  cn=\"%s\"", it->ai_canonname);
        printf("\n");
    }
    err = 0;
endFn:
    if( res != NULL ) freeaddrinfo(res);
#ifdef __WIN32
    WSACleanup();
#endif
    return !!err;
}