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
);
220 /* check MAC address */
221 if (strlen(pszEthAddr
) != 17) {
222 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
225 for (i
=0; i
<17; i
++) {
226 if (pszEthAddr
[i
] == SEPERATOR
) {
229 if (!isxdigit(pszEthAddr
[i
])) {
230 _tprintf(_T("ARP: bad argument: %s\n"), pszEthAddr
);
235 /* reserve memory on heap and zero */
236 pAddHost
= (MIB_IPNETROW
*) malloc(sizeof(MIB_IPNETROW
));
237 ZeroMemory(pAddHost
, sizeof(MIB_IPNETROW
));
242 /* set dwIndex field to the index of a local IP address to
243 * indicate the network on which the ARP entry applies */
245 sscanf(pszIfAddr
, "%lx", &pAddHost
->dwIndex
);
247 /* map the IP to the index */
248 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
249 GetIpAddrTable(pIpAddrTable
, &dwSize
, 0);
251 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
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());
257 printf("printing pIpAddrTable->table[0].dwIndex = %lx\n", pIpAddrTable
->table
[0].dwIndex
);
258 pAddHost
->dwIndex
= 4;
263 /* Set MAC address to 6 bytes (typical) */
264 pAddHost
->dwPhysAddrLen
= 6;
267 /* Encode bPhysAddr into correct byte array */
268 for (i
=0; i
<6; i
++) {
270 c
= toupper(pszEthAddr
[i
*3]);
271 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
274 c
= toupper(pszEthAddr
[i
*3 + 1]);
275 c
= c
- (isdigit(c
) ? '0' : ('A' - 10));
277 pAddHost
->bPhysAddr
[i
] = val
;
282 /* copy converted IP address */
283 pAddHost
->dwAddr
= dwIpAddr
;
286 /* set type to static */
287 pAddHost
->dwType
= MIB_IPNET_TYPE_STATIC
;
290 /* Add the ARP entry */
291 if ((iRet
= SetIpNetEntry(pAddHost
)) != NO_ERROR
) {
292 _tprintf(_T("The ARP entry addition failed: %d\n"), iRet
);
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.
311 INT
Deletehost(PTCHAR pszInetAddr
, PTCHAR pszIfAddr
)
313 PMIB_IPNETROW pDelHost
;
314 PMIB_IPADDRTABLE pIpAddrTable
;
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
);
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 */
339 sscanf(pszIfAddr
, "%lx", &pDelHost
->dwIndex
);
341 /* map the IP to the index */
342 if (GetIpAddrTable(pIpAddrTable
, &dwSize
, 0) == ERROR_INSUFFICIENT_BUFFER
) {
343 pIpAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
345 if ((iret
= GetIpAddrTable(pIpAddrTable
, &dwSize
, TRUE
)) != NO_ERROR
) {
346 _tprintf(_T("GetIpAddrTable failed: %d\n"), iret
);
347 _tprintf(_T("error: %d\n"), WSAGetLastError());
349 pDelHost
->dwIndex
= 4; //pIpAddrTable->table[0].dwIndex;
352 /* copy converted IP address */
353 pDelHost
->dwAddr
= dwIpAddr
;
355 /* Add the ARP entry */
356 if ((iret
= DeleteIpNetEntry(pDelHost
)) != NO_ERROR
) {
357 _tprintf(_T("The ARP entry deletion failed: %d\n"), iret
);
371 * print program usage to screen
376 _tprintf(_T("\nDisplays and modifies the IP-to-Physical address translation tables used by\n"
377 "address resolution protocol (ARP).\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"
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"
389 " inet_addr Specifies an internet address.\n"
390 " -N if_addr Displays the ARP entries for the network interface specified\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"
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"
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"));
412 * Parse command line and call the required function
415 INT
main(int argc
, char* argv
[])
417 const char N
[] = "-N";
419 if ((argc
< 2) || (argc
> 5))
426 if (argv
[1][0] == '-') {
427 switch (argv
[1][1]) {
429 /* need better control for -a, as -N might not be arg 4 */
430 case 'a': if (argc
== 2)
431 DisplayArpEntries(NULL
, NULL
);
433 DisplayArpEntries(argv
[2], NULL
);
434 else if ((argc
== 5) && ((strcmp(argv
[3], N
)) == 0))
435 DisplayArpEntries(argv
[2], argv
[4]);
440 case 'd': if (argc
== 3)
441 Deletehost(argv
[2], NULL
);
443 Deletehost(argv
[2], argv
[3]);
447 case 's': if (argc
== 4)
448 Addhost(argv
[2], argv
[3], NULL
);
450 Addhost(argv
[2], argv
[3], argv
[4]);