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)
22 #define WIN32_LEAN_AND_MEAN
29 const char SEPERATOR
= '-';
34 * function declerations
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
);
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
53 /* FIXME: allow user to specify an interface address, via pszIfAddr */
54 INT
DisplayArpEntries(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
58 PMIB_IPNETTABLE pIpNetTable
;
59 PMIB_IPADDRTABLE pIpAddrTable
;
61 struct in_addr inaddr
, inaddr2
;
64 TCHAR szIntIpAddr
[20];
66 /* Return required buffer size */
67 GetIpNetTable(NULL
, &ulSize
, 0);
69 /* allocate memory for ARP address table */
70 pIpNetTable
= (PMIB_IPNETTABLE
) malloc(ulSize
* sizeof(BYTE
));
71 ZeroMemory(pIpNetTable
, sizeof(*pIpNetTable
));
73 /* get Arp address table */
74 if (pIpNetTable
!= NULL
) {
75 GetIpNetTable(pIpNetTable
, &ulSize
, TRUE
);
77 _tprintf(_T("failed to allocate memory for GetIpNetTable\n"));
82 /* check there are entries in the table */
83 if (pIpNetTable
->dwNumEntries
== 0) {
84 _tprintf(_T("No ARP entires found\n"));
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 ?
98 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
99 //ZeroMemory(pIpAddrTable, sizeof(*pIpAddrTable));
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());
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
);
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"));
121 /* go through all ARP entries */
122 for (i
=0; i
< pIpNetTable
->dwNumEntries
; i
++) {
124 /* if the user has supplied their own internet addesss *
125 * only print the arp entry which matches that */
127 inaddr
.S_un
.S_addr
= pIpNetTable
->table
[i
].dwAddr
;
128 pszIpAddr
= inet_ntoa(inaddr
);
130 /* check if it matches, print it */
131 if (strcmp(pszIpAddr
, pszInetAddr
) == 0) {
132 PrintEntries(&pIpNetTable
->table
[i
]);
135 /* if an address is not supplied, print all entries */
136 PrintEntries(&pIpNetTable
->table
[i
]);
151 * Takes an ARP entry and prints the IP address,
152 * the MAC address and the entry type to screen
155 INT
PrintEntries(PMIB_IPNETROW pIpAddRow
)
160 /* print IP addresses */
161 inaddr
.S_un
.S_addr
= pIpAddRow
->dwAddr
;
162 _tprintf(_T(" %-22s"), inet_ntoa(inaddr
)); //error checking
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
);
174 /* print cache type */
175 switch (pIpAddRow
->dwType
) {
176 case MIB_IPNET_TYPE_DYNAMIC
: _tprintf(_T("dynamic\n"));
178 case MIB_IPNET_TYPE_STATIC
: _tprintf(_T("static\n"));
180 case MIB_IPNET_TYPE_INVALID
: _tprintf(_T("invalid\n"));
182 case MIB_IPNET_TYPE_OTHER
: _tprintf(_T("other\n"));
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.
198 INT
Addhost(PTCHAR pszInetAddr
, PTCHAR pszEthAddr
, PTCHAR pszIfAddr
)
200 PMIB_IPNETROW pAddHost
;
201 PMIB_IPADDRTABLE pIpAddrTable
;
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
);
219 /* check MAC address */
220 if (strlen(pszEthAddr
) != 17) {
221 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
224 for (i
=0; i
<17; i
++) {
225 if (pszEthAddr
[i
] == SEPERATOR
) {
228 if (!isxdigit(pszEthAddr
[i
])) {
229 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
234 /* reserve memory on heap and zero */
235 pAddHost
= (MIB_IPNETROW
*) malloc(sizeof(MIB_IPNETROW
));
236 ZeroMemory(pAddHost
, sizeof(MIB_IPNETROW
));
241 /* set dwIndex field to the index of a local IP address to
242 * indicate the network on which the ARP entry applies */
244 sscanf(pszIfAddr
, "%lx", &pAddHost
->dwIndex
);
246 /* map the IP to the index */
247 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
248 GetIpAddrTable(pIpAddrTable
, &dwSize
, 0);
250 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
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());
256 printf("printing pIpAddrTable->table[0].dwIndex = %lx\n", pIpAddrTable
->table
[0].dwIndex
);
257 pAddHost
->dwIndex
= 4;
260 /* Set MAC address to 6 bytes (typical) */
261 pAddHost
->dwPhysAddrLen
= 6;
264 /* Encode bPhysAddr into correct byte array */
265 for (i
=0; i
<6; i
++) {
267 c
= toupper(pszEthAddr
[i
*3]);
268 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
271 c
= toupper(pszEthAddr
[i
*3 + 1]);
272 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
274 pAddHost
->bPhysAddr
[i
] = val
;
279 /* copy converted IP address */
280 pAddHost
->dwAddr
= dwIpAddr
;
283 /* set type to static */
284 pAddHost
->dwType
= MIB_IPNET_TYPE_STATIC
;
287 /* Add the ARP entry */
288 if ((iRet
= SetIpNetEntry(pAddHost
)) != NO_ERROR
) {
289 _tprintf(_T("The ARP entry addition failed: %d\n"), iRet
);
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.
309 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
311 PMIB_IPNETROW pDelHost
;
312 PMIB_IPADDRTABLE pIpAddrTable
;
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
);
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 */
337 sscanf(pszIfAddr
, "%lx", &pDelHost
->dwIndex
);
339 /* map the IP to the index */
340 if (GetIpAddrTable(pIpAddrTable
, &dwSize
, 0) == ERROR_INSUFFICIENT_BUFFER
) {
341 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
343 if ((iret
= GetIpAddrTable(pIpAddrTable
, &dwSize
, TRUE
)) != NO_ERROR
) {
344 _tprintf(_T("GetIpAddrTable failed: %d\n"), iret
);
345 _tprintf(_T("error: %d\n"), WSAGetLastError());
347 pDelHost
->dwIndex
= 4; //pIpAddrTable->table[0].dwIndex;
350 /* copy converted IP address */
351 pDelHost
->dwAddr
= dwIpAddr
;
353 /* Add the ARP entry */
354 if ((iret
= DeleteIpNetEntry(pDelHost
)) != NO_ERROR
) {
355 _tprintf(_T("The ARP entry deletion failed: %d\n"), iret
);
369 * print program usage to screen
374 _tprintf(_T("\nDisplays and modifies the IP-to-Physical address translation tables used by\n"
375 "address resolution protocol (ARP).\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"
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"
387 " inet_addr Specifies an internet address.\n"
388 " -N if_addr Displays the ARP entries for the network interface specified\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"
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"
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"));
410 * Parse command line and call the required function
413 INT
main(int argc
, char* argv
[])
415 const char N
[] = "-N";
417 if ((argc
< 2) || (argc
> 5))
424 if (argv
[1][0] == '-') {
425 switch (argv
[1][1]) {
427 /* need better control for -a, as -N might not be arg 4 */
428 case 'a': if (argc
== 2)
429 DisplayArpEntries(NULL
, NULL
);
431 DisplayArpEntries(argv
[2], NULL
);
432 else if ((argc
== 5) && ((strcmp(argv
[3], N
)) == 0))
433 DisplayArpEntries(argv
[2], argv
[4]);
438 case 'd': if (argc
== 3)
439 Deletehost(argv
[2], NULL
);
441 Deletehost(argv
[2], argv
[3]);
445 case 's': if (argc
== 4)
446 Addhost(argv
[2], argv
[3], NULL
);
448 Addhost(argv
[2], argv
[3], argv
[4]);