1 | 1 | simandl | #include <arpa/inet.h> |
2 | | | #include <netinet/in.h> |
3 | | | #include <stdio.h> |
4 | | | #include <sys/types.h> |
5 | | | #include <sys/socket.h> |
6 | | | #include <unistd.h> |
7 | | | #include <stdlib.h> |
8 | | | #include <string.h> |
9 | | | #include <ctype.h> |
10 | | | #include <netdb.h> |
11 | | | #include <sys/select.h> |
12 | | | #include <sys/time.h> |
13 | | | #include <ifaddrs.h> |
14 | | | #include <net/if.h> |
15 | | | |
16 | | | #define BUFLEN 1024 |
17 | | | #define UBNT_PORT 10001 |
18 | | | |
19 | | | #define SNDLEN 4 |
20 | | | |
21 | | | |
22 | | | struct udisc_msg_hdr { |
23 | | | uint8_t vh; |
24 | | | uint8_t vl; |
25 | | | uint16_t length; |
26 | | | } __attribute__((packed)); |
27 | | | |
28 | | | struct udisc_rec_hdr { |
29 | | | uint8_t type; |
30 | | | uint16_t length; |
31 | | | } __attribute__((packed)); |
32 | | | |
33 | | | int main(int argc, char *argv[]) |
34 | | | { |
35 | | | |
36 | | | struct sockaddr_in si_srv; |
37 | | | struct sockaddr_in si_clnt; |
38 | | | int sock; |
39 | | | socklen_t soutlen = sizeof(si_srv); |
40 | | | socklen_t sinlen = sizeof(si_srv); |
41 | | | char rcvbuf[BUFLEN]; |
42 | | | char sendbuf[BUFLEN]; |
43 | | | ssize_t rlen; |
44 | | | |
45 | | | struct udisc_msg_hdr *umh; |
46 | | | struct udisc_rec_hdr *urh; |
47 | | | char *p; |
48 | | | char *dest; |
49 | | | |
50 | | | struct addrinfo hints; |
51 | | | struct addrinfo *ai_res; |
52 | | | int result; |
53 | | | int i, t; |
54 | | | |
55 | | | fd_set socks; |
56 | | | struct timeval tv; |
57 | | | |
58 | | | int multicast; |
59 | | | |
60 | | | int responses = 0; |
61 | | | |
62 | | | struct ifaddrs *ifa; |
63 | | | |
64 | 3 | simandl | memset(&hints, 0, sizeof(hints)); |
65 | 1 | simandl | hints.ai_protocol = IPPROTO_UDP; |
66 | | | hints.ai_socktype = SOCK_DGRAM; |
67 | | | hints.ai_flags = AI_CANONNAME; |
68 | | | hints.ai_family = PF_UNSPEC; |
69 | | | |
70 | | | if (argc < 2) { |
71 | | | dest = "233.89.188.1"; |
72 | | | multicast = 1; |
73 | | | } else { |
74 | | | dest = argv[1]; |
75 | | | multicast = 0; |
76 | | | } |
77 | | | |
78 | | | if ((result = getaddrinfo(dest, NULL, &hints, &ai_res))) { |
79 | | | printf("getaddrinfo-failed: %s\n", gai_strerror(result)); |
80 | | | exit(1); |
81 | | | } |
82 | | | |
83 | | | if ((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { |
84 | | | perror("socket"); |
85 | | | exit(1); |
86 | | | } |
87 | | | |
88 | | | memset((char *) &si_clnt, 0, sizeof(si_clnt)); |
89 | | | si_clnt.sin_family = AF_INET; |
90 | | | si_clnt.sin_port = htons(UBNT_PORT); |
91 | | | si_clnt.sin_addr = ((struct sockaddr_in *)ai_res->ai_addr)->sin_addr; |
92 | | | |
93 | | | sendbuf[0] = 1; |
94 | | | sendbuf[1] = 0; |
95 | | | sendbuf[2] = 0; |
96 | | | sendbuf[3] = 0; |
97 | | | |
98 | | | if (multicast) { |
99 | | | |
100 | | | char loop = 0; |
101 | | | setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(char)); |
102 | | | |
103 | | | if (getifaddrs(&ifa)) { |
104 | | | perror("getifaddrs"); |
105 | | | exit(1); |
106 | | | } |
107 | | | |
108 | | | for (; ifa; ifa = ifa->ifa_next) { |
109 | | | |
110 | | | if (!(ifa->ifa_flags & IFF_UP)) |
111 | | | continue; |
112 | | | if (!ifa->ifa_addr) |
113 | | | continue; |
114 | | | if (ifa->ifa_addr->sa_family != AF_INET) |
115 | | | continue; |
116 | | | if (!strcmp(ifa->ifa_name, "lo")) |
117 | | | continue; |
118 | | | if (!strncmp(ifa->ifa_name, "dummy", 5)) |
119 | | | continue; |
120 | | | |
121 | | | printf("Probing %s:%d", inet_ntoa(si_clnt.sin_addr), UBNT_PORT); |
122 | | | printf(" via %s (%s).\n", ifa->ifa_name, inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr)); |
123 | | | |
124 | | | if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr), sizeof(struct in_addr))) { |
125 | | | perror("setsockopt"); |
126 | | | exit(1); |
127 | | | } |
128 | | | |
129 | | | if (sendto(sock, sendbuf, SNDLEN, 0, (struct sockaddr *)&si_clnt, soutlen) == -1) { |
130 | | | perror("socket"); |
131 | | | exit(1); |
132 | | | } |
133 | | | } |
134 | | | |
135 | | | } else { |
136 | | | |
137 | | | printf("Probing %s:%d.\n", inet_ntoa(si_clnt.sin_addr), UBNT_PORT); |
138 | | | |
139 | | | if (sendto(sock, sendbuf, SNDLEN, 0, (struct sockaddr *)&si_clnt, soutlen) == -1) { |
140 | | | perror("socket"); |
141 | | | exit(1); |
142 | | | } |
143 | | | } |
144 | | | |
145 | | | |
146 | | | FD_ZERO(&socks); |
147 | | | FD_SET(sock, &socks); |
148 | | | tv.tv_sec = 0; |
149 | | | tv.tv_usec = 200000; |
150 | | | |
151 | | | while (select(sock + 1, &socks, NULL, NULL, &tv)) { |
152 | | | |
153 | | | if ((rlen = recvfrom(sock, rcvbuf, BUFLEN, 0, (struct sockaddr *)&si_srv, &sinlen)) == -1) { |
154 | | | perror("recvfrom"); |
155 | | | exit(1); |
156 | | | } |
157 | | | |
158 | | | if (ntohs(si_srv.sin_port) != UBNT_PORT) |
159 | | | continue; |
160 | | | |
161 | | | responses++; |
162 | | | |
163 | | | printf("\n"); |
164 | | | printf("Response : %s:%d\n", inet_ntoa(si_srv.sin_addr), ntohs(si_srv.sin_port)); |
165 | | | |
166 | | | p = rcvbuf; |
167 | | | |
168 | | | umh = (void*)p; |
169 | | | p += sizeof(struct udisc_msg_hdr); |
170 | | | rlen -= sizeof(struct udisc_msg_hdr); |
171 | | | |
172 | | | printf("Discovery: v%d.%02d\n", umh->vh, umh->vl); |
173 | | | |
174 | | | if (umh->vh != 1 && umh->vl != 0 && ntohs(umh->length) != rlen) { |
175 | | | fprintf(stderr, "protocol invalid\n"); |
176 | | | exit(1); |
177 | | | } |
178 | | | |
179 | | | while (rlen > 0) { |
180 | | | |
181 | | | urh = (void*)p; |
182 | | | p += sizeof(struct udisc_rec_hdr); |
183 | | | rlen -= sizeof(struct udisc_rec_hdr); |
184 | | | |
185 | | | |
186 | | | |
187 | | | |
188 | | | switch (urh->type) { |
189 | | | |
190 | | | |
191 | | | |
192 | | | case 2: |
193 | | | printf("IP Address: "); |
194 | | | for (i = 0; i < 4; i++) { |
195 | | | printf("%d", (unsigned char) p[i + 6]); |
196 | | | if (i < 3) |
197 | | | printf("."); |
198 | | | } |
199 | | | |
200 | | | printf(" ("); |
201 | | | for (i = 0; i < 6; i++) { |
202 | | | printf("%02x", (unsigned char) p[i]); |
203 | | | if (i < 5) |
204 | | | printf(":"); |
205 | | | } |
206 | | | |
207 | | | printf(")\n"); |
208 | | | break; |
209 | | | |
210 | | | |
211 | | | case 1: |
212 | | | printf("MAC Address: "); |
213 | | | for (i = 0; i < 6; i++) { |
214 | | | printf("%02x", (unsigned char) p[i]); |
215 | | | if (i < 5) |
216 | | | printf(":"); |
217 | | | } |
218 | | | |
219 | | | printf("\n"); |
220 | | | break; |
221 | | | |
222 | | | |
223 | | | case 3: |
224 | | | case 11: |
225 | | | case 12: |
226 | | | case 13: |
227 | | | |
228 | | | switch(urh->type) { |
229 | | | |
230 | | | case 3: |
231 | | | printf("FW Version: "); |
232 | | | break; |
233 | | | case 11: |
234 | | | printf("Hostname: "); |
235 | | | break; |
236 | | | case 12: |
237 | | | printf("Model: "); |
238 | | | break; |
239 | | | case 13: |
240 | | | printf("ESSID: "); |
241 | | | break; |
242 | | | } |
243 | | | |
244 | | | for (i = 0; i < ntohs(urh->length); i++) |
245 | | | printf("%c", isprint(p[i]) ? p[i] : '.'); |
246 | | | printf("\n"); |
247 | | | |
248 | | | break; |
249 | | | |
250 | | | case 14: |
251 | | | |
252 | | | printf("Mode: %s (%d)\n", *p == 2 ? "Station" : (*p == 3 ? "AP" : "?"), *p); |
253 | | | break; |
254 | | | |
255 | | | case 10: |
256 | | | t = ntohl(*(uint32_t *)p); |
257 | | | printf("Uptime: %dd, %d:%02d:%02d\n", t / 60 / 60 / 24, t / 60 / 60 % 24, t / 60 % 60, t % 60); |
258 | | | break; |
259 | | | |
260 | 4 | simandl | case 16: |
261 | | | printf("System ID: 0x%02hhX%02hhX\n", p[0], p[1]); |
262 | | | break; |
263 | | | |
264 | 1 | simandl | default: |
265 | | | |
266 | | | printf("Entry %3d: ", urh->type); |
267 | | | |
268 | | | for (i = 0; i < ntohs(urh->length); i++) |
269 | | | printf("%02x ", (unsigned char) p[i]); |
270 | | | |
271 | | | printf(" >"); |
272 | | | |
273 | | | for (i = 0; i < ntohs(urh->length); i++) |
274 | | | printf("%c", isprint(p[i]) ? p[i] : '.'); |
275 | | | printf("<\n"); |
276 | | | |
277 | | | |
278 | | | } |
279 | | | |
280 | | | p += ntohs(urh->length); |
281 | | | rlen -= ntohs(urh->length); |
282 | | | } |
283 | | | |
284 | | | |
285 | | | } |
286 | | | |
287 | | | |
288 | | | close(sock); |
289 | | | |
290 | | | if (!responses) { |
291 | | | printf("No UBNT routers found.\n"); |
292 | | | return 1; |
293 | | | } |
294 | | | |
295 | | | printf("\n"); |
296 | | | |
297 | | | return 0; |
298 | | | |
299 | | | } |
300 | | | |