1 /* Copyright (C) 2003 Art Yerkes 2 * A reimplementation of ifenum.c by Juan Lang 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 * This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on 19 * tcpip.sys 20 */ 21 22 #include "iphlpapi_private.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); 25 26 #ifndef TCPS_ESTABLISHED 27 # define TCPS_ESTABLISHED TCP_ESTABLISHED 28 #endif 29 #ifndef TCPS_SYN_SENT 30 # define TCPS_SYN_SENT TCP_SYN_SENT 31 #endif 32 #ifndef TCPS_SYN_RECEIVED 33 # define TCPS_SYN_RECEIVED TCP_SYN_RECV 34 #endif 35 #ifndef TCPS_FIN_WAIT_1 36 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1 37 #endif 38 #ifndef TCPS_FIN_WAIT_2 39 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2 40 #endif 41 #ifndef TCPS_TIME_WAIT 42 # define TCPS_TIME_WAIT TCP_TIME_WAIT 43 #endif 44 #ifndef TCPS_CLOSED 45 # define TCPS_CLOSED TCP_CLOSE 46 #endif 47 #ifndef TCPS_CLOSE_WAIT 48 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT 49 #endif 50 #ifndef TCPS_LAST_ACK 51 # define TCPS_LAST_ACK TCP_LAST_ACK 52 #endif 53 #ifndef TCPS_LISTEN 54 # define TCPS_LISTEN TCP_LISTEN 55 #endif 56 #ifndef TCPS_CLOSING 57 # define TCPS_CLOSING TCP_CLOSING 58 #endif 59 60 BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) { 61 return (ent->tei_entity == CL_NL_ENTITY || 62 ent->tei_entity == CO_NL_ENTITY); 63 } 64 65 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) { 66 DWORD numEntities = 0; 67 DWORD numRoutes = 0; 68 TDIEntityID *entitySet = 0; 69 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); 70 int i; 71 72 if( !NT_SUCCESS(status) ) 73 return status; 74 75 for( i = 0; i < numEntities; i++ ) { 76 if( isIpEntity( tcpFile, &entitySet[i] ) ) { 77 TRACE("Entity %d is an IP Entity\n", i); 78 if( numRoutes == index ) break; 79 else numRoutes++; 80 } 81 } 82 83 if( numRoutes == index && i < numEntities ) { 84 TRACE("Index %d is entity #%d - %04x:%08x\n", index, i, 85 entitySet[i].tei_entity, entitySet[i].tei_instance ); 86 memcpy( ent, &entitySet[i], sizeof(*ent) ); 87 tdiFreeThingSet( entitySet ); 88 return STATUS_SUCCESS; 89 } else { 90 tdiFreeThingSet( entitySet ); 91 return STATUS_UNSUCCESSFUL; 92 } 93 } 94 95 NTSTATUS tdiGetMibForIpEntity 96 ( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) { 97 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; 98 NTSTATUS status = STATUS_SUCCESS; 99 DWORD returnSize; 100 101 memset( entry, 0, sizeof( *entry ) ); 102 103 TRACE("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n", 104 (DWORD)tcpFile, ent->tei_instance); 105 106 req.ID.toi_class = INFO_CLASS_PROTOCOL; 107 req.ID.toi_type = INFO_TYPE_PROVIDER; 108 req.ID.toi_id = IP_MIB_STATS_ID; 109 req.ID.toi_entity = *ent; 110 111 status = DeviceIoControl( tcpFile, 112 IOCTL_TCP_QUERY_INFORMATION_EX, 113 &req, 114 sizeof(req), 115 entry, 116 sizeof(*entry), 117 &returnSize, 118 NULL ); 119 120 TRACE("TdiGetMibForIpEntity() => {\n" 121 " ipsi_forwarding ............ %d\n" 122 " ipsi_defaultttl ............ %d\n" 123 " ipsi_inreceives ............ %d\n" 124 " ipsi_indelivers ............ %d\n" 125 " ipsi_outrequests ........... %d\n" 126 " ipsi_routingdiscards ....... %d\n" 127 " ipsi_outdiscards ........... %d\n" 128 " ipsi_outnoroutes ........... %d\n" 129 " ipsi_numif ................. %d\n" 130 " ipsi_numaddr ............... %d\n" 131 " ipsi_numroutes ............. %d\n" 132 "} status %08x\n", 133 entry->ipsi_forwarding, 134 entry->ipsi_defaultttl, 135 entry->ipsi_inreceives, 136 entry->ipsi_indelivers, 137 entry->ipsi_outrequests, 138 entry->ipsi_routingdiscards, 139 entry->ipsi_outdiscards, 140 entry->ipsi_outnoroutes, 141 entry->ipsi_numif, 142 entry->ipsi_numaddr, 143 entry->ipsi_numroutes, 144 status); 145 146 return status; 147 } 148 149 NTSTATUS tdiGetRoutesForIpEntity 150 ( HANDLE tcpFile, TDIEntityID *ent, IPRouteEntry **routes, PDWORD numRoutes ) { 151 NTSTATUS status = STATUS_SUCCESS; 152 153 TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n", 154 (DWORD)tcpFile, ent->tei_instance); 155 156 status = tdiGetSetOfThings( tcpFile, 157 INFO_CLASS_PROTOCOL, 158 INFO_TYPE_PROVIDER, 159 IP_MIB_ARPTABLE_ENTRY_ID, 160 CL_NL_ENTITY, 161 ent->tei_instance, 162 0, 163 sizeof(IPRouteEntry), 164 (PVOID *)routes, 165 numRoutes); 166 167 return status; 168 } 169 170 NTSTATUS tdiGetIpAddrsForIpEntity 171 ( HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, PDWORD numAddrs ) { 172 NTSTATUS status; 173 174 TRACE("TdiGetIpAddrsForIpEntity(tcpFile %x,entityId %x)\n", 175 (DWORD)tcpFile, ent->tei_instance); 176 177 status = tdiGetSetOfThings( tcpFile, 178 INFO_CLASS_PROTOCOL, 179 INFO_TYPE_PROVIDER, 180 IP_MIB_ADDRTABLE_ENTRY_ID, 181 CL_NL_ENTITY, 182 ent->tei_instance, 183 0, 184 sizeof(IPAddrEntry), 185 (PVOID *)addrs, 186 numAddrs ); 187 188 return status; 189 } 190 191 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry) 192 { 193 if (!name) 194 return ERROR_INVALID_PARAMETER; 195 if (!entry) 196 return ERROR_INVALID_PARAMETER; 197 198 return NO_ERROR; 199 } 200 201 DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry) 202 { 203 return ERROR_INVALID_PARAMETER; 204 } 205 206 DWORD getICMPStats(MIB_ICMP *stats) 207 { 208 FILE *fp; 209 210 if (!stats) 211 return ERROR_INVALID_PARAMETER; 212 213 memset(stats, 0, sizeof(MIB_ICMP)); 214 /* get most of these stats from /proc/net/snmp, no error if can't */ 215 fp = fopen("/proc/net/snmp", "r"); 216 if (fp) { 217 const char hdr[] = "Icmp:"; 218 char buf[512] = { 0 }, *ptr; 219 220 do { 221 ptr = fgets(buf, sizeof(buf), fp); 222 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1)); 223 if (ptr) { 224 /* last line was a header, get another */ 225 ptr = fgets(buf, sizeof(buf), fp); 226 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) { 227 char *endPtr; 228 229 ptr += sizeof(hdr); 230 if (ptr && *ptr) { 231 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10); 232 ptr = endPtr; 233 } 234 if (ptr && *ptr) { 235 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10); 236 ptr = endPtr; 237 } 238 if (ptr && *ptr) { 239 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); 240 ptr = endPtr; 241 } 242 if (ptr && *ptr) { 243 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); 244 ptr = endPtr; 245 } 246 if (ptr && *ptr) { 247 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10); 248 ptr = endPtr; 249 } 250 if (ptr && *ptr) { 251 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); 252 ptr = endPtr; 253 } 254 if (ptr && *ptr) { 255 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10); 256 ptr = endPtr; 257 } 258 if (ptr && *ptr) { 259 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10); 260 ptr = endPtr; 261 } 262 if (ptr && *ptr) { 263 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10); 264 ptr = endPtr; 265 } 266 if (ptr && *ptr) { 267 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); 268 ptr = endPtr; 269 } 270 if (ptr && *ptr) { 271 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); 272 ptr = endPtr; 273 } 274 if (ptr && *ptr) { 275 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); 276 ptr = endPtr; 277 } 278 if (ptr && *ptr) { 279 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10); 280 ptr = endPtr; 281 } 282 if (ptr && *ptr) { 283 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10); 284 ptr = endPtr; 285 } 286 if (ptr && *ptr) { 287 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); 288 ptr = endPtr; 289 } 290 if (ptr && *ptr) { 291 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); 292 ptr = endPtr; 293 } 294 if (ptr && *ptr) { 295 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10); 296 ptr = endPtr; 297 } 298 if (ptr && *ptr) { 299 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); 300 ptr = endPtr; 301 } 302 if (ptr && *ptr) { 303 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10); 304 ptr = endPtr; 305 } 306 if (ptr && *ptr) { 307 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10); 308 ptr = endPtr; 309 } 310 if (ptr && *ptr) { 311 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10); 312 ptr = endPtr; 313 } 314 if (ptr && *ptr) { 315 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); 316 ptr = endPtr; 317 } 318 if (ptr && *ptr) { 319 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); 320 ptr = endPtr; 321 } 322 if (ptr && *ptr) { 323 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); 324 ptr = endPtr; 325 } 326 } 327 } 328 fclose(fp); 329 } 330 return NO_ERROR; 331 } 332 333 DWORD getIPStats(PMIB_IPSTATS stats, DWORD family) 334 { 335 if (!stats) 336 return ERROR_INVALID_PARAMETER; 337 return NO_ERROR; 338 } 339 340 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family) 341 { 342 if (!stats) 343 return ERROR_INVALID_PARAMETER; 344 return NO_ERROR; 345 } 346 347 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family) 348 { 349 if (!stats) 350 return ERROR_INVALID_PARAMETER; 351 return NO_ERROR; 352 } 353 354 static DWORD getNumWithOneHeader(const char *filename) 355 { 356 return 0; 357 } 358 359 DWORD getNumRoutes(void) 360 { 361 DWORD numEntities, numRoutes = 0; 362 TDIEntityID *entitySet; 363 HANDLE tcpFile; 364 int i; 365 NTSTATUS status; 366 367 TRACE("called.\n"); 368 369 status = openTcpFile( &tcpFile, FILE_READ_DATA ); 370 371 if( !NT_SUCCESS(status) ) { 372 TRACE("failure: %08x\n", (int)status ); 373 return 0; 374 } 375 376 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); 377 378 if( !NT_SUCCESS(status) ) { 379 TRACE("failure: %08x\n", (int)status ); 380 closeTcpFile( tcpFile ); 381 return 0; 382 } 383 384 for( i = 0; i < numEntities; i++ ) { 385 if( isIpEntity( tcpFile, &entitySet[i] ) ) { 386 IPSNMPInfo isnmp; 387 memset( &isnmp, 0, sizeof( isnmp ) ); 388 status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp ); 389 if( !NT_SUCCESS(status) ) { 390 WARN("tdiGetMibForIpEntity failed for i = %d", i); 391 numRoutes = 0; 392 break; 393 } 394 numRoutes += isnmp.ipsi_numroutes; 395 } 396 } 397 398 TRACE("numRoutes: %d\n", (int)numRoutes); 399 400 tdiFreeThingSet( entitySet ); 401 closeTcpFile( tcpFile ); 402 403 return numRoutes; 404 } 405 406 VOID HexDump( PCHAR Data, DWORD Len ) { 407 int i; 408 409 for( i = 0; i < Len; i++ ) { 410 if( !(i & 0xf) ) { 411 if( i ) fprintf(stderr,"\n"); 412 fprintf(stderr,"%08x:", i); 413 } 414 fprintf( stderr, " %02x", Data[i] & 0xff ); 415 } 416 fprintf(stderr,"\n"); 417 } 418 419 RouteTable *getRouteTable(void) 420 { 421 RouteTable *out_route_table; 422 DWORD numRoutes = getNumRoutes(), routesAdded = 0; 423 TDIEntityID ent; 424 HANDLE tcpFile; 425 NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA ); 426 int i; 427 428 if( !NT_SUCCESS(status) ) 429 return 0; 430 431 TRACE("GETTING ROUTE TABLE\n"); 432 433 out_route_table = HeapAlloc( GetProcessHeap(), 0, 434 sizeof(RouteTable) + 435 (sizeof(RouteEntry) * (numRoutes - 1)) ); 436 if (!out_route_table) { 437 closeTcpFile(tcpFile); 438 return NULL; 439 } 440 441 out_route_table->numRoutes = numRoutes; 442 443 for( i = 0; routesAdded < out_route_table->numRoutes; i++ ) { 444 int j; 445 IPRouteEntry *route_set; 446 447 getNthIpEntity( tcpFile, i, &ent ); 448 449 tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes ); 450 451 if( !route_set ) { 452 closeTcpFile( tcpFile ); 453 HeapFree( GetProcessHeap(), 0, out_route_table ); 454 return 0; 455 } 456 457 TRACE( "%d routes in instance %d\n", numRoutes, i ); 458 #if 0 459 HexDump( route_set, 460 sizeof( IPRouteEntry ) * 461 snmpInfo.ipsi_numroutes ); 462 #endif 463 464 for( j = 0; j < numRoutes; j++ ) { 465 int routeNum = j + routesAdded; 466 out_route_table->routes[routeNum].dest = 467 route_set[j].ire_dest; 468 out_route_table->routes[routeNum].mask = 469 route_set[j].ire_mask; 470 out_route_table->routes[routeNum].gateway = 471 route_set[j].ire_gw; 472 out_route_table->routes[routeNum].ifIndex = 473 route_set[j].ire_index; 474 out_route_table->routes[routeNum].metric = 475 route_set[j].ire_metric1; 476 } 477 478 if( route_set ) tdiFreeThingSet( route_set ); 479 480 routesAdded += numRoutes; 481 } 482 483 closeTcpFile( tcpFile ); 484 485 TRACE("Return: %08x, %08x\n", status, out_route_table); 486 487 return out_route_table; 488 } 489 490 DWORD getNumArpEntries(void) 491 { 492 DWORD numEntities; 493 TDIEntityID *entitySet = NULL; 494 HANDLE tcpFile; 495 int i, totalNumber = 0; 496 NTSTATUS status; 497 PMIB_IPNETROW IpArpTable = NULL; 498 DWORD returnSize; 499 500 TRACE("called.\n"); 501 502 status = openTcpFile( &tcpFile, FILE_READ_DATA ); 503 504 if( !NT_SUCCESS(status) ) { 505 TRACE("failure: %08x\n", (int)status ); 506 return 0; 507 } 508 509 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); 510 511 for( i = 0; i < numEntities; i++ ) { 512 if( isInterface( &entitySet[i] ) && 513 hasArp( tcpFile, &entitySet[i] ) ) { 514 515 status = tdiGetSetOfThings( tcpFile, 516 INFO_CLASS_PROTOCOL, 517 INFO_TYPE_PROVIDER, 518 IP_MIB_ARPTABLE_ENTRY_ID, 519 AT_ENTITY, 520 entitySet[i].tei_instance, 521 0, 522 sizeof(MIB_IPNETROW), 523 (PVOID *)&IpArpTable, 524 &returnSize ); 525 526 if( status == STATUS_SUCCESS ) totalNumber += returnSize; 527 if( IpArpTable ) { 528 tdiFreeThingSet( IpArpTable ); 529 IpArpTable = NULL; 530 } 531 } 532 } 533 534 closeTcpFile( tcpFile ); 535 if( IpArpTable ) tdiFreeThingSet( IpArpTable ); 536 if( entitySet ) tdiFreeThingSet( entitySet ); 537 return totalNumber; 538 } 539 540 PMIB_IPNETTABLE getArpTable(void) 541 { 542 DWORD numEntities, returnSize; 543 TDIEntityID *entitySet; 544 HANDLE tcpFile; 545 int i, totalNumber, TmpIdx, CurrIdx = 0; 546 NTSTATUS status; 547 PMIB_IPNETTABLE IpArpTable = NULL; 548 PMIB_IPNETROW AdapterArpTable = NULL; 549 550 TRACE("called.\n"); 551 552 totalNumber = getNumArpEntries(); 553 554 status = openTcpFile( &tcpFile, FILE_READ_DATA ); 555 556 if( !NT_SUCCESS(status) ) { 557 TRACE("failure: %08x\n", (int)status ); 558 return 0; 559 } 560 561 IpArpTable = HeapAlloc 562 ( GetProcessHeap(), 0, 563 sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) ); 564 if (!IpArpTable) { 565 closeTcpFile(tcpFile); 566 return NULL; 567 } 568 569 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); 570 571 for( i = 0; i < numEntities; i++ ) { 572 if( isInterface( &entitySet[i] ) && 573 hasArp( tcpFile, &entitySet[i] ) ) { 574 575 status = tdiGetSetOfThings( tcpFile, 576 INFO_CLASS_PROTOCOL, 577 INFO_TYPE_PROVIDER, 578 IP_MIB_ARPTABLE_ENTRY_ID, 579 AT_ENTITY, 580 entitySet[i].tei_instance, 581 0, 582 sizeof(MIB_IPNETROW), 583 (PVOID *)&AdapterArpTable, 584 &returnSize ); 585 586 if( status == STATUS_SUCCESS ) { 587 for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ ) 588 IpArpTable->table[CurrIdx] = AdapterArpTable[TmpIdx]; 589 tdiFreeThingSet( AdapterArpTable ); 590 } 591 } 592 } 593 594 closeTcpFile( tcpFile ); 595 596 tdiFreeThingSet( entitySet ); 597 IpArpTable->dwNumEntries = CurrIdx; 598 599 return IpArpTable; 600 } 601 602 DWORD getNumUdpEntries(void) 603 { 604 return getNumWithOneHeader("/proc/net/udp"); 605 } 606 607 PMIB_UDPTABLE getUdpTable(void) 608 { 609 DWORD numEntries = getNumUdpEntries(); 610 PMIB_UDPTABLE ret; 611 612 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) + 613 (numEntries - 1) * sizeof(MIB_UDPROW)); 614 if (ret) { 615 FILE *fp; 616 617 /* get from /proc/net/udp, no error if can't */ 618 fp = fopen("/proc/net/udp", "r"); 619 if (fp) { 620 char buf[512] = { 0 }, *ptr; 621 622 /* skip header line */ 623 ptr = fgets(buf, sizeof(buf), fp); 624 while (ptr && ret->dwNumEntries < numEntries) { 625 ptr = fgets(buf, sizeof(buf), fp); 626 if (ptr) { 627 char *endPtr; 628 629 if (ptr && *ptr) { 630 strtoul(ptr, &endPtr, 16); /* skip */ 631 ptr = endPtr; 632 } 633 if (ptr && *ptr) { 634 ptr++; 635 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr, 636 16); 637 ptr = endPtr; 638 } 639 if (ptr && *ptr) { 640 ptr++; 641 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr, 642 16); 643 ptr = endPtr; 644 } 645 ret->dwNumEntries++; 646 } 647 } 648 fclose(fp); 649 } 650 } 651 return ret; 652 } 653 654 DWORD getNumTcpEntries(void) 655 { 656 return getNumWithOneHeader("/proc/net/tcp"); 657 } 658 659 PMIB_TCPTABLE getTcpTable(void) 660 { 661 return 0; 662 } 663