1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <wchar.h>
5 
6 #include <sys/types.h>
7 #include <ifaddrs.h>
8 #include <netdb.h>
9 
10 #ifdef __linux__
11 #   include <netpacket/packet.h>
12 #else
13 #   include <sys/socket.h>
14 #   include <net/if.h>
15 #   ifndef __GNU__
16 #      include <net/if_dl.h>
17 #      ifndef __sun
18 #         define AF_PACKET AF_LINK
19 #      endif
20 #   endif
21 #   if defined(__sun) || defined(__GNU__)
22 #      include <net/if_arp.h>
23 #      include <stropts.h>
24 #   endif
25 #   ifdef __sun
26 #      include <unistd.h>
27 #      include <sys/sockio.h>
28 #   endif
29 #endif
30 
31 #ifdef __FreeBSD__
32 #   include <netinet/in.h>
33 #endif
34 
35 #ifdef __DragonFly__
36 #   include <netinet/in.h>
37 #endif
38 
39 #include "network.h"
40 #include "common.h"
41 
42 #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP))
maccopy_arp(unsigned char * dst,struct sockaddr * addr)43 int maccopy_arp(unsigned char *dst, struct sockaddr *addr)
44 {
45     // SOURCE DERIVED FROM: http://www.pauliesworld.org/project/getmac.c
46     int sock;
47     if ((sock=socket(AF_INET,SOCK_DGRAM,0)) > -1) {
48         struct arpreq arpreq;
49         memset(&arpreq, 0, sizeof (struct arpreq));
50         arpreq.arp_pa = *addr;
51         if (ioctl(sock,SIOCGARP,(char*)&arpreq) == 0) {
52             close (sock);
53             memcpy(dst, (unsigned char *)arpreq.arp_ha.sa_data, MAC_SIZE);
54             return 0;
55         } else {
56             close (sock);
57             return 1;
58         }
59     } else {
60         return 1;
61     }
62 }
63 #endif
64 
65 #ifdef AF_PACKET
maccopy(unsigned char * dst,struct sockaddr * addr)66 void maccopy(unsigned char *dst, struct sockaddr *addr)
67 {
68 #ifdef __linux__
69     /* TODO check that sll_halen is equal to 6 (MAC_SIZE) */
70     memcpy(dst, ((struct sockaddr_ll *)addr)->sll_addr, MAC_SIZE);
71 #else
72     /* TODO check that sdl_alen is equal to 6 (MAC_SIZE) */
73     struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
74     memcpy(dst, sdl->sdl_data + sdl->sdl_nlen, MAC_SIZE);
75 #endif
76 }
77 #endif
78 
add_interface(struct network_interface * ns,const wchar_t * name,int max_ns)79 struct network_interface *add_interface(struct network_interface *ns, const wchar_t *name, int max_ns)
80 {
81     int i;
82     for (i = 0; i < max_ns; i++) {
83         if (wcsempty(ns[i].name)) {
84             wszcopy(ns[i].name, name, NAME_SIZE);
85             return &ns[i];
86         } else if (wcscmp(ns[i].name, name) == 0) {
87             return &ns[i];
88         }
89     }
90     return NULL;
91 }
92 
count_interfaces(struct network_interface * ns,int max_ns)93 int count_interfaces(struct network_interface *ns, int max_ns)
94 {
95     int i;
96     for (i = 0; i < max_ns; i++) {
97         if (wcsempty(ns[i].name)) {
98             break;
99         }
100     }
101     return i;
102 }
103 
c_get_network_interfaces(struct network_interface * ns,int max_ns)104 int c_get_network_interfaces(struct network_interface *ns, int max_ns)
105 {
106     struct network_interface *n;
107     struct ifaddrs *ifaddr, *ifa;
108     struct sockaddr *addr;
109     wchar_t name[NAME_SIZE];
110     int family, error;
111 
112     error = getifaddrs(&ifaddr);
113     if (error != 0) {
114         /* TODO printing the error to stderr is not a very nice thing for
115          * TODO a library to do, but i've never seen this happen and its
116          * TODO probably better than failing silently. */
117         perror("getifaddrs");
118         return 0;
119     }
120 
121     memset(ns, 0, sizeof(struct network_interface) * max_ns);
122 
123     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
124         /* check we actually have an address in this item */
125         addr = ifa->ifa_addr;
126         if (addr == NULL)
127             continue;
128 
129         /* convert the interface name to wide characters */
130         mbswszcopy(name, ifa->ifa_name, NAME_SIZE);
131 
132         /* lookup or add a new interface with the given name */
133         n = add_interface(ns, name, max_ns);
134 
135         /* extract the address from this item */
136         family = addr->sa_family;
137         if (family == AF_INET) {
138             ipv4copy(&n->ip_address, addr);
139 #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP))
140             if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) {
141                 maccopy_arp(n->mac_address, addr);
142             }
143 #endif
144         } else if (family == AF_INET6) {
145             ipv6copy(&n->ip6_address, addr);
146 #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP))
147             if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) {
148                 maccopy_arp(n->mac_address, addr);
149             }
150 #endif
151 #ifdef AF_PACKET
152         } else if (family == AF_PACKET) {
153             maccopy(n->mac_address, addr);
154 #endif
155         }
156     }
157 
158     freeifaddrs(ifaddr);
159     return count_interfaces(ns, max_ns);
160 }
161 
162 #include "common.inc"
163