a563291afed695672e84ea14a679a1aa6c7d331a
[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 return -1;
218 }
219
220 /* check MAC address */
221 if (strlen(pszEthAddr) != 17) {
222 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr);
223 return -1;
224 }
225 for (i=0; i<17; i++) {
226 if (pszEthAddr[i] == SEPERATOR) {
227 continue;
228 }
229 if (!isxdigit(pszEthAddr[i])) {
230 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr);
231 return -1;
232 }
233 }
234
235 /* reserve memory on heap and zero */
236 pAddHost = (MIB_IPNETROW *) malloc(sizeof(MIB_IPNETROW));
237 ZeroMemory(pAddHost, sizeof(MIB_IPNETROW));
238
239
240
241
242 /* set dwIndex field to the index of a local IP address to
243 * indicate the network on which the ARP entry applies */
244 if (pszIfAddr) {
245 sscanf(pszIfAddr, "%lx", &pAddHost->dwIndex);
246 } else {
247 /* map the IP to the index */
248 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
249 GetIpAddrTable(pIpAddrTable, &dwSize, 0);
250
251 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
252
253 if ((iRet = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE)) != NO_ERROR) { // NO_ERROR = 0
254 _tprintf(_T("GetIpAddrTable failed: %d\n"), iRet);
255 _tprintf(_T("error: %d\n"), WSAGetLastError());
256 }
257 printf("printing pIpAddrTable->table[0].dwIndex = %lx\n", pIpAddrTable->table[0].dwIndex);
258 pAddHost->dwIndex = 4;
259
260 free(pIpAddrTable);
261 }
262
263 /* Set MAC address to 6 bytes (typical) */
264 pAddHost->dwPhysAddrLen = 6;
265
266
267 /* Encode bPhysAddr into correct byte array */
268 for (i=0; i<6; i++) {
269 val =0;
270 c = toupper(pszEthAddr[i*3]);
271 c = c - (isdigit(c) ? '0' : ('A' - 10));
272 val += c;
273 val = (val << 4);
274 c = toupper(pszEthAddr[i*3 + 1]);
275 c = c - (isdigit(c) ? '0' : ('A' - 10));
276 val += c;
277 pAddHost->bPhysAddr[i] = val;
278
279 }
280
281
282 /* copy converted IP address */
283 pAddHost->dwAddr = dwIpAddr;
284
285
286 /* set type to static */
287 pAddHost->dwType = MIB_IPNET_TYPE_STATIC;
288
289
290 /* Add the ARP entry */
291 if ((iRet = SetIpNetEntry(pAddHost)) != NO_ERROR) {
292 _tprintf(_T("The ARP entry addition failed: %d\n"), iRet);
293 return -1;
294 }
295
296 free(pAddHost);
297
298 return 0;
299 }
300
301
302
303 /*
304 *
305 * Takes an internet address and an optional interface address as
306 * arguments and checks their validity.
307 * Add the interface number and IP to an MIB_IPNETROW structure
308 * and remove the entrty from the ARP cache.
309 *
310 */
311 INT Deletehost(PTCHAR pszInetAddr, PTCHAR pszIfAddr)
312 {
313 PMIB_IPNETROW pDelHost;
314 PMIB_IPADDRTABLE pIpAddrTable;
315 DWORD dwIpAddr;
316 DWORD dwSize = 0;
317 INT iret;
318
319 /* error checking */
320
321 /* check IP address */
322 if (pszInetAddr != NULL) {
323 if ((dwIpAddr = inet_addr(pszInetAddr)) == INADDR_NONE) {
324 _tprintf(_T("ARP: bad IP address: %s\n"), pszInetAddr);
325 return -1;
326 }
327 } else {
328 Usage();
329 }
330
331
332 pIpAddrTable = (MIB_IPADDRTABLE*) malloc(sizeof(MIB_IPADDRTABLE));
333 pDelHost = (MIB_IPNETROW *) malloc(sizeof(MIB_IPNETROW));
334 ZeroMemory(pIpAddrTable, sizeof(MIB_IPADDRTABLE));
335 ZeroMemory(pDelHost, sizeof(MIB_IPNETROW));
336 /* set dwIndex field to the index of a local IP address to
337 * indicate the network on which the ARP entry applies */
338 if (pszIfAddr) {
339 sscanf(pszIfAddr, "%lx", &pDelHost->dwIndex);
340 } else {
341 /* map the IP to the index */
342 if (GetIpAddrTable(pIpAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
343 pIpAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
344 }
345 if ((iret = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE)) != NO_ERROR) {
346 _tprintf(_T("GetIpAddrTable failed: %d\n"), iret);
347 _tprintf(_T("error: %d\n"), WSAGetLastError());
348 }
349 pDelHost->dwIndex = 4; //pIpAddrTable->table[0].dwIndex;
350 }
351
352 /* copy converted IP address */
353 pDelHost->dwAddr = dwIpAddr;
354
355 /* Add the ARP entry */
356 if ((iret = DeleteIpNetEntry(pDelHost)) != NO_ERROR) {
357 _tprintf(_T("The ARP entry deletion failed: %d\n"), iret);
358 return -1;
359 }
360
361 free(pIpAddrTable);
362 free(pDelHost);
363
364 return 0;
365 }
366
367
368
369 /*
370 *
371 * print program usage to screen
372 *
373 */
374 VOID Usage(VOID)
375 {
376 _tprintf(_T("\nDisplays and modifies the IP-to-Physical address translation tables used by\n"
377 "address resolution protocol (ARP).\n"
378 "\n"
379 "ARP -s inet_addr eth_addr [if_addr]\n"
380 "ARP -d inet_addr [if_addr]\n"
381 "ARP -a [inet_addr] [-N if_addr]\n"
382 "\n"
383 " -a Displays current ARP entries by interrogating the current\n"
384 " protocol data. If inet_addr is specified, the IP and Physical\n"
385 " addresses for only the specified computer are displayed. If\n"
386 " more than one network interface uses ARP, entries for each ARP\n"
387 " table are displayed.\n"
388 " -g Same as -a.\n"
389 " inet_addr Specifies an internet address.\n"
390 " -N if_addr Displays the ARP entries for the network interface specified\n"
391 " by if_addr.\n"
392 " -d Deletes the host specified by inet_addr. inet_addr may be\n"
393 " wildcarded with * to delete all hosts.\n"
394 " -s Adds the host and associates the Internet address inet_addr\n"
395 " with the Physical address eth_addr. The Physical address is\n"
396 " given as 6 hexadecimal bytes separated by hyphens. The entry\n"
397 " is permanent.\n"
398 " eth_addr Specifies a physical address.\n"
399 " if_addr If present, this specifies the Internet address of the\n"
400 " interface whose address translation table should be modified.\n"
401 " If not present, the first applicable interface will be used.\n"
402 "Example:\n"
403 " > arp -s 157.55.85.212 00-aa-00-62-c6-09 .... Adds a static entry.\n"
404 " > arp -a .... Displays the arp table.\n\n"));
405 }
406
407
408
409 /*
410 *
411 * Program entry.
412 * Parse command line and call the required function
413 *
414 */
415 INT main(int argc, char* argv[])
416 {
417 const char N[] = "-N";
418
419 if ((argc < 2) || (argc > 5))
420 {
421 Usage();
422 return FALSE;
423 }
424
425
426 if (argv[1][0] == '-') {
427 switch (argv[1][1]) {
428 /* FIX ME */
429 /* need better control for -a, as -N might not be arg 4 */
430 case 'a': if (argc == 2)
431 DisplayArpEntries(NULL, NULL);
432 else if (argc == 3)
433 DisplayArpEntries(argv[2], NULL);
434 else if ((argc == 5) && ((strcmp(argv[3], N)) == 0))
435 DisplayArpEntries(argv[2], argv[4]);
436 else
437 Usage();
438 break;
439 case 'g': break;
440 case 'd': if (argc == 3)
441 Deletehost(argv[2], NULL);
442 else if (argc == 4)
443 Deletehost(argv[2], argv[3]);
444 else
445 Usage();
446 break;
447 case 's': if (argc == 4)
448 Addhost(argv[2], argv[3], NULL);
449 else if (argc == 5)
450 Addhost(argv[2], argv[3], argv[4]);
451 else
452 Usage();
453 break;
454 default:
455 Usage();
456 return -1;
457 }
458 } else {
459 Usage();
460 return -1;
461 }
462
463 return 0;
464 }