fixed some signed/unsigned comparison warnings with -Wsign-compare
[reactos.git] / reactos / apps / utils / net / arp / arp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS arp utility
4 * FILE: apps/utils/net/arp/arp.c
5 * PURPOSE: view and manipulate the ARP cache
6 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
7 * REVISIONS:
8 * GM 27/06/05 Created
9 *
10 */
11
12
13 #include <windows.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <tchar.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <winsock2.h>
20 #include <iphlpapi.h>
21
22 #define WIN32_LEAN_AND_MEAN
23 #define UNICODE
24 #define _UNICODE
25
26 /*
27 * Globals
28 */
29 const char SEPERATOR = '-';
30
31
32
33 /*
34 * function declerations
35 */
36 INT DisplayArpEntries(PTCHAR pszInetAddr, PTCHAR pszIfAddr);
37 INT PrintEntries(PMIB_IPNETROW pIpAddRow);
38 INT Addhost(PTCHAR pszInetAddr, PTCHAR pszEthAddr, PTCHAR pszIfAddr);
39 INT Deletehost(PTCHAR pszInetAddr, PTCHAR pszIfAddr);
40 VOID Usage(VOID);
41
42
43
44 /*
45 *
46 * Takes optional parameters of an internet address and interface address.
47 * Retrieve all entries in the ARP cache. If an internet address is
48 * specified, display the ARP entry relating to that address. If an
49 * interface address is specified, display all entries relating to
50 * that interface.
51 *
52 */
53 /* FIXME: allow user to specify an interface address, via pszIfAddr */
54 INT DisplayArpEntries(PTCHAR pszInetAddr, PTCHAR pszIfAddr)
55 {
56 INT iRet;
57 UINT i, k;
58 PMIB_IPNETTABLE pIpNetTable;
59 PMIB_IPADDRTABLE pIpAddrTable;
60 ULONG ulSize = 0;
61 struct in_addr inaddr, inaddr2;
62 DWORD dwSize = 0;
63 PTCHAR pszIpAddr;
64 TCHAR szIntIpAddr[20];
65
66 /* Return required buffer size */
67 GetIpNetTable(NULL, &ulSize, 0);
68
69 /* allocate memory for ARP address table */
70 pIpNetTable = (PMIB_IPNETTABLE) malloc(ulSize * sizeof(BYTE));
71 ZeroMemory(pIpNetTable, sizeof(*pIpNetTable));
72
73 /* get Arp address table */
74 if (pIpNetTable != NULL) {
75 GetIpNetTable(pIpNetTable, &ulSize, TRUE);
76 } else {
77 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
78 free(pIpNetTable);
79 return -1;
80 }
81
82 /* check there are entries in the table */
83 if (pIpNetTable->dwNumEntries == 0) {
84 _tprintf(_T("No ARP entires found\n"));
85 free(pIpNetTable);
86 return -1;
87 }
88
89
90
91 /* try doing this in the way it's done above, it's clearer */
92 /* Retrieve the interface-to-ip address mapping
93 * table to get the IP address for adapter */
94 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
95 GetIpAddrTable(pIpAddrTable, &dwSize, 0); // NULL ?
96
97
98 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
99 //ZeroMemory(pIpAddrTable, sizeof(*pIpAddrTable));
100
101 if ((iRet = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE)) != NO_ERROR) { // NO_ERROR = 0
102 _tprintf(_T("GetIpAddrTable failed: %d\n"), iRet);
103 _tprintf(_T("error: %d\n"), WSAGetLastError());
104 }
105
106
107 for (k=0; k < pIpAddrTable->dwNumEntries; k++) {
108 if (pIpNetTable->table[0].dwIndex == pIpAddrTable->table[k].dwIndex) {
109 //printf("printing pIpAddrTable->table[?].dwIndex = %lx\n", pIpNetTable->table[k].dwIndex);
110 inaddr2.s_addr = pIpAddrTable->table[k].dwAddr;
111 pszIpAddr = inet_ntoa(inaddr2);
112 strcpy(szIntIpAddr, pszIpAddr);
113 }
114 }
115
116
117 /* print header, including interface IP address and index number */
118 _tprintf(_T("\nInterface: %s --- 0x%lx \n"), szIntIpAddr, pIpNetTable->table[0].dwIndex);
119 _tprintf(_T(" Internet Address Physical Address Type\n"));
120
121 /* go through all ARP entries */
122 for (i=0; i < pIpNetTable->dwNumEntries; i++) {
123
124 /* if the user has supplied their own internet addesss *
125 * only print the arp entry which matches that */
126 if (pszInetAddr) {
127 inaddr.S_un.S_addr = pIpNetTable->table[i].dwAddr;
128 pszIpAddr = inet_ntoa(inaddr);
129
130 /* check if it matches, print it */
131 if (strcmp(pszIpAddr, pszInetAddr) == 0) {
132 PrintEntries(&pIpNetTable->table[i]);
133 }
134 } else {
135 /* if an address is not supplied, print all entries */
136 PrintEntries(&pIpNetTable->table[i]);
137 }
138
139 }
140
141 free(pIpNetTable);
142 free(pIpAddrTable);
143
144 return 0;
145 }
146
147
148
149 /*
150 *
151 * Takes an ARP entry and prints the IP address,
152 * the MAC address and the entry type to screen
153 *
154 */
155 INT PrintEntries(PMIB_IPNETROW pIpAddRow)
156 {
157 IN_ADDR inaddr;
158 TCHAR cMacAddr[20];
159
160 /* print IP addresses */
161 inaddr.S_un.S_addr = pIpAddRow->dwAddr;
162 _tprintf(_T(" %-22s"), inet_ntoa(inaddr)); //error checking
163
164 /* print MAC address */
165 _stprintf(cMacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
166 pIpAddRow->bPhysAddr[0],
167 pIpAddRow->bPhysAddr[1],
168 pIpAddRow->bPhysAddr[2],
169 pIpAddRow->bPhysAddr[3],
170 pIpAddRow->bPhysAddr[4],
171 pIpAddRow->bPhysAddr[5]);
172 _tprintf(_T("%-22s"), cMacAddr);
173
174 /* print cache type */
175 switch (pIpAddRow->dwType) {
176 case MIB_IPNET_TYPE_DYNAMIC : _tprintf(_T("dynamic\n"));
177 break;
178 case MIB_IPNET_TYPE_STATIC : _tprintf(_T("static\n"));
179 break;
180 case MIB_IPNET_TYPE_INVALID : _tprintf(_T("invalid\n"));
181 break;
182 case MIB_IPNET_TYPE_OTHER : _tprintf(_T("other\n"));
183 break;
184 }
185 return 0;
186 }
187
188
189
190 /*
191 *
192 * Takes an internet address, a MAC address and an optional interface
193 * address as arguments and checks their validity.
194 * Fill out an MIB_IPNETROW structure and insert the data into the
195 * ARP cache as a static entry.
196 *
197 */
198 INT Addhost(PTCHAR pszInetAddr, PTCHAR pszEthAddr, PTCHAR pszIfAddr)
199 {
200 PMIB_IPNETROW pAddHost;
201 PMIB_IPADDRTABLE pIpAddrTable;
202 DWORD dwIpAddr;
203 DWORD dwSize = 0;
204 INT iRet, i, val;
205 TCHAR c;
206
207 /* error checking */
208
209 /* check IP address */
210 if (pszInetAddr != NULL) {
211 if ((dwIpAddr = inet_addr(pszInetAddr)) == INADDR_NONE) {
212 _tprintf(_T("ARP: bad IP address: %s\n"), pszInetAddr);
213 return -1;
214 }
215 } else {
216 Usage();
217 }
218
219 /* check MAC address */
220 if (strlen(pszEthAddr) != 17) {
221 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr);
222 return -1;
223 }
224 for (i=0; i<17; i++) {
225 if (pszEthAddr[i] == SEPERATOR) {
226 continue;
227 }
228 if (!isxdigit(pszEthAddr[i])) {
229 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr);
230 return -1;
231 }
232 }
233
234 /* reserve memory on heap and zero */
235 pAddHost = (MIB_IPNETROW *) malloc(sizeof(MIB_IPNETROW));
236 ZeroMemory(pAddHost, sizeof(MIB_IPNETROW));
237
238
239
240
241 /* set dwIndex field to the index of a local IP address to
242 * indicate the network on which the ARP entry applies */
243 if (pszIfAddr) {
244 sscanf(pszIfAddr, "%lx", &pAddHost->dwIndex);
245 } else {
246 /* map the IP to the index */
247 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
248 GetIpAddrTable(pIpAddrTable, &dwSize, 0);
249
250 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
251
252 if ((iRet = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE)) != NO_ERROR) { // NO_ERROR = 0
253 _tprintf(_T("GetIpAddrTable failed: %d\n"), iRet);
254 _tprintf(_T("error: %d\n"), WSAGetLastError());
255 }
256 printf("printing pIpAddrTable->table[0].dwIndex = %lx\n", pIpAddrTable->table[0].dwIndex);
257 pAddHost->dwIndex = 4;
258 }
259
260 /* Set MAC address to 6 bytes (typical) */
261 pAddHost->dwPhysAddrLen = 6;
262
263
264 /* Encode bPhysAddr into correct byte array */
265 for (i=0; i<6; i++) {
266 val =0;
267 c = toupper(pszEthAddr[i*3]);
268 c = c - (isdigit(c) ? '0' : ('A' - 10));
269 val += c;
270 val = (val << 4);
271 c = toupper(pszEthAddr[i*3 + 1]);
272 c = c - (isdigit(c) ? '0' : ('A' - 10));
273 val += c;
274 pAddHost->bPhysAddr[i] = val;
275
276 }
277
278
279 /* copy converted IP address */
280 pAddHost->dwAddr = dwIpAddr;
281
282
283 /* set type to static */
284 pAddHost->dwType = MIB_IPNET_TYPE_STATIC;
285
286
287 /* Add the ARP entry */
288 if ((iRet = SetIpNetEntry(pAddHost)) != NO_ERROR) {
289 _tprintf(_T("The ARP entry addition failed: %d\n"), iRet);
290 return -1;
291 }
292
293 free(pIpAddrTable);
294 free(pAddHost);
295
296 return 0;
297 }
298
299
300
301 /*
302 *
303 * Takes an internet address and an optional interface address as
304 * arguments and checks their validity.
305 * Add the interface number and IP to an MIB_IPNETROW structure
306 * and remove the entrty from the ARP cache.
307 *
308 */
309 INT Deletehost(PTCHAR pszInetAddr, PTCHAR pszIfAddr)
310 {
311 PMIB_IPNETROW pDelHost;
312 PMIB_IPADDRTABLE pIpAddrTable;
313 DWORD dwIpAddr;
314 DWORD dwSize = 0;
315 INT iret;
316
317 /* error checking */
318
319 /* check IP address */
320 if (pszInetAddr != NULL) {
321 if ((dwIpAddr = inet_addr(pszInetAddr)) == INADDR_NONE) {
322 _tprintf(_T("ARP: bad IP address: %s\n"), pszInetAddr);
323 return -1;
324 }
325 } else {
326 Usage();
327 }
328
329
330 pIpAddrTable = (MIB_IPADDRTABLE*) malloc(sizeof(MIB_IPADDRTABLE));
331 pDelHost = (MIB_IPNETROW *) malloc(sizeof(MIB_IPNETROW));
332 ZeroMemory(pIpAddrTable, sizeof(MIB_IPADDRTABLE));
333 ZeroMemory(pDelHost, sizeof(MIB_IPNETROW));
334 /* set dwIndex field to the index of a local IP address to
335 * indicate the network on which the ARP entry applies */
336 if (pszIfAddr) {
337 sscanf(pszIfAddr, "%lx", &pDelHost->dwIndex);
338 } else {
339 /* map the IP to the index */
340 if (GetIpAddrTable(pIpAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
341 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
342 }
343 if ((iret = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE)) != NO_ERROR) {
344 _tprintf(_T("GetIpAddrTable failed: %d\n"), iret);
345 _tprintf(_T("error: %d\n"), WSAGetLastError());
346 }
347 pDelHost->dwIndex = 4; //pIpAddrTable->table[0].dwIndex;
348 }
349
350 /* copy converted IP address */
351 pDelHost->dwAddr = dwIpAddr;
352
353 /* Add the ARP entry */
354 if ((iret = DeleteIpNetEntry(pDelHost)) != NO_ERROR) {
355 _tprintf(_T("The ARP entry deletion failed: %d\n"), iret);
356 return -1;
357 }
358
359 free(pIpAddrTable);
360 free(pDelHost);
361
362 return 0;
363 }
364
365
366
367 /*
368 *
369 * print program usage to screen
370 *
371 */
372 VOID Usage(VOID)
373 {
374 _tprintf(_T("\nDisplays and modifies the IP-to-Physical address translation tables used by\n"
375 "address resolution protocol (ARP).\n"
376 "\n"
377 "ARP -s inet_addr eth_addr [if_addr]\n"
378 "ARP -d inet_addr [if_addr]\n"
379 "ARP -a [inet_addr] [-N if_addr]\n"
380 "\n"
381 " -a Displays current ARP entries by interrogating the current\n"
382 " protocol data. If inet_addr is specified, the IP and Physical\n"
383 " addresses for only the specified computer are displayed. If\n"
384 " more than one network interface uses ARP, entries for each ARP\n"
385 " table are displayed.\n"
386 " -g Same as -a.\n"
387 " inet_addr Specifies an internet address.\n"
388 " -N if_addr Displays the ARP entries for the network interface specified\n"
389 " by if_addr.\n"
390 " -d Deletes the host specified by inet_addr. inet_addr may be\n"
391 " wildcarded with * to delete all hosts.\n"
392 " -s Adds the host and associates the Internet address inet_addr\n"
393 " with the Physical address eth_addr. The Physical address is\n"
394 " given as 6 hexadecimal bytes separated by hyphens. The entry\n"
395 " is permanent.\n"
396 " eth_addr Specifies a physical address.\n"
397 " if_addr If present, this specifies the Internet address of the\n"
398 " interface whose address translation table should be modified.\n"
399 " If not present, the first applicable interface will be used.\n"
400 "Example:\n"
401 " > arp -s 157.55.85.212 00-aa-00-62-c6-09 .... Adds a static entry.\n"
402 " > arp -a .... Displays the arp table.\n\n"));
403 }
404
405
406
407 /*
408 *
409 * Program entry.
410 * Parse command line and call the required function
411 *
412 */
413 INT main(int argc, char* argv[])
414 {
415 const char N[] = "-N";
416
417 if ((argc < 2) || (argc > 5))
418 {
419 Usage();
420 return FALSE;
421 }
422
423
424 if (argv[1][0] == '-') {
425 switch (argv[1][1]) {
426 /* FIX ME */
427 /* need better control for -a, as -N might not be arg 4 */
428 case 'a': if (argc == 2)
429 DisplayArpEntries(NULL, NULL);
430 else if (argc == 3)
431 DisplayArpEntries(argv[2], NULL);
432 else if ((argc == 5) && ((strcmp(argv[3], N)) == 0))
433 DisplayArpEntries(argv[2], argv[4]);
434 else
435 Usage();
436 break;
437 case 'g': break;
438 case 'd': if (argc == 3)
439 Deletehost(argv[2], NULL);
440 else if (argc == 4)
441 Deletehost(argv[2], argv[3]);
442 else
443 Usage();
444 break;
445 case 's': if (argc == 4)
446 Addhost(argv[2], argv[3], NULL);
447 else if (argc == 5)
448 Addhost(argv[2], argv[3], argv[4]);
449 else
450 Usage();
451 break;
452 default:
453 Usage();
454 return -1;
455 }
456 } else {
457 Usage();
458 return -1;
459 }
460
461 return 0;
462 }