about summary refs log tree commit diff
path: root/src/nm-daemon-helper/nm-daemon-helper.c
blob: 810ea5fa944ff67943eb9343c77705c6bc19300e (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
/* SPDX-License-Identifier: LGPL-2.1-or-later */

/* Copyright (C) 2021 Red Hat, Inc. */

#include "libnm-std-aux/nm-default-std.h"

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#if defined(__GLIBC__)
#include <nss.h>
#endif
#include <stdarg.h>

enum {
    RETURN_SUCCESS      = 0,
    RETURN_INVALID_CMD  = 1,
    RETURN_INVALID_ARGS = 2,
    RETURN_ERROR        = 3,
};

static char *
read_arg(void)
{
    nm_auto_free char *arg = NULL;
    size_t             len = 0;

    if (getdelim(&arg, &len, '\0', stdin) < 0)
        return NULL;

    return nm_steal_pointer(&arg);
}

static int
more_args(void)
{
    nm_auto_free char *arg = NULL;

    arg = read_arg();

    return !!arg;
}

static int
cmd_version(void)
{
    if (more_args())
        return RETURN_INVALID_ARGS;

    printf("1");
    return RETURN_SUCCESS;
}

static int
cmd_resolve_address(void)
{
    nm_auto_free char *address = NULL;
    union {
        struct sockaddr_in  in;
        struct sockaddr_in6 in6;
    } sockaddr;
    socklen_t sockaddr_size;
    char      name[NI_MAXHOST];
    int       ret;

    address = read_arg();
    if (!address)
        return RETURN_INVALID_ARGS;

    if (more_args())
        return RETURN_INVALID_ARGS;

    memset(&sockaddr, 0, sizeof(sockaddr));
#if defined(__GLIBC__)
    __nss_configure_lookup("hosts", "dns");
#endif

    if (inet_pton(AF_INET, address, &sockaddr.in.sin_addr) == 1) {
        sockaddr.in.sin_family = AF_INET;
        sockaddr_size          = sizeof(struct sockaddr_in);
    } else if (inet_pton(AF_INET6, address, &sockaddr.in6.sin6_addr) == 1) {
        sockaddr.in6.sin6_family = AF_INET6;
        sockaddr_size            = sizeof(struct sockaddr_in6);
    } else
        return RETURN_INVALID_ARGS;

    ret = getnameinfo((struct sockaddr *) &sockaddr,
                      sockaddr_size,
                      name,
                      sizeof(name),
                      NULL,
                      0,
                      NI_NAMEREQD);
    if (ret != 0) {
        if (ret == EAI_SYSTEM) {
            int  errsv = errno;
            char buf[1024];

            fprintf(stderr,
                    "getnameinfo() failed: %d (%s), system error: %d (%s)\n",
                    ret,
                    gai_strerror(ret),
                    errsv,
                    _nm_strerror_r(errsv, buf, sizeof(buf)));
        } else {
            fprintf(stderr, "getnameinfo() failed: %d (%s)\n", ret, gai_strerror(ret));
        }
        return RETURN_ERROR;
    }

    printf("%s", name);

    return RETURN_SUCCESS;
}

int
main(int argc, char **argv)
{
    nm_auto_free char *cmd = NULL;

    cmd = read_arg();
    if (!cmd)
        return RETURN_INVALID_CMD;

    if (nm_streq(cmd, "version"))
        return cmd_version();
    if (nm_streq(cmd, "resolve-address"))
        return cmd_resolve_address();

    return RETURN_INVALID_CMD;
}