summaryrefslogtreecommitdiffstats
path: root/src/interface_reader.cpp
blob: 9b0bf1489c6c31fbe7593bed54a2cdfca200b1ad (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
#include "interface_reader.hpp"
#include "interface.hpp"
#include "interface_read_error.hpp"

#include <vector>
#include <optional>
#include <iostream>
#include <fmt/core.h>

#ifndef _GNU_SOURCE
#define _GNU_SOURCE     /* To get defns of NI_MAXSERV and NI_MAXHOST */
#endif // _GNU_SOURCE

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <linux/if_link.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

interface_reader::interface_reader(std::vector<std::string> interfaces) : interface_names(interfaces), interfaces() {
}

std::optional<interface_read_error>
interface_reader::read_interfaces(void)
{
    struct ifaddrs* interface_addresses;
    int getifaddrs_result;

    getifaddrs_result = getifaddrs(&interface_addresses);

    if (getifaddrs_result == -1) {
        // error while reading interfaces
        return std::optional(interface_read_error("Reading interfaces failed"));
    }

    char host[NI_MAXHOST];

    for (struct ifaddrs *ifa = interface_addresses; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL)
            continue;

        std::string interface_name = ifa->ifa_name;

        std::optional<std::string> address;
        int family = ifa->ifa_addr->sa_family;
        if (family == AF_INET || family == AF_INET6) {
            int s = getnameinfo(ifa->ifa_addr,
                    (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
                    host, NI_MAXHOST,
                    NULL, 0, NI_NUMERICHOST);

            if (s != 0) {
                std::string errmsg = fmt::format("getnameinfo() failed for interface '{}': {}", interface_name, gai_strerror(s));
                return std::optional<interface_read_error>(interface_read_error(errmsg));
            }

            address = std::optional<std::string>(std::string(host));
        }

        interface ifc(interface_name, address);
        this->interfaces.push_back(ifc);
    }

    freeifaddrs(interface_addresses);

    return {};
}

std::vector<interface> const&
interface_reader::get_interfaces(void) const
{
    return this->interfaces;
}