File: network-unix.c

package info (click to toggle)
haskell-network-info 0.2.0.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 100 kB
  • ctags: 23
  • sloc: ansic: 209; haskell: 12; sh: 3; makefile: 2
file content (154 lines) | stat: -rw-r--r-- 4,070 bytes parent folder | download
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#include <sys/types.h>
#include <ifaddrs.h>
#include <netdb.h>

#ifdef __linux__
#   include <netpacket/packet.h>
#else
#   include <sys/socket.h>
#   include <net/if.h>
#   ifndef __GNU__
#      include <net/if_dl.h>
#      ifndef __sun
#         define AF_PACKET AF_LINK
#      endif
#   endif
#   ifdef __sun
#      include <net/if_arp.h>
#      include <unistd.h>
#      include <stropts.h>
#      include <sys/sockio.h>
#   endif
#endif

#ifdef __FreeBSD__
#   include <net/pfvar.h>
#endif

#include "network.h"
#include "common.h"

#if defined(__sun) || !defined(AF_PACKET)
int maccopy_arp(unsigned char *dst, struct sockaddr *addr)
{
    // SOURCE DERIVED FROM: http://www.pauliesworld.org/project/getmac.c
    int sock;
    if ((sock=socket(AF_INET,SOCK_DGRAM,0)) > -1) {
        struct arpreq arpreq;
        memset(&arpreq, 0, sizeof (struct arpreq));
        arpreq.arp_pa = *addr;
        if (ioctl(sock,SIOCGARP,(char*)&arpreq) == 0) {
            close (sock);
            memcpy(dst, (unsigned char *)arpreq.arp_ha.sa_data, MAC_SIZE);
            return 0;
        } else {
            close (sock);
            return 1;
        }
    } else {
        return 1;
    }
}
#endif

#ifdef AF_PACKET
void maccopy(unsigned char *dst, struct sockaddr *addr)
{
#ifdef __linux__
    /* TODO check that sll_halen is equal to 6 (MAC_SIZE) */
    memcpy(dst, ((struct sockaddr_ll *)addr)->sll_addr, MAC_SIZE);
#else
    /* TODO check that sdl_alen is equal to 6 (MAC_SIZE) */
    struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
    memcpy(dst, sdl->sdl_data + sdl->sdl_nlen, MAC_SIZE);
#endif
}
#endif

struct network_interface *add_interface(struct network_interface *ns, const wchar_t *name, int max_ns)
{
    int i;
    for (i = 0; i < max_ns; i++) {
        if (wcsempty(ns[i].name)) {
            wszcopy(ns[i].name, name, NAME_SIZE);
            return &ns[i];
        } else if (wcscmp(ns[i].name, name) == 0) {
            return &ns[i];
        }
    }
    return NULL;
}

int count_interfaces(struct network_interface *ns, int max_ns)
{
    int i;
    for (i = 0; i < max_ns; i++) {
        if (wcsempty(ns[i].name)) {
            break;
        }
    }
    return i;
}

int c_get_network_interfaces(struct network_interface *ns, int max_ns)
{
    struct network_interface *n;
    struct ifaddrs *ifaddr, *ifa;
    struct sockaddr *addr;
    wchar_t name[NAME_SIZE];
    int family, error;

    error = getifaddrs(&ifaddr);
    if (error != 0) {
        /* TODO printing the error to stderr is not a very nice thing for
         * TODO a library to do, but i've never seen this happen and its
         * TODO probably better than failing silently. */
        perror("getifaddrs");
        return 0;
    }

    memset(ns, 0, sizeof(struct network_interface) * max_ns);

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        /* check we actually have an address in this item */
        addr = ifa->ifa_addr;
        if (addr == NULL)
            continue;

        /* convert the interface name to wide characters */
        mbswszcopy(name, ifa->ifa_name, NAME_SIZE);

        /* lookup or add a new interface with the given name */
        n = add_interface(ns, name, max_ns);

        /* extract the address from this item */
        family = addr->sa_family;
        if (family == AF_INET) {
            ipv4copy(&n->ip_address, addr);
#if defined(__sun) || !defined(AF_PACKET)
            if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) {
                maccopy_arp(n->mac_address, addr);
            }
#endif
        } else if (family == AF_INET6) {
            ipv6copy(&n->ip6_address, addr);
#if defined(__sun) || !defined(AF_PACKET)
            if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) {
                maccopy_arp(n->mac_address, addr);
            }
#endif
#ifdef AF_PACKET
        } else if (family == AF_PACKET) {
            maccopy(n->mac_address, addr);
#endif
        }
    }

    freeifaddrs(ifaddr);
    return count_interfaces(ns, max_ns);
}