1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
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.
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.
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 St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
23 #include "wine/port.h"
24 #include "wine/debug.h"
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
75 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
87 #ifndef HAVE_NETINET_TCP_FSM_H
88 #define TCPS_ESTABLISHED 1
89 #define TCPS_SYN_SENT 2
90 #define TCPS_SYN_RECEIVED 3
91 #define TCPS_FIN_WAIT_1 4
92 #define TCPS_FIN_WAIT_2 5
93 #define TCPS_TIME_WAIT 6
95 #define TCPS_CLOSE_WAIT 8
96 #define TCPS_LAST_ACK 9
97 #define TCPS_LISTEN 10
98 #define TCPS_CLOSING 11
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
103 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
108 return ERROR_INVALID_PARAMETER
;
110 return ERROR_INVALID_PARAMETER
;
112 /* get interface stats from /proc/net/dev, no error if can't
113 no inUnknownProtos, outNUcastPkts, outQLen */
114 fp
= fopen("/proc/net/dev", "r");
116 char buf
[512] = { 0 }, *ptr
;
117 int nameLen
= strlen(name
), nameFound
= 0;
120 ptr
= fgets(buf
, sizeof(buf
), fp
);
121 while (ptr
&& !nameFound
) {
122 while (*ptr
&& isspace(*ptr
))
124 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
127 ptr
= fgets(buf
, sizeof(buf
), fp
);
134 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
138 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
142 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
146 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
150 strtoul(ptr
, &endPtr
, 10); /* skip */
154 strtoul(ptr
, &endPtr
, 10); /* skip */
158 strtoul(ptr
, &endPtr
, 10); /* skip */
162 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
166 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
170 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
174 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
178 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
186 ERR ("unimplemented!\n");
187 return ERROR_NOT_SUPPORTED
;
193 DWORD
getICMPStats(MIB_ICMP
*stats
)
198 return ERROR_INVALID_PARAMETER
;
200 memset(stats
, 0, sizeof(MIB_ICMP
));
201 /* get most of these stats from /proc/net/snmp, no error if can't */
202 fp
= fopen("/proc/net/snmp", "r");
204 static const char hdr
[] = "Icmp:";
205 char buf
[512] = { 0 }, *ptr
;
208 ptr
= fgets(buf
, sizeof(buf
), fp
);
209 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
211 /* last line was a header, get another */
212 ptr
= fgets(buf
, sizeof(buf
), fp
);
213 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
218 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
222 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
226 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
230 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
234 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
238 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
242 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
246 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
250 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
254 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
258 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
262 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
266 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
270 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
274 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
278 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
282 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
286 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
290 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
294 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
298 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
302 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
306 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
310 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
319 ERR ("unimplemented!\n");
320 return ERROR_NOT_SUPPORTED
;
326 DWORD
getIPStats(PMIB_IPSTATS stats
)
331 return ERROR_INVALID_PARAMETER
;
333 memset(stats
, 0, sizeof(MIB_IPSTATS
));
334 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
335 stats
->dwNumRoutes
= getNumRoutes();
337 /* get most of these stats from /proc/net/snmp, no error if can't */
338 fp
= fopen("/proc/net/snmp", "r");
340 static const char hdr
[] = "Ip:";
341 char buf
[512] = { 0 }, *ptr
;
344 ptr
= fgets(buf
, sizeof(buf
), fp
);
345 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
347 /* last line was a header, get another */
348 ptr
= fgets(buf
, sizeof(buf
), fp
);
349 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
354 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
358 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
362 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
366 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
370 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
374 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
378 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
382 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
386 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
390 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
394 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
398 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
402 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
406 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
410 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
414 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
418 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
422 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
426 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
429 /* hmm, no routingDiscards */
436 ERR ("unimplemented!\n");
437 return ERROR_NOT_SUPPORTED
;
443 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
448 return ERROR_INVALID_PARAMETER
;
450 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
452 /* get from /proc/net/snmp, no error if can't */
453 fp
= fopen("/proc/net/snmp", "r");
455 static const char hdr
[] = "Tcp:";
456 char buf
[512] = { 0 }, *ptr
;
460 ptr
= fgets(buf
, sizeof(buf
), fp
);
461 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
463 /* last line was a header, get another */
464 ptr
= fgets(buf
, sizeof(buf
), fp
);
465 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
470 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
474 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
478 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
482 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
486 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
490 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
494 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
498 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
502 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
506 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
510 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
514 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
518 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
522 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
525 stats
->dwNumConns
= getNumTcpEntries();
532 ERR ("unimplemented!\n");
533 return ERROR_NOT_SUPPORTED
;
539 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
544 return ERROR_INVALID_PARAMETER
;
546 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
548 /* get from /proc/net/snmp, no error if can't */
549 fp
= fopen("/proc/net/snmp", "r");
551 static const char hdr
[] = "Udp:";
552 char buf
[512] = { 0 }, *ptr
;
556 ptr
= fgets(buf
, sizeof(buf
), fp
);
557 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
559 /* last line was a header, get another */
560 ptr
= fgets(buf
, sizeof(buf
), fp
);
561 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
566 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
570 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
574 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
578 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
582 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
591 ERR ("unimplemented!\n");
592 return ERROR_NOT_SUPPORTED
;
598 static DWORD
getNumWithOneHeader(const char *filename
)
600 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
603 struct xinpgen
*pXIG
, *pOrigXIG
;
605 DWORD NumEntries
= 0;
607 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
608 Protocol
= IPPROTO_TCP
;
609 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
610 Protocol
= IPPROTO_UDP
;
613 ERR ("Unsupported mib '%s', needs protocol mapping\n",
618 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
620 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
624 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
627 ERR ("Out of memory!\n");
631 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
633 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
634 HeapFree (GetProcessHeap (), 0, Buf
);
638 /* Might be nothing here; first entry is just a header it seems */
639 if (Len
<= sizeof (struct xinpgen
))
641 HeapFree (GetProcessHeap (), 0, Buf
);
645 pOrigXIG
= (struct xinpgen
*)Buf
;
648 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
649 pXIG
->xig_len
> sizeof (struct xinpgen
);
650 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
652 struct tcpcb
*pTCPData
= NULL
;
653 struct inpcb
*pINData
;
654 struct xsocket
*pSockData
;
656 if (Protocol
== IPPROTO_TCP
)
658 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
659 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
660 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
664 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
665 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
668 /* Ignore sockets for other protocols */
669 if (pSockData
->xso_protocol
!= Protocol
)
672 /* Ignore PCBs that were freed while generating the data */
673 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
676 /* we're only interested in IPv4 addresses */
677 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
678 (pINData
->inp_vflag
& INP_IPV6
))
681 /* If all 0's, skip it */
682 if (!pINData
->inp_laddr
.s_addr
&&
683 !pINData
->inp_lport
&&
684 !pINData
->inp_faddr
.s_addr
&&
691 HeapFree (GetProcessHeap (), 0, Buf
);
697 fp
= fopen(filename
, "r");
699 char buf
[512] = { 0 }, *ptr
;
702 ptr
= fgets(buf
, sizeof(buf
), fp
);
705 ptr
= fgets(buf
, sizeof(buf
), fp
);
713 ERR ("Unable to open '%s' to count entries!\n", filename
);
719 DWORD
getNumRoutes(void)
721 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
722 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
724 char *buf
, *lim
, *next
;
725 struct rt_msghdr
*rtm
;
726 DWORD RouteCount
= 0;
728 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
730 ERR ("sysctl 1 failed!\n");
734 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
737 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
739 ERR ("sysctl 2 failed!\n");
740 HeapFree (GetProcessHeap (), 0, buf
);
745 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
747 rtm
= (struct rt_msghdr
*)next
;
749 if (rtm
->rtm_type
!= RTM_GET
)
751 WARN ("Got unexpected message type 0x%x!\n",
756 /* Ignore all entries except for gateway routes which aren't
758 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
764 HeapFree (GetProcessHeap (), 0, buf
);
767 return getNumWithOneHeader("/proc/net/route");
771 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
776 if (!ppIpForwardTable
)
777 ret
= ERROR_INVALID_PARAMETER
;
779 DWORD numRoutes
= getNumRoutes();
780 DWORD size
= sizeof(MIB_IPFORWARDTABLE
);
781 PMIB_IPFORWARDTABLE table
;
784 size
+= (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
);
785 table
= HeapAlloc(heap
, flags
, size
);
787 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
788 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
790 char *buf
, *lim
, *next
, *addrPtr
;
791 struct rt_msghdr
*rtm
;
793 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
795 ERR ("sysctl 1 failed!\n");
796 HeapFree (GetProcessHeap (), 0, table
);
800 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
803 HeapFree (GetProcessHeap (), 0, table
);
804 return ERROR_OUTOFMEMORY
;
807 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
809 ERR ("sysctl 2 failed!\n");
810 HeapFree (GetProcessHeap (), 0, table
);
811 HeapFree (GetProcessHeap (), 0, buf
);
815 *ppIpForwardTable
= table
;
816 table
->dwNumEntries
= 0;
819 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
823 rtm
= (struct rt_msghdr
*)next
;
825 if (rtm
->rtm_type
!= RTM_GET
)
827 WARN ("Got unexpected message type 0x%x!\n",
832 /* Ignore all entries except for gateway routes which aren't
834 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
835 (rtm
->rtm_flags
& RTF_MULTICAST
))
838 memset (&table
->table
[table
->dwNumEntries
], 0,
839 sizeof (MIB_IPFORWARDROW
));
840 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
841 table
->table
[table
->dwNumEntries
].dwForwardType
=
842 MIB_IPROUTE_TYPE_INDIRECT
;
843 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
844 rtm
->rtm_rmx
.rmx_hopcount
;
845 table
->table
[table
->dwNumEntries
].dwForwardProto
=
848 addrPtr
= (char *)(rtm
+ 1);
850 for (i
= 1; i
; i
<<= 1)
855 if (!(i
& rtm
->rtm_addrs
))
858 sa
= (struct sockaddr
*)addrPtr
;
859 ADVANCE (addrPtr
, sa
);
861 /* default routes are encoded by length-zero sockaddr */
864 else if (sa
->sa_family
!= AF_INET
)
866 ERR ("Received unsupported sockaddr family 0x%x\n",
872 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
874 addr
= sin
->sin_addr
.s_addr
;
880 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
884 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
888 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
892 ERR ("Unexpected address type 0x%x\n", i
);
896 table
->dwNumEntries
++;
899 HeapFree (GetProcessHeap (), 0, buf
);
905 *ppIpForwardTable
= table
;
906 table
->dwNumEntries
= 0;
907 /* get from /proc/net/route, no error if can't */
908 fp
= fopen("/proc/net/route", "r");
910 char buf
[512] = { 0 }, *ptr
;
912 /* skip header line */
913 ptr
= fgets(buf
, sizeof(buf
), fp
);
914 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
915 memset(&table
->table
[table
->dwNumEntries
], 0,
916 sizeof(MIB_IPFORWARDROW
));
917 ptr
= fgets(buf
, sizeof(buf
), fp
);
921 while (!isspace(*ptr
))
925 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
928 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
930 table
->table
[table
->dwNumEntries
].dwForwardDest
=
931 strtoul(ptr
, &endPtr
, 16);
935 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
936 strtoul(ptr
, &endPtr
, 16);
940 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
942 if (!(flags
& RTF_UP
))
943 table
->table
[table
->dwNumEntries
].dwForwardType
=
944 MIB_IPROUTE_TYPE_INVALID
;
945 else if (flags
& RTF_GATEWAY
)
946 table
->table
[table
->dwNumEntries
].dwForwardType
=
947 MIB_IPROUTE_TYPE_INDIRECT
;
949 table
->table
[table
->dwNumEntries
].dwForwardType
=
950 MIB_IPROUTE_TYPE_DIRECT
;
954 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
958 strtoul(ptr
, &endPtr
, 16); /* use, skip */
962 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
963 strtoul(ptr
, &endPtr
, 16);
967 table
->table
[table
->dwNumEntries
].dwForwardMask
=
968 strtoul(ptr
, &endPtr
, 16);
971 /* FIXME: other protos might be appropriate, e.g. the default
972 * route is typically set with MIB_IPPROTO_NETMGMT instead */
973 table
->table
[table
->dwNumEntries
].dwForwardProto
=
975 table
->dwNumEntries
++;
983 ERR ("unimplemented!\n");
984 return ERROR_NOT_SUPPORTED
;
989 ret
= ERROR_OUTOFMEMORY
;
994 DWORD
getNumArpEntries(void)
996 return getNumWithOneHeader("/proc/net/arp");
999 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
1003 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1004 ERR ("unimplemented!\n");
1005 return ERROR_NOT_SUPPORTED
;
1009 ret
= ERROR_INVALID_PARAMETER
;
1011 DWORD numEntries
= getNumArpEntries();
1012 DWORD size
= sizeof(MIB_IPNETTABLE
);
1013 PMIB_IPNETTABLE table
;
1016 size
+= (numEntries
- 1) * sizeof(MIB_IPNETROW
);
1017 table
= HeapAlloc(heap
, flags
, size
);
1022 *ppIpNetTable
= table
;
1023 table
->dwNumEntries
= 0;
1024 /* get from /proc/net/arp, no error if can't */
1025 fp
= fopen("/proc/net/arp", "r");
1027 char buf
[512] = { 0 }, *ptr
;
1029 /* skip header line */
1030 ptr
= fgets(buf
, sizeof(buf
), fp
);
1031 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1032 ptr
= fgets(buf
, sizeof(buf
), fp
);
1036 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1037 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1038 while (ptr
&& *ptr
&& !isspace(*ptr
))
1042 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1046 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1049 if (flags
& ATF_COM
)
1050 table
->table
[table
->dwNumEntries
].dwType
=
1051 MIB_IPNET_TYPE_DYNAMIC
;
1055 if (flags
& ATF_PERM
)
1056 table
->table
[table
->dwNumEntries
].dwType
=
1057 MIB_IPNET_TYPE_STATIC
;
1060 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1064 while (ptr
&& *ptr
&& isspace(*ptr
))
1066 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1067 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1069 if (endPtr
&& *endPtr
) {
1071 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1072 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1078 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1081 getInterfaceIndexByName(ptr
,
1082 &table
->table
[table
->dwNumEntries
].dwIndex
);
1083 table
->dwNumEntries
++;
1089 ret
= ERROR_NOT_SUPPORTED
;
1092 ret
= ERROR_OUTOFMEMORY
;
1097 DWORD
getNumUdpEntries(void)
1099 return getNumWithOneHeader("/proc/net/udp");
1102 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1106 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1107 ERR ("unimplemented!\n");
1108 return ERROR_NOT_SUPPORTED
;
1112 ret
= ERROR_INVALID_PARAMETER
;
1114 DWORD numEntries
= getNumUdpEntries();
1115 DWORD size
= sizeof(MIB_UDPTABLE
);
1116 PMIB_UDPTABLE table
;
1119 size
+= (numEntries
- 1) * sizeof(MIB_UDPROW
);
1120 table
= HeapAlloc(heap
, flags
, size
);
1125 *ppUdpTable
= table
;
1126 table
->dwNumEntries
= 0;
1127 /* get from /proc/net/udp, no error if can't */
1128 fp
= fopen("/proc/net/udp", "r");
1130 char buf
[512] = { 0 }, *ptr
;
1132 /* skip header line */
1133 ptr
= fgets(buf
, sizeof(buf
), fp
);
1134 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1135 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_UDPROW
));
1136 ptr
= fgets(buf
, sizeof(buf
), fp
);
1141 strtoul(ptr
, &endPtr
, 16); /* skip */
1146 table
->table
[table
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
,
1152 table
->table
[table
->dwNumEntries
].dwLocalPort
= strtoul(ptr
,
1156 table
->dwNumEntries
++;
1162 ret
= ERROR_NOT_SUPPORTED
;
1165 ret
= ERROR_OUTOFMEMORY
;
1171 DWORD
getNumTcpEntries(void)
1173 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1174 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1176 return getNumWithOneHeader ("/proc/net/tcp");
1181 /* Why not a lookup table? Because the TCPS_* constants are different
1182 on different platforms */
1183 static DWORD
TCPStateToMIBState (int state
)
1187 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1188 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1189 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1190 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1191 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1192 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1193 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1194 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1195 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1196 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1198 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1203 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, DWORD maxEntries
, HANDLE heap
,
1207 PMIB_TCPTABLE table
;
1208 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1211 struct xinpgen
*pXIG
, *pOrigXIG
;
1214 char buf
[512] = { 0 }, *ptr
;
1218 return ERROR_INVALID_PARAMETER
;
1220 numEntries
= getNumTcpEntries ();
1224 DWORD size
= sizeof(MIB_TCPTABLE
);
1227 size
+= (numEntries
- 1) * sizeof (MIB_TCPROW
);
1228 *ppTcpTable
= HeapAlloc (heap
, flags
, size
);
1231 ERR ("Out of memory!\n");
1232 return ERROR_OUTOFMEMORY
;
1234 maxEntries
= numEntries
;
1237 table
= *ppTcpTable
;
1238 table
->dwNumEntries
= 0;
1242 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1244 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1246 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1247 return ERROR_OUTOFMEMORY
;
1250 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1253 ERR ("Out of memory!\n");
1254 return ERROR_OUTOFMEMORY
;
1257 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1259 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1260 HeapFree (GetProcessHeap (), 0, Buf
);
1261 return ERROR_OUTOFMEMORY
;
1264 /* Might be nothing here; first entry is just a header it seems */
1265 if (Len
<= sizeof (struct xinpgen
))
1267 HeapFree (GetProcessHeap (), 0, Buf
);
1271 pOrigXIG
= (struct xinpgen
*)Buf
;
1274 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1275 (pXIG
->xig_len
> sizeof (struct xinpgen
)) &&
1276 (table
->dwNumEntries
< maxEntries
);
1277 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1279 struct tcpcb
*pTCPData
= NULL
;
1280 struct inpcb
*pINData
;
1281 struct xsocket
*pSockData
;
1283 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1284 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1285 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1287 /* Ignore sockets for other protocols */
1288 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1291 /* Ignore PCBs that were freed while generating the data */
1292 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1295 /* we're only interested in IPv4 addresses */
1296 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1297 (pINData
->inp_vflag
& INP_IPV6
))
1300 /* If all 0's, skip it */
1301 if (!pINData
->inp_laddr
.s_addr
&&
1302 !pINData
->inp_lport
&&
1303 !pINData
->inp_faddr
.s_addr
&&
1304 !pINData
->inp_fport
)
1307 /* Fill in structure details */
1308 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1309 pINData
->inp_laddr
.s_addr
;
1310 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1312 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1313 pINData
->inp_faddr
.s_addr
;
1314 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1316 table
->table
[table
->dwNumEntries
].dwState
=
1317 TCPStateToMIBState (pTCPData
->t_state
);
1319 table
->dwNumEntries
++;
1322 HeapFree (GetProcessHeap (), 0, Buf
);
1324 /* get from /proc/net/tcp, no error if can't */
1325 fp
= fopen("/proc/net/tcp", "r");
1327 return ERROR_NOT_SUPPORTED
;
1329 /* skip header line */
1330 ptr
= fgets(buf
, sizeof(buf
), fp
);
1331 while (ptr
&& table
->dwNumEntries
< maxEntries
) {
1332 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_TCPROW
));
1333 ptr
= fgets(buf
, sizeof(buf
), fp
);
1337 while (ptr
&& *ptr
&& *ptr
!= ':')
1342 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1343 strtoul(ptr
, &endPtr
, 16);
1348 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1349 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1353 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1354 strtoul(ptr
, &endPtr
, 16);
1359 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1360 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1364 DWORD state
= strtoul(ptr
, &endPtr
, 16);
1366 table
->table
[table
->dwNumEntries
].dwState
=
1367 TCPStateToMIBState (state
);
1370 table
->dwNumEntries
++;