2 * ReactOS Win32 Applications
3 * Copyright (C) 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS arp utility
23 * FILE: base/applications/network/arp/arp.c
24 * PURPOSE: view and manipulate the ARP cache
25 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
31 #define WIN32_NO_STATUS
45 const char SEPARATOR
= '-';
46 int _CRT_glob
= 0; // stop * from listing dir files in arp -d *
49 * function declarations
51 DWORD
DoFormatMessage(VOID
);
52 INT
PrintEntries(PMIB_IPNETROW pIpAddRow
);
53 INT
DisplayArpEntries(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
);
54 INT
Addhost(PTCHAR pszInetAddr
, PTCHAR pszEthAddr
, PTCHAR pszIfAddr
);
55 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
);
59 * convert error code into meaningful message
61 DWORD
DoFormatMessage(VOID
)
66 DWORD ErrorCode
= GetLastError();
68 if (ErrorCode
!= ERROR_SUCCESS
)
70 RetVal
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
71 FORMAT_MESSAGE_FROM_SYSTEM
|
72 FORMAT_MESSAGE_IGNORE_INSERTS
,
75 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), /* Default language */
84 /* return number of TCHAR's stored in output buffer
85 * excluding '\0' - as FormatMessage does*/
99 RetVal
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
100 FORMAT_MESSAGE_FROM_HMODULE
|
101 FORMAT_MESSAGE_IGNORE_INSERTS
,
102 GetModuleHandleW(NULL
),
124 va_start(args
, dwMessage
);
126 RetVal
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_HMODULE
,
127 GetModuleHandleW(NULL
),
144 * Takes an ARP entry and prints the IP address,
145 * the MAC address and the entry type to screen
148 INT
PrintEntries(PMIB_IPNETROW pIpAddRow
)
153 /* print IP addresses */
154 inaddr
.S_un
.S_addr
= pIpAddRow
->dwAddr
;
155 _tprintf(_T(" %-22s"), inet_ntoa(inaddr
));
157 /* print MAC address */
158 _stprintf(cMacAddr
, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
159 pIpAddRow
->bPhysAddr
[0],
160 pIpAddRow
->bPhysAddr
[1],
161 pIpAddRow
->bPhysAddr
[2],
162 pIpAddRow
->bPhysAddr
[3],
163 pIpAddRow
->bPhysAddr
[4],
164 pIpAddRow
->bPhysAddr
[5]);
165 _tprintf(_T("%-22s"), cMacAddr
);
167 /* print cache type */
168 switch (pIpAddRow
->dwType
)
170 case MIB_IPNET_TYPE_DYNAMIC
:
174 case MIB_IPNET_TYPE_STATIC
:
178 case MIB_IPNET_TYPE_INVALID
:
182 case MIB_IPNET_TYPE_OTHER
:
191 * Takes optional parameters of an internet address and interface address.
192 * Retrieve all entries in the ARP cache. If an internet address is
193 * specified, display the ARP entry relating to that address. If an
194 * interface address is specified, display all entries relating to
198 /* FIXME: allow user to specify an interface address, via pszIfAddr */
199 INT
DisplayArpEntries(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
203 PMIB_IPNETTABLE pIpNetTable
= NULL
;
204 PMIB_IPADDRTABLE pIpAddrTable
= NULL
;
206 struct in_addr inaddr
, inaddr2
;
208 TCHAR szIntIpAddr
[20];
210 /* retrieve the IP-to-physical address mapping table */
213 GetIpNetTable(pIpNetTable
, &Size
, 0);
215 /* allocate memory for ARP address table */
216 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
217 if (pIpNetTable
== NULL
)
220 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
222 if (GetIpNetTable(pIpNetTable
, &Size
, TRUE
) != NO_ERROR
)
224 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
229 /* check there are entries in the table */
230 if (pIpNetTable
->dwNumEntries
== 0)
238 /* Retrieve the interface-to-ip address mapping
239 * table to get the IP address for adapter */
243 GetIpAddrTable(pIpAddrTable
, &Size
, 0);
245 pIpAddrTable
= (MIB_IPADDRTABLE
*) HeapAlloc(GetProcessHeap(), 0, Size
);
246 if (pIpAddrTable
== NULL
)
249 ZeroMemory(pIpAddrTable
, sizeof(*pIpAddrTable
));
251 if ((iRet
= GetIpAddrTable(pIpAddrTable
, &Size
, TRUE
)) != NO_ERROR
)
253 _tprintf(_T("GetIpAddrTable failed: %d\n"), iRet
);
259 for (k
=0; k
< pIpAddrTable
->dwNumEntries
; k
++)
261 if (pIpNetTable
->table
[0].dwIndex
== pIpAddrTable
->table
[k
].dwIndex
)
263 //printf("debug print: pIpAddrTable->table[?].dwIndex = %lx\n", pIpNetTable->table[k].dwIndex);
264 inaddr2
.s_addr
= pIpAddrTable
->table
[k
].dwAddr
;
265 pszIpAddr
= inet_ntoa(inaddr2
);
266 strcpy(szIntIpAddr
, pszIpAddr
);
271 /* print header, including interface IP address and index number */
272 PrintMessageV(10003, szIntIpAddr
, pIpNetTable
->table
[0].dwIndex
);
274 /* go through all ARP entries */
275 for (i
=0; i
< pIpNetTable
->dwNumEntries
; i
++)
278 /* if the user has supplied their own internet address *
279 * only print the arp entry which matches that */
282 inaddr
.S_un
.S_addr
= pIpNetTable
->table
[i
].dwAddr
;
283 pszIpAddr
= inet_ntoa(inaddr
);
285 /* check if it matches, print it */
286 if (strcmp(pszIpAddr
, pszInetAddr
) == 0)
287 PrintEntries(&pIpNetTable
->table
[i
]);
290 /* if an address is not supplied, print all entries */
291 PrintEntries(&pIpNetTable
->table
[i
]);
297 if (pIpNetTable
!= NULL
)
298 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
299 if (pIpAddrTable
!= NULL
)
300 HeapFree(GetProcessHeap(), 0, pIpAddrTable
);
306 * Takes an internet address, a MAC address and an optional interface
307 * address as arguments and checks their validity.
308 * Fill out an MIB_IPNETROW structure and insert the data into the
309 * ARP cache as a static entry.
312 INT
Addhost(PTCHAR pszInetAddr
, PTCHAR pszEthAddr
, PTCHAR pszIfAddr
)
314 PMIB_IPNETROW pAddHost
= NULL
;
315 PMIB_IPNETTABLE pIpNetTable
= NULL
;
322 /* check IP address */
323 if (pszInetAddr
!= NULL
)
325 if ((dwIpAddr
= inet_addr(pszInetAddr
)) == INADDR_NONE
)
327 PrintMessageV(10001, pszInetAddr
);
337 /* check MAC address */
338 if (strlen(pszEthAddr
) != 17)
340 PrintMessageV(10002, pszEthAddr
);
345 if (pszEthAddr
[i
] == SEPARATOR
)
348 if (!isxdigit(pszEthAddr
[i
]))
350 PrintMessageV(10002, pszEthAddr
);
355 /* We need the IpNetTable to get the adapter index */
356 /* Return required buffer size */
357 GetIpNetTable(pIpNetTable
, &Size
, 0);
359 /* allocate memory for ARP address table */
360 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
361 if (pIpNetTable
== NULL
)
364 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
366 if (GetIpNetTable(pIpNetTable
, &Size
, TRUE
) != NO_ERROR
)
368 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
374 /* reserve memory on heap and zero */
375 pAddHost
= (MIB_IPNETROW
*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW
));
376 if (pAddHost
== NULL
)
379 ZeroMemory(pAddHost
, sizeof(MIB_IPNETROW
));
381 /* set dwIndex field to the index of a local IP address to
382 * indicate the network on which the ARP entry applies */
385 if (sscanf(pszIfAddr
, "%lx", &pAddHost
->dwIndex
) == EOF
)
392 //printf("debug print: pIpNetTable->table[0].dwIndex = %lx\n", pIpNetTable->table[0].dwIndex);
393 /* needs testing. I get the correct index on my machine, but need others
394 * to test their card index. Any problems and we can use GetAdaptersInfo instead */
395 pAddHost
->dwIndex
= pIpNetTable
->table
[0].dwIndex
;
398 /* Set MAC address to 6 bytes (typical) */
399 pAddHost
->dwPhysAddrLen
= 6;
402 /* Encode bPhysAddr into correct byte array */
406 c
= toupper(pszEthAddr
[i
*3]);
407 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
410 c
= toupper(pszEthAddr
[i
*3 + 1]);
411 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
413 pAddHost
->bPhysAddr
[i
] = (BYTE
)val
;
417 /* copy converted IP address */
418 pAddHost
->dwAddr
= dwIpAddr
;
421 /* set type to static */
422 pAddHost
->dwType
= MIB_IPNET_TYPE_STATIC
;
425 /* Add the ARP entry */
426 if (SetIpNetEntry(pAddHost
) != NO_ERROR
)
432 HeapFree(GetProcessHeap(), 0, pAddHost
);
437 if (pIpNetTable
!= NULL
)
438 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
439 if (pAddHost
!= NULL
)
440 HeapFree(GetProcessHeap(), 0, pAddHost
);
446 * Takes an internet address and an optional interface address as
447 * arguments and checks their validity.
448 * Add the interface number and IP to an MIB_IPNETROW structure
449 * and remove the entry from the ARP cache.
452 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
454 PMIB_IPNETROW pDelHost
= NULL
;
455 PMIB_IPNETTABLE pIpNetTable
= NULL
;
458 BOOL bFlushTable
= FALSE
;
462 /* check IP address */
463 if (pszInetAddr
!= NULL
)
465 /* if wildcard is given, set flag to delete all hosts */
466 if (strncmp(pszInetAddr
, "*", 1) == 0)
468 else if ((dwIpAddr
= inet_addr(pszInetAddr
)) == INADDR_NONE
)
470 PrintMessageV(10001, pszInetAddr
);
480 /* We need the IpNetTable to get the adapter index */
481 /* Return required buffer size */
482 GetIpNetTable(NULL
, &Size
, 0);
484 /* allocate memory for ARP address table */
485 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
486 if (pIpNetTable
== NULL
)
489 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
491 if (GetIpNetTable(pIpNetTable
, &Size
, TRUE
) != NO_ERROR
)
493 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
498 /* reserve memory on heap and zero */
499 pDelHost
= (MIB_IPNETROW
*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW
));
500 if (pDelHost
== NULL
)
503 ZeroMemory(pDelHost
, sizeof(MIB_IPNETROW
));
506 /* set dwIndex field to the index of a local IP address to
507 * indicate the network on which the ARP entry applies */
510 if (sscanf(pszIfAddr
, "%lx", &pDelHost
->dwIndex
) == EOF
)
517 /* needs testing. I get the correct index on my machine, but need others
518 * to test their card index. Any problems and we can use GetAdaptersInfo instead */
519 pDelHost
->dwIndex
= pIpNetTable
->table
[0].dwIndex
;
522 if (bFlushTable
!= FALSE
)
524 /* delete arp cache */
525 if (FlushIpNetTable(pDelHost
->dwIndex
) != NO_ERROR
)
532 HeapFree(GetProcessHeap(), 0, pDelHost
);
537 /* copy converted IP address */
538 pDelHost
->dwAddr
= dwIpAddr
;
540 /* Add the ARP entry */
541 if (DeleteIpNetEntry(pDelHost
) != NO_ERROR
)
547 HeapFree(GetProcessHeap(), 0, pDelHost
);
552 if (pIpNetTable
!= NULL
)
553 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
554 if (pDelHost
!= NULL
)
555 HeapFree(GetProcessHeap(), 0, pDelHost
);
561 * print program usage to screen
572 * Parse command line and call the required function
575 INT
main(int argc
, char* argv
[])
577 if ((argc
< 2) || (argc
> 5))
583 if (argv
[1][0] == '-')
587 case 'a': /* fall through */
590 DisplayArpEntries(NULL
, NULL
);
592 DisplayArpEntries(argv
[2], NULL
);
593 else if ((argc
== 4) && ((strcmp(argv
[2], "-N")) == 0))
594 DisplayArpEntries(NULL
, argv
[3]);
595 else if ((argc
== 5) && ((strcmp(argv
[3], "-N")) == 0))
596 DisplayArpEntries(argv
[2], argv
[4]);
603 case 'd': if (argc
== 3)
604 Deletehost(argv
[2], NULL
);
606 Deletehost(argv
[2], argv
[3]);
613 case 's': if (argc
== 4)
614 Addhost(argv
[2], argv
[3], NULL
);
616 Addhost(argv
[2], argv
[3], argv
[4]);