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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS arp utility
23 * FILE: apps/utils/net/arp/arp.c
24 * PURPOSE: view and manipulate the ARP cache
25 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
31 #define WIN32_LEAN_AND_MEAN
47 const char SEPERATOR
= '-';
48 int _CRT_glob
= 0; // stop * from listing dir files in arp -d *
52 * function declerations
54 DWORD
DoFormatMessage(VOID
);
55 INT
PrintEntries(PMIB_IPNETROW pIpAddRow
);
56 INT
DisplayArpEntries(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
);
57 INT
Addhost(PTCHAR pszInetAddr
, PTCHAR pszEthAddr
, PTCHAR pszIfAddr
);
58 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
);
63 * convert error code into meaningful message
65 DWORD
DoFormatMessage(VOID
)
70 DWORD ErrorCode
= GetLastError();
72 if (ErrorCode
!= ERROR_SUCCESS
)
74 RetVal
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
75 FORMAT_MESSAGE_FROM_SYSTEM
|
76 FORMAT_MESSAGE_IGNORE_INSERTS
,
79 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), /* Default language */
86 _tprintf(_T("%s"), (LPTSTR
)lpMsgBuf
);
89 /* return number of TCHAR's stored in output buffer
90 * excluding '\0' - as FormatMessage does*/
101 * Takes an ARP entry and prints the IP address,
102 * the MAC address and the entry type to screen
105 INT
PrintEntries(PMIB_IPNETROW pIpAddRow
)
110 /* print IP addresses */
111 inaddr
.S_un
.S_addr
= pIpAddRow
->dwAddr
;
112 _tprintf(_T(" %-22s"), inet_ntoa(inaddr
));
114 /* print MAC address */
115 _stprintf(cMacAddr
, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
116 pIpAddRow
->bPhysAddr
[0],
117 pIpAddRow
->bPhysAddr
[1],
118 pIpAddRow
->bPhysAddr
[2],
119 pIpAddRow
->bPhysAddr
[3],
120 pIpAddRow
->bPhysAddr
[4],
121 pIpAddRow
->bPhysAddr
[5]);
122 _tprintf(_T("%-22s"), cMacAddr
);
124 /* print cache type */
125 switch (pIpAddRow
->dwType
)
127 case MIB_IPNET_TYPE_DYNAMIC
: _tprintf(_T("dynamic\n"));
129 case MIB_IPNET_TYPE_STATIC
: _tprintf(_T("static\n"));
131 case MIB_IPNET_TYPE_INVALID
: _tprintf(_T("invalid\n"));
133 case MIB_IPNET_TYPE_OTHER
: _tprintf(_T("other\n"));
142 * Takes optional parameters of an internet address and interface address.
143 * Retrieve all entries in the ARP cache. If an internet address is
144 * specified, display the ARP entry relating to that address. If an
145 * interface address is specified, display all entries relating to
149 /* FIXME: allow user to specify an interface address, via pszIfAddr */
150 INT
DisplayArpEntries(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
154 PMIB_IPNETTABLE pIpNetTable
= NULL
;
155 PMIB_IPADDRTABLE pIpAddrTable
= NULL
;
157 struct in_addr inaddr
, inaddr2
;
159 TCHAR szIntIpAddr
[20];
161 /* retrieve the IP-to-physical address mapping table */
164 GetIpNetTable(pIpNetTable
, &Size
, 0);
166 /* allocate memory for ARP address table */
167 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
168 if (pIpNetTable
== NULL
)
171 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
173 iRet
= GetIpNetTable(pIpNetTable
, &Size
, TRUE
);
175 if (iRet
!= NO_ERROR
)
177 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
182 /* check there are entries in the table */
183 if (pIpNetTable
->dwNumEntries
== 0)
185 _tprintf(_T("No ARP entires found\n"));
191 /* Retrieve the interface-to-ip address mapping
192 * table to get the IP address for adapter */
196 GetIpAddrTable(pIpAddrTable
, &Size
, 0);
198 pIpAddrTable
= (MIB_IPADDRTABLE
*) HeapAlloc(GetProcessHeap(), 0, Size
);
199 if (pIpAddrTable
== NULL
)
202 ZeroMemory(pIpAddrTable
, sizeof(*pIpAddrTable
));
204 iRet
= GetIpAddrTable(pIpAddrTable
, &Size
, TRUE
);
206 if (iRet
!= NO_ERROR
)
208 _tprintf(_T("GetIpAddrTable failed: %d\n"), iRet
);
214 for (k
=0; k
< pIpAddrTable
->dwNumEntries
; k
++)
216 if (pIpNetTable
->table
[0].dwIndex
== pIpAddrTable
->table
[k
].dwIndex
)
218 //printf("debug print: pIpAddrTable->table[?].dwIndex = %lx\n", pIpNetTable->table[k].dwIndex);
219 inaddr2
.s_addr
= pIpAddrTable
->table
[k
].dwAddr
;
220 pszIpAddr
= inet_ntoa(inaddr2
);
221 strcpy(szIntIpAddr
, pszIpAddr
);
226 /* print header, including interface IP address and index number */
227 _tprintf(_T("\nInterface: %s --- 0x%lx \n"), szIntIpAddr
, pIpNetTable
->table
[0].dwIndex
);
228 _tprintf(_T(" Internet Address Physical Address Type\n"));
230 /* go through all ARP entries */
231 for (i
=0; i
< pIpNetTable
->dwNumEntries
; i
++)
234 /* if the user has supplied their own internet addesss *
235 * only print the arp entry which matches that */
238 inaddr
.S_un
.S_addr
= pIpNetTable
->table
[i
].dwAddr
;
239 pszIpAddr
= inet_ntoa(inaddr
);
241 /* check if it matches, print it */
242 if (strcmp(pszIpAddr
, pszInetAddr
) == 0)
243 PrintEntries(&pIpNetTable
->table
[i
]);
246 /* if an address is not supplied, print all entries */
247 PrintEntries(&pIpNetTable
->table
[i
]);
253 if (pIpNetTable
!= NULL
)
254 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
255 if (pIpAddrTable
!= NULL
)
256 HeapFree(GetProcessHeap(), 0, pIpAddrTable
);
263 * Takes an internet address, a MAC address and an optional interface
264 * address as arguments and checks their validity.
265 * Fill out an MIB_IPNETROW structure and insert the data into the
266 * ARP cache as a static entry.
269 INT
Addhost(PTCHAR pszInetAddr
, PTCHAR pszEthAddr
, PTCHAR pszIfAddr
)
271 PMIB_IPNETROW pAddHost
= NULL
;
272 PMIB_IPNETTABLE pIpNetTable
= NULL
;
279 /* check IP address */
280 if (pszInetAddr
!= NULL
)
282 if ((dwIpAddr
= inet_addr(pszInetAddr
)) == INADDR_NONE
)
284 _tprintf(_T("ARP: bad IP address: %s\n"), pszInetAddr
);
294 /* check MAC address */
295 if (strlen(pszEthAddr
) != 17)
297 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
302 if (pszEthAddr
[i
] == SEPERATOR
)
305 if (!isxdigit(pszEthAddr
[i
]))
307 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
312 /* We need the IpNetTable to get the adapter index */
313 /* Return required buffer size */
314 GetIpNetTable(pIpNetTable
, &Size
, 0);
316 /* allocate memory for ARP address table */
317 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
318 if (pIpNetTable
== NULL
)
321 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
323 iRet
= GetIpNetTable(pIpNetTable
, &Size
, TRUE
);
325 if (iRet
!= NO_ERROR
)
327 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
333 /* reserve memory on heap and zero */
334 pAddHost
= (MIB_IPNETROW
*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW
));
335 if (pAddHost
== NULL
)
338 ZeroMemory(pAddHost
, sizeof(MIB_IPNETROW
));
340 /* set dwIndex field to the index of a local IP address to
341 * indicate the network on which the ARP entry applies */
344 if (sscanf(pszIfAddr
, "%lx", &pAddHost
->dwIndex
) == EOF
)
351 //printf("debug print: pIpNetTable->table[0].dwIndex = %lx\n", pIpNetTable->table[0].dwIndex);
352 /* needs testing. I get the correct index on my machine, but need others
353 * to test their card index. Any problems and we can use GetAdaptersInfo instead */
354 pAddHost
->dwIndex
= pIpNetTable
->table
[0].dwIndex
;
357 /* Set MAC address to 6 bytes (typical) */
358 pAddHost
->dwPhysAddrLen
= 6;
361 /* Encode bPhysAddr into correct byte array */
365 c
= toupper(pszEthAddr
[i
*3]);
366 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
369 c
= toupper(pszEthAddr
[i
*3 + 1]);
370 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
372 pAddHost
->bPhysAddr
[i
] = (BYTE
)val
;
376 /* copy converted IP address */
377 pAddHost
->dwAddr
= dwIpAddr
;
380 /* set type to static */
381 pAddHost
->dwType
= MIB_IPNET_TYPE_STATIC
;
384 /* Add the ARP entry */
385 if ((iRet
= SetIpNetEntry(pAddHost
)) != NO_ERROR
)
391 HeapFree(GetProcessHeap(), 0, pAddHost
);
396 if (pIpNetTable
!= NULL
)
397 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
398 if (pAddHost
!= NULL
)
399 HeapFree(GetProcessHeap(), 0, pAddHost
);
406 * Takes an internet address and an optional interface address as
407 * arguments and checks their validity.
408 * Add the interface number and IP to an MIB_IPNETROW structure
409 * and remove the entry from the ARP cache.
412 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
414 PMIB_IPNETROW pDelHost
= NULL
;
415 PMIB_IPNETTABLE pIpNetTable
= NULL
;
419 BOOL bFlushTable
= FALSE
;
423 /* check IP address */
424 if (pszInetAddr
!= NULL
)
426 /* if wildcard is given, set flag to delete all hosts */
427 if (strncmp(pszInetAddr
, "*", 1) == 0)
429 else if ((dwIpAddr
= inet_addr(pszInetAddr
)) == INADDR_NONE
)
431 _tprintf(_T("ARP: bad IP address: %s\n"), pszInetAddr
);
441 /* We need the IpNetTable to get the adapter index */
442 /* Return required buffer size */
443 GetIpNetTable(NULL
, &Size
, 0);
445 /* allocate memory for ARP address table */
446 pIpNetTable
= (PMIB_IPNETTABLE
) HeapAlloc(GetProcessHeap(), 0, Size
);
447 if (pIpNetTable
== NULL
)
450 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
452 iRet
= GetIpNetTable(pIpNetTable
, &Size
, TRUE
);
454 if (iRet
!= NO_ERROR
)
456 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
461 /* reserve memory on heap and zero */
462 pDelHost
= (MIB_IPNETROW
*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPNETROW
));
463 if (pDelHost
== NULL
)
466 ZeroMemory(pDelHost
, sizeof(MIB_IPNETROW
));
469 /* set dwIndex field to the index of a local IP address to
470 * indicate the network on which the ARP entry applies */
473 if (sscanf(pszIfAddr
, "%lx", &pDelHost
->dwIndex
) == EOF
)
480 /* needs testing. I get the correct index on my machine, but need others
481 * to test their card index. Any problems and we can use GetAdaptersInfo instead */
482 pDelHost
->dwIndex
= pIpNetTable
->table
[0].dwIndex
;
485 if (bFlushTable
== TRUE
)
487 /* delete arp cache */
488 if ((iRet
= FlushIpNetTable(pDelHost
->dwIndex
)) != NO_ERROR
)
495 HeapFree(GetProcessHeap(), 0, pDelHost
);
500 /* copy converted IP address */
501 pDelHost
->dwAddr
= dwIpAddr
;
503 /* Add the ARP entry */
504 if ((iRet
= DeleteIpNetEntry(pDelHost
)) != NO_ERROR
)
510 HeapFree(GetProcessHeap(), 0, pDelHost
);
515 if (pIpNetTable
!= NULL
)
516 HeapFree(GetProcessHeap(), 0, pIpNetTable
);
517 if (pDelHost
!= NULL
)
518 HeapFree(GetProcessHeap(), 0, pDelHost
);
526 * print program usage to screen
531 _tprintf(_T("\nDisplays and modifies the IP-to-Physical address translation tables used by\n"
532 "address resolution protocol (ARP).\n"
534 "ARP -s inet_addr eth_addr [if_addr]\n"
535 "ARP -d inet_addr [if_addr]\n"
536 "ARP -a [inet_addr] [-N if_addr]\n"
538 " -a Displays current ARP entries by interrogating the current\n"
539 " protocol data. If inet_addr is specified, the IP and Physical\n"
540 " addresses for only the specified computer are displayed. If\n"
541 " more than one network interface uses ARP, entries for each ARP\n"
542 " table are displayed.\n"
544 " inet_addr Specifies an internet address.\n"
545 " -N if_addr Displays the ARP entries for the network interface specified\n"
547 " -d Deletes the host specified by inet_addr. inet_addr may be\n"
548 " wildcarded with * to delete all hosts.\n"
549 " -s Adds the host and associates the Internet address inet_addr\n"
550 " with the Physical address eth_addr. The Physical address is\n"
551 " given as 6 hexadecimal bytes separated by hyphens. The entry\n"
553 " eth_addr Specifies a physical address.\n"
554 " if_addr If present, this specifies the Internet address of the\n"
555 " interface whose address translation table should be modified.\n"
556 " If not present, the first applicable interface will be used.\n"
558 " > arp -s 157.55.85.212 00-aa-00-62-c6-09 .... Adds a static entry.\n"
559 " > arp -a .... Displays the arp table.\n\n"));
567 * Parse command line and call the required function
570 INT
main(int argc
, char* argv
[])
572 if ((argc
< 2) || (argc
> 5))
578 if (argv
[1][0] == '-')
582 case 'a': /* fall through */
585 DisplayArpEntries(NULL
, NULL
);
587 DisplayArpEntries(argv
[2], NULL
);
588 else if ((argc
== 4) && ((strcmp(argv
[2], "-N")) == 0))
589 DisplayArpEntries(NULL
, argv
[3]);
590 else if ((argc
== 5) && ((strcmp(argv
[3], "-N")) == 0))
591 DisplayArpEntries(argv
[2], argv
[4]);
596 case 'd': if (argc
== 3)
597 Deletehost(argv
[2], NULL
);
599 Deletehost(argv
[2], argv
[3]);
604 case 's': if (argc
== 4)
605 Addhost(argv
[2], argv
[3], NULL
);
607 Addhost(argv
[2], argv
[3], argv
[4]);