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